From 07c2b01e845fc99aa98b80c22e4c8556c1e1a31e Mon Sep 17 00:00:00 2001 From: T3sh Date: Tue, 13 Oct 2026 23:32:36 -0300 Subject: [PATCH 01/24] feat(i18n): registra locale pt-BR e adiciona check de paridade - src/renderer/src/i18n/index.ts: LANGUAGES + resources + supportedLngs - src/renderer/src/i18n/locales/pt-BR.json: stub inicial (copia de en.json, 1203 chaves) - tools/check-ptBR-parity.cjs + npm run check:ptBR: ausentes/orfas/placeholders --- package.json | 1 + src/renderer/src/i18n/index.ts | 5 +- src/renderer/src/i18n/locales/pt-BR.json | 1409 ++++++++++++++++++++++ tools/check-ptBR-parity.cjs | 111 ++ 4 files changed, 1525 insertions(+), 1 deletion(-) create mode 100644 src/renderer/src/i18n/locales/pt-BR.json create mode 100644 tools/check-ptBR-parity.cjs diff --git a/package.json b/package.json index eb5a2384df..706152bc6e 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "typecheck": "npm run typecheck:node && npm run typecheck:web", "test:focused": "node --test test/*.test.cjs", "check:links": "node tools/check-release-links.cjs", + "check:ptBR": "node tools/check-ptBR-parity.cjs", "dist": "npm run build && electron-builder", "dist:mac": "npm run build && electron-builder --mac", "dist:win": "npm run build && electron-builder --win", diff --git a/src/renderer/src/i18n/index.ts b/src/renderer/src/i18n/index.ts index 3068eb7a62..57e195ef3d 100644 --- a/src/renderer/src/i18n/index.ts +++ b/src/renderer/src/i18n/index.ts @@ -21,6 +21,7 @@ import { DEFAULT_GOD_NAME } from '@shared/godIdentity'; import en from './locales/en.json'; import zhCN from './locales/zh-CN.json'; import ar from './locales/ar.json'; +import ptBR from './locales/pt-BR.json'; /** * The languages the Settings picker offers, in display order. @@ -34,6 +35,7 @@ import ar from './locales/ar.json'; */ export const LANGUAGES = [ { code: 'en', label: 'English', dir: 'ltr' }, + { code: 'pt-BR', label: 'Português (BR)', dir: 'ltr' }, { code: 'zh-CN', label: '简体中文', dir: 'ltr' }, { code: 'ar', label: 'العربية', dir: 'rtl' } ] as const; @@ -109,12 +111,13 @@ void i18n .init({ resources: { en: { translation: en }, + 'pt-BR': { translation: ptBR }, 'zh-CN': { translation: zhCN }, ar: { translation: ar } }, lng: detectLanguage(), fallbackLng: 'en', - supportedLngs: ['en', 'zh-CN', 'ar'], + supportedLngs: ['en', 'pt-BR', 'zh-CN', 'ar'], // Resources are bundled inline, so nothing ever suspends — the string is // there at init time. Keeping this false lets every component call // useTranslation() without wrapping the tree in . diff --git a/src/renderer/src/i18n/locales/pt-BR.json b/src/renderer/src/i18n/locales/pt-BR.json new file mode 100644 index 0000000000..68aac27438 --- /dev/null +++ b/src/renderer/src/i18n/locales/pt-BR.json @@ -0,0 +1,1409 @@ +{ + "common": { + "on": "on", + "off": "off", + "cancel": "cancel", + "save": "save", + "close": "close", + "back": "back", + "next": "next", + "finish": "finish", + "saving": "saving...", + "copy": "copy", + "delete": "delete", + "hide": "hide", + "show": "show", + "search": "search", + "tokens": "tokens", + "restarting": "restarting…", + "add": "add" + }, + "commandBar": { + "free": "free", + "skill": "/skill", + "quick": "quick", + "placeholder": "Type a command", + "placeholderBusy": "Ada is working...", + "placeholderBlocked": "Ada needs you...", + "send": "send", + "busyNote": "Ada is mid-tool. Queue or hit pause.", + "blockedNote": "Approval needed." + }, + "blockedBanner": { + "needsYou": "needs you" + }, + "costHud": { + "spendCap": "Spend cap", + "none": "none", + "usd": "USD", + "off": "(off)", + "thisSession": "{{usd}} this session", + "thisSessionWithCap": "{{usd}} this session / {{cap}}", + "audioTokens": "{{input}} in · {{output}} out audio tokens", + "overCap": "Over the spend cap — time to wrap up.", + "nearCap": "Approaching the spend cap.", + "lastSession": "Last session: {{usd}}", + "noSession": "No active voice session.", + "compactTitle": "{{count}} voice audio tokens this session", + "tok": "tok" + }, + "badge": { + "idle": "idle", + "thinking": "working", + "working": "working", + "waiting": "waiting", + "blocked": "needs you", + "success": "done", + "ghost": "gone", + "compacting": "compacting", + "looping": "looping", + "typing": "your draft" + }, + "agentControl": { + "deliveryPaused": "queued messages held (whole floor)", + "halting": "stopping after this step…", + "steersQueued": "{{count}} notes waiting", + "steerPlaceholder": "send this agent a note… (arrives as context on its next turn, nothing is typed into its terminal)", + "steer": "steer", + "flashResumed": "tools allowed again", + "flashPaused": "tools blocked from the next call on", + "flashHalt": "will stop after the current step", + "flashSteer": "note queued, arrives on its next turn", + "allowTools": "allow tools", + "allowToolsTip": "Give its tools back. The agent keeps its session and picks up where it stopped.", + "allowToolsAria": "Allow tools again", + "blockTools": "block tools", + "blockToolsTip": "The agent keeps thinking and talking to you, but cannot read, write or run anything until you allow it again. Immediate, and reversible.", + "blockToolsAria": "Block this agent from using tools", + "stopAfterStep": "stop after this step", + "stopAfterStepTip": "Let it finish the step it is on, then stop. The process and its session survive, so Restart and Continue can pick it back up. To end the process outright, use the X.", + "stopAfterStepAria": "Stop this agent after the current step", + "steerTip": "Hands the agent a note at its next turn boundary. It does not interrupt what it is doing now, and nothing is typed into its terminal.", + "steerAria": "Send this agent a note" + }, + "agentCard": { + "boss": "BOSS", + "contextTitle": "Context: {{used}} / {{limit}} tokens ({{pct}}%)", + "contextGaugeTitle": "Context gauge — fills once the agent reports activity", + "doingTasks": "actively working {{count}} task — click to open", + "doingTasksPlural": "actively working {{count}} tasks — click to open", + "editNote": "Edit private note", + "addNote": "Add private note", + "editNoteAria": "Edit note for {{name}}", + "noteAria": "Note for {{name}}" + }, + "askMe": { + "emptyTitle": "Nothing needs you right now. 🌿", + "emptySub": "When the team blocks a task on your input — a question to answer or a to-do only you can perform — it shows up here (and on the ASK ME board on the floor).", + "openDetail": "open the full task detail", + "dismissTitle": "dismiss — clear this off the ASK ME board without answering (history kept)", + "dismissAria": "dismiss this ask", + "answerPlaceholder": "Your answer — or 'done', with the result… (Ctrl+Enter to send)", + "sending": "sending…", + "respond": "respond & unblock", + "viewAnswers": "VIEW {{count}} EARLIER ANSWER", + "viewAnswersPlural": "VIEW {{count}} EARLIER ANSWERS", + "viewAnswersHistory": "open the task detail with the full Q&A history", + "blockingDownstream": "BLOCKING {{count}} DOWNSTREAM TASK", + "blockingDownstreamPlural": "BLOCKING {{count}} DOWNSTREAM TASKS", + "more": "… +{{count}} more" + }, + "agentStrip": { + "privateNote": "PRIVATE NOTE · {{name}}", + "done": "Done", + "closeNoteEditor": "Close note editor", + "notePlaceholder": "one line per bullet…", + "oneLineOneBullet": "one line = one bullet · esc to close", + "addAgent": "add agent", + "restoringTitle": "Your previous session's agents are being respawned with their original ids, so memory and inboxes reattach.", + "restoreTitle": "Previous session: {{names}}", + "restoringTeam": "restoring your team…", + "restoreTeam": "restore team ({{count}}) ▴", + "previousSession": "previous session", + "restorable": "{{name}} — restorable from last session", + "dismiss": "Dismiss {{name}} — remove permanently from the restore list", + "dismissAria": "Dismiss {{name}}", + "restoreAll": "restore all ({{count}})" + }, + "sidebar": { + "terminal": "terminal", + "git": "git", + "messages": "messages", + "traces": "traces" + }, + "toolWaterfall": { + "fresh": "fresh {{tokens}}t", + "cache": "cache {{tokens}}t ({{pct}}%)", + "total": "{{tokens}}t total", + "noTelemetry": "no live telemetry yet — spawn / respawn this agent to instrument it", + "empty": "No tool calls captured yet. Each tool the agent runs appears here with its real duration.", + "barOk": "{{tool}} · {{ms}}ms · ok", + "barFailed": "{{tool}} · {{ms}}ms · failed" + }, + "agentDetail": { + "open": "open", + "opening": "...", + "ok": "ok", + "err": "err", + "inFullscreen": "In focus mode", + "fullscreenDesc": "This terminal is open in focus mode. Press Esc or exit focus mode to bring it back here.", + "noPty": "No PTY", + "noPtyDesc": "This agent has no live terminal. Spawn an agent through \"add agent\" to use the terminal tab.", + "killConfirm": "Close {{name}}? The PTY process will terminate and the agent is archived (kept in history, off the floor).", + "ideTip": "Open the IDE: browse and edit files in {{project}}, and see uncommitted changes as a diff.", + "terminalTip": "Open your system terminal app in {{cwd}} — a normal shell in this agent's folder, separate from the agent's own terminal.", + "openIde": "Open the IDE", + "ide": "IDE", + "openTerminalAria": "Open a system terminal in this agent's folder" + }, + "settingsHero": { + "sponsoredBy": "Sponsored by", + "visit": "visit", + "whatsNew": "what's new", + "whatsNewTitle": "Show the release notes for the update you were last told about", + "starOnGitHub": "star on GitHub", + "reportProblem": "report a problem", + "fullChangelog": "full changelog →", + "announcement": "Announcement", + "proLaunch": "v0.5.0 launches with Munder Difflin Pro.", + "proCommunityFree": "Community stays free, stays open, and keeps getting updates.", + "proParagraph": "Pro ships with new features and integrations, with more posted throughout the year, and it stays ahead of Community, for power users who want the full potential of coding agents and agent harnesses. The Pro roadmap also includes a mobile app.", + "foundersWallTitle": "On the Founders' Wall?", + "foundersWallBody": "A month of Munder Difflin Pro free, then 50% off the annual plan. For the first 100 people on the wall.", + "seeTheWall": "see the wall", + "joinDiscord": "join Discord" + }, + "officeTheme": { + "title": "Office Theme", + "tvShow": "TV-show office themes", + "experimental": "experimental", + "desc": "Re-skin the pixel office as a TV show. Switching starts a fresh cast.", + "current": "current", + "soon": "soon", + "notBuiltYet": "{{label}} isn't built yet — showing the office for now.", + "switchAborted": "Switch aborted — a terminal wouldn't close: {{error}}", + "confirmTitle": "SWITCH OFFICE TO \"{{label}}\"?", + "startsFreshCast": "STARTS A FRESH CAST", + "deleteCount": "Your {{count}} current agent will be deleted — their terminals close and any in-progress work stops.", + "deleteCountPlural": "Your {{count}} current agents will be deleted — their terminals close and any in-progress work stops.", + "onlyCarries": "Only {{god}} carries over.", + "stillWorking": "⚠ {{count}} agent is still working.", + "stillWorkingPlural": "⚠ {{count}} agents are still working.", + "cantUndo": "This can't be undone.", + "switching": "switching…", + "deleteSwitch": "delete {{count}} & switch" + }, + "settings": { + "title": "SETTINGS", + "changeHomeTitle": "CHANGE HOME FOLDER", + "resetTitle": "RESET EVERYTHING?", + "close": "close", + "change": "change...", + "apply": "applying...", + "moveAndRestart": "move & restart", + "switchAndRestart": "switch & restart", + "resetting": "resetting...", + "eraseEverything": "erase everything & restart", + "nav": { + "general": "General", + "prerequisites": "Prerequisites", + "agentsModels": "Agents & Models", + "autonomyBudgets": "Autonomy & Budgets", + "connections": "Connections", + "voice": "Voice", + "memoryKnowledge": "Memory & Knowledge" + }, + "changeHome": { + "newHome": "New home folder", + "moveTitle": "Move existing data (recommended)", + "moveDesc": "Copy this harness's hive (every agent, memory, task) and the semantic-memory palace into the new folder. The old folder is left untouched as a backup you can delete later.", + "freshTitle": "Start fresh", + "freshDesc": "Point the harness at the new (empty) folder. Your existing data stays in the old folder, simply unused." + }, + "resetConfirm": { + "body": "This permanently erases all of {{godName}}'s memories and the entire hive, and cannot be undone. Any running sessions will be terminated and the app will relaunch into onboarding. Are you sure?" + }, + "general": { + "homeFolder": "Home folder", + "environment": "Environment", + "keepAwake": "Keep Mac awake while agents run", + "keepAwakeDesc": "Blocks display sleep so schedules and terminals keep firing on time. Costs battery — best on AC.", + "simpleMode": "Explain things simply", + "simpleModeDesc": "Agents brief you in plain language instead of engineering shorthand.", + "notifications": "Notifications", + "desktopNotifications": "Desktop notifications", + "desktopNotificationsDesc": "Native toasts when an agent finishes or needs your input.", + "maintenance": "Maintenance", + "autoCompact": "Scheduled auto-compact", + "autoCompactDesc": "Queue /compact for every agent on a schedule (hourly by default; interval in the Triggers tab). Off by default — long-running agents may overflow their context without it.", + "autoUpdate": "Auto-update", + "autoUpdateDesc": "Check GitHub releases and download updates in the background; you choose when to restart. Never restarts on its own.", + "telemetry": "Anonymous usage stats", + "telemetryDesc": "A handful of anonymous events (app opened, agent spawned, feature used) — never prompts, code, paths, or agent output. Full list in TELEMETRY.md.", + "language": "Language", + "languageDesc": "Choose the language for the app interface. English is the default.", + "dangerZone": "DANGER ZONE", + "dangerDesc": "Reset wipes {{godName}}'s memories, the entire hive (every agent, message, task, and the board), the semantic-memory palace, and all settings - then takes you back to onboarding.", + "resetStartOver": "reset & start over", + "arabicTerminal": "Arabic / RTL text in terminals", + "arabicTerminalDesc": "Renders terminals with the browser's text engine so Arabic joins and reads right-to-left (xterm has no bidi of its own). Off is the GPU renderer: faster, but RTL-blind. Applies to open terminals and new ones alike.", + "arabicTerminalFollowsLanguage": "Following your app language. Switch it here to override that either way — the choice sticks even if you change language again." + }, + "agentsModels": { + "defaultModel": "Default agent model", + "defaultModelDesc": "Every newly spawned Claude agent ({{godName}} included) starts on this model unless picked per-agent. Marked \"· default\" in the model pickers.", + "savedNote": "saved — applies to newly spawned agents", + "saveFailed": "save failed", + "advanced": "Advanced", + "maxTurns": "Max turns per run", + "unlimited": "unlimited", + "blankUnlimited": "blank = unlimited" + }, + "autonomy": { + "autonomy": "Autonomy", + "autoOn": "Autonomous — agents act without asking", + "autoOff": "Ask-first — agents pause for tool approval", + "autoDesc": "Applies to newly spawned agents (each agent's command can still override).", + "autonomous": "autonomous", + "askFirst": "ask-first", + "breaker": "Circuit breaker", + "breakerDesc": "Guard against runaway agents and spend. The breaker steers, then constrains, then stops an agent that crosses these.", + "floorBudget": "floor token budget", + "budgetPlaceholder": "e.g. 1000000", + "budgetEquals": "= {{value}} tokens", + "budgetTotal": "total tokens across the floor", + "velocity": "token velocity (tok/min)", + "velocityPlaceholder": "e.g. 200000", + "repeatedLimit": "repeated-tool limit", + "errorStormLimit": "error-storm limit", + "defaultPlaceholder": "default", + "hardStop": "Hard stop", + "hardStopDesc": "When tripped, KILL the agent instead of just constraining it. Off = steer-first (recommended).", + "killOnTrip": "kill on trip", + "steerFirst": "steer first", + "saved": "saved" + }, + "memory": { + "semanticMemory": "Semantic memory", + "crossSession": "Cross-session recall", + "crossSessionDesc": "Agents' markdown memory is indexed for instant search. The embedding model lives in the Memory panel.", + "kg": "Knowledge Graph", + "kgTitle": "Enterprise knowledge base", + "kgDesc": "Add your docs, images & PDFs; agents query them on demand via the kg tool.", + "adding": "adding…", + "addFiles": "add files…", + "docCount": "{{count}} document indexed", + "docCountPlural": "{{count}} documents indexed" + }, + "connections": { + "slack": "Slack", + "slackIntegration": "Slack integration", + "showSlackHelp": "Show Slack connect steps", + "slackDesc": "Pipe a Slack channel's messages straight into {{godName}}'s queue.", + "connected": "● Connected", + "notConnected": "○ Not connected", + "signingSecret": "Signing secret", + "signingSecretPlaceholder": "Slack app -> Basic Information -> Signing Secret", + "botToken": "Bot token", + "channelId": "Channel id (optional)", + "channelPlaceholder": "C0123... or blank for any", + "port": "Port", + "proactivePosting": "Proactive posting (app-initiated) — off by default", + "start": "start", + "connectedBtn": "connected", + "stop": "stop", + "listening": "listening", + "stopped": "stopped", + "requestUrl": "Request URL - paste into Slack Event Subscriptions", + "lastRequestUrl": "last Request URL - Slack reuses it until you Stop", + "slackHint": "In your Slack app: enable Event Subscriptions, add the message.channels / message.groups bot event, set the Request URL above, and reinstall to your workspace. The tunnel URL changes on every restart, so re-paste it after pressing Start again.", + "webhooks": "Webhook triggers", + "showWebhookHelp": "Show webhook API format", + "webhooksDesc": "One endpoint per caller, each with its own secret and mode. They all share one server, so another webhook costs nothing.", + "listeningOn": "● Listening", + "notListening": "○ Not listening", + "addWebhook": "add webhook", + "webhookWarning": "Every webhook you switch on is a PUBLIC endpoint anyone holding its secret can post to. New ones arrive off.", + "noWebhooks": "No webhooks yet. Add one to give a tool a URL it can hand work to.", + "namePlaceholder": "what calls this?", + "sure": "sure?", + "url": "URL", + "endpointPlaceholder": "starts once the webhook server is listening", + "secret": "Secret", + "rotate": "rotate", + "mode": "Mode", + "webhooksHint": "Callers POST to a webhook's URL with its secret in the x-md-webhook-secret header. Each one checks bodies against its own JSON schema — edit that in the Triggers tab of {{godName}}'s Command Center, where the history of everything that arrived lives too.", + "organisation": "Organisation", + "orgKey": "Organisation key", + "orgKeyDesc": "How a teammate's install addresses yours.", + "apiKey": "API key", + "orgKeyPlaceholder": "paste your organisation key", + "orgConfigOnly": "Configuration only for now. The organisation messaging service does not exist yet, so a key here starts no transport — it is saved, shown in the Triggers tab, and waits." + }, + "voice": { + "freeFlow": "Free Flow", + "freeFlowTitle": "Free Flow (voice dictation)", + "freeFlowDesc": "Push-to-talk dictation: speak, and Groq Whisper drops the text into the queue composer.", + "groqKey": "Groq API key", + "groqPlaceholder": "gsk_... (get a free key at console.groq.com)", + "model": "Model", + "fast": "whisper-large-v3-turbo (fast)", + "accurate": "whisper-large-v3 (accurate)", + "freeFlowHint": "Two ways to dictate: click the mic button above Send in the queue composer (click to record, click again to transcribe), or — while viewing any agent's terminal — hold Option (⌥) to talk and release to transcribe. Either way the text lands in the composer draft for you to review before sending. macOS will ask for microphone permission the first time you record.", + "realtime": "Realtime {{godName}}", + "voiceChat": "Voice chat with {{godName}}", + "voiceChatDesc": "Talk to the orchestrator in real time. Toggle it on from {{godName}}'s tab; choose which microphone and speaker the voice loop uses here.", + "openaiKey": "OpenAI API key · voice", + "openaiKeyDesc1": "Talking to {{godName}} runs on OpenAI's Realtime API — speech in, speech out, over a live connection to {{model}}. That is a different service from the Claude subscription your agents run on, so it needs its own OpenAI API key.", + "openaiKeyDesc2": "Paste it once below. It is encrypted on this machine and never shown again — each voice session mints its own short-lived token from it, and the key itself never leaves your computer. It is the same OpenAI key listed under Agents & Models; setting it in either place is enough.", + "keyPlaceholderSaved": "key saved — paste a new one to replace it", + "save": "Save", + "keySaved": "Key saved — Talk is ready. Start it from {{godName}}'s card.", + "noKey": "No key yet — Talk stays disabled until one is saved.", + "keySavedNote": "Key saved — Talk is ready.", + "couldNotSave": "Could not save the key.", + "idleDisconnect": "Idle auto-disconnect", + "30s": "30 seconds", + "1m": "1 minute", + "2m": "2 minutes", + "3m": "3 minutes", + "5m": "5 minutes", + "10m": "10 minutes", + "never": "Off (never)", + "idleDisconnectDesc": "How long the voice session stays open with no talking before it auto-closes. The spend cap still stops a runaway session even when this is off." + }, + "saved": "Saved", + "saving": "Saving…", + "unsavedChanges": "unsaved changes", + "unsavedWarning": "You have unsaved settings. Close anyway and lose them?" + }, + "commandCenter": { + "title": "COMMAND CENTER", + "runsTheFloor": "{{name}} runs the floor", + "deliveryPaused": "paused", + "deliveryAuto": "auto", + "deliveryPausedTitle": "Queued messages are being held for EVERY agent on the floor. Nothing is lost; it is delivered when you switch this back on.", + "deliveryOnTitle": "Queued messages are delivered to every agent automatically. Click to hold the whole floor.", + "ideTitle": "Open the IDE: browse and edit files in the selected agent's workspace, and see uncommitted changes as a diff.", + "ide": "IDE", + "tabs": { + "terminal": "terminal", + "floor": "monitor", + "tasks": "tasks", + "human": "ask me", + "triggers": "triggers", + "history": "history", + "memory": "memory", + "graph": "graph", + "activity": "activity", + "skills": "skills", + "workers": "workers" + }, + "terminalFullscreen": "Terminal is open in fullscreen. Press Esc to bring it back.", + "noTerminal": "{{name}} has no live terminal.", + "dispatchViaMichael": "DISPATCH — VIA {{godName}}", + "suggestedOwner": "SUGGESTED OWNER", + "michaelDecides": "{{godName}} decides", + "dispatchPlaceholder": "Describe the task… ({{godName}} decomposes, writes the card, and assigns)", + "dispatch": "dispatch", + "sentToMichael": "sent to {{godName}}", + "sentToWithSuggestion": "sent to {{godName}} (suggesting {{name}})", + "dispatchFailed": "failed: {{error}}", + "dispatchSuggestion": "(The human suggests {{name}} ({{id}}) for this — your call as orchestrator.)", + "taskFromHuman": "Task from the human", + "agents": "AGENTS", + "godTag": " (god)", + "toolCalls": "{{count}} tool calls", + "rate": "rate", + "budget": "budget", + "meterTitle": "CUMULATIVE session usage: {{used}} of {{limit}} tokens{{note}} — not the context window", + "agentLimit": " (agent limit — work tokens, cache reads excluded)", + "floorBudget": " (floor budget)", + "ctx": "ctx", + "contextTitle": "Context window: {{used}} of {{limit}} tokens ({{pct}}%)", + "noStatusTick": "no status tick yet", + "modelRestarts": "{{provider}} model (restarts agent)", + "restartContinue": "restart & continue", + "restartContinueTitle": "Kill and respawn {{name}}, resuming its current conversation — fixes a corrupted/garbled terminal without losing context", + "engine": "engine:", + "apply": "apply", + "confirmRestartEngine": "This restarts {{name}}; a conversation on a different engine can't be resumed.", + "restartFailed": "Restart failed.", + "archived": "ARCHIVED ({{count}})", + "showClosed": "show closed agents", + "hideClosed": "hide closed agents", + "directories": "DIRECTORIES", + "noRepos": "No registered repos.", + "openInTerminal": "Open in Terminal.app", + "issues": "ISSUES", + "fetching": "fetching…", + "fetchIssues": "Fetch issues", + "noRepoSelected": "No repo selected.", + "fetchFailed": "Failed to fetch issues.", + "noIssues": "No issues fetched yet.", + "assign": "Assign", + "textSearch": "TEXT SEARCH (board, tasks, memory)", + "textSearchPlaceholder": "Find exact text across hive files…", + "nothingMatched": "Nothing matched.", + "searchNoMatch": "Nothing matched yet.", + "semanticSearch": "SEMANTIC SEARCH (MemPalace)", + "semanticPlaceholder": "What does the hive know about…", + "memoryFile": "MEMORY FILE", + "noMemory": "No memory recorded yet.", + "activity": "ACTIVITY", + "nothingYet": "Nothing yet.", + "board": "BOARD", + "boardEmpty": "The board is empty.", + "logSpawn": "spawned {{name}}", + "logMessage": "{{from}} → {{to}}: {{subject}}", + "logDrain": "{{agent}} drained {{count}} msg(s)", + "logEscalate": "escalated to human: {{subject}}", + "logApprovalGranted": "approval granted", + "logApprovalDenied": "approval denied", + "tokenLimitTitle": "Set this agent's token limit (work tokens: input + output + cache writes; cache reads don't count)", + "tokenLimit": "limit {{value}}", + "setLimit": "set limit", + "saveLimit": "Save limit", + "fleetTokens": "Σ {{value}} tok", + "fleetInputs": "inputs {{value}} (cache {{pct}}%)", + "fleetRate": "{{value}} tok/min", + "telemetryNote": "live from each agent's OpenTelemetry · bars show tokens used vs each agent's limit, else the {{cap}} floor budget", + "defaultBudgetNote": " (default — set a floor token budget in Settings)", + "openIssue": "GitHub Issue #{{num}}: {{title}}", + "deliveryResumeAria": "Resume automatic delivery for the whole floor", + "deliveryHoldAria": "Hold automatic delivery for the whole floor", + "openIdeAria": "Open the IDE" + }, + "addAgent": { + "title": "ADD AGENT", + "hireImported": "hire imported:", + "byAuthor": " · by {{author}}", + "reviewFields": "review every field — especially the command — before spawning.", + "hireFlags": "⚠️ flags this hire appends to the command:", + "hireSkills": "skills this hire activates:", + "mcpSafe": "MCP servers (safe, pre-enabled):", + "mcpConsent": "⚠️ MCP (needs your consent — NOT auto-enabled):", + "mcpEnableInSettings": "— enable in Settings → MCP after reviewing", + "sections": { + "identity": { + "label": "Identity", + "hint": "name · character · color" + }, + "workspace": { + "label": "Workspace", + "hint": "folder · isolation · resume" + }, + "engine": { + "label": "Engine", + "hint": "provider · model · command" + }, + "briefing": { + "label": "Briefing", + "hint": "description · goal" + } + }, + "name": "Name", + "namePlaceholder": "Ada", + "character": "Character", + "color": "Color", + "project": "Project", + "pickProject": "Pick a project, or add a new one:", + "noProjects": "No projects yet — add one to get started:", + "addProject": "add project", + "addProjectTitle": "Pick a folder and register it as a project", + "projectPlaceholder": "/path/to/your/project", + "pick": "pick", + "saveAsProject": "save as project", + "saveAsProjectTitle": "Save this folder to your projects so it's a one-click pick next time", + "gitIsolation": "Git isolation (own worktree)", + "resumeSession": "Resume session ID (optional)", + "resumePlaceholder": "paste a Claude session id to continue its conversation", + "folderFromSession": "folder set from session: {{path}}", + "resumeNote": "Will resume this session in the chosen folder (git isolation disabled).", + "provider": "Provider", + "providerAntigravity": "Spawn the Antigravity CLI (agy) with a Gemini model", + "providerCodex": "Spawn the Codex CLI (codex) without Claude-only flags", + "providerCustom": "Run any command — no Claude-only flags", + "model": "Model", + "cliDefaultModel": "CLI default model", + "fromHire": "{{model}} (from hire)", + "ossModels": "OSS models", + "ossLocal": "Local · no key (Ollama / LM Studio)", + "ossByok": "Via OSS provider · BYOK", + "ossLocalTitle": "{{slug}} · needs ~{{ram}} RAM — pull with: ollama pull {{tag}}", + "ossByokTitle": "{{slug}} · set {{keyEnv}} in Settings → AI Engines", + "byokNote": "BYOK keys & local endpoints for this engine live in Settings → AI Engines. New to local models? Read run on open models or set up on a Mac Mini. Live end-to-end is pending real model calls (verify on-device).", + "runOnOpenModels": "run on open models", + "setUpMacMini": "set up on a Mac Mini", + "command": "Command", + "commandAuto": "Command (auto mode on)", + "templates": "Templates", + "templatesHint": { + "repoJanitor": { + "label": "Repo janitor" + }, + "docsWriter": { + "label": "Docs writer" + }, + "bugTriager": { + "label": "Bug triager" + }, + "researchAssistant": { + "label": "Research assistant" + }, + "releaseManager": { + "label": "Release manager" + } + }, + "description": "Description", + "descriptionPlaceholder": "job — what this agent is for, not live status", + "goal": "Goal (optional)", + "goalPlaceholder": "long-running directive injected on every prompt", + "importHire": "Import hire", + "importHireDesc": "Import hire loads a ready-made agent from a .json manifest — it fills in every field below for you to review. Nothing spawns until you hit spawn.", + "generateWithAI": "generate one with AI…", + "hideAIPrompt": "hide AI prompt", + "aiPromptHint": "Copy this into Claude/ChatGPT/Gemini, fill in the details at the bottom, then save its JSON reply as a .json file and import it here.", + "copied": "copied ✓", + "copyPrompt": "copy prompt", + "importHireBtn": "import hire…", + "importHireBtnTitle": "Import a hire manifest (.json)", + "spawn": "spawn", + "spawning": "spawning...", + "errName": "Name is required", + "errFolder": "Pick a folder first", + "errCommand": "Command is required", + "hireProgress": "hire {{current}} of {{total}}", + "skipHire": "skip hire" + }, + "onboarding": { + "titles": { + "persona": "WELCOME TO MUNDER DIFFLIN", + "welcome": "MEET YOUR OFFICE", + "home": "STEP 1 OF 4 · HARNESS HOME", + "homePlain": "STEP 1 OF 4 · A HOME FOR THE APP", + "orchestrator": "STEP 2 OF 4 · YOUR CLONE'S ENGINE", + "orchestratorPlain": "STEP 2 OF 4 · YOUR CLONE", + "repos": "STEP 3 OF 4 · YOUR REPOS", + "reposPlain": "STEP 3 OF 4 · YOUR PROJECTS", + "permissions": "STEP 4 OF 4 · PERMISSIONS & RELIABILITY", + "done": "ALL SET" + }, + "persona": { + "headline": "A CLONE OF YOU, WORKING 24/7", + "body": "Munder Difflin turns the CLI agent you already use into a clone of you — one that runs an office of long-running agents and keeps working while you're away. It manages everything around them: context, memory, tasks, triggers, environment, files, and integrations.", + "bodyLocal": " Everything runs on this machine.", + "ask": "FIRST — WHO ARE YOU? (we'll tailor the setup)", + "technicalTitle": "I'M TECHNICAL", + "technicalDesc": "I write code or work in a terminal. Show me CLI commands, flags, and model ids.", + "nonTechnicalTitle": "I'M NON-TECHNICAL", + "nonTechnicalDesc": "I'm in marketing, sales, ops, or just starting out. Explain things in plain language." + }, + "welcome": { + "headline": "YOUR CLONE AND THE FLOOR IT RUNS", + "descPlain": "Your clone runs a small office of AI workers, and you watch it all from one screen. Here's what's inside:", + "desc": "Your clone coordinates a hive of AI coding agents — persistent, watchable, all local. Here's what's inside:", + "features": { + "engines": { + "label": "ELEVEN ENGINES, ONE OFFICE", + "desc": "Claude Code, Codex, Grok, Kimi, Antigravity, Qwen, OpenCode, Crush, pi, Copilot & Cursor — live agents on one floor.", + "descPlain": "Eleven AI assistants — Claude, Codex, Cursor, Gemini, Grok and more — working side by side in one shared office." + }, + "clone": { + "label": "{{godName}} IS YOUR CLONE", + "desc": "Your clone runs the floor — triages requests, routes tasks, and escalates only what needs you.", + "descPlain": "Your clone, {{godName}}, takes your requests, hands work to the right agent, and only interrupts you when it matters." + }, + "memory": { + "label": "LONG-TERM MEMORY", + "desc": "Each agent keeps notes, mined into a shared, searchable MemPalace.", + "descPlain": "Agents remember what they've done, so they don't start from scratch every time." + }, + "commandCenter": { + "label": "COMMAND CENTER", + "desc": "Terminal · Floor · Memory · Activity · Tasks · Triggers in one control surface.", + "descPlain": "One dashboard to watch the work, the agents' memory, tasks, and triggers." + }, + "guardrails": { + "label": "GUARDRAILS", + "desc": "Per-agent token budgets, a steer→constrain→stop circuit breaker, and human approvals.", + "descPlain": "Spending limits and safety stops keep agents in check — and they can ask you before big actions." + }, + "hires": { + "label": "READY-MADE HIRES", + "desc": "Grab a pre-configured agent from the Agent Gallery and spawn it in one click.", + "descPlain": "Hire a ready-made agent from the gallery in one click — no setup needed." + } + } + }, + "providerBlurb": { + "claude": "Claude Code — Anthropic", + "codex": "Codex — OpenAI", + "antigravity": "Antigravity — Google Gemini", + "qwen": "Qwen — runs a local Qwen model on your machine", + "gemini": "Gemini CLI - Google Gemini", + "cursor": "Cursor Agent CLI — uses your Cursor credits (Luna, Composer, …)" + }, + "home": { + "descPlain": "Create a new, empty folder for the app to call home. Everything the app remembers — its own settings and your agents' memory — is stored here. Something like ~/HarnessAgents works well. We'll create it for you if it doesn't exist.", + "desc": "Pick a folder where the harness will keep its own files — agent metadata, logs, and any new repos you create from here. Something like ~/HarnessAgents is a fine default. We'll create it if it doesn't exist.", + "placeholder": "/path/to/HarnessAgents", + "createPick": "create / pick", + "pick": "pick", + "notePlain": "You won't need to open this folder day-to-day — it's just where the app keeps its notes so nothing is lost when you restart.", + "note": "Think of this as the \"town hall.\" The harness pins agent state there so sessions can be picked back up after a restart." + }, + "orchestrator": { + "descPlain": "{{godName}} is your clone — he reads your requests, breaks them into tasks, and hands them to the right agent. He's the boss of the floor; you're still the boss of him. Choose which AI engine powers him.", + "desc": "{{godName}} is your clone — the boss of the floor you just met. He triages your requests, assigns tasks, and manages the team, while escalating anything that genuinely needs you. Pick the engine and model that power him; give him a longer-context, higher-capability model.", + "cliAgentPlain": "A CLI agent is an AI coding assistant that runs on your computer — popular ones are Claude Code (Anthropic), Codex (OpenAI) and Antigravity (Google Gemini). Your clone is the always-on one that runs your whole office. We recommend Claude Code on Opus 4.8 (1M). You can add or switch the others later.", + "cliAgent": "Each option is a CLI engine (Claude Code, Codex, Antigravity/Gemini, or a local proxy like Qwen). Engines marked INSTALLED are already on this machine; INSTALLS ON FIRST RUN means the app sets it up when {{godName}} first starts. Your clone ({{godName}}) is the engine that orchestrates the whole hive. Recommended: Claude Code · Opus 4.8 · 1M. Other providers can be wired per agent later.", + "recommended": "RECOMMENDED", + "workersOnly": "WORKERS ONLY", + "workersOnlyHint": "Can't drain hive mail yet, so it can't run your clone — still available when hiring workers.", + "model": "Model", + "modelNote": "This only sets {{godName}}'s engine. You can run other providers per agent later." + }, + "repos": { + "descPlain": "Add your projects. A project is simply a folder — it can hold code, documents, notes, or any files you want your agents to work with. You can create a brand-new folder or pick an existing one, and add more anytime.", + "desc": "Add the repos you want your agents to work in. Each folder becomes a project (a room on the floor) — multiple agents can share one. You can add more later.", + "emptyPlain": "No projects added yet. Optional — you can add one later.", + "empty": "No repos added yet. Optional, but recommended.", + "addProject": "add a project", + "addRepo": "add a repo" + }, + "permissions": { + "autonomyHead": "HOW MUCH CAN AGENTS DO ON THEIR OWN?", + "autoLabelPlain": "LET AGENTS WORK ON THEIR OWN", + "autoLabel": "WORK AUTONOMOUSLY (AUTO MODE)", + "autoOnPlain": "On. Agents carry out tasks without stopping to ask — the smoothest experience.", + "autoOffPlain": "Off. Agents pause and ask you before changing files or running commands.", + "autoOn": "On. Agents never pause — Claude runs bypassPermissions, Codex bypasses approvals + sandbox, etc.", + "autoOff": "Off. Each agent asks before edits / shell commands (Claude default, codex -a untrusted, …).", + "autoNotePlain": "Best when agents work in their own projects. You can change this later, including for individual agents.", + "autoNote": "The right default for the \"control room\" experience; a foot-gun on production repos. Override per agent in the Add Agent dialog.", + "reliabilityHead": "KEEP THINGS RUNNING WHILE YOU'RE AWAY", + "reliabilityDescPlain": "Your agents keep working on a schedule and in live terminals, even when you step away. These settings keep you in the loop and keep things running.", + "reliabilityDesc": "Your agents keep working on a schedule and in live terminals. If your computer fully sleeps those timers pause and catch up the moment you're back — nothing is lost, it may just run late.", + "keepAwake": "KEEP WORKING WHILE AWAY", + "keepAwakeDesc": "Strong keep-alive: stops your computer from sleeping while an agent is live, so schedules and terminals fire on time even when you step away. Uses more battery — best on power. Off by default.", + "notifications": "DESKTOP NOTIFICATIONS", + "notificationsDesc": "Get pinged when an agent needs you or a terminal needs reviving — even while you're away. Your system may ask permission the first time one fires.", + "openAtLogin": "OPEN AT LOGIN", + "openAtLoginDesc": "Relaunch the harness after a reboot so scheduled missions resume on their own. No prompt — applies immediately.", + "shareStats": "SHARE ANONYMOUS USAGE STATS", + "shareStatsDesc": "A handful of anonymous events (app opened, agent spawned, feature used) that help improve Munder Difflin — never prompts, code, file paths, or agent output. Full list in TELEMETRY.md; change anytime in Settings.", + "stayAwake": "STAY AWAKE ON POWER (MANUAL)", + "stayAwakeDescMac": "macOS only lets you set this one yourself. In Battery → Options, turn on \"Prevent automatic sleeping when the display is off\" (on power adapter) so timers keep firing with the display asleep. Without a sleep-preventing setting the Mac still truly sleeps — work survives and catches up on wake.", + "stayAwakeDescWindows": "Windows only lets you set this one yourself. In Settings → System → Power & battery → Screen, blank & sleep, set \"On battery power, put my device to sleep\" and \"When plugged in\" to Never (or increase them) so timers keep firing. Without a sleep-preventing setting Windows still truly sleeps — work survives and catches up on wake.", + "stayAwakeDescLinux": "Your desktop environment only lets you set this one yourself. Look for a Power Settings panel (e.g. GNOME Settings → Power, or KDE System Settings → Power Management) and disable automatic sleep/suspend while on power. Without a sleep-preventing setting your machine still truly sleeps — work survives and catches up on wake.", + "openBatteryMac": "open Battery settings", + "openBatteryWindows": "open Power settings", + "setItUp": "set it up", + "next": "next" + }, + "errPickHome": "Pick a harness home folder first.", + "errCreateHome": "could not create harness home", + "errEngineNotInstalled": "{{label}} is not installed. Install it and press \"check again\", or pick another engine." + }, + "office": { + "gpuError": "The office floor lost its GPU context.\n\nToo many terminals are using the GPU at once.\nClose a few agent terminals, or restart the app, to bring it back.", + "errand": { + "water": [ + "watering the plants 🌿", + "giving the plants a drink", + "they grow so fast" + ], + "window": [ + "letting some air in 🍃", + "a bit of fresh air", + "nice breeze today" + ], + "dispenser": [ + "getting some water 💧", + "hydration break", + "staying sharp" + ], + "fridge": [ + "anything good in the fridge?", + "who took my yogurt?", + "just looking…" + ], + "shelf": [ + "checking out the shelf 📚", + "anything new in here?", + "so much good stuff" + ], + "bin": [ + "out with the scrap paper 🗑️", + "desk cleanup day", + "tidying up a little" + ], + "smoke": [ + "the floor runs itself 🚬", + "boss break.", + "thinking big thoughts 🚬", + "I DECLARE… a break" + ] + }, + "suckUp": [ + "already shipped {{done}} tasks, {{godName}}. raise? 🥺", + "{{done}} tasks done this week, boss!", + "great vision as always, boss!", + "I was JUST about to do exactly that!", + "love the tie today, {{godName}}", + "working hard, boss! 💪", + "best boss ever. genuinely." + ], + "gossip": [ + "has he ever actually written code?", + "another 'quick sync' that took an hour…", + "'world's best boss' — he bought that mug himself", + "he pinned MY task as his idea", + "the cigar smell, honestly…", + "he watered the plant. ONE plant. his own.", + "did you hear him? 'I DECLARE… a break'" + ], + "cheer": [ + "done! ✔", + "nailed it", + "that's a wrap", + "ship it 🚀", + "another one done", + "crushed it", + "in the books" + ], + "mugs": { + "empty": "no clean mugs left…", + "brewing": "brewing a fresh one ☕", + "washing": "washing the mug" + }, + "activity": { + "waiting": "waiting", + "needsYou": "needs you", + "compacting": "compacting context", + "looping": "looping — breaker armed", + "runningFloor": "running the floor", + "idle": "idle" + } + }, + "setupPanel": { + "title": "PREREQUISITES", + "checking": "Checking what is installed…", + "summary": "{{ready}} of {{total}} ready{{missing}}", + "summaryMissing": " · {{count}} recommended missing", + "recheck": "re-check", + "checkingBtn": "checking…", + "statusReady": "READY", + "statusMissing": "MISSING", + "statusNotSetUp": "NOT SET UP", + "recommended": "recommended", + "docs": "docs →", + "askDesc": "{{godName}} can install the {{count}} missing recommended tool for you. This fills in his dispatch box — nothing runs until you press dispatch.", + "askDescPlural": "{{godName}} can install the {{count}} missing recommended tools for you. This fills in his dispatch box — nothing runs until you press dispatch.", + "allReady": "Everything recommended is installed. Individual engines above are optional — set up only the ones you use.", + "askMichael": "ask {{godName}} to set up everything", + "sections": { + "prerequisites": { + "title": "Prerequisites", + "blurb": "The groundwork everything else builds on." + }, + "memory": { + "title": "Memory layer", + "blurb": "Meaning-based recall across everything your agents learn." + }, + "engine": { + "title": "Agent engines", + "blurb": "The CLIs your agents run on. You need whichever ones you actually use — not all of them." + } + } + }, + "aiEngines": { + "providers": "AI ENGINE PROVIDERS (BYOK)", + "providersDesc": "API keys + local endpoints for the OpenCode, Crush, pi.dev and Qwen engines. Keys are stored write-only (encrypted at rest; never shown again) and used only when those engines spawn. Claude Code and Codex use their own login.", + "apiKeys": "API KEYS", + "setCheck": "set ✓", + "keyStoredPlaceholder": "•••••••• (stored — type to replace)", + "keyPlaceholder": "paste {{label}} key", + "saved": "saved", + "failed": "failed", + "cleared": "cleared", + "localEndpoint": "LOCAL ENDPOINT · DEFAULT MODEL (PER ENGINE)", + "defaultModelPlaceholder": "default model (provider/model)", + "runningOpenModels": "Running open models? Step-by-step guides:", + "runOnOpenModels": "run Munder Difflin on open models", + "setUpMacMini": "set it up on a Mac Mini", + "autoModeCaveat": "⚠ In auto mode these engines run with full filesystem + shell access (no sandbox) — like Claude's bypass mode. Turn auto mode off (General) to make them ask first. Live end-to-end verification with real model calls is pending your keys / a local LLM." + }, + "mcpDefaults": { + "title": "Default MCP servers", + "desc": "These servers are merged into each new agent's session settings. Safe servers are on by default; write/secret servers are off until you consent. Changes take effect on the next agent spawn — running agents are not affected.", + "toggleNote": "{{id}}: {{state}}", + "couldNotSave": "could not save", + "tiers": { + "safeReadonly": "Safe & Read-Only (on by default)", + "write": "Write Access (consent required)", + "secret": "Requires Secret / API Key (consent required)", + "safeReadonlyNote": "These servers read data only, need no secrets, and are scoped to the agent workspace. They are enabled for every new agent.", + "writeNote": "These servers can mutate state beyond the workspace. Off by default — enable only after reviewing.", + "secretNote": "These servers require an API key or credentials. Off by default — add your credentials and enable after consent." + } + }, + "devicePicker": { + "microphone": "Microphone", + "speaker": "Speaker", + "systemDefault": "System default", + "namesHint": "Device names appear after you first start a voice session and grant mic access. The microphone choice applies the next time {{godName}} connects; the speaker switches live." + }, + "realtimeToggle": { + "talk": "talk", + "connecting": "…", + "listening": "listening", + "speaking": "speaking", + "working": "working", + "helpOff": "Talk to {{godName}} — start the voice session", + "helpConnecting": "Connecting to {{godName}}…", + "helpListening": "Listening — {{godName}} is hearing you (click to stop)", + "helpSpeaking": "{{godName}} is speaking (click to stop)", + "helpWorking": "{{godName}} is running a tool — mic muted (click to stop)", + "noKeyTitle": "Talk needs your OpenAI API key (used for the Realtime voice API). Add it in Settings → Voice.", + "whyDisabled": "Why is Talk disabled?", + "popoverBody": "An OpenAI API key is needed to use this feature.", + "setItUpNow": "set it up now" + }, + "updatesSection": { + "title": "Updates", + "onVersion": "You're on v{{v}}", + "checkingDetail": "Checking for a newer release…", + "availableHeadline": "v{{version}} is available", + "availableDetail": "You're on v{{v}}. Download it now — you'll be asked to restart once it's ready.", + "downloadBtn": "Download v{{version}}", + "downloadingHeadline": "Downloading v{{version}}", + "downloadingDetail": "{{percent}}% done. You can keep working; the restart is yours to trigger.", + "downloadedHeadline": "v{{version}} is ready to install", + "downloadedDetail": "Restart Munder Difflin to finish updating from v{{v}}.", + "restartBtn": "Restart to update", + "manualDetail": "This install can't update itself — download it from the release page.", + "manualDetailReason": "This install can't update itself ({{reason}}) — download it from the release page.", + "openReleaseBtn": "Open release page", + "errorHeadline": "Update check failed", + "errorDetail": "{{message}} (you're on v{{v}}).", + "retryBtn": "Try again", + "latestHeadline": "v{{v}} is the latest version", + "latestDetail": "You're already up to date — nothing to install.", + "checkAgainBtn": "Check again", + "idleDetail": "Updates are checked automatically every 6 hours. Check now if you want to be sure.", + "checkBtn": "Check for updates", + "downloadManually": "download manually", + "downloadManuallyTitle": "Download the v{{version}} installer and replace the app yourself", + "manualDownloadingTitle": "v{{version}} is downloading in your browser.", + "manualDownloadingBody": "When it lands, quit this app, install the new version over the current one, open it and pick the same project. On {{os}}:" + }, + "triggersTab": { + "intro": "Everything that can start work without you typing.", + "schedules": "SCHEDULES", + "schedulesBlurb": "Run a prompt on a repeating clock.", + "context": "CONTEXT", + "contextBlurb": "Compact or clear an agent as its context fills.", + "webhooks": "WEBHOOKS", + "webhooksBlurb": "Let an outside system post work in.", + "organisation": "ORGANISATION", + "organisationBlurb": "Let a teammate's Munder Difflin message yours." + }, + "orgSection": { + "acceptMessages": "Accept messages from your organisation", + "key": "ORGANISATION KEY", + "keyPlaceholder": "paste your key", + "trust": "TRUST", + "settingsOnly": "Settings only, for now. The org messaging service does not exist yet, so a key here starts no connection and nothing is sent or received. It is stored ready for when it does.", + "noKeyWarning": "This is switched on with no key set, so no teammate can reach you yet.", + "noKey": "no key" + }, + "contextSection": { + "loading": "One sec…", + "intro": "A rule fires only when both halves agree: the gap since its last run has passed, AND that agent's context is at least as full as the bar. A bar of 0% means the clock alone.", + "compact": "Compact", + "compactBlurb": "Summarises the context so the thread keeps going.", + "clear": "Clear", + "clearBlurb": "Discards the context. Nothing is summarised.", + "clearCaution": "Clearing throws context away — it is not a smaller version of compaction. An agent mid-task forgets what it was doing. Leave this off unless you keep context another way.", + "extraFocus": "EXTRA FOCUS", + "extraFocusHint": "Appended to the provider's compaction command. Empty sends the bare command.", + "extraFocusPlaceholder": "What the summary must keep…", + "command": "COMMAND", + "commandHint": "Sent literally. Empty sends the bare clear command.", + "bothOff": "both off", + "off": "Off.", + "hintEvery": "Every {{interval}}, once context passes {{pct}}%.", + "noSoonerThan": "NO SOONER THAN EVERY", + "contextBar": "CONTEXT BAR", + "contextBarHint": "How full the window must be before this may run. 0% = time alone.", + "bigWindows": "BAR ON BIG WINDOWS", + "bigWindowsHint": "Used on ~1M-token windows, where a smaller slice is still an enormous amount of text." + }, + "schedulesSection": { + "justNow": "just now", + "ago": "{{unit}} ago", + "in": "in {{unit}}", + "summaryNone": "none", + "summary": "{{on}} of {{total}} on", + "nothingScheduled": "Nothing is scheduled yet.", + "addSchedule": "add a schedule", + "newSchedule": "NEW SCHEDULE", + "label": "LABEL", + "labelPlaceholder": "What this run is for", + "goesTo": "GOES TO", + "everyone": "everyone", + "prompt": "PROMPT", + "promptPlaceholder": "Sent word for word on every run.", + "fired": "fired {{time}}", + "notFired": "not yet fired", + "next": "next {{time}}", + "beat": "♥ beat", + "noPrompt": "No prompt set.", + "saved": "saved", + "when": "WHEN", + "beatCeiling": "The beat adapts to how quiet the floor is, so this is the ceiling, not the exact gap." + }, + "webhooksSection": { + "summaryNone": "none", + "summary": "{{count}} · {{state}}", + "live": "live", + "offline": "offline", + "intro": "Anyone holding a URL and its secret can post work in. Each endpoint carries its own secret, so revoking one caller leaves the others alone.", + "noEndpoints": "No endpoints yet.", + "minting": "minting…", + "addWebhook": "add webhook", + "newEndpointHint": "A new endpoint starts switched off. Copy its URL and secret, then turn it on.", + "unnamed": "unnamed", + "reachable": "reachable", + "noUrlYet": "no URL yet", + "serverOffline": "server offline", + "name": "NAME", + "namePlaceholder": "Who calls this", + "postTo": "POST TO", + "noAddressYet": "This endpoint has no public address yet. It appears once the tunnel picks it up.", + "serverNotListening": "The webhook server is not listening, so there is no address to hand out yet.", + "secret": "SECRET", + "secretHint": "Callers echo this in the x-md-webhook-secret header.", + "trust": "TRUST", + "bodySchema": "BODY SCHEMA", + "editSchema": "edit schema", + "schemaDesc": "what an inbound body must look like", + "notValidJson": "Not valid JSON — {{error}}. Nothing was saved.", + "saved": "saved", + "saveSchema": "save schema", + "sure": "Sure?", + "deleteIt": "delete it", + "keep": "keep" + }, + "triggersUi": { + "custom": "custom", + "customEllipsis": "custom…", + "min": "min", + "every": "every…", + "onDays": "on days…", + "at": "at", + "weekdays": "weekdays", + "everyDay": "every day", + "pickDayHint": "Pick at least one day, or this will never run." + }, + "triggerHistory": { + "justNow": "just now", + "ago": "{{unit}} ago", + "in": "in {{unit}}", + "kindDirective": "directive", + "kindCommunication": "communication", + "decisionPending": "needs you", + "decisionApproved": "approved", + "decisionRejected": "rejected", + "decisionAuto": "auto-allowed", + "emptyMessage": "(empty message)", + "showLess": "show less", + "showAll": "show all {{count}} characters", + "tailRejected": "You turned this down. Nothing was sent to the hive.", + "tailNoReply": "No reply yet. {{godName}} has this one.", + "waitingForYou": "WAITING FOR YOU", + "unnamedSource": "unnamed source", + "from": "from", + "to": "to", + "unknown": "unknown", + "theySent": "THEY SENT", + "weReplied": "WE REPLIED", + "weSent": "WE SENT", + "pendingDirectiveDesc": "Approve and this goes to {{godName}}, who will put the hive to work on it. Reject and it is dropped — nothing runs.", + "pendingDesc": "Approve and {{godName}} reads this. Reject and it is dropped — nothing runs.", + "approveTitle": "Send this message through to {{godName}}", + "oneSec": "one sec…", + "approve": "approve", + "rejectTitle": "Drop this message. Nothing is sent", + "reject": "reject", + "task": "TASK {{id}}", + "sectionWebhooks": "Webhooks", + "sectionWebhooksBlurb": "Everything posted to your webhook endpoints, next to what {{godName}} sent back.", + "sectionOrg": "Organization", + "sectionOrgBlurb": "Messages from your teammates' clone nodes, next to what {{godName}} sent back.", + "heldOne": "One message is held, waiting on your yes or no.", + "heldMany": "{{count}} messages are held, waiting on your yes or no.", + "decideFailed": "That did not go through. Try again.", + "clearFailed": "Could not clear it. Try again.", + "emptyOrgTitle": "Nothing here yet, and nothing is broken.", + "emptyOrgBody": "Teammate messaging is not built yet. You can set an org key and pick a mode today, but no one's clone node can reach yours until the transport ships. When it does, their messages and our replies land here.", + "emptyWebhookTitle": "No webhook messages yet.", + "emptyWebhookBody": "When something posts to one of your endpoints, it lands here with {{godName}}'s reply underneath. Nothing has called in so far. Add an endpoint under Webhooks to get a URL you can hand out.", + "clearConfirm": "Delete all {{count}} messages? The record is gone for good.", + "deleteThem": "delete them", + "keepThem": "keep them", + "clearHistoryTitle": "Delete this section's history", + "clearHistory": "clear history" + }, + "fileTree": { + "loading": "loading…", + "copyPathTitle": "Copy path to clipboard" + }, + "fileEditor": { + "file": "FILE", + "edit": "edit", + "preview": "preview", + "editTitle": "Edit the source", + "previewTitle": "Rendered preview (of the saved file)", + "openInIde": "open in IDE", + "openInIdeTitle": "Open this file in the full IDE", + "closeTitle": "Close (Esc)" + }, + "gitTab": { + "notARepo": "Not a git repo.", + "notARepoHint": "Run git init in the agent's terminal.", + "detachedHead": "DETACHED HEAD", + "refresh": "refresh", + "sectionStatus": "status", + "sectionBranches": "branches", + "sectionLog": "log", + "staged": "staged", + "changes": "changes", + "untracked": "untracked", + "clean": "working tree clean", + "noCommits": "no commits yet", + "modified": "modified", + "added": "added", + "deleted": "deleted", + "renamed": "renamed", + "unmerged": "unmerged", + "copyPath": "Copy path" + }, + "fullscreenTerminal": { + "showAgentList": "Show the agent list", + "hideAgentList": "Hide the agent list — full-width terminal", + "lightTheme": "Switch to the light theme", + "darkTheme": "Switch to the dark theme", + "toggleTheme": "Toggle dark mode", + "exitFullscreen": "Exit focus mode (Esc)", + "addAgent": "Add agent", + "respawnTitle": "Respawn from last session: {{names}} — same ids, memory and inboxes reattach automatically", + "contextTitle": "Context: {{used}} / {{limit}} tokens ({{pct}}%)", + "modelTitle": "Model: {{model}}", + "cliDefault": "CLI default", + "closeAgent": "Close {{name}} — ends the process and archives the agent", + "ideTip": "Open the IDE: browse and edit files in {{name}}'s workspace, and see their uncommitted changes as a diff.", + "openIdeAria": "Open the IDE", + "openTerminalTip": "Open your system terminal app in {{cwd}} — a normal shell in this agent's folder, separate from the agent's own terminal.", + "openTerminalAria": "Open a system terminal in this agent's folder" + }, + "memoryPanel": { + "pill": "🧠 memory", + "pillActive": "🧠 memory", + "openTitle": "Search the shared memory your agents build up", + "title": "HIVE MEMORY", + "intro": "What your agents remember across sessions, shared between them. Search it by meaning, not just exact words.", + "notSetUp": "Not set up", + "onReady": "On · ready", + "onGettingReady": "On · getting ready…", + "turnOff": "Turn off", + "turnOn": "Turn on", + "notInstalled": "Meaning-based search isn't installed yet.", + "setUpInPrereqs": "set it up in Prerequisites →", + "plainNotesStill": "Agents still keep plain notes without it.", + "searchLanguage": "Search language", + "modelFast": "Fast", + "modelFastDetail": "English only · ~90 MB", + "modelMultilingual": "Multilingual", + "modelMultilingualDetail": "all languages · ~300 MB", + "searchPlaceholder": "Search by meaning…", + "nothingMatched": "Nothing matched yet.", + "searchFailed": "Couldn't search" + }, + "threads": { + "noSubject": "(no subject)", + "empty": "No conversations yet. Messages this agent receives will appear here as threads.", + "less": "less", + "more": "more", + "replyPlaceholder": "Reply to {{name}}…", + "send": "Send" + }, + "skillsTab": { + "installed": "Installed", + "browse": "browse", + "searchInstalled": "Search installed skills…", + "searchCatalog": "Search the skills catalog…", + "categoryTitle": "Categories as published by the catalog", + "allCategories": "all categories", + "allPublishers": "all publishers", + "loading": "loading…", + "refresh": "refresh", + "scanning": "Scanning…", + "noSkillsInstalled": "No skills installed yet. Open Browse to see what is available.", + "nothingMatches": "Nothing matches that search.", + "openFolder": "open folder", + "shipsWithApp": "ships with the app", + "deleteConfirm": "delete {{name}}?", + "removing": "removing…", + "uninstall": "uninstall", + "loadingCatalog": "Loading the catalog…", + "cachedCopy": "Showing a cached copy — {{error}}.", + "matching": "{{count}} matching", + "matchingFirst": "{{count}} matching · showing the first {{shown}}", + "curatedBy": "curated by abubakarsiddik31/claude-skills-collection", + "installing": "installing…", + "install": "install", + "learnMore": "learn more", + "installFailed": "install failed", + "removeFailed": "could not remove it", + "uninstallFailed": "uninstall failed", + "catalogUnreachable": "could not reach the catalog" + }, + "workersTab": { + "stopping": "stopping", + "working": "working", + "liveWorkers": "Live workers", + "liveIntro": "Isolated workers {{godName}} spins up to handle Slack messages — they run to completion, reply in-thread, then tear down.", + "noneRunning": "No workers running right now.", + "repliesToSlack": "replies to a Slack thread", + "stoppingEllipsis": "stopping…", + "stop": "stop", + "workerIdTitle": "worker / PTY id", + "baseBranchTitle": "base branch the worktree was cut from", + "base": "base: {{branch}}", + "upSinceTitle": "time since spawn", + "up": "up {{age}}", + "idleTitle": "time since last terminal output", + "ptyGone": "pty gone", + "idle": "idle {{age}}", + "tokensTitle": "cumulative tokens (input+output+cache)", + "tokens": "tokens {{value}}", + "uncapped": "uncapped", + "preserved": "Preserved worktrees ({{count}})", + "preservedIntro": "Finished workers whose worktree held un-integrated work — kept (never auto-discarded) and auto-reclaimed once the work lands in its base branch.", + "keptAgo": "kept {{age}} ago" + }, + "memoryGraph": { + "topics": "topics", + "refresh": "refresh", + "readingMemory": "reading memory…", + "topicsShown": "showing {{shown}} of {{total}} topics", + "loadingMemory": "loading memory…", + "messageLinks": "{{count}} message links", + "knowsAbout": "{{a}} knows about “{{b}}”", + "messagesLast": "{{count}} messages · last: {{act}}", + "noMemory": "No memory recorded yet.", + "legendRequest": "request", + "legendQuery": "query", + "legendPropose": "propose", + "legendAgreeDone": "agree/done", + "legendRefuse": "refuse", + "legendInformTopic": "inform/topic" + }, + "integrations": { + "errLabel": "Give it a label.", + "errId": "Could not derive a valid id from the label.", + "errBaseUrl": "Base URL is required.", + "errBaseUrlFormat": "Base URL must be https:// (or http://127.0.0.1 / localhost for a local target).", + "errHeader": "Header name must be 1–64 chars of A–Z, 0–9, or \"-\".", + "couldNotSave": "Could not save.", + "added": "Integration added.", + "updated": "Integration updated.", + "removed": "Removed “{{label}}”.", + "couldNotRemove": "Could not remove.", + "testFailed": "Test failed to run.", + "connected": "✓ Connected", + "connectedWith": "✓ Connected ({{status}})", + "failed": "✕", + "backToList": "← Integrations", + "pickTemplate": "Pick a template", + "galleryDesc": "Choose what you're connecting. The template sets the defaults. Pick Custom REST for anything not listed.", + "anyHttpApi": "Any HTTP API", + "continue": "continue", + "backToTemplates": "← Templates", + "needsSecret": "Needs a {{label}}", + "publicApi": "Public API — no secret needed", + "label": "Label", + "labelHint": "Shown in your list. Id", + "fixed": "fixed", + "baseUrl": "Base URL", + "baseUrlHint": "Set by the {{label}} template.", + "preset": "preset", + "authentication": "Authentication", + "setByTemplate": "set by template", + "headerName": "Header name", + "headerHint": "The secret is sent as {{header}}: .", + "saved": "saved", + "replaceKey": "Replace key", + "pasteYour": "Paste your", + "writeOnly": "Write-only", + "secretDesc": "Encrypted in the main process and never shown again. To change it, paste a new key — the old one can't be read back.", + "blankKeepsKey": "Leave blank to keep the saved key.", + "availability": "Availability", + "enabled": "enabled", + "disabled": "disabled", + "availableToAll": "✓ Available to all workers", + "notAvailableYet": "Not available to workers yet", + "addSecretToEnable": "Add a secret and enable to make it available.", + "readyOnceSaved": "Ready once saved.", + "disabledNoUse": "Disabled — no worker can use it.", + "v1Note": "v1 grants every enabled integration to all workers. Per-worker scoping is coming.", + "testConnection": "Test connection", + "testing": "testing…", + "testAfterSave": "Save the integration first, then test the live connection.", + "testLiveDesc": "Runs a live read-only probe against the base URL with the stored secret.", + "saveIntegration": "Save integration", + "saveChanges": "Save changes", + "title": "Integrations", + "titleDesc": "Connect outside tools so your agents can read and act on them. Secrets are stored encrypted in the main process and never shown again.", + "addIntegration": "add integration", + "empty": "No integrations yet. Connect GitHub or a custom REST API so your agents can use it.", + "addFirst": "add your first integration", + "count": "{{count}} integrations · {{usable}} available to workers", + "needsSecretShort": "Needs secret", + "test": "test", + "edit": "edit" + }, + "kanban": { + "count": "{{count}} tasks", + "newWorkHint": "new work? dispatch it to {{godName}} (monitor tab)", + "colTodo": "TODO", + "colDoing": "DOING", + "colBlocked": "BLOCKED", + "colDone": "DONE", + "openTaskDetails": "open task details", + "needsYouTitle": "waiting on YOUR answer — see the ASK ME tab", + "dismissTitle": "dismiss this task (removes it from the board)", + "dismissAria": "dismiss task", + "taskTitle": "TASK", + "unassigned": "unassigned", + "noDescription": "(no description on this card)", + "humanQA": "HUMAN Q&A", + "awaitingAnswer": "AWAITING YOUR ANSWER — ASK ME TAB", + "dependsOn": "DEPENDS ON", + "assign": "assign", + "priority": "Priority {{level}}/5" + }, + "queueComposer": { + "recording": "● recording — click stop to transcribe", + "transcribing": "transcribing…", + "voice": "voice", + "busyQueued": "{{name}} is busy — {{count}} queued", + "heldFloor": "held — delivery paused floor-wide", + "heldDraft": "held — {{name}}'s terminal has unsent text on its prompt", + "heldPicker": "held — a slash-command picker is open in {{name}}'s terminal", + "heldExited": "held — {{name}}'s terminal has exited", + "sendingOneByOne": "sending to {{name}} one-by-one…", + "pausedTitle": "Auto-delivery is paused for the whole floor. Resume it in the Command Center, or use \"send now\" on a message below.", + "dropToAttach": "DROP TO ATTACH", + "queue": "QUEUE", + "closePicker": "close picker", + "recoverPrompt": "recover prompt", + "clearAllTitle": "Clear all queued messages", + "clearAll": "clear all", + "removeAttachment": "Remove attachment", + "messagePlaceholder": "Message {{name}}", + "busyPlaceholder": "{{name}} is busy — queue a message", + "files": "files", + "collapse": "Collapse this message", + "showFull": "Show the full message", + "seeLess": "see less", + "seeMore": "see more", + "sendNowTitle": "Deliver this message even though auto-delivery is paused. It moves to the front of the queue and types in as soon as the terminal is free.", + "sendNow": "send now", + "sendingWhenFree": "sending when free…", + "removeFromQueue": "Remove from queue", + "ffNoKeyTitle": "Dictation needs a free Groq API key. Click the info mark for the steps.", + "ffStopTranscribe": "Stop & transcribe", + "ffTitle": "Free Flow — dictate into the queue. Click, or hold Option (⌥).", + "stop": "stop", + "ffHowEnable": "How do I enable dictation?", + "ffSetupTitle": "Set up dictation", + "ffSetupIntro": "Speak instead of typing. Groq transcribes it, and their free tier covers this — no card, no cost.", + "ffCreateKey": "Create a free key at", + "ffPasteKey": "Paste it into Settings → Voice → Groq API key", + "ffClickOrHold": "Click voice, or hold the right Option key to talk", + "ffHoldHint": "Hold it ALONE for a moment to start; release to transcribe into the composer, where you can edit before sending. Either Option key works, and Option+key combos still reach the terminal untouched." + }, + "idePanel": { + "workspace": "{{name}}'s workspace", + "workspaceInferred": "No agent was named when the IDE opened — showing {{name}}'s workspace (the current selection)", + "assumed": "assumed", + "noAgent": "no agent", + "noWorkspace": "no workspace", + "closeIde": "Close IDE (Esc)", + "expandGit": "Expand the git panel", + "collapseGit": "Collapse the git panel — more room for the file tree", + "rail": { + "changes": "changes", + "history": "history", + "compare": "compare" + }, + "refresh": "Refresh", + "files": "files", + "rev": "REV", + "img": "IMG", + "diff": "DIFF", + "closeTab": "Close tab", + "loadingDiff": "loading diff…", + "binaryDiff": "binary file — no text diff", + "workingTree": "working tree", + "refreshDiff": "Refresh diff", + "mdSourceOnly": "Source only", + "mdSplit": "Source + preview", + "mdPreview": "Rendered preview", + "code": "code", + "split": "split", + "preview": "preview", + "viewImage": "view image", + "copyPath": "copy path", + "saveTitle": "Save (Cmd/Ctrl+S)", + "saved": "saved", + "save": "save" + }, + "gitPanes": { + "jumpConfirm": "Jump the repo to {{sha}} (\"{{subject}}\")?\n\nThis detaches HEAD. Blocked automatically if the tree is dirty or an agent is mid-run.", + "nowAt": "now at {{sha}} (detached HEAD)", + "loadingHistory": "loading history…", + "loadOlder": "load older…", + "checkoutTitle": "Check out this commit (detached HEAD)", + "jumpHere": "jump here", + "loadingFiles": "loading files…", + "noFileChanges": "no file changes (merge?)", + "comparing": "comparing…", + "switchConfirm": "Switch this repo to '{{head}}'?\n\nBlocked automatically if the tree is dirty or an agent is mid-run.", + "switchedTo": "switched to {{head}}", + "baseTitle": "Base — the branch you're comparing against", + "swapTitle": "Swap base ↔ compare", + "compareTitle": "Compare — the branch whose changes you're viewing", + "aheadBehind": "'{{head}}' is {{ahead}} ahead and {{behind}} behind '{{base}}'", + "modeThreeTitle": "Showing what the compare branch ADDS since the common ancestor (PR-style). Click for the literal two-dot difference.", + "modeTwoTitle": "Showing the literal difference between the two branch states. Click for PR-style (what compare adds).", + "sinceCommonAncestor": "since common ancestor", + "literalDifference": "literal difference", + "switchToTitle": "Check out '{{head}}'", + "switchTo": "switch to {{branch}}", + "noDifferences": "no differences" + }, + "imagePreview": { + "fitTitle": "Scale the image down to fit the pane", + "oneToOneTitle": "Show every pixel at 1:1 (scroll to pan)", + "fit": "fit", + "viewSourceTitle": "Open the SVG markup in the editor", + "viewSource": "view source", + "loading": "loading image…", + "decodeFailed": "could not decode this image — the file may be corrupt or misnamed" + } +} diff --git a/tools/check-ptBR-parity.cjs b/tools/check-ptBR-parity.cjs new file mode 100644 index 0000000000..e8e9b1b1de --- /dev/null +++ b/tools/check-ptBR-parity.cjs @@ -0,0 +1,111 @@ +#!/usr/bin/env node +/** + * check-ptBR-parity.cjs — paridade de chaves en.json <-> pt-BR.json. + * + * O i18next cai em silencio para o ingles (`fallbackLng: 'en'`) quando uma + * chave falta no locale ativo. Este script impede que isso passe batido: + * falha (exit 1) listando chaves ausentes, orfas e placeholders `{{...}}` + * divergentes. Rode antes de cada push da branch feat/pt-BR. + * + * Uso: + * node tools/check-ptBR-parity.cjs [--audit-copies] + * + * --audit-copies: lista (sem falhar) strings ainda identicas ao ingles, + * util na revisao final (Task 7). Nao falha porque nomes proprios, CLIs + * e comandos ficam propositalmente em ingles. + * + * Segue o mesmo espirito de test/arabic-ui.test.cjs e + * test/i18n-god-name.test.cjs, mas focado no par en/pt-BR. + */ +'use strict'; + +const fs = require('fs'); +const path = require('path'); + +const ROOT = path.join(__dirname, '..'); +const EN_PATH = path.join(ROOT, 'src', 'renderer', 'src', 'i18n', 'locales', 'en.json'); +const PT_PATH = path.join(ROOT, 'src', 'renderer', 'src', 'i18n', 'locales', 'pt-BR.json'); + +const AUDIT_COPIES = process.argv.includes('--audit-copies'); + +function load(p) { + return JSON.parse(fs.readFileSync(p, 'utf8')); +} + +/** Achata objeto em mapa caminho -> valor-folha. Arrays viram `chave.indice`. */ +function flatten(node, prefix, out) { + if (typeof node === 'string' || typeof node !== 'object' || node === null) { + out.set(prefix, node); + return out; + } + const entries = Array.isArray(node) + ? node.map((v, i) => [String(i), v]) + : Object.entries(node); + for (const [k, v] of entries) { + flatten(v, prefix ? `${prefix}.${k}` : k, out); + } + return out; +} + +/** Extrai placeholders `{{nome}}` de uma string, como conjunto ordenado. */ +function placeholders(s) { + const found = s.match(/\{\{[^}]+\}\}/g) || []; + return [...new Set(found)].sort(); +} + +function main() { + const en = flatten(load(EN_PATH), '', new Map()); + const pt = flatten(load(PT_PATH), '', new Map()); + + const missing = [...en.keys()].filter((k) => !pt.has(k)).sort(); + const orphan = [...pt.keys()].filter((k) => !en.has(k)).sort(); + + const placeholderBreaks = []; + const typeBreaks = []; + for (const [k, enVal] of en) { + if (!pt.has(k)) continue; + const ptVal = pt.get(k); + if (typeof enVal !== typeof ptVal) { + typeBreaks.push(`${k} (en: ${typeof enVal}, pt-BR: ${typeof ptVal})`); + continue; + } + if (typeof enVal === 'string') { + const a = placeholders(enVal); + const b = placeholders(ptVal); + if (a.join('|') !== b.join('|')) { + placeholderBreaks.push(`${k} (en: ${a.join(', ') || '—'} | pt-BR: ${b.join(', ') || '—'})`); + } + } + } + + let failed = false; + const report = (title, items) => { + if (!items.length) return; + failed = true; + console.error(`\n${title} (${items.length}):`); + for (const i of items) console.error(` - ${i}`); + }; + + report('CHAVES AUSENTES em pt-BR.json (cairiam p/ ingles em silencio)', missing); + report('CHAVES ORFAS em pt-BR.json (nao existem em en.json)', orphan); + report('PLACEHOLDERS DIVERGENTES (ex. {{godName}} quebrado)', placeholderBreaks); + report('TIPOS DIVERGENTES', typeBreaks); + + if (AUDIT_COPIES) { + const copies = [...en.entries()] + .filter(([k, v]) => typeof v === 'string' && pt.get(k) === v) + .map(([k]) => k) + .sort(); + console.log(`\nStrings ainda identicas ao ingles: ${copies.length}/${en.size}`); + for (const k of copies.slice(0, 50)) console.log(` = ${k}`); + if (copies.length > 50) console.log(` ... e mais ${copies.length - 50}`); + } + + if (failed) { + console.error('\nPARIDADE FALHOU. Traduza as chaves listadas e rode de novo.'); + process.exit(1); + } + console.log(`Paridade OK: ${pt.size} chaves, 0 ausentes, 0 orfas, placeholders intactos.`); +} + +main(); From cb15525fc3cc361588c75b8b4ba663beddc850db Mon Sep 17 00:00:00 2001 From: T3sh Date: Tue, 13 Oct 2026 23:37:16 -0300 Subject: [PATCH 02/24] feat(i18n): traduz Task 3 pt-BR - nucleo comum (315 chaves) common, settings, settingsHero, onboarding, setupPanel. Glossario: agente, escritorio (floor), colmeia (hive), criar (spawn), quadro (board), tarefa (task), gatilho (trigger), Configuracoes. --- src/renderer/src/i18n/locales/pt-BR.json | 604 +++++++++++------------ 1 file changed, 302 insertions(+), 302 deletions(-) diff --git a/src/renderer/src/i18n/locales/pt-BR.json b/src/renderer/src/i18n/locales/pt-BR.json index 68aac27438..89729186b4 100644 --- a/src/renderer/src/i18n/locales/pt-BR.json +++ b/src/renderer/src/i18n/locales/pt-BR.json @@ -1,22 +1,22 @@ { "common": { - "on": "on", - "off": "off", - "cancel": "cancel", - "save": "save", - "close": "close", - "back": "back", - "next": "next", - "finish": "finish", - "saving": "saving...", - "copy": "copy", - "delete": "delete", - "hide": "hide", - "show": "show", - "search": "search", + "on": "ativado", + "off": "desativado", + "cancel": "cancelar", + "save": "salvar", + "close": "fechar", + "back": "voltar", + "next": "avançar", + "finish": "concluir", + "saving": "salvando…", + "copy": "copiar", + "delete": "excluir", + "hide": "ocultar", + "show": "mostrar", + "search": "pesquisar", "tokens": "tokens", - "restarting": "restarting…", - "add": "add" + "restarting": "reiniciando…", + "add": "adicionar" }, "commandBar": { "free": "free", @@ -157,21 +157,21 @@ "openTerminalAria": "Open a system terminal in this agent's folder" }, "settingsHero": { - "sponsoredBy": "Sponsored by", - "visit": "visit", - "whatsNew": "what's new", - "whatsNewTitle": "Show the release notes for the update you were last told about", - "starOnGitHub": "star on GitHub", - "reportProblem": "report a problem", - "fullChangelog": "full changelog →", - "announcement": "Announcement", - "proLaunch": "v0.5.0 launches with Munder Difflin Pro.", - "proCommunityFree": "Community stays free, stays open, and keeps getting updates.", - "proParagraph": "Pro ships with new features and integrations, with more posted throughout the year, and it stays ahead of Community, for power users who want the full potential of coding agents and agent harnesses. The Pro roadmap also includes a mobile app.", - "foundersWallTitle": "On the Founders' Wall?", - "foundersWallBody": "A month of Munder Difflin Pro free, then 50% off the annual plan. For the first 100 people on the wall.", - "seeTheWall": "see the wall", - "joinDiscord": "join Discord" + "sponsoredBy": "Patrocinado por", + "visit": "visitar", + "whatsNew": "novidades", + "whatsNewTitle": "Mostrar as notas da versão sobre a atualização que você viu por último", + "starOnGitHub": "estrela no GitHub", + "reportProblem": "relatar um problema", + "fullChangelog": "changelog completo →", + "announcement": "Anúncio", + "proLaunch": "A v0.5.0 chega com o Munder Difflin Pro.", + "proCommunityFree": "O Community continua gratuito, aberto e recebendo atualizações.", + "proParagraph": "O Pro vem com novos recursos e integrações, com mais novidades ao longo do ano, e segue à frente do Community — para usuários avançados que querem todo o potencial de agentes de código e harnesses de agentes. O roadmap do Pro também inclui um app mobile.", + "foundersWallTitle": "No Mural dos Fundadores?", + "foundersWallBody": "Um mês de Munder Difflin Pro grátis, depois 50% de desconto no plano anual. Para as primeiras 100 pessoas no mural.", + "seeTheWall": "ver o mural", + "joinDiscord": "entrar no Discord" }, "officeTheme": { "title": "Office Theme", @@ -194,188 +194,188 @@ "deleteSwitch": "delete {{count}} & switch" }, "settings": { - "title": "SETTINGS", - "changeHomeTitle": "CHANGE HOME FOLDER", - "resetTitle": "RESET EVERYTHING?", - "close": "close", - "change": "change...", - "apply": "applying...", - "moveAndRestart": "move & restart", - "switchAndRestart": "switch & restart", - "resetting": "resetting...", - "eraseEverything": "erase everything & restart", + "title": "CONFIGURAÇÕES", + "changeHomeTitle": "TROCAR PASTA DE LAR", + "resetTitle": "APAGAR TUDO?", + "close": "fechar", + "change": "alterar…", + "apply": "aplicando…", + "moveAndRestart": "mover e reiniciar", + "switchAndRestart": "trocar e reiniciar", + "resetting": "apagando…", + "eraseEverything": "apagar tudo e reiniciar", "nav": { - "general": "General", - "prerequisites": "Prerequisites", - "agentsModels": "Agents & Models", - "autonomyBudgets": "Autonomy & Budgets", - "connections": "Connections", - "voice": "Voice", - "memoryKnowledge": "Memory & Knowledge" + "general": "Geral", + "prerequisites": "Pré-requisitos", + "agentsModels": "Agentes e Modelos", + "autonomyBudgets": "Autonomia e Orçamentos", + "connections": "Conexões", + "voice": "Voz", + "memoryKnowledge": "Memória e Conhecimento" }, "changeHome": { - "newHome": "New home folder", - "moveTitle": "Move existing data (recommended)", - "moveDesc": "Copy this harness's hive (every agent, memory, task) and the semantic-memory palace into the new folder. The old folder is left untouched as a backup you can delete later.", - "freshTitle": "Start fresh", - "freshDesc": "Point the harness at the new (empty) folder. Your existing data stays in the old folder, simply unused." + "newHome": "Nova pasta de lar", + "moveTitle": "Mover dados existentes (recomendado)", + "moveDesc": "Copia a colmeia deste harness (cada agente, memória, tarefa) e o palácio de memória semântica para a nova pasta. A pasta antiga fica intacta como backup que você pode apagar depois.", + "freshTitle": "Começar do zero", + "freshDesc": "Aponta o harness para a nova pasta (vazia). Seus dados existentes ficam na pasta antiga, simplesmente sem uso." }, "resetConfirm": { - "body": "This permanently erases all of {{godName}}'s memories and the entire hive, and cannot be undone. Any running sessions will be terminated and the app will relaunch into onboarding. Are you sure?" + "body": "Isso apaga permanentemente as memórias do {{godName}} e a colmeia inteira, sem volta. Sessões em execução serão encerradas e o app vai reabrir no onboarding. Tem certeza?" }, "general": { - "homeFolder": "Home folder", - "environment": "Environment", - "keepAwake": "Keep Mac awake while agents run", - "keepAwakeDesc": "Blocks display sleep so schedules and terminals keep firing on time. Costs battery — best on AC.", - "simpleMode": "Explain things simply", - "simpleModeDesc": "Agents brief you in plain language instead of engineering shorthand.", - "notifications": "Notifications", - "desktopNotifications": "Desktop notifications", - "desktopNotificationsDesc": "Native toasts when an agent finishes or needs your input.", - "maintenance": "Maintenance", - "autoCompact": "Scheduled auto-compact", - "autoCompactDesc": "Queue /compact for every agent on a schedule (hourly by default; interval in the Triggers tab). Off by default — long-running agents may overflow their context without it.", - "autoUpdate": "Auto-update", - "autoUpdateDesc": "Check GitHub releases and download updates in the background; you choose when to restart. Never restarts on its own.", - "telemetry": "Anonymous usage stats", - "telemetryDesc": "A handful of anonymous events (app opened, agent spawned, feature used) — never prompts, code, paths, or agent output. Full list in TELEMETRY.md.", - "language": "Language", - "languageDesc": "Choose the language for the app interface. English is the default.", - "dangerZone": "DANGER ZONE", - "dangerDesc": "Reset wipes {{godName}}'s memories, the entire hive (every agent, message, task, and the board), the semantic-memory palace, and all settings - then takes you back to onboarding.", - "resetStartOver": "reset & start over", - "arabicTerminal": "Arabic / RTL text in terminals", - "arabicTerminalDesc": "Renders terminals with the browser's text engine so Arabic joins and reads right-to-left (xterm has no bidi of its own). Off is the GPU renderer: faster, but RTL-blind. Applies to open terminals and new ones alike.", - "arabicTerminalFollowsLanguage": "Following your app language. Switch it here to override that either way — the choice sticks even if you change language again." + "homeFolder": "Pasta de lar", + "environment": "Ambiente", + "keepAwake": "Manter o Mac acordado enquanto agentes rodam", + "keepAwakeDesc": "Bloqueia o repouso da tela para agendas e terminais dispararem na hora. Custa bateria — melhor na tomada.", + "simpleMode": "Explicar tudo de forma simples", + "simpleModeDesc": "Os agentes informam você em linguagem simples em vez de jargão de engenharia.", + "notifications": "Notificações", + "desktopNotifications": "Notificações na área de trabalho", + "desktopNotificationsDesc": "Avisos nativos quando um agente termina ou precisa da sua entrada.", + "maintenance": "Manutenção", + "autoCompact": "Auto-compactação agendada", + "autoCompactDesc": "Enfileira /compact para cada agente por agenda (de hora em hora por padrão; intervalo na aba Gatilhos). Desligado por padrão — agentes de longa duração podem estourar o contexto sem isso.", + "autoUpdate": "Atualização automática", + "autoUpdateDesc": "Verifica releases no GitHub e baixa atualizações em segundo plano; você escolhe quando reiniciar. Nunca reinicia sozinho.", + "telemetry": "Estatísticas anônimas de uso", + "telemetryDesc": "Um punhado de eventos anônimos (app aberto, agente criado, recurso usado) — nunca prompts, código, caminhos ou saída de agentes. Lista completa em TELEMETRY.md.", + "language": "Idioma", + "languageDesc": "Escolha o idioma da interface do app. Inglês é o padrão.", + "dangerZone": "ZONA DE PERIGO", + "dangerDesc": "Apagar limpa as memórias do {{godName}}, a colmeia inteira (cada agente, mensagem, tarefa e o quadro), o palácio de memória semântica e todas as configurações — e leva você de volta ao onboarding.", + "resetStartOver": "apagar e recomeçar", + "arabicTerminal": "Texto árabe / RTL em terminais", + "arabicTerminalDesc": "Renderiza terminais com o engine de texto do navegador para o árabe ligar as letras e ler da direita para a esquerda (o xterm não tem bidi próprio). Desligado é o renderizador GPU: mais rápido, mas cego a RTL. Vale para terminais abertos e novos.", + "arabicTerminalFollowsLanguage": "Seguindo o idioma do app. Troque aqui para forçar de um jeito ou de outro — a escolha persiste mesmo se você trocar de idioma de novo." }, "agentsModels": { - "defaultModel": "Default agent model", - "defaultModelDesc": "Every newly spawned Claude agent ({{godName}} included) starts on this model unless picked per-agent. Marked \"· default\" in the model pickers.", - "savedNote": "saved — applies to newly spawned agents", - "saveFailed": "save failed", - "advanced": "Advanced", - "maxTurns": "Max turns per run", - "unlimited": "unlimited", - "blankUnlimited": "blank = unlimited" + "defaultModel": "Modelo padrão dos agentes", + "defaultModelDesc": "Todo agente Claude recém-criado (incluindo {{godName}}) começa neste modelo, salvo escolha por agente. Marcado \"· default\" nos seletores de modelo.", + "savedNote": "salvo — vale para agentes recém-criados", + "saveFailed": "falha ao salvar", + "advanced": "Avançado", + "maxTurns": "Máx. de turnos por execução", + "unlimited": "ilimitado", + "blankUnlimited": "em branco = ilimitado" }, "autonomy": { - "autonomy": "Autonomy", - "autoOn": "Autonomous — agents act without asking", - "autoOff": "Ask-first — agents pause for tool approval", - "autoDesc": "Applies to newly spawned agents (each agent's command can still override).", - "autonomous": "autonomous", - "askFirst": "ask-first", + "autonomy": "Autonomia", + "autoOn": "Autônomo — agentes agem sem perguntar", + "autoOff": "Perguntar antes — agentes pausam para aprovar ferramentas", + "autoDesc": "Vale para agentes recém-criados (o comando de cada agente ainda pode sobrescrever).", + "autonomous": "autônomo", + "askFirst": "perguntar primeiro", "breaker": "Circuit breaker", - "breakerDesc": "Guard against runaway agents and spend. The breaker steers, then constrains, then stops an agent that crosses these.", - "floorBudget": "floor token budget", - "budgetPlaceholder": "e.g. 1000000", + "breakerDesc": "Proteção contra agentes descontrolados e gastos. O breaker conduz, depois restringe e depois para um agente que cruzar estes limites.", + "floorBudget": "orçamento de tokens do escritório", + "budgetPlaceholder": "ex. 1000000", "budgetEquals": "= {{value}} tokens", - "budgetTotal": "total tokens across the floor", - "velocity": "token velocity (tok/min)", - "velocityPlaceholder": "e.g. 200000", - "repeatedLimit": "repeated-tool limit", - "errorStormLimit": "error-storm limit", - "defaultPlaceholder": "default", - "hardStop": "Hard stop", - "hardStopDesc": "When tripped, KILL the agent instead of just constraining it. Off = steer-first (recommended).", - "killOnTrip": "kill on trip", - "steerFirst": "steer first", - "saved": "saved" + "budgetTotal": "total de tokens no escritório", + "velocity": "velocidade de tokens (tok/min)", + "velocityPlaceholder": "ex. 200000", + "repeatedLimit": "limite de ferramenta repetida", + "errorStormLimit": "limite de tempestade de erros", + "defaultPlaceholder": "padrão", + "hardStop": "Parada total", + "hardStopDesc": "Quando disparado, MATA o agente em vez de só restringi-lo. Desligado = conduzir primeiro (recomendado).", + "killOnTrip": "matar ao disparar", + "steerFirst": "conduzir primeiro", + "saved": "salvo" }, "memory": { - "semanticMemory": "Semantic memory", - "crossSession": "Cross-session recall", - "crossSessionDesc": "Agents' markdown memory is indexed for instant search. The embedding model lives in the Memory panel.", - "kg": "Knowledge Graph", - "kgTitle": "Enterprise knowledge base", - "kgDesc": "Add your docs, images & PDFs; agents query them on demand via the kg tool.", - "adding": "adding…", - "addFiles": "add files…", - "docCount": "{{count}} document indexed", - "docCountPlural": "{{count}} documents indexed" + "semanticMemory": "Memória semântica", + "crossSession": "Recuperação entre sessões", + "crossSessionDesc": "A memória markdown dos agentes é indexada para pesquisa instantânea. O modelo de embedding fica no painel Memória.", + "kg": "Grafo de Conhecimento", + "kgTitle": "Base de conhecimento empresarial", + "kgDesc": "Adicione seus docs, imagens e PDFs; os agentes consultam sob demanda via a ferramenta kg.", + "adding": "adicionando…", + "addFiles": "adicionar arquivos…", + "docCount": "{{count}} documento indexado", + "docCountPlural": "{{count}} documentos indexados" }, "connections": { "slack": "Slack", - "slackIntegration": "Slack integration", - "showSlackHelp": "Show Slack connect steps", - "slackDesc": "Pipe a Slack channel's messages straight into {{godName}}'s queue.", - "connected": "● Connected", - "notConnected": "○ Not connected", - "signingSecret": "Signing secret", + "slackIntegration": "Integração com Slack", + "showSlackHelp": "Mostrar passos de conexão do Slack", + "slackDesc": "Canaliza as mensagens de um canal do Slack direto para a fila do {{godName}}.", + "connected": "● Conectado", + "notConnected": "○ Não conectado", + "signingSecret": "Segredo de assinatura", "signingSecretPlaceholder": "Slack app -> Basic Information -> Signing Secret", - "botToken": "Bot token", - "channelId": "Channel id (optional)", - "channelPlaceholder": "C0123... or blank for any", - "port": "Port", - "proactivePosting": "Proactive posting (app-initiated) — off by default", - "start": "start", - "connectedBtn": "connected", - "stop": "stop", - "listening": "listening", - "stopped": "stopped", - "requestUrl": "Request URL - paste into Slack Event Subscriptions", - "lastRequestUrl": "last Request URL - Slack reuses it until you Stop", - "slackHint": "In your Slack app: enable Event Subscriptions, add the message.channels / message.groups bot event, set the Request URL above, and reinstall to your workspace. The tunnel URL changes on every restart, so re-paste it after pressing Start again.", - "webhooks": "Webhook triggers", - "showWebhookHelp": "Show webhook API format", - "webhooksDesc": "One endpoint per caller, each with its own secret and mode. They all share one server, so another webhook costs nothing.", - "listeningOn": "● Listening", - "notListening": "○ Not listening", - "addWebhook": "add webhook", - "webhookWarning": "Every webhook you switch on is a PUBLIC endpoint anyone holding its secret can post to. New ones arrive off.", - "noWebhooks": "No webhooks yet. Add one to give a tool a URL it can hand work to.", - "namePlaceholder": "what calls this?", - "sure": "sure?", + "botToken": "Token do bot", + "channelId": "ID do canal (opcional)", + "channelPlaceholder": "C0123... ou em branco para qualquer um", + "port": "Porta", + "proactivePosting": "Postagem proativa (iniciada pelo app) — desligada por padrão", + "start": "iniciar", + "connectedBtn": "conectado", + "stop": "parar", + "listening": "ouvindo", + "stopped": "parado", + "requestUrl": "URL de solicitação — cole em Assinaturas de Eventos do Slack", + "lastRequestUrl": "última URL de solicitação — o Slack reutiliza até você pressionar parar", + "slackHint": "No seu app do Slack: ative Assinaturas de Eventos, adicione o evento de bot message.channels / message.groups, defina a URL de solicitação acima e reinstale no seu workspace. A URL do túnel muda a cada reinício, então cole de novo após pressionar Iniciar.", + "webhooks": "Gatilhos de webhook", + "showWebhookHelp": "Mostrar formato da API de webhooks", + "webhooksDesc": "Um endpoint por chamador, cada um com seu segredo e modo. Todos dividem um servidor só, então outro webhook não custa nada.", + "listeningOn": "● Ouvindo", + "notListening": "○ Não ouvindo", + "addWebhook": "adicionar webhook", + "webhookWarning": "Todo webhook que você liga é um endpoint PÚBLICO em que qualquer um com o segredo pode postar. Novos chegam desligados.", + "noWebhooks": "Sem webhooks ainda. Adicione um para dar a uma ferramenta uma URL para entregar trabalho.", + "namePlaceholder": "quem chama isso?", + "sure": "certo?", "url": "URL", - "endpointPlaceholder": "starts once the webhook server is listening", - "secret": "Secret", - "rotate": "rotate", - "mode": "Mode", - "webhooksHint": "Callers POST to a webhook's URL with its secret in the x-md-webhook-secret header. Each one checks bodies against its own JSON schema — edit that in the Triggers tab of {{godName}}'s Command Center, where the history of everything that arrived lives too.", - "organisation": "Organisation", - "orgKey": "Organisation key", - "orgKeyDesc": "How a teammate's install addresses yours.", - "apiKey": "API key", - "orgKeyPlaceholder": "paste your organisation key", - "orgConfigOnly": "Configuration only for now. The organisation messaging service does not exist yet, so a key here starts no transport — it is saved, shown in the Triggers tab, and waits." + "endpointPlaceholder": "inicia quando o servidor de webhooks estiver ouvindo", + "secret": "Segredo", + "rotate": "girar", + "mode": "Modo", + "webhooksHint": "Chamadores fazem POST na URL do webhook com o segredo no header x-md-webhook-secret. Cada um valida corpos contra seu próprio esquema JSON — edite na aba Gatilhos do Centro de Comando do {{godName}}, onde o histórico de tudo que chegou também vive.", + "organisation": "Organização", + "orgKey": "Chave da organização", + "orgKeyDesc": "Como a instalação de um colega de equipe endereça a sua.", + "apiKey": "Chave de API", + "orgKeyPlaceholder": "cole sua chave da organização", + "orgConfigOnly": "Só configuração por enquanto. O serviço de mensagens da organização ainda não existe, então uma chave aqui não inicia transporte nenhum — ela é salva, mostrada na aba Gatilhos, e aguarda." }, "voice": { "freeFlow": "Free Flow", - "freeFlowTitle": "Free Flow (voice dictation)", - "freeFlowDesc": "Push-to-talk dictation: speak, and Groq Whisper drops the text into the queue composer.", - "groqKey": "Groq API key", - "groqPlaceholder": "gsk_... (get a free key at console.groq.com)", - "model": "Model", - "fast": "whisper-large-v3-turbo (fast)", - "accurate": "whisper-large-v3 (accurate)", - "freeFlowHint": "Two ways to dictate: click the mic button above Send in the queue composer (click to record, click again to transcribe), or — while viewing any agent's terminal — hold Option (⌥) to talk and release to transcribe. Either way the text lands in the composer draft for you to review before sending. macOS will ask for microphone permission the first time you record.", - "realtime": "Realtime {{godName}}", - "voiceChat": "Voice chat with {{godName}}", - "voiceChatDesc": "Talk to the orchestrator in real time. Toggle it on from {{godName}}'s tab; choose which microphone and speaker the voice loop uses here.", - "openaiKey": "OpenAI API key · voice", - "openaiKeyDesc1": "Talking to {{godName}} runs on OpenAI's Realtime API — speech in, speech out, over a live connection to {{model}}. That is a different service from the Claude subscription your agents run on, so it needs its own OpenAI API key.", - "openaiKeyDesc2": "Paste it once below. It is encrypted on this machine and never shown again — each voice session mints its own short-lived token from it, and the key itself never leaves your computer. It is the same OpenAI key listed under Agents & Models; setting it in either place is enough.", - "keyPlaceholderSaved": "key saved — paste a new one to replace it", - "save": "Save", - "keySaved": "Key saved — Talk is ready. Start it from {{godName}}'s card.", - "noKey": "No key yet — Talk stays disabled until one is saved.", - "keySavedNote": "Key saved — Talk is ready.", - "couldNotSave": "Could not save the key.", - "idleDisconnect": "Idle auto-disconnect", - "30s": "30 seconds", - "1m": "1 minute", - "2m": "2 minutes", - "3m": "3 minutes", - "5m": "5 minutes", - "10m": "10 minutes", - "never": "Off (never)", - "idleDisconnectDesc": "How long the voice session stays open with no talking before it auto-closes. The spend cap still stops a runaway session even when this is off." + "freeFlowTitle": "Free Flow (ditado por voz)", + "freeFlowDesc": "Ditado push-to-talk: fale, e o Groq Whisper joga o texto no composer da fila.", + "groqKey": "Chave de API da Groq", + "groqPlaceholder": "gsk_... (pegue uma chave grátis em console.groq.com)", + "model": "Modelo", + "fast": "whisper-large-v3-turbo (rápido)", + "accurate": "whisper-large-v3 (preciso)", + "freeFlowHint": "Dois jeitos de ditar: clique o botão do microfone acima de Enviar no composer da fila (clique para gravar, clique de novo para transcrever), ou — vendo o terminal de qualquer agente — segure Option (⌥) para falar e solte para transcrever. De todo jeito o texto cai no rascunho do composer para você revisar antes de enviar. O macOS vai pedir permissão de microfone na primeira gravação.", + "realtime": "{{godName}} em Tempo Real", + "voiceChat": "Chat de voz com {{godName}}", + "voiceChatDesc": "Fale com o orquestrador em tempo real. Ative na aba do {{godName}}; escolha aqui qual microfone e alto-falante o loop de voz usa.", + "openaiKey": "Chave de API da OpenAI · voz", + "openaiKeyDesc1": "Falar com {{godName}} roda na Realtime API da OpenAI — fala entra, fala sai, numa conexão ao vivo com {{model}}. É um serviço diferente da assinatura Claude em que seus agentes rodam, então precisa da própria chave de API da OpenAI.", + "openaiKeyDesc2": "Cole uma vez abaixo. Ela é criptografada nesta máquina e nunca mais mostrada — cada sessão de voz cunha seu próprio token de curta duração a partir dela, e a chave em si nunca sai do seu computador. É a mesma chave OpenAI listada em Agentes e Modelos; definir em qualquer um dos lugares basta.", + "keyPlaceholderSaved": "chave salva — cole uma nova para substituir", + "save": "Salvar", + "keySaved": "Chave salva — Falar está pronto. Inicie no cartão do {{godName}}.", + "noKey": "Sem chave ainda — Falar fica desativado até salvar uma.", + "keySavedNote": "Chave salva — Falar está pronto.", + "couldNotSave": "Não foi possível salvar a chave.", + "idleDisconnect": "Desconexão automática por ociosidade", + "30s": "30 segundos", + "1m": "1 minuto", + "2m": "2 minutos", + "3m": "3 minutos", + "5m": "5 minutos", + "10m": "10 minutos", + "never": "Desligado (nunca)", + "idleDisconnectDesc": "Quanto tempo a sessão de voz fica aberta sem ninguém falar antes de fechar sozinha. O teto de gasto ainda para uma sessão descontrolada mesmo com isso desligado." }, - "saved": "Saved", - "saving": "Saving…", - "unsavedChanges": "unsaved changes", - "unsavedWarning": "You have unsaved settings. Close anyway and lose them?" + "saved": "Salvo", + "saving": "Salvando…", + "unsavedChanges": "alterações não salvas", + "unsavedWarning": "Você tem configurações não salvas. Fechar mesmo assim e perdê-las?" }, "commandCenter": { "title": "COMMAND CENTER", @@ -578,61 +578,61 @@ }, "onboarding": { "titles": { - "persona": "WELCOME TO MUNDER DIFFLIN", - "welcome": "MEET YOUR OFFICE", - "home": "STEP 1 OF 4 · HARNESS HOME", - "homePlain": "STEP 1 OF 4 · A HOME FOR THE APP", - "orchestrator": "STEP 2 OF 4 · YOUR CLONE'S ENGINE", - "orchestratorPlain": "STEP 2 OF 4 · YOUR CLONE", - "repos": "STEP 3 OF 4 · YOUR REPOS", - "reposPlain": "STEP 3 OF 4 · YOUR PROJECTS", - "permissions": "STEP 4 OF 4 · PERMISSIONS & RELIABILITY", - "done": "ALL SET" + "persona": "BOAS-VINDAS AO MUNDER DIFFLIN", + "welcome": "CONHEÇA SEU ESCRITÓRIO", + "home": "PASSO 1 DE 4 · LAR DO HARNESS", + "homePlain": "PASSO 1 DE 4 · UM LAR PARA O APP", + "orchestrator": "PASSO 2 DE 4 · O ENGINE DO SEU CLONE", + "orchestratorPlain": "PASSO 2 DE 4 · SEU CLONE", + "repos": "PASSO 3 DE 4 · SEUS REPOS", + "reposPlain": "PASSO 3 DE 4 · SEUS PROJETOS", + "permissions": "PASSO 4 DE 4 · PERMISSÕES E CONFIABILIDADE", + "done": "TUDO PRONTO" }, "persona": { - "headline": "A CLONE OF YOU, WORKING 24/7", - "body": "Munder Difflin turns the CLI agent you already use into a clone of you — one that runs an office of long-running agents and keeps working while you're away. It manages everything around them: context, memory, tasks, triggers, environment, files, and integrations.", - "bodyLocal": " Everything runs on this machine.", - "ask": "FIRST — WHO ARE YOU? (we'll tailor the setup)", - "technicalTitle": "I'M TECHNICAL", - "technicalDesc": "I write code or work in a terminal. Show me CLI commands, flags, and model ids.", - "nonTechnicalTitle": "I'M NON-TECHNICAL", - "nonTechnicalDesc": "I'm in marketing, sales, ops, or just starting out. Explain things in plain language." + "headline": "UM CLONE SEU, TRABALHANDO 24/7", + "body": "O Munder Difflin transforma o agente CLI que você já usa num clone seu — um clone que comanda um escritório de agentes de longa duração e continua trabalhando enquanto você está fora. Ele gerencia tudo ao redor deles: contexto, memória, tarefas, gatilhos, ambiente, arquivos e integrações.", + "bodyLocal": " Tudo roda nesta máquina.", + "ask": "PRIMEIRO — QUEM É VOCÊ? (vamos adaptar a configuração)", + "technicalTitle": "SOU DA ÁREA TÉCNICA", + "technicalDesc": "Escrevo código ou trabalho no terminal. Mostre-me comandos CLI, flags e ids de modelos.", + "nonTechnicalTitle": "NÃO SOU DA ÁREA TÉCNICA", + "nonTechnicalDesc": "Trabalho com marketing, vendas, operações ou estou começando agora. Explique tudo em linguagem simples." }, "welcome": { - "headline": "YOUR CLONE AND THE FLOOR IT RUNS", - "descPlain": "Your clone runs a small office of AI workers, and you watch it all from one screen. Here's what's inside:", - "desc": "Your clone coordinates a hive of AI coding agents — persistent, watchable, all local. Here's what's inside:", + "headline": "SEU CLONE E O ESCRITÓRIO QUE ELE COMANDA", + "descPlain": "Seu clone comanda um pequeno escritório de trabalhadores de IA, e você acompanha tudo de uma tela só. Veja o que tem dentro:", + "desc": "Seu clone coordena uma colmeia de agentes de código de IA — persistentes, observáveis, todos locais. Veja o que tem dentro:", "features": { "engines": { - "label": "ELEVEN ENGINES, ONE OFFICE", - "desc": "Claude Code, Codex, Grok, Kimi, Antigravity, Qwen, OpenCode, Crush, pi, Copilot & Cursor — live agents on one floor.", - "descPlain": "Eleven AI assistants — Claude, Codex, Cursor, Gemini, Grok and more — working side by side in one shared office." + "label": "ONZE ENGINES, UM ESCRITÓRIO", + "desc": "Claude Code, Codex, Grok, Kimi, Antigravity, Qwen, OpenCode, Crush, pi, Copilot e Cursor — agentes ao vivo num escritório só.", + "descPlain": "Onze assistentes de IA — Claude, Codex, Cursor, Gemini, Grok e mais — trabalhando lado a lado num escritório compartilhado." }, "clone": { - "label": "{{godName}} IS YOUR CLONE", - "desc": "Your clone runs the floor — triages requests, routes tasks, and escalates only what needs you.", - "descPlain": "Your clone, {{godName}}, takes your requests, hands work to the right agent, and only interrupts you when it matters." + "label": "{{godName}} É SEU CLONE", + "desc": "Seu clone comanda o escritório — tria pedidos, distribui tarefas e só escala o que precisa de você.", + "descPlain": "Seu clone, {{godName}}, recebe seus pedidos, passa o trabalho ao agente certo e só interrompe você quando importa." }, "memory": { - "label": "LONG-TERM MEMORY", - "desc": "Each agent keeps notes, mined into a shared, searchable MemPalace.", - "descPlain": "Agents remember what they've done, so they don't start from scratch every time." + "label": "MEMÓRIA DE LONGO PRAZO", + "desc": "Cada agente mantém anotações, mineradas num MemPalace compartilhado e pesquisável.", + "descPlain": "Os agentes lembram o que já fizeram, então não começam do zero toda vez." }, "commandCenter": { - "label": "COMMAND CENTER", - "desc": "Terminal · Floor · Memory · Activity · Tasks · Triggers in one control surface.", - "descPlain": "One dashboard to watch the work, the agents' memory, tasks, and triggers." + "label": "CENTRO DE COMANDO", + "desc": "Terminal · Escritório · Memória · Atividade · Tarefas · Gatilhos numa superfície de controle só.", + "descPlain": "Um painel para acompanhar o trabalho, a memória dos agentes, tarefas e gatilhos." }, "guardrails": { - "label": "GUARDRAILS", - "desc": "Per-agent token budgets, a steer→constrain→stop circuit breaker, and human approvals.", - "descPlain": "Spending limits and safety stops keep agents in check — and they can ask you before big actions." + "label": "LIMITES DE SEGURANÇA", + "desc": "Orçamentos de tokens por agente, um circuit breaker de conduzir→restringir→parar e aprovações humanas.", + "descPlain": "Limites de gasto e paradas de segurança mantêm os agentes sob controle — e eles podem perguntar a você antes de ações grandes." }, "hires": { - "label": "READY-MADE HIRES", - "desc": "Grab a pre-configured agent from the Agent Gallery and spawn it in one click.", - "descPlain": "Hire a ready-made agent from the gallery in one click — no setup needed." + "label": "CONTRATAÇÕES PRONTAS", + "desc": "Pegue um agente pré-configurado na Galeria de Agentes e crie-o num clique.", + "descPlain": "Contrate um agente pronto na galeria num clique — sem configuração." } } }, @@ -640,71 +640,71 @@ "claude": "Claude Code — Anthropic", "codex": "Codex — OpenAI", "antigravity": "Antigravity — Google Gemini", - "qwen": "Qwen — runs a local Qwen model on your machine", + "qwen": "Qwen — roda um modelo Qwen local na sua máquina", "gemini": "Gemini CLI - Google Gemini", - "cursor": "Cursor Agent CLI — uses your Cursor credits (Luna, Composer, …)" + "cursor": "Cursor Agent CLI — usa seus créditos do Cursor (Luna, Composer, …)" }, "home": { - "descPlain": "Create a new, empty folder for the app to call home. Everything the app remembers — its own settings and your agents' memory — is stored here. Something like ~/HarnessAgents works well. We'll create it for you if it doesn't exist.", - "desc": "Pick a folder where the harness will keep its own files — agent metadata, logs, and any new repos you create from here. Something like ~/HarnessAgents is a fine default. We'll create it if it doesn't exist.", + "descPlain": "Crie uma pasta nova e vazia para o app chamar de lar. Tudo que o app lembra — as próprias configurações e a memória dos seus agentes — fica guardado aqui. Algo como ~/HarnessAgents funciona bem. Criamos para você se não existir.", + "desc": "Escolha uma pasta onde o harness vai guardar os próprios arquivos — metadados de agentes, logs e novos repos que você criar daqui. Algo como ~/HarnessAgents é um bom padrão. Criamos se não existir.", "placeholder": "/path/to/HarnessAgents", - "createPick": "create / pick", - "pick": "pick", - "notePlain": "You won't need to open this folder day-to-day — it's just where the app keeps its notes so nothing is lost when you restart.", - "note": "Think of this as the \"town hall.\" The harness pins agent state there so sessions can be picked back up after a restart." + "createPick": "criar / escolher", + "pick": "escolher", + "notePlain": "Você não vai precisar abrir essa pasta no dia a dia — é só onde o app guarda as anotações para nada se perder ao reiniciar.", + "note": "Pense nisso como a \"sede\". O harness fixa o estado dos agentes lá para as sessões continuarem após reiniciar." }, "orchestrator": { - "descPlain": "{{godName}} is your clone — he reads your requests, breaks them into tasks, and hands them to the right agent. He's the boss of the floor; you're still the boss of him. Choose which AI engine powers him.", - "desc": "{{godName}} is your clone — the boss of the floor you just met. He triages your requests, assigns tasks, and manages the team, while escalating anything that genuinely needs you. Pick the engine and model that power him; give him a longer-context, higher-capability model.", - "cliAgentPlain": "A CLI agent is an AI coding assistant that runs on your computer — popular ones are Claude Code (Anthropic), Codex (OpenAI) and Antigravity (Google Gemini). Your clone is the always-on one that runs your whole office. We recommend Claude Code on Opus 4.8 (1M). You can add or switch the others later.", - "cliAgent": "Each option is a CLI engine (Claude Code, Codex, Antigravity/Gemini, or a local proxy like Qwen). Engines marked INSTALLED are already on this machine; INSTALLS ON FIRST RUN means the app sets it up when {{godName}} first starts. Your clone ({{godName}}) is the engine that orchestrates the whole hive. Recommended: Claude Code · Opus 4.8 · 1M. Other providers can be wired per agent later.", - "recommended": "RECOMMENDED", - "workersOnly": "WORKERS ONLY", - "workersOnlyHint": "Can't drain hive mail yet, so it can't run your clone — still available when hiring workers.", - "model": "Model", - "modelNote": "This only sets {{godName}}'s engine. You can run other providers per agent later." + "descPlain": "{{godName}} é seu clone — ele lê seus pedidos, quebra em tarefas e entrega ao agente certo. Ele é o chefe do escritório; você continua sendo chefe dele. Escolha qual engine de IA o alimenta.", + "desc": "{{godName}} é seu clone — o chefe do escritório que você acabou de conhecer. Ele tria seus pedidos, distribui tarefas e gerencia a equipe, escalando só o que realmente precisa de você. Escolha o engine e o modelo que o alimentam; dê a ele um modelo de contexto longo e alta capacidade.", + "cliAgentPlain": "Um agente CLI é um assistente de código de IA que roda no seu computador — os populares são Claude Code (Anthropic), Codex (OpenAI) e Antigravity (Google Gemini). Seu clone é aquele sempre ligado que comanda seu escritório inteiro. Recomendamos Claude Code com Opus 4.8 (1M). Você pode adicionar ou trocar os outros depois.", + "cliAgent": "Cada opção é um engine CLI (Claude Code, Codex, Antigravity/Gemini ou um proxy local como Qwen). Engines marcados INSTALLED já estão nesta máquina; INSTALLS ON FIRST RUN significa que o app configura quando {{godName}} inicia pela primeira vez. Seu clone ({{godName}}) é o engine que orquestra a colmeia inteira. Recomendado: Claude Code · Opus 4.8 · 1M. Outros provedores podem ser ligados por agente depois.", + "recommended": "RECOMENDADO", + "workersOnly": "SÓ WORKERS", + "workersOnlyHint": "Ainda não drena o correio da colmeia, então não pode rodar seu clone — segue disponível ao contratar workers.", + "model": "Modelo", + "modelNote": "Isso só define o engine do {{godName}}. Você pode rodar outros provedores por agente depois." }, "repos": { - "descPlain": "Add your projects. A project is simply a folder — it can hold code, documents, notes, or any files you want your agents to work with. You can create a brand-new folder or pick an existing one, and add more anytime.", - "desc": "Add the repos you want your agents to work in. Each folder becomes a project (a room on the floor) — multiple agents can share one. You can add more later.", - "emptyPlain": "No projects added yet. Optional — you can add one later.", - "empty": "No repos added yet. Optional, but recommended.", - "addProject": "add a project", - "addRepo": "add a repo" + "descPlain": "Adicione seus projetos. Um projeto é simplesmente uma pasta — pode ter código, documentos, anotações ou quaisquer arquivos com que você queira que seus agentes trabalhem. Você pode criar uma pasta novinha ou escolher uma existente, e adicionar mais quando quiser.", + "desc": "Adicione os repos em que você quer que seus agentes trabalhem. Cada pasta vira um projeto (uma sala no escritório) — vários agentes podem dividir um. Você pode adicionar mais depois.", + "emptyPlain": "Nenhum projeto adicionado ainda. Opcional — você pode adicionar um depois.", + "empty": "Nenhum repo adicionado ainda. Opcional, mas recomendado.", + "addProject": "adicionar um projeto", + "addRepo": "adicionar um repo" }, "permissions": { - "autonomyHead": "HOW MUCH CAN AGENTS DO ON THEIR OWN?", - "autoLabelPlain": "LET AGENTS WORK ON THEIR OWN", - "autoLabel": "WORK AUTONOMOUSLY (AUTO MODE)", - "autoOnPlain": "On. Agents carry out tasks without stopping to ask — the smoothest experience.", - "autoOffPlain": "Off. Agents pause and ask you before changing files or running commands.", - "autoOn": "On. Agents never pause — Claude runs bypassPermissions, Codex bypasses approvals + sandbox, etc.", - "autoOff": "Off. Each agent asks before edits / shell commands (Claude default, codex -a untrusted, …).", - "autoNotePlain": "Best when agents work in their own projects. You can change this later, including for individual agents.", - "autoNote": "The right default for the \"control room\" experience; a foot-gun on production repos. Override per agent in the Add Agent dialog.", - "reliabilityHead": "KEEP THINGS RUNNING WHILE YOU'RE AWAY", - "reliabilityDescPlain": "Your agents keep working on a schedule and in live terminals, even when you step away. These settings keep you in the loop and keep things running.", - "reliabilityDesc": "Your agents keep working on a schedule and in live terminals. If your computer fully sleeps those timers pause and catch up the moment you're back — nothing is lost, it may just run late.", - "keepAwake": "KEEP WORKING WHILE AWAY", - "keepAwakeDesc": "Strong keep-alive: stops your computer from sleeping while an agent is live, so schedules and terminals fire on time even when you step away. Uses more battery — best on power. Off by default.", - "notifications": "DESKTOP NOTIFICATIONS", - "notificationsDesc": "Get pinged when an agent needs you or a terminal needs reviving — even while you're away. Your system may ask permission the first time one fires.", - "openAtLogin": "OPEN AT LOGIN", - "openAtLoginDesc": "Relaunch the harness after a reboot so scheduled missions resume on their own. No prompt — applies immediately.", - "shareStats": "SHARE ANONYMOUS USAGE STATS", - "shareStatsDesc": "A handful of anonymous events (app opened, agent spawned, feature used) that help improve Munder Difflin — never prompts, code, file paths, or agent output. Full list in TELEMETRY.md; change anytime in Settings.", - "stayAwake": "STAY AWAKE ON POWER (MANUAL)", - "stayAwakeDescMac": "macOS only lets you set this one yourself. In Battery → Options, turn on \"Prevent automatic sleeping when the display is off\" (on power adapter) so timers keep firing with the display asleep. Without a sleep-preventing setting the Mac still truly sleeps — work survives and catches up on wake.", - "stayAwakeDescWindows": "Windows only lets you set this one yourself. In Settings → System → Power & battery → Screen, blank & sleep, set \"On battery power, put my device to sleep\" and \"When plugged in\" to Never (or increase them) so timers keep firing. Without a sleep-preventing setting Windows still truly sleeps — work survives and catches up on wake.", - "stayAwakeDescLinux": "Your desktop environment only lets you set this one yourself. Look for a Power Settings panel (e.g. GNOME Settings → Power, or KDE System Settings → Power Management) and disable automatic sleep/suspend while on power. Without a sleep-preventing setting your machine still truly sleeps — work survives and catches up on wake.", - "openBatteryMac": "open Battery settings", - "openBatteryWindows": "open Power settings", - "setItUp": "set it up", - "next": "next" + "autonomyHead": "QUANTO OS AGENTES PODEM FAZER SOZINHOS?", + "autoLabelPlain": "DEIXAR OS AGENTES TRABALHAREM SOZINHOS", + "autoLabel": "TRABALHAR DE FORMA AUTÔNOMA (MODO AUTO)", + "autoOnPlain": "Ligado. Os agentes executam tarefas sem parar para perguntar — a experiência mais fluida.", + "autoOffPlain": "Desligado. Os agentes pausam e perguntam a você antes de alterar arquivos ou rodar comandos.", + "autoOn": "Ligado. Os agentes nunca pausam — Claude roda bypassPermissions, Codex ignora aprovações + sandbox etc.", + "autoOff": "Desligado. Cada agente pergunta antes de edições / comandos shell (padrão do Claude, codex -a untrusted, …).", + "autoNotePlain": "Melhor quando os agentes trabalham nos próprios projetos. Você pode mudar isso depois, inclusive por agente.", + "autoNote": "O padrão certo para a experiência de \"sala de controle\"; um tiro no pé em repos de produção. Sobrescreva por agente no diálogo Adicionar Agente.", + "reliabilityHead": "MANTER TUDO RODANDO ENQUANTO VOCÊ ESTÁ FORA", + "reliabilityDescPlain": "Seus agentes seguem trabalhando por agenda e em terminais ao vivo, mesmo quando você se afasta. Essas configurações mantêm você informado e tudo rodando.", + "reliabilityDesc": "Seus agentes seguem trabalhando por agenda e em terminais ao vivo. Se o computador dormir por completo, esses temporizadores pausam e recuperam o atraso assim que você volta — nada se perde, pode só executar com atraso.", + "keepAwake": "CONTINUAR TRABALHANDO NA AUSÊNCIA", + "keepAwakeDesc": "Keep-alive forte: impede o computador de dormir enquanto um agente está ao vivo, para agendas e terminais dispararem na hora mesmo quando você se afasta. Usa mais bateria — melhor na tomada. Desligado por padrão.", + "notifications": "NOTIFICAÇÕES NA ÁREA DE TRABALHO", + "notificationsDesc": "Receba um toque quando um agente precisar de você ou um terminal precisar ser reanimado — mesmo longe. Seu sistema pode pedir permissão na primeira vez que uma disparar.", + "openAtLogin": "ABRIR AO LOGAR", + "openAtLoginDesc": "Reabrir o harness após reiniciar para as missões agendadas continuarem sozinhas. Sem pergunta — aplica na hora.", + "shareStats": "COMPARTILHAR ESTATÍSTICAS ANÔNIMAS DE USO", + "shareStatsDesc": "Um punhado de eventos anônimos (app aberto, agente criado, recurso usado) que ajudam a melhorar o Munder Difflin — nunca prompts, código, caminhos de arquivo ou saída de agentes. Lista completa em TELEMETRY.md; mude quando quiser em Configurações.", + "stayAwake": "MANTER ACORDADO NA TOMADA (MANUAL)", + "stayAwakeDescMac": "O macOS só deixa você definir isso manualmente. Em Bateria → Opções, ative \"Impedir repouso automático quando o monitor estiver desligado\" (no adaptador de energia) para os temporizadores continuarem com a tela apagada. Sem uma configuração anti-repouso, o Mac realmente dorme — o trabalho sobrevive e recupera ao acordar.", + "stayAwakeDescWindows": "O Windows só deixa você definir isso manualmente. Em Configurações → Sistema → Energia e bateria → Tela e suspensão, defina \"Na bateria, colocar o dispositivo em suspensão\" e \"Quando conectado\" como Nunca (ou aumente) para os temporizadores continuarem. Sem uma configuração anti-repouso, o Windows realmente dorme — o trabalho sobrevive e recupera ao acordar.", + "stayAwakeDescLinux": "Seu ambiente de área de trabalho só deixa você definir isso manualmente. Procure um painel de Energia (ex. Configurações → Energia no GNOME, ou Configurações do Sistema → Gerenciamento de Energia no KDE) e desative suspensão/hibernação automática na tomada. Sem uma configuração anti-repouso, sua máquina realmente dorme — o trabalho sobrevive e recupera ao acordar.", + "openBatteryMac": "abrir configurações de Bateria", + "openBatteryWindows": "abrir configurações de Energia", + "setItUp": "configurar", + "next": "avançar" }, - "errPickHome": "Pick a harness home folder first.", - "errCreateHome": "could not create harness home", - "errEngineNotInstalled": "{{label}} is not installed. Install it and press \"check again\", or pick another engine." + "errPickHome": "Escolha primeiro uma pasta de lar do harness.", + "errCreateHome": "não foi possível criar o lar do harness", + "errEngineNotInstalled": "{{label}} não está instalado. Instale e pressione \"verificar novamente\", ou escolha outro engine." }, "office": { "gpuError": "The office floor lost its GPU context.\n\nToo many terminals are using the GPU at once.\nClose a few agent terminals, or restart the app, to bring it back.", @@ -788,33 +788,33 @@ } }, "setupPanel": { - "title": "PREREQUISITES", - "checking": "Checking what is installed…", - "summary": "{{ready}} of {{total}} ready{{missing}}", - "summaryMissing": " · {{count}} recommended missing", - "recheck": "re-check", - "checkingBtn": "checking…", - "statusReady": "READY", - "statusMissing": "MISSING", - "statusNotSetUp": "NOT SET UP", - "recommended": "recommended", + "title": "PRÉ-REQUISITOS", + "checking": "Verificando o que está instalado…", + "summary": "{{ready}} de {{total}} prontos{{missing}}", + "summaryMissing": " · faltam {{count}} recomendados", + "recheck": "verificar novamente", + "checkingBtn": "verificando…", + "statusReady": "PRONTO", + "statusMissing": "FALTANDO", + "statusNotSetUp": "NÃO CONFIGURADO", + "recommended": "recomendado", "docs": "docs →", - "askDesc": "{{godName}} can install the {{count}} missing recommended tool for you. This fills in his dispatch box — nothing runs until you press dispatch.", - "askDescPlural": "{{godName}} can install the {{count}} missing recommended tools for you. This fills in his dispatch box — nothing runs until you press dispatch.", - "allReady": "Everything recommended is installed. Individual engines above are optional — set up only the ones you use.", - "askMichael": "ask {{godName}} to set up everything", + "askDesc": "{{godName}} pode instalar a {{count}} ferramenta recomendada que falta para você. Isso preenche a caixa de despacho dele — nada é executado até você despachar.", + "askDescPlural": "{{godName}} pode instalar as {{count}} ferramentas recomendadas que faltam para você. Isso preenche a caixa de despacho dele — nada é executado até você despachar.", + "allReady": "Tudo recomendado está instalado. Os engines individuais acima são opcionais — configure só os que você usa.", + "askMichael": "pedir ao {{godName}} para configurar tudo", "sections": { "prerequisites": { - "title": "Prerequisites", - "blurb": "The groundwork everything else builds on." + "title": "Pré-requisitos", + "blurb": "A base sobre a qual todo o resto se apoia." }, "memory": { - "title": "Memory layer", - "blurb": "Meaning-based recall across everything your agents learn." + "title": "Camada de memória", + "blurb": "Recuperação por significado de tudo que seus agentes aprendem." }, "engine": { - "title": "Agent engines", - "blurb": "The CLIs your agents run on. You need whichever ones you actually use — not all of them." + "title": "Engines de agentes", + "blurb": "As CLIs em que seus agentes rodam. Você precisa das que realmente usa — não de todas." } } }, From 6627ea12d69ac4cde03857422792624731897540 Mon Sep 17 00:00:00 2001 From: T3sh Date: Tue, 13 Oct 2026 23:40:30 -0300 Subject: [PATCH 03/24] feat(i18n): traduz Task 4 pt-BR - area de agentes (161 chaves) agentCard, agentDetail, agentControl, agentStrip, addAgent, askMe, badge, blockedBanner. Aba 'ask me' -> 'me pergunte'; botao spawn -> criar. --- src/renderer/src/i18n/locales/pt-BR.json | 310 +++++++++++------------ 1 file changed, 155 insertions(+), 155 deletions(-) diff --git a/src/renderer/src/i18n/locales/pt-BR.json b/src/renderer/src/i18n/locales/pt-BR.json index 89729186b4..504fafbf40 100644 --- a/src/renderer/src/i18n/locales/pt-BR.json +++ b/src/renderer/src/i18n/locales/pt-BR.json @@ -30,7 +30,7 @@ "blockedNote": "Approval needed." }, "blockedBanner": { - "needsYou": "needs you" + "needsYou": "precisa de você" }, "costHud": { "spendCap": "Spend cap", @@ -48,82 +48,82 @@ "tok": "tok" }, "badge": { - "idle": "idle", - "thinking": "working", - "working": "working", - "waiting": "waiting", - "blocked": "needs you", - "success": "done", - "ghost": "gone", - "compacting": "compacting", - "looping": "looping", - "typing": "your draft" + "idle": "ocioso", + "thinking": "trabalhando", + "working": "trabalhando", + "waiting": "aguardando", + "blocked": "precisa de você", + "success": "concluído", + "ghost": "fora", + "compacting": "compactando", + "looping": "em loop", + "typing": "seu rascunho" }, "agentControl": { - "deliveryPaused": "queued messages held (whole floor)", - "halting": "stopping after this step…", - "steersQueued": "{{count}} notes waiting", - "steerPlaceholder": "send this agent a note… (arrives as context on its next turn, nothing is typed into its terminal)", - "steer": "steer", - "flashResumed": "tools allowed again", - "flashPaused": "tools blocked from the next call on", - "flashHalt": "will stop after the current step", - "flashSteer": "note queued, arrives on its next turn", - "allowTools": "allow tools", - "allowToolsTip": "Give its tools back. The agent keeps its session and picks up where it stopped.", - "allowToolsAria": "Allow tools again", - "blockTools": "block tools", - "blockToolsTip": "The agent keeps thinking and talking to you, but cannot read, write or run anything until you allow it again. Immediate, and reversible.", - "blockToolsAria": "Block this agent from using tools", - "stopAfterStep": "stop after this step", - "stopAfterStepTip": "Let it finish the step it is on, then stop. The process and its session survive, so Restart and Continue can pick it back up. To end the process outright, use the X.", - "stopAfterStepAria": "Stop this agent after the current step", - "steerTip": "Hands the agent a note at its next turn boundary. It does not interrupt what it is doing now, and nothing is typed into its terminal.", - "steerAria": "Send this agent a note" + "deliveryPaused": "mensagens enfileiradas retidas (escritório todo)", + "halting": "parando após este passo…", + "steersQueued": "{{count}} notas aguardando", + "steerPlaceholder": "envie uma nota a este agente… (chega como contexto no próximo turno; nada é digitado no terminal dele)", + "steer": "conduzir", + "flashResumed": "ferramentas permitidas de novo", + "flashPaused": "ferramentas bloqueadas a partir da próxima chamada", + "flashHalt": "vai parar após o passo atual", + "flashSteer": "nota enfileirada, chega no próximo turno", + "allowTools": "permitir ferramentas", + "allowToolsTip": "Devolva as ferramentas. O agente mantém a sessão e continua de onde parou.", + "allowToolsAria": "Permitir ferramentas de novo", + "blockTools": "bloquear ferramentas", + "blockToolsTip": "O agente continua pensando e falando com você, mas não pode ler, escrever nem executar nada até você permitir de novo. Imediato e reversível.", + "blockToolsAria": "Bloquear este agente de usar ferramentas", + "stopAfterStep": "parar após este passo", + "stopAfterStepTip": "Deixe terminar o passo atual e pare. O processo e a sessão sobrevivem, então Reiniciar e Continuar pode retomar. Para encerrar o processo de vez, use o X.", + "stopAfterStepAria": "Parar este agente após o passo atual", + "steerTip": "Entrega uma nota ao agente na próxima virada de turno. Não interrompe o que ele está fazendo agora, e nada é digitado no terminal dele.", + "steerAria": "Enviar uma nota a este agente" }, "agentCard": { - "boss": "BOSS", - "contextTitle": "Context: {{used}} / {{limit}} tokens ({{pct}}%)", - "contextGaugeTitle": "Context gauge — fills once the agent reports activity", - "doingTasks": "actively working {{count}} task — click to open", - "doingTasksPlural": "actively working {{count}} tasks — click to open", - "editNote": "Edit private note", - "addNote": "Add private note", - "editNoteAria": "Edit note for {{name}}", - "noteAria": "Note for {{name}}" + "boss": "CHEFE", + "contextTitle": "Contexto: {{used}} / {{limit}} tokens ({{pct}}%)", + "contextGaugeTitle": "Medidor de contexto — enche quando o agente relata atividade", + "doingTasks": "trabalhando ativamente em {{count}} tarefa — clique para abrir", + "doingTasksPlural": "trabalhando ativamente em {{count}} tarefas — clique para abrir", + "editNote": "Editar nota privada", + "addNote": "Adicionar nota privada", + "editNoteAria": "Editar nota de {{name}}", + "noteAria": "Nota de {{name}}" }, "askMe": { - "emptyTitle": "Nothing needs you right now. 🌿", - "emptySub": "When the team blocks a task on your input — a question to answer or a to-do only you can perform — it shows up here (and on the ASK ME board on the floor).", - "openDetail": "open the full task detail", - "dismissTitle": "dismiss — clear this off the ASK ME board without answering (history kept)", - "dismissAria": "dismiss this ask", - "answerPlaceholder": "Your answer — or 'done', with the result… (Ctrl+Enter to send)", - "sending": "sending…", - "respond": "respond & unblock", - "viewAnswers": "VIEW {{count}} EARLIER ANSWER", - "viewAnswersPlural": "VIEW {{count}} EARLIER ANSWERS", - "viewAnswersHistory": "open the task detail with the full Q&A history", - "blockingDownstream": "BLOCKING {{count}} DOWNSTREAM TASK", - "blockingDownstreamPlural": "BLOCKING {{count}} DOWNSTREAM TASKS", - "more": "… +{{count}} more" + "emptyTitle": "Nada precisa de você agora. 🌿", + "emptySub": "Quando a equipe trava uma tarefa aguardando sua entrada — uma pergunta para responder ou algo só você pode fazer — aparece aqui (e no quadro ME PERGUNTE no escritório).", + "openDetail": "abrir o detalhe completo da tarefa", + "dismissTitle": "dispensar — tirar do quadro ME PERGUNTE sem responder (histórico mantido)", + "dismissAria": "dispensar este pedido", + "answerPlaceholder": "Sua resposta — ou 'pronto', com o resultado… (Ctrl+Enter para enviar)", + "sending": "enviando…", + "respond": "responder e desbloquear", + "viewAnswers": "VER {{count}} RESPOSTA ANTERIOR", + "viewAnswersPlural": "VER {{count}} RESPOSTAS ANTERIORES", + "viewAnswersHistory": "abrir o detalhe da tarefa com o histórico completo de P&R", + "blockingDownstream": "BLOQUEANDO {{count}} TAREFA DEPENDENTE", + "blockingDownstreamPlural": "BLOQUEANDO {{count}} TAREFAS DEPENDENTES", + "more": "… +{{count}} mais" }, "agentStrip": { - "privateNote": "PRIVATE NOTE · {{name}}", - "done": "Done", - "closeNoteEditor": "Close note editor", - "notePlaceholder": "one line per bullet…", - "oneLineOneBullet": "one line = one bullet · esc to close", - "addAgent": "add agent", - "restoringTitle": "Your previous session's agents are being respawned with their original ids, so memory and inboxes reattach.", - "restoreTitle": "Previous session: {{names}}", - "restoringTeam": "restoring your team…", - "restoreTeam": "restore team ({{count}}) ▴", - "previousSession": "previous session", - "restorable": "{{name}} — restorable from last session", - "dismiss": "Dismiss {{name}} — remove permanently from the restore list", - "dismissAria": "Dismiss {{name}}", - "restoreAll": "restore all ({{count}})" + "privateNote": "NOTA PRIVADA · {{name}}", + "done": "Concluído", + "closeNoteEditor": "Fechar editor de nota", + "notePlaceholder": "uma linha por marcador…", + "oneLineOneBullet": "uma linha = um marcador · esc para fechar", + "addAgent": "adicionar agente", + "restoringTitle": "Os agentes da sua sessão anterior estão sendo recriados com os ids originais, para memória e caixas de entrada se reconectarem.", + "restoreTitle": "Sessão anterior: {{names}}", + "restoringTeam": "restaurando sua equipe…", + "restoreTeam": "restaurar equipe ({{count}}) ▴", + "previousSession": "sessão anterior", + "restorable": "{{name}} — restaurável da última sessão", + "dismiss": "Dispensar {{name}} — remover permanentemente da lista de restauração", + "dismissAria": "Dispensar {{name}}", + "restoreAll": "restaurar tudo ({{count}})" }, "sidebar": { "terminal": "terminal", @@ -141,20 +141,20 @@ "barFailed": "{{tool}} · {{ms}}ms · failed" }, "agentDetail": { - "open": "open", - "opening": "...", + "open": "abrir", + "opening": "…", "ok": "ok", - "err": "err", - "inFullscreen": "In focus mode", - "fullscreenDesc": "This terminal is open in focus mode. Press Esc or exit focus mode to bring it back here.", - "noPty": "No PTY", - "noPtyDesc": "This agent has no live terminal. Spawn an agent through \"add agent\" to use the terminal tab.", - "killConfirm": "Close {{name}}? The PTY process will terminate and the agent is archived (kept in history, off the floor).", - "ideTip": "Open the IDE: browse and edit files in {{project}}, and see uncommitted changes as a diff.", - "terminalTip": "Open your system terminal app in {{cwd}} — a normal shell in this agent's folder, separate from the agent's own terminal.", - "openIde": "Open the IDE", + "err": "erro", + "inFullscreen": "No modo foco", + "fullscreenDesc": "Este terminal está aberto no modo foco. Pressione Esc ou saia do modo foco para trazê-lo de volta aqui.", + "noPty": "Sem PTY", + "noPtyDesc": "Este agente não tem terminal ao vivo. Crie um agente em \"adicionar agente\" para usar a aba de terminal.", + "killConfirm": "Fechar {{name}}? O processo PTY vai terminar e o agente é arquivado (fica no histórico, fora do escritório).", + "ideTip": "Abra a IDE: navegue e edite arquivos em {{project}} e veja alterações não commitadas como diff.", + "terminalTip": "Abra o terminal do sistema em {{cwd}} — um shell normal na pasta deste agente, separado do próprio terminal do agente.", + "openIde": "Abrir a IDE", "ide": "IDE", - "openTerminalAria": "Open a system terminal in this agent's folder" + "openTerminalAria": "Abrir um terminal do sistema na pasta deste agente" }, "settingsHero": { "sponsoredBy": "Patrocinado por", @@ -475,106 +475,106 @@ "openIdeAria": "Open the IDE" }, "addAgent": { - "title": "ADD AGENT", - "hireImported": "hire imported:", - "byAuthor": " · by {{author}}", - "reviewFields": "review every field — especially the command — before spawning.", - "hireFlags": "⚠️ flags this hire appends to the command:", - "hireSkills": "skills this hire activates:", - "mcpSafe": "MCP servers (safe, pre-enabled):", - "mcpConsent": "⚠️ MCP (needs your consent — NOT auto-enabled):", - "mcpEnableInSettings": "— enable in Settings → MCP after reviewing", + "title": "ADICIONAR AGENTE", + "hireImported": "contratação importada:", + "byAuthor": " · por {{author}}", + "reviewFields": "revise cada campo — especialmente o comando — antes de criar.", + "hireFlags": "⚠️ flags que esta contratação anexa ao comando:", + "hireSkills": "skills que esta contratação ativa:", + "mcpSafe": "Servidores MCP (seguros, pré-ativados):", + "mcpConsent": "⚠️ MCP (precisa do seu consentimento — NÃO auto-ativado):", + "mcpEnableInSettings": "— ative em Configurações → MCP após revisar", "sections": { "identity": { - "label": "Identity", - "hint": "name · character · color" + "label": "Identidade", + "hint": "nome · personagem · cor" }, "workspace": { - "label": "Workspace", - "hint": "folder · isolation · resume" + "label": "Espaço de trabalho", + "hint": "pasta · isolamento · retomada" }, "engine": { "label": "Engine", - "hint": "provider · model · command" + "hint": "provedor · modelo · comando" }, "briefing": { "label": "Briefing", - "hint": "description · goal" + "hint": "descrição · objetivo" } }, - "name": "Name", + "name": "Nome", "namePlaceholder": "Ada", - "character": "Character", - "color": "Color", - "project": "Project", - "pickProject": "Pick a project, or add a new one:", - "noProjects": "No projects yet — add one to get started:", - "addProject": "add project", - "addProjectTitle": "Pick a folder and register it as a project", + "character": "Personagem", + "color": "Cor", + "project": "Projeto", + "pickProject": "Escolha um projeto ou adicione um novo:", + "noProjects": "Sem projetos ainda — adicione um para começar:", + "addProject": "adicionar projeto", + "addProjectTitle": "Escolha uma pasta e registre como projeto", "projectPlaceholder": "/path/to/your/project", - "pick": "pick", - "saveAsProject": "save as project", - "saveAsProjectTitle": "Save this folder to your projects so it's a one-click pick next time", - "gitIsolation": "Git isolation (own worktree)", - "resumeSession": "Resume session ID (optional)", - "resumePlaceholder": "paste a Claude session id to continue its conversation", - "folderFromSession": "folder set from session: {{path}}", - "resumeNote": "Will resume this session in the chosen folder (git isolation disabled).", - "provider": "Provider", - "providerAntigravity": "Spawn the Antigravity CLI (agy) with a Gemini model", - "providerCodex": "Spawn the Codex CLI (codex) without Claude-only flags", - "providerCustom": "Run any command — no Claude-only flags", - "model": "Model", - "cliDefaultModel": "CLI default model", - "fromHire": "{{model}} (from hire)", - "ossModels": "OSS models", - "ossLocal": "Local · no key (Ollama / LM Studio)", - "ossByok": "Via OSS provider · BYOK", - "ossLocalTitle": "{{slug}} · needs ~{{ram}} RAM — pull with: ollama pull {{tag}}", - "ossByokTitle": "{{slug}} · set {{keyEnv}} in Settings → AI Engines", - "byokNote": "BYOK keys & local endpoints for this engine live in Settings → AI Engines. New to local models? Read run on open models or set up on a Mac Mini. Live end-to-end is pending real model calls (verify on-device).", - "runOnOpenModels": "run on open models", - "setUpMacMini": "set up on a Mac Mini", - "command": "Command", - "commandAuto": "Command (auto mode on)", - "templates": "Templates", + "pick": "escolher", + "saveAsProject": "salvar como projeto", + "saveAsProjectTitle": "Salve esta pasta nos seus projetos para escolher num clique da próxima vez", + "gitIsolation": "Isolamento Git (worktree próprio)", + "resumeSession": "Retomar ID de sessão (opcional)", + "resumePlaceholder": "cole um id de sessão do Claude para continuar a conversa", + "folderFromSession": "pasta definida pela sessão: {{path}}", + "resumeNote": "Vai retomar esta sessão na pasta escolhida (isolamento git desativado).", + "provider": "Provedor", + "providerAntigravity": "Cria o CLI Antigravity (agy) com um modelo Gemini", + "providerCodex": "Cria o CLI Codex (codex) sem flags exclusivas do Claude", + "providerCustom": "Roda qualquer comando — sem flags exclusivas do Claude", + "model": "Modelo", + "cliDefaultModel": "Modelo padrão do CLI", + "fromHire": "{{model}} (da contratação)", + "ossModels": "Modelos OSS", + "ossLocal": "Local · sem chave (Ollama / LM Studio)", + "ossByok": "Via provedor OSS · BYOK", + "ossLocalTitle": "{{slug}} · precisa de ~{{ram}} RAM — baixe com: ollama pull {{tag}}", + "ossByokTitle": "{{slug}} · defina {{keyEnv}} em Configurações → Engines de IA", + "byokNote": "Chaves BYOK e endpoints locais deste engine ficam em Configurações → Engines de IA. Novo em modelos locais? Leia rodar com modelos abertos ou configurar num Mac Mini. O funcionamento ao vivo de ponta a ponta depende de chamadas reais de modelo (verifique no dispositivo).", + "runOnOpenModels": "rodar com modelos abertos", + "setUpMacMini": "configurar num Mac Mini", + "command": "Comando", + "commandAuto": "Comando (modo auto ligado)", + "templates": "Modelos", "templatesHint": { "repoJanitor": { - "label": "Repo janitor" + "label": "Zelador do repo" }, "docsWriter": { - "label": "Docs writer" + "label": "Redator de docs" }, "bugTriager": { - "label": "Bug triager" + "label": "Triador de bugs" }, "researchAssistant": { - "label": "Research assistant" + "label": "Assistente de pesquisa" }, "releaseManager": { - "label": "Release manager" + "label": "Gerente de release" } }, - "description": "Description", - "descriptionPlaceholder": "job — what this agent is for, not live status", - "goal": "Goal (optional)", - "goalPlaceholder": "long-running directive injected on every prompt", - "importHire": "Import hire", - "importHireDesc": "Import hire loads a ready-made agent from a .json manifest — it fills in every field below for you to review. Nothing spawns until you hit spawn.", - "generateWithAI": "generate one with AI…", - "hideAIPrompt": "hide AI prompt", - "aiPromptHint": "Copy this into Claude/ChatGPT/Gemini, fill in the details at the bottom, then save its JSON reply as a .json file and import it here.", - "copied": "copied ✓", - "copyPrompt": "copy prompt", - "importHireBtn": "import hire…", - "importHireBtnTitle": "Import a hire manifest (.json)", - "spawn": "spawn", - "spawning": "spawning...", - "errName": "Name is required", - "errFolder": "Pick a folder first", - "errCommand": "Command is required", - "hireProgress": "hire {{current}} of {{total}}", - "skipHire": "skip hire" + "description": "Descrição", + "descriptionPlaceholder": "função — para que serve este agente, não status ao vivo", + "goal": "Objetivo (opcional)", + "goalPlaceholder": "diretriz contínua injetada em todo prompt", + "importHire": "Importar contratação", + "importHireDesc": "Importar contratação carrega um agente pronto de um manifesto .json — preenche cada campo abaixo para você revisar. Nada é criado até você pressionar criar.", + "generateWithAI": "gerar um com IA…", + "hideAIPrompt": "ocultar prompt de IA", + "aiPromptHint": "Copie para Claude/ChatGPT/Gemini, preencha os detalhes no fim, salve o JSON de resposta como .json e importe aqui.", + "copied": "copiado ✓", + "copyPrompt": "copiar prompt", + "importHireBtn": "importar contratação…", + "importHireBtnTitle": "Importar um manifesto de contratação (.json)", + "spawn": "criar", + "spawning": "criando…", + "errName": "Nome é obrigatório", + "errFolder": "Escolha uma pasta primeiro", + "errCommand": "Comando é obrigatório", + "hireProgress": "contratação {{current}} de {{total}}", + "skipHire": "pular contratação" }, "onboarding": { "titles": { From 19e2068b0c1cf1ebbc8731f846307fa22239b840 Mon Sep 17 00:00:00 2001 From: T3sh Date: Tue, 13 Oct 2026 23:47:54 -0300 Subject: [PATCH 04/24] feat(i18n): traduz Task 5 pt-BR - command center e trabalho (259 chaves) commandCenter, kanban, queueComposer, triggersUi, triggersTab, triggerHistory, schedulesSection, workersTab. dispatch->despachar, tabs: monitor/tarefas/me pergunte/gatilhos/historico/memoria/grafo. --- src/renderer/src/i18n/locales/pt-BR.json | 478 +++++++++++------------ 1 file changed, 239 insertions(+), 239 deletions(-) diff --git a/src/renderer/src/i18n/locales/pt-BR.json b/src/renderer/src/i18n/locales/pt-BR.json index 504fafbf40..8e884c0f7b 100644 --- a/src/renderer/src/i18n/locales/pt-BR.json +++ b/src/renderer/src/i18n/locales/pt-BR.json @@ -378,101 +378,101 @@ "unsavedWarning": "Você tem configurações não salvas. Fechar mesmo assim e perdê-las?" }, "commandCenter": { - "title": "COMMAND CENTER", - "runsTheFloor": "{{name}} runs the floor", - "deliveryPaused": "paused", + "title": "CENTRO DE COMANDO", + "runsTheFloor": "{{name}} comanda o escritório", + "deliveryPaused": "pausado", "deliveryAuto": "auto", - "deliveryPausedTitle": "Queued messages are being held for EVERY agent on the floor. Nothing is lost; it is delivered when you switch this back on.", - "deliveryOnTitle": "Queued messages are delivered to every agent automatically. Click to hold the whole floor.", - "ideTitle": "Open the IDE: browse and edit files in the selected agent's workspace, and see uncommitted changes as a diff.", + "deliveryPausedTitle": "Mensagens enfileiradas estão retidas para TODOS os agentes do escritório. Nada se perde; é entregue quando você reativa.", + "deliveryOnTitle": "Mensagens enfileiradas são entregues a cada agente automaticamente. Clique para reter o escritório todo.", + "ideTitle": "Abra a IDE: navegue e edite arquivos no workspace do agente selecionado e veja alterações não commitadas como diff.", "ide": "IDE", "tabs": { "terminal": "terminal", "floor": "monitor", - "tasks": "tasks", - "human": "ask me", - "triggers": "triggers", - "history": "history", - "memory": "memory", - "graph": "graph", - "activity": "activity", + "tasks": "tarefas", + "human": "me pergunte", + "triggers": "gatilhos", + "history": "histórico", + "memory": "memória", + "graph": "grafo", + "activity": "atividade", "skills": "skills", "workers": "workers" }, - "terminalFullscreen": "Terminal is open in fullscreen. Press Esc to bring it back.", - "noTerminal": "{{name}} has no live terminal.", - "dispatchViaMichael": "DISPATCH — VIA {{godName}}", - "suggestedOwner": "SUGGESTED OWNER", - "michaelDecides": "{{godName}} decides", - "dispatchPlaceholder": "Describe the task… ({{godName}} decomposes, writes the card, and assigns)", - "dispatch": "dispatch", - "sentToMichael": "sent to {{godName}}", - "sentToWithSuggestion": "sent to {{godName}} (suggesting {{name}})", - "dispatchFailed": "failed: {{error}}", - "dispatchSuggestion": "(The human suggests {{name}} ({{id}}) for this — your call as orchestrator.)", - "taskFromHuman": "Task from the human", - "agents": "AGENTS", + "terminalFullscreen": "O terminal está aberto em tela cheia. Pressione Esc para trazê-lo de volta.", + "noTerminal": "{{name}} não tem terminal ao vivo.", + "dispatchViaMichael": "DESPACHAR — VIA {{godName}}", + "suggestedOwner": "RESPONSÁVEL SUGERIDO", + "michaelDecides": "{{godName}} decide", + "dispatchPlaceholder": "Descreva a tarefa… ({{godName}} decompõe, escreve o cartão e atribui)", + "dispatch": "despachar", + "sentToMichael": "enviado ao {{godName}}", + "sentToWithSuggestion": "enviado ao {{godName}} (sugerindo {{name}})", + "dispatchFailed": "falha: {{error}}", + "dispatchSuggestion": "(O humano sugere {{name}} ({{id}}) para esta — sua decisão como orquestrador.)", + "taskFromHuman": "Tarefa do humano", + "agents": "AGENTES", "godTag": " (god)", - "toolCalls": "{{count}} tool calls", - "rate": "rate", - "budget": "budget", - "meterTitle": "CUMULATIVE session usage: {{used}} of {{limit}} tokens{{note}} — not the context window", - "agentLimit": " (agent limit — work tokens, cache reads excluded)", - "floorBudget": " (floor budget)", + "toolCalls": "{{count}} chamadas de ferramenta", + "rate": "taxa", + "budget": "orçamento", + "meterTitle": "Uso acumulado da sessão: {{used}} de {{limit}} tokens{{note}} — não é a janela de contexto", + "agentLimit": " (limite do agente — tokens de trabalho, leituras de cache excluídas)", + "floorBudget": " (orçamento do escritório)", "ctx": "ctx", - "contextTitle": "Context window: {{used}} of {{limit}} tokens ({{pct}}%)", - "noStatusTick": "no status tick yet", - "modelRestarts": "{{provider}} model (restarts agent)", - "restartContinue": "restart & continue", - "restartContinueTitle": "Kill and respawn {{name}}, resuming its current conversation — fixes a corrupted/garbled terminal without losing context", + "contextTitle": "Janela de contexto: {{used}} de {{limit}} tokens ({{pct}}%)", + "noStatusTick": "sem tick de status ainda", + "modelRestarts": "modelo {{provider}} (reinicia o agente)", + "restartContinue": "reiniciar e continuar", + "restartContinueTitle": "Mata e recria {{name}}, retomando a conversa atual — corrige um terminal corrompido/ilegível sem perder contexto", "engine": "engine:", - "apply": "apply", - "confirmRestartEngine": "This restarts {{name}}; a conversation on a different engine can't be resumed.", - "restartFailed": "Restart failed.", - "archived": "ARCHIVED ({{count}})", - "showClosed": "show closed agents", - "hideClosed": "hide closed agents", - "directories": "DIRECTORIES", - "noRepos": "No registered repos.", - "openInTerminal": "Open in Terminal.app", + "apply": "aplicar", + "confirmRestartEngine": "Isso reinicia {{name}}; uma conversa num engine diferente não pode ser retomada.", + "restartFailed": "Falha ao reiniciar.", + "archived": "ARQUIVADOS ({{count}})", + "showClosed": "mostrar agentes encerrados", + "hideClosed": "ocultar agentes encerrados", + "directories": "DIRETÓRIOS", + "noRepos": "Sem repos registrados.", + "openInTerminal": "Abrir no Terminal.app", "issues": "ISSUES", - "fetching": "fetching…", - "fetchIssues": "Fetch issues", - "noRepoSelected": "No repo selected.", - "fetchFailed": "Failed to fetch issues.", - "noIssues": "No issues fetched yet.", - "assign": "Assign", - "textSearch": "TEXT SEARCH (board, tasks, memory)", - "textSearchPlaceholder": "Find exact text across hive files…", - "nothingMatched": "Nothing matched.", - "searchNoMatch": "Nothing matched yet.", - "semanticSearch": "SEMANTIC SEARCH (MemPalace)", - "semanticPlaceholder": "What does the hive know about…", - "memoryFile": "MEMORY FILE", - "noMemory": "No memory recorded yet.", - "activity": "ACTIVITY", - "nothingYet": "Nothing yet.", - "board": "BOARD", - "boardEmpty": "The board is empty.", - "logSpawn": "spawned {{name}}", + "fetching": "buscando…", + "fetchIssues": "Buscar issues", + "noRepoSelected": "Nenhum repo selecionado.", + "fetchFailed": "Falha ao buscar issues.", + "noIssues": "Sem issues buscadas ainda.", + "assign": "atribuir", + "textSearch": "BUSCA DE TEXTO (quadro, tarefas, memória)", + "textSearchPlaceholder": "Encontre texto exato nos arquivos da colmeia…", + "nothingMatched": "Nada correspondeu.", + "searchNoMatch": "Nada correspondeu ainda.", + "semanticSearch": "BUSCA SEMÂNTICA (MemPalace)", + "semanticPlaceholder": "O que a colmeia sabe sobre…", + "memoryFile": "ARQUIVO DE MEMÓRIA", + "noMemory": "Sem memória registrada ainda.", + "activity": "ATIVIDADE", + "nothingYet": "Nada ainda.", + "board": "QUADRO", + "boardEmpty": "O quadro está vazio.", + "logSpawn": "{{name}} foi criado", "logMessage": "{{from}} → {{to}}: {{subject}}", - "logDrain": "{{agent}} drained {{count}} msg(s)", - "logEscalate": "escalated to human: {{subject}}", - "logApprovalGranted": "approval granted", - "logApprovalDenied": "approval denied", - "tokenLimitTitle": "Set this agent's token limit (work tokens: input + output + cache writes; cache reads don't count)", - "tokenLimit": "limit {{value}}", - "setLimit": "set limit", - "saveLimit": "Save limit", + "logDrain": "{{agent}} esvaziou {{count}} msg(s)", + "logEscalate": "escalado para o humano: {{subject}}", + "logApprovalGranted": "aprovação concedida", + "logApprovalDenied": "aprovação negada", + "tokenLimitTitle": "Defina o limite de tokens deste agente (tokens de trabalho: entrada + saída + escritas de cache; leituras de cache não contam)", + "tokenLimit": "limite {{value}}", + "setLimit": "definir limite", + "saveLimit": "Salvar limite", "fleetTokens": "Σ {{value}} tok", - "fleetInputs": "inputs {{value}} (cache {{pct}}%)", + "fleetInputs": "entradas {{value}} (cache {{pct}}%)", "fleetRate": "{{value}} tok/min", - "telemetryNote": "live from each agent's OpenTelemetry · bars show tokens used vs each agent's limit, else the {{cap}} floor budget", - "defaultBudgetNote": " (default — set a floor token budget in Settings)", + "telemetryNote": "ao vivo do OpenTelemetry de cada agente · barras mostram tokens usados vs o limite de cada agente, senão o orçamento {{cap}} do escritório", + "defaultBudgetNote": " (padrão — defina um orçamento de tokens do escritório em Configurações)", "openIssue": "GitHub Issue #{{num}}: {{title}}", - "deliveryResumeAria": "Resume automatic delivery for the whole floor", - "deliveryHoldAria": "Hold automatic delivery for the whole floor", - "openIdeAria": "Open the IDE" + "deliveryResumeAria": "Retomar entrega automática para o escritório todo", + "deliveryHoldAria": "Reter entrega automática para o escritório todo", + "openIdeAria": "Abrir a IDE" }, "addAgent": { "title": "ADICIONAR AGENTE", @@ -900,15 +900,15 @@ "manualDownloadingBody": "When it lands, quit this app, install the new version over the current one, open it and pick the same project. On {{os}}:" }, "triggersTab": { - "intro": "Everything that can start work without you typing.", - "schedules": "SCHEDULES", - "schedulesBlurb": "Run a prompt on a repeating clock.", - "context": "CONTEXT", - "contextBlurb": "Compact or clear an agent as its context fills.", + "intro": "Tudo que pode iniciar trabalho sem você digitar.", + "schedules": "AGENDAS", + "schedulesBlurb": "Roda um prompt num relógio repetitivo.", + "context": "CONTEXTO", + "contextBlurb": "Compacta ou limpa um agente conforme o contexto enche.", "webhooks": "WEBHOOKS", - "webhooksBlurb": "Let an outside system post work in.", - "organisation": "ORGANISATION", - "organisationBlurb": "Let a teammate's Munder Difflin message yours." + "webhooksBlurb": "Deixa um sistema externo postar trabalho.", + "organisation": "ORGANIZAÇÃO", + "organisationBlurb": "Deixa o Munder Difflin de um colega mandar mensagem para o seu." }, "orgSection": { "acceptMessages": "Accept messages from your organisation", @@ -942,28 +942,28 @@ "bigWindowsHint": "Used on ~1M-token windows, where a smaller slice is still an enormous amount of text." }, "schedulesSection": { - "justNow": "just now", - "ago": "{{unit}} ago", - "in": "in {{unit}}", - "summaryNone": "none", - "summary": "{{on}} of {{total}} on", - "nothingScheduled": "Nothing is scheduled yet.", - "addSchedule": "add a schedule", - "newSchedule": "NEW SCHEDULE", - "label": "LABEL", - "labelPlaceholder": "What this run is for", - "goesTo": "GOES TO", - "everyone": "everyone", + "justNow": "agora mesmo", + "ago": "{{unit}} atrás", + "in": "em {{unit}}", + "summaryNone": "nenhuma", + "summary": "{{on}} de {{total}} ligadas", + "nothingScheduled": "Nada agendado ainda.", + "addSchedule": "adicionar agenda", + "newSchedule": "NOVA AGENDA", + "label": "RÓTULO", + "labelPlaceholder": "Para que serve esta execução", + "goesTo": "VAI PARA", + "everyone": "todos", "prompt": "PROMPT", - "promptPlaceholder": "Sent word for word on every run.", - "fired": "fired {{time}}", - "notFired": "not yet fired", - "next": "next {{time}}", - "beat": "♥ beat", - "noPrompt": "No prompt set.", - "saved": "saved", - "when": "WHEN", - "beatCeiling": "The beat adapts to how quiet the floor is, so this is the ceiling, not the exact gap." + "promptPlaceholder": "Enviado palavra por palavra a cada execução.", + "fired": "disparou {{time}}", + "notFired": "ainda não disparou", + "next": "próximo {{time}}", + "beat": "♥ batida", + "noPrompt": "Sem prompt definido.", + "saved": "salvo", + "when": "QUANDO", + "beatCeiling": "A batida se adapta ao silêncio do escritório, então isto é o teto, não o intervalo exato." }, "webhooksSection": { "summaryNone": "none", @@ -998,64 +998,64 @@ "keep": "keep" }, "triggersUi": { - "custom": "custom", - "customEllipsis": "custom…", + "custom": "personalizado", + "customEllipsis": "personalizado…", "min": "min", - "every": "every…", - "onDays": "on days…", - "at": "at", - "weekdays": "weekdays", - "everyDay": "every day", - "pickDayHint": "Pick at least one day, or this will never run." + "every": "a cada…", + "onDays": "nos dias…", + "at": "às", + "weekdays": "dias úteis", + "everyDay": "todo dia", + "pickDayHint": "Escolha ao menos um dia, ou nunca vai executar." }, "triggerHistory": { - "justNow": "just now", - "ago": "{{unit}} ago", - "in": "in {{unit}}", - "kindDirective": "directive", - "kindCommunication": "communication", - "decisionPending": "needs you", - "decisionApproved": "approved", - "decisionRejected": "rejected", - "decisionAuto": "auto-allowed", - "emptyMessage": "(empty message)", - "showLess": "show less", - "showAll": "show all {{count}} characters", - "tailRejected": "You turned this down. Nothing was sent to the hive.", - "tailNoReply": "No reply yet. {{godName}} has this one.", - "waitingForYou": "WAITING FOR YOU", - "unnamedSource": "unnamed source", - "from": "from", - "to": "to", - "unknown": "unknown", - "theySent": "THEY SENT", - "weReplied": "WE REPLIED", - "weSent": "WE SENT", - "pendingDirectiveDesc": "Approve and this goes to {{godName}}, who will put the hive to work on it. Reject and it is dropped — nothing runs.", - "pendingDesc": "Approve and {{godName}} reads this. Reject and it is dropped — nothing runs.", - "approveTitle": "Send this message through to {{godName}}", - "oneSec": "one sec…", - "approve": "approve", - "rejectTitle": "Drop this message. Nothing is sent", - "reject": "reject", - "task": "TASK {{id}}", + "justNow": "agora mesmo", + "ago": "{{unit}} atrás", + "in": "em {{unit}}", + "kindDirective": "diretriz", + "kindCommunication": "comunicação", + "decisionPending": "precisa de você", + "decisionApproved": "aprovado", + "decisionRejected": "rejeitado", + "decisionAuto": "auto-permitido", + "emptyMessage": "(mensagem vazia)", + "showLess": "mostrar menos", + "showAll": "mostrar todos os {{count}} caracteres", + "tailRejected": "Você recusou. Nada foi enviado à colmeia.", + "tailNoReply": "Sem resposta ainda. {{godName}} está com esta.", + "waitingForYou": "AGUARDANDO VOCÊ", + "unnamedSource": "fonte sem nome", + "from": "de", + "to": "para", + "unknown": "desconhecido", + "theySent": "ELES ENVIARAM", + "weReplied": "NÓS RESPONDEMOS", + "weSent": "NÓS ENVIAMOS", + "pendingDirectiveDesc": "Aprove e isso vai ao {{godName}}, que vai pôr a colmeia para trabalhar. Rejeite e é descartado — nada executa.", + "pendingDesc": "Aprove e {{godName}} lê isso. Rejeite e é descartado — nada executa.", + "approveTitle": "Enviar esta mensagem ao {{godName}}", + "oneSec": "um seg…", + "approve": "aprovar", + "rejectTitle": "Descartar esta mensagem. Nada é enviado", + "reject": "rejeitar", + "task": "TAREFA {{id}}", "sectionWebhooks": "Webhooks", - "sectionWebhooksBlurb": "Everything posted to your webhook endpoints, next to what {{godName}} sent back.", - "sectionOrg": "Organization", - "sectionOrgBlurb": "Messages from your teammates' clone nodes, next to what {{godName}} sent back.", - "heldOne": "One message is held, waiting on your yes or no.", - "heldMany": "{{count}} messages are held, waiting on your yes or no.", - "decideFailed": "That did not go through. Try again.", - "clearFailed": "Could not clear it. Try again.", - "emptyOrgTitle": "Nothing here yet, and nothing is broken.", - "emptyOrgBody": "Teammate messaging is not built yet. You can set an org key and pick a mode today, but no one's clone node can reach yours until the transport ships. When it does, their messages and our replies land here.", - "emptyWebhookTitle": "No webhook messages yet.", - "emptyWebhookBody": "When something posts to one of your endpoints, it lands here with {{godName}}'s reply underneath. Nothing has called in so far. Add an endpoint under Webhooks to get a URL you can hand out.", - "clearConfirm": "Delete all {{count}} messages? The record is gone for good.", - "deleteThem": "delete them", - "keepThem": "keep them", - "clearHistoryTitle": "Delete this section's history", - "clearHistory": "clear history" + "sectionWebhooksBlurb": "Tudo postado nos seus endpoints de webhook, ao lado do que {{godName}} respondeu.", + "sectionOrg": "Organização", + "sectionOrgBlurb": "Mensagens dos nós clones dos seus colegas, ao lado do que {{godName}} respondeu.", + "heldOne": "Uma mensagem retida, aguardando seu sim ou não.", + "heldMany": "{{count}} mensagens retidas, aguardando seu sim ou não.", + "decideFailed": "Não foi. Tente de novo.", + "clearFailed": "Não foi possível limpar. Tente de novo.", + "emptyOrgTitle": "Nada aqui ainda, e nada está quebrado.", + "emptyOrgBody": "Mensagens de colegas ainda não existem. Você pode definir uma chave de org e escolher um modo hoje, mas nenhum nó clone alcança o seu até o transporte chegar. Quando chegar, as mensagens deles e nossas respostas caem aqui.", + "emptyWebhookTitle": "Sem mensagens de webhook ainda.", + "emptyWebhookBody": "Quando algo postar num dos seus endpoints, cai aqui com a resposta do {{godName}} embaixo. Nada chamou até agora. Adicione um endpoint em Webhooks para ter uma URL para distribuir.", + "clearConfirm": "Apagar todas as {{count}} mensagens? O registro some para sempre.", + "deleteThem": "apague-as", + "keepThem": "mantenha-as", + "clearHistoryTitle": "Apagar o histórico desta seção", + "clearHistory": "limpar histórico" }, "fileTree": { "loading": "loading…", @@ -1172,28 +1172,28 @@ "catalogUnreachable": "could not reach the catalog" }, "workersTab": { - "stopping": "stopping", - "working": "working", - "liveWorkers": "Live workers", - "liveIntro": "Isolated workers {{godName}} spins up to handle Slack messages — they run to completion, reply in-thread, then tear down.", - "noneRunning": "No workers running right now.", - "repliesToSlack": "replies to a Slack thread", - "stoppingEllipsis": "stopping…", - "stop": "stop", - "workerIdTitle": "worker / PTY id", - "baseBranchTitle": "base branch the worktree was cut from", + "stopping": "parando", + "working": "trabalhando", + "liveWorkers": "Workers ao vivo", + "liveIntro": "Workers isolados que {{godName}} cria para tratar mensagens do Slack — rodam até concluir, respondem na thread e desmontam.", + "noneRunning": "Sem workers rodando agora.", + "repliesToSlack": "responde numa thread do Slack", + "stoppingEllipsis": "parando…", + "stop": "parar", + "workerIdTitle": "id do worker / PTY", + "baseBranchTitle": "branch base de onde o worktree foi cortado", "base": "base: {{branch}}", - "upSinceTitle": "time since spawn", - "up": "up {{age}}", - "idleTitle": "time since last terminal output", - "ptyGone": "pty gone", - "idle": "idle {{age}}", - "tokensTitle": "cumulative tokens (input+output+cache)", + "upSinceTitle": "tempo desde a criação", + "up": "ativo há {{age}}", + "idleTitle": "tempo desde a última saída do terminal", + "ptyGone": "pty sumiu", + "idle": "ocioso há {{age}}", + "tokensTitle": "tokens acumulados (entrada+saída+cache)", "tokens": "tokens {{value}}", - "uncapped": "uncapped", - "preserved": "Preserved worktrees ({{count}})", - "preservedIntro": "Finished workers whose worktree held un-integrated work — kept (never auto-discarded) and auto-reclaimed once the work lands in its base branch.", - "keptAgo": "kept {{age}} ago" + "uncapped": "sem teto", + "preserved": "Worktrees preservados ({{count}})", + "preservedIntro": "Workers terminados cujo worktree tinha trabalho não integrado — mantidos (nunca auto-descartados) e auto-recuperados quando o trabalho cai na branch base.", + "keptAgo": "mantido há {{age}}" }, "memoryGraph": { "topics": "topics", @@ -1277,65 +1277,65 @@ "edit": "edit" }, "kanban": { - "count": "{{count}} tasks", - "newWorkHint": "new work? dispatch it to {{godName}} (monitor tab)", - "colTodo": "TODO", - "colDoing": "DOING", - "colBlocked": "BLOCKED", - "colDone": "DONE", - "openTaskDetails": "open task details", - "needsYouTitle": "waiting on YOUR answer — see the ASK ME tab", - "dismissTitle": "dismiss this task (removes it from the board)", - "dismissAria": "dismiss task", - "taskTitle": "TASK", - "unassigned": "unassigned", - "noDescription": "(no description on this card)", - "humanQA": "HUMAN Q&A", - "awaitingAnswer": "AWAITING YOUR ANSWER — ASK ME TAB", - "dependsOn": "DEPENDS ON", - "assign": "assign", - "priority": "Priority {{level}}/5" + "count": "{{count}} tarefas", + "newWorkHint": "trabalho novo? despache para {{godName}} (aba monitor)", + "colTodo": "A FAZER", + "colDoing": "FAZENDO", + "colBlocked": "BLOQUEADO", + "colDone": "CONCLUÍDO", + "openTaskDetails": "abrir detalhes da tarefa", + "needsYouTitle": "aguardando SUA resposta — ver a aba ME PERGUNTE", + "dismissTitle": "dispensar esta tarefa (remove do quadro)", + "dismissAria": "dispensar tarefa", + "taskTitle": "TAREFA", + "unassigned": "não atribuído", + "noDescription": "(sem descrição neste cartão)", + "humanQA": "P&R COM HUMANO", + "awaitingAnswer": "AGUARDANDO SUA RESPOSTA — ABA ME PERGUNTE", + "dependsOn": "DEPENDE DE", + "assign": "atribuir", + "priority": "Prioridade {{level}}/5" }, "queueComposer": { - "recording": "● recording — click stop to transcribe", - "transcribing": "transcribing…", - "voice": "voice", - "busyQueued": "{{name}} is busy — {{count}} queued", - "heldFloor": "held — delivery paused floor-wide", - "heldDraft": "held — {{name}}'s terminal has unsent text on its prompt", - "heldPicker": "held — a slash-command picker is open in {{name}}'s terminal", - "heldExited": "held — {{name}}'s terminal has exited", - "sendingOneByOne": "sending to {{name}} one-by-one…", - "pausedTitle": "Auto-delivery is paused for the whole floor. Resume it in the Command Center, or use \"send now\" on a message below.", - "dropToAttach": "DROP TO ATTACH", - "queue": "QUEUE", - "closePicker": "close picker", - "recoverPrompt": "recover prompt", - "clearAllTitle": "Clear all queued messages", - "clearAll": "clear all", - "removeAttachment": "Remove attachment", - "messagePlaceholder": "Message {{name}}", - "busyPlaceholder": "{{name}} is busy — queue a message", - "files": "files", - "collapse": "Collapse this message", - "showFull": "Show the full message", - "seeLess": "see less", - "seeMore": "see more", - "sendNowTitle": "Deliver this message even though auto-delivery is paused. It moves to the front of the queue and types in as soon as the terminal is free.", - "sendNow": "send now", - "sendingWhenFree": "sending when free…", - "removeFromQueue": "Remove from queue", - "ffNoKeyTitle": "Dictation needs a free Groq API key. Click the info mark for the steps.", - "ffStopTranscribe": "Stop & transcribe", - "ffTitle": "Free Flow — dictate into the queue. Click, or hold Option (⌥).", - "stop": "stop", - "ffHowEnable": "How do I enable dictation?", - "ffSetupTitle": "Set up dictation", - "ffSetupIntro": "Speak instead of typing. Groq transcribes it, and their free tier covers this — no card, no cost.", - "ffCreateKey": "Create a free key at", - "ffPasteKey": "Paste it into Settings → Voice → Groq API key", - "ffClickOrHold": "Click voice, or hold the right Option key to talk", - "ffHoldHint": "Hold it ALONE for a moment to start; release to transcribe into the composer, where you can edit before sending. Either Option key works, and Option+key combos still reach the terminal untouched." + "recording": "● gravando — clique em parar para transcrever", + "transcribing": "transcrevendo…", + "voice": "voz", + "busyQueued": "{{name}} está ocupado — {{count}} na fila", + "heldFloor": "retido — entrega pausada no escritório todo", + "heldDraft": "retido — o terminal do {{name}} tem texto não enviado no prompt", + "heldPicker": "retido — um seletor de slash-command está aberto no terminal do {{name}}", + "heldExited": "retido — o terminal do {{name}} foi encerrado", + "sendingOneByOne": "enviando para {{name}} um a um…", + "pausedTitle": "Entrega automática pausada para o escritório todo. Retome no Centro de Comando, ou use \"enviar agora\" numa mensagem abaixo.", + "dropToAttach": "SOLTE PARA ANEXAR", + "queue": "FILA", + "closePicker": "fechar seletor", + "recoverPrompt": "recuperar prompt", + "clearAllTitle": "Limpar todas as mensagens enfileiradas", + "clearAll": "limpar tudo", + "removeAttachment": "Remover anexo", + "messagePlaceholder": "Mensagem para {{name}}", + "busyPlaceholder": "{{name}} está ocupado — enfileire uma mensagem", + "files": "arquivos", + "collapse": "Recolher esta mensagem", + "showFull": "Mostrar a mensagem completa", + "seeLess": "ver menos", + "seeMore": "ver mais", + "sendNowTitle": "Entrega esta mensagem mesmo com a entrega automática pausada. Ela passa para a frente da fila e é digitada assim que o terminal libera.", + "sendNow": "enviar agora", + "sendingWhenFree": "enviando quando liberar…", + "removeFromQueue": "Remover da fila", + "ffNoKeyTitle": "Ditado precisa de uma chave grátis da Groq. Clique na marca de info para os passos.", + "ffStopTranscribe": "Parar e transcrever", + "ffTitle": "Free Flow — dite na fila. Clique, ou segure Option (⌥).", + "stop": "parar", + "ffHowEnable": "Como ativo o ditado?", + "ffSetupTitle": "Configurar ditado", + "ffSetupIntro": "Fale em vez de digitar. A Groq transcreve, e o plano grátis deles cobre isso — sem cartão, sem custo.", + "ffCreateKey": "Crie uma chave grátis em", + "ffPasteKey": "Cole em Configurações → Voz → Chave de API da Groq", + "ffClickOrHold": "Clique em voz, ou segure o Option direito para falar", + "ffHoldHint": "Segure SOZINHO por um instante para começar; solte para transcrever no composer, onde você pode editar antes de enviar. Qualquer Option funciona, e combos Option+tecla chegam ao terminal intactos." }, "idePanel": { "workspace": "{{name}}'s workspace", From a1ba7c69adec55c631aacf614e98dc7de507249e Mon Sep 17 00:00:00 2001 From: T3sh Date: Wed, 14 Oct 2026 00:48:31 -0300 Subject: [PATCH 05/24] feat(i18n): traduz Task 6 pt-BR - restante da UI (468 chaves) office, tema, sidebar, commandBar, custos, engines, MCP, integracoes, memoria, skills, arquivos, git, IDE, terminal, voz, updates, org, contexto, webhooks, waterfall, threads. 1203/1203 chaves traduzidas. --- src/renderer/src/i18n/locales/pt-BR.json | 888 +++++++++++------------ 1 file changed, 444 insertions(+), 444 deletions(-) diff --git a/src/renderer/src/i18n/locales/pt-BR.json b/src/renderer/src/i18n/locales/pt-BR.json index 8e884c0f7b..ed732b3205 100644 --- a/src/renderer/src/i18n/locales/pt-BR.json +++ b/src/renderer/src/i18n/locales/pt-BR.json @@ -19,32 +19,32 @@ "add": "adicionar" }, "commandBar": { - "free": "free", + "free": "grátis", "skill": "/skill", - "quick": "quick", - "placeholder": "Type a command", - "placeholderBusy": "Ada is working...", - "placeholderBlocked": "Ada needs you...", - "send": "send", - "busyNote": "Ada is mid-tool. Queue or hit pause.", - "blockedNote": "Approval needed." + "quick": "rápido", + "placeholder": "Digite um comando", + "placeholderBusy": "Ada está trabalhando…", + "placeholderBlocked": "Ada precisa de você…", + "send": "enviar", + "busyNote": "Ada está no meio de uma ferramenta. Enfileire ou pause.", + "blockedNote": "Aprovação necessária." }, "blockedBanner": { "needsYou": "precisa de você" }, "costHud": { - "spendCap": "Spend cap", - "none": "none", + "spendCap": "Teto de gasto", + "none": "nenhum", "usd": "USD", - "off": "(off)", - "thisSession": "{{usd}} this session", - "thisSessionWithCap": "{{usd}} this session / {{cap}}", - "audioTokens": "{{input}} in · {{output}} out audio tokens", - "overCap": "Over the spend cap — time to wrap up.", - "nearCap": "Approaching the spend cap.", - "lastSession": "Last session: {{usd}}", - "noSession": "No active voice session.", - "compactTitle": "{{count}} voice audio tokens this session", + "off": "(desligado)", + "thisSession": "{{usd}} nesta sessão", + "thisSessionWithCap": "{{usd}} nesta sessão / {{cap}}", + "audioTokens": "{{input}} entrada · {{output}} saída tokens de áudio", + "overCap": "Passou do teto de gasto — hora de encerrar.", + "nearCap": "Chegando no teto de gasto.", + "lastSession": "Última sessão: {{usd}}", + "noSession": "Sem sessão de voz ativa.", + "compactTitle": "{{count}} tokens de áudio de voz nesta sessão", "tok": "tok" }, "badge": { @@ -128,17 +128,17 @@ "sidebar": { "terminal": "terminal", "git": "git", - "messages": "messages", + "messages": "mensagens", "traces": "traces" }, "toolWaterfall": { - "fresh": "fresh {{tokens}}t", - "cache": "cache {{tokens}}t ({{pct}}%)", + "fresh": "{{tokens}}t novos", + "cache": "{{tokens}}t cache ({{pct}}%)", "total": "{{tokens}}t total", - "noTelemetry": "no live telemetry yet — spawn / respawn this agent to instrument it", - "empty": "No tool calls captured yet. Each tool the agent runs appears here with its real duration.", + "noTelemetry": "sem telemetria ao vivo ainda — crie / recrie este agente para instrumentá-lo", + "empty": "Sem chamadas de ferramenta capturadas ainda. Cada ferramenta que o agente roda aparece aqui com a duração real.", "barOk": "{{tool}} · {{ms}}ms · ok", - "barFailed": "{{tool}} · {{ms}}ms · failed" + "barFailed": "{{tool}} · {{ms}}ms · falhou" }, "agentDetail": { "open": "abrir", @@ -174,24 +174,24 @@ "joinDiscord": "entrar no Discord" }, "officeTheme": { - "title": "Office Theme", - "tvShow": "TV-show office themes", + "title": "Tema do Escritório", + "tvShow": "Temas de escritório de seriados", "experimental": "experimental", - "desc": "Re-skin the pixel office as a TV show. Switching starts a fresh cast.", - "current": "current", - "soon": "soon", - "notBuiltYet": "{{label}} isn't built yet — showing the office for now.", - "switchAborted": "Switch aborted — a terminal wouldn't close: {{error}}", - "confirmTitle": "SWITCH OFFICE TO \"{{label}}\"?", - "startsFreshCast": "STARTS A FRESH CAST", - "deleteCount": "Your {{count}} current agent will be deleted — their terminals close and any in-progress work stops.", - "deleteCountPlural": "Your {{count}} current agents will be deleted — their terminals close and any in-progress work stops.", - "onlyCarries": "Only {{god}} carries over.", - "stillWorking": "⚠ {{count}} agent is still working.", - "stillWorkingPlural": "⚠ {{count}} agents are still working.", - "cantUndo": "This can't be undone.", - "switching": "switching…", - "deleteSwitch": "delete {{count}} & switch" + "desc": "Reveste o escritório pixelado como um seriado. Trocar começa um elenco novo.", + "current": "atual", + "soon": "em breve", + "notBuiltYet": "{{label}} ainda não existe — mostrando o escritório por enquanto.", + "switchAborted": "Troca abortada — um terminal não fechou: {{error}}", + "confirmTitle": "TROCAR ESCRITÓRIO PARA \"{{label}}\"?", + "startsFreshCast": "COMEÇA UM ELENCO NOVO", + "deleteCount": "Seu {{count}} agente atual será apagado — os terminais fecham e qualquer trabalho em curso para.", + "deleteCountPlural": "Seus {{count}} agentes atuais serão apagados — os terminais fecham e qualquer trabalho em curso para.", + "onlyCarries": "Só {{god}} passa.", + "stillWorking": "⚠ {{count}} agente ainda trabalhando.", + "stillWorkingPlural": "⚠ {{count}} agentes ainda trabalhando.", + "cantUndo": "Sem volta.", + "switching": "trocando…", + "deleteSwitch": "apagar {{count}} e trocar" }, "settings": { "title": "CONFIGURAÇÕES", @@ -707,84 +707,84 @@ "errEngineNotInstalled": "{{label}} não está instalado. Instale e pressione \"verificar novamente\", ou escolha outro engine." }, "office": { - "gpuError": "The office floor lost its GPU context.\n\nToo many terminals are using the GPU at once.\nClose a few agent terminals, or restart the app, to bring it back.", + "gpuError": "O escritório perdeu o contexto GPU.\n\nTerminais demais usando a GPU ao mesmo tempo.\nFeche alguns terminais de agentes, ou reinicie o app, para trazê-lo de volta.", "errand": { "water": [ - "watering the plants 🌿", - "giving the plants a drink", - "they grow so fast" + "regando as plantas 🌿", + "dando água às plantas", + "como crescem rápido" ], "window": [ - "letting some air in 🍃", - "a bit of fresh air", - "nice breeze today" + "entrando um ar 🍃", + "um pouco de ar fresco", + "que brisa boa hoje" ], "dispenser": [ - "getting some water 💧", - "hydration break", - "staying sharp" + "pegando água 💧", + "pausa para hidratar", + "mantendo o foco" ], "fridge": [ - "anything good in the fridge?", - "who took my yogurt?", - "just looking…" + "algo bom na geladeira?", + "quem pegou meu iogurte?", + "só olhando…" ], "shelf": [ - "checking out the shelf 📚", - "anything new in here?", - "so much good stuff" + "olhando a estante 📚", + "algo novo aqui?", + "quanta coisa boa" ], "bin": [ - "out with the scrap paper 🗑️", - "desk cleanup day", - "tidying up a little" + "fora com o papel usado 🗑️", + "dia de limpar a mesa", + "arrumando um pouco" ], "smoke": [ - "the floor runs itself 🚬", - "boss break.", - "thinking big thoughts 🚬", - "I DECLARE… a break" + "o escritório se vira sozinho 🚬", + "pausa do chefe.", + "pensando grande 🚬", + "EU DECLARO… uma pausa" ] }, "suckUp": [ - "already shipped {{done}} tasks, {{godName}}. raise? 🥺", - "{{done}} tasks done this week, boss!", - "great vision as always, boss!", - "I was JUST about to do exactly that!", - "love the tie today, {{godName}}", - "working hard, boss! 💪", - "best boss ever. genuinely." + "já entreguei {{done}} tarefas, {{godName}}. aumento? 🥺", + "{{done}} tarefas prontas esta semana, chefe!", + "visão ótima como sempre, chefe!", + "eu IA fazer exatamente isso!", + "adorei a gravata hoje, {{godName}}", + "trabalhando duro, chefe! 💪", + "melhor chefe ever. sério." ], "gossip": [ - "has he ever actually written code?", - "another 'quick sync' that took an hour…", - "'world's best boss' — he bought that mug himself", - "he pinned MY task as his idea", - "the cigar smell, honestly…", - "he watered the plant. ONE plant. his own.", - "did you hear him? 'I DECLARE… a break'" + "ele já escreveu código alguma vez?", + "mais um ‘alinhamento rápido’ de uma hora…", + "‘melhor chefe do mundo’ — ele mesmo comprou a caneca", + "ele apresentou MINHA tarefa como ideia dele", + "o cheiro de charuto, sério…", + "ele regou a planta. UMA planta. a dele.", + "ouviu ele? ‘EU DECLARO… uma pausa’" ], "cheer": [ - "done! ✔", - "nailed it", - "that's a wrap", - "ship it 🚀", - "another one done", - "crushed it", - "in the books" + "pronto! ✔", + "mandou bem", + "é isso", + "envia 🚀", + "mais uma pronta", + "arrasou", + "registrado" ], "mugs": { - "empty": "no clean mugs left…", - "brewing": "brewing a fresh one ☕", - "washing": "washing the mug" + "empty": "sem canecas limpas…", + "brewing": "passando um fresquinho ☕", + "washing": "lavando a caneca" }, "activity": { - "waiting": "waiting", - "needsYou": "needs you", - "compacting": "compacting context", - "looping": "looping — breaker armed", - "runningFloor": "running the floor", - "idle": "idle" + "waiting": "aguardando", + "needsYou": "precisa de você", + "compacting": "compactando contexto", + "looping": "em loop — breaker armado", + "runningFloor": "comandando o escritório", + "idle": "ocioso" } }, "setupPanel": { @@ -819,85 +819,85 @@ } }, "aiEngines": { - "providers": "AI ENGINE PROVIDERS (BYOK)", - "providersDesc": "API keys + local endpoints for the OpenCode, Crush, pi.dev and Qwen engines. Keys are stored write-only (encrypted at rest; never shown again) and used only when those engines spawn. Claude Code and Codex use their own login.", - "apiKeys": "API KEYS", - "setCheck": "set ✓", - "keyStoredPlaceholder": "•••••••• (stored — type to replace)", - "keyPlaceholder": "paste {{label}} key", - "saved": "saved", - "failed": "failed", - "cleared": "cleared", - "localEndpoint": "LOCAL ENDPOINT · DEFAULT MODEL (PER ENGINE)", - "defaultModelPlaceholder": "default model (provider/model)", - "runningOpenModels": "Running open models? Step-by-step guides:", - "runOnOpenModels": "run Munder Difflin on open models", - "setUpMacMini": "set it up on a Mac Mini", - "autoModeCaveat": "⚠ In auto mode these engines run with full filesystem + shell access (no sandbox) — like Claude's bypass mode. Turn auto mode off (General) to make them ask first. Live end-to-end verification with real model calls is pending your keys / a local LLM." + "providers": "PROVEDORES DE ENGINE DE IA (BYOK)", + "providersDesc": "Chaves de API + endpoints locais para os engines OpenCode, Crush, pi.dev e Qwen. Chaves são write-only (criptografadas em repouso; nunca mais mostradas) e usadas só quando esses engines criam. Claude Code e Codex usam o próprio login.", + "apiKeys": "CHAVES DE API", + "setCheck": "definida ✓", + "keyStoredPlaceholder": "•••••••• (guardada — digite para substituir)", + "keyPlaceholder": "cole a chave {{label}}", + "saved": "salva", + "failed": "falhou", + "cleared": "limpa", + "localEndpoint": "ENDPOINT LOCAL · MODELO PADRÃO (POR ENGINE)", + "defaultModelPlaceholder": "modelo padrão (provedor/modelo)", + "runningOpenModels": "Rodando modelos abertos? Guias passo a passo:", + "runOnOpenModels": "rodar Munder Difflin com modelos abertos", + "setUpMacMini": "configurar num Mac Mini", + "autoModeCaveat": "⚠ No modo auto esses engines rodam com acesso total a arquivos + shell (sem sandbox) — como o modo bypass do Claude. Desligue o modo auto (Geral) para fazê-los perguntar antes. Verificação ao vivo de ponta a ponta com chamadas reais de modelo depende das suas chaves / um LLM local." }, "mcpDefaults": { - "title": "Default MCP servers", - "desc": "These servers are merged into each new agent's session settings. Safe servers are on by default; write/secret servers are off until you consent. Changes take effect on the next agent spawn — running agents are not affected.", + "title": "Servidores MCP padrão", + "desc": "Estes servidores entram nas configurações de sessão de cada agente novo. Servidores seguros ficam ligados por padrão; os de escrita/segredo ficam desligados até você consentir. Mudanças valem no próximo agente criado — agentes rodando não são afetados.", "toggleNote": "{{id}}: {{state}}", - "couldNotSave": "could not save", + "couldNotSave": "não foi possível salvar", "tiers": { - "safeReadonly": "Safe & Read-Only (on by default)", - "write": "Write Access (consent required)", - "secret": "Requires Secret / API Key (consent required)", - "safeReadonlyNote": "These servers read data only, need no secrets, and are scoped to the agent workspace. They are enabled for every new agent.", - "writeNote": "These servers can mutate state beyond the workspace. Off by default — enable only after reviewing.", - "secretNote": "These servers require an API key or credentials. Off by default — add your credentials and enable after consent." + "safeReadonly": "Seguro e Só-Leitura (ligado por padrão)", + "write": "Acesso de Escrita (requer consentimento)", + "secret": "Requer Segredo / Chave de API (requer consentimento)", + "safeReadonlyNote": "Estes servidores só leem dados, não precisam de segredos e valem no workspace do agente. Ativados para todo agente novo.", + "writeNote": "Estes servidores podem mudar estado além do workspace. Desligados por padrão — ative só após revisar.", + "secretNote": "Estes servidores exigem chave de API ou credenciais. Desligados por padrão — adicione suas credenciais e ative após consentir." } }, "devicePicker": { - "microphone": "Microphone", - "speaker": "Speaker", - "systemDefault": "System default", - "namesHint": "Device names appear after you first start a voice session and grant mic access. The microphone choice applies the next time {{godName}} connects; the speaker switches live." + "microphone": "Microfone", + "speaker": "Alto-falante", + "systemDefault": "Padrão do sistema", + "namesHint": "Nomes de dispositivos aparecem após iniciar sua primeira sessão de voz e dar acesso ao microfone. A escolha de microfone vale na próxima vez que {{godName}} conectar; o alto-falante troca ao vivo." }, "realtimeToggle": { - "talk": "talk", + "talk": "falar", "connecting": "…", - "listening": "listening", - "speaking": "speaking", - "working": "working", - "helpOff": "Talk to {{godName}} — start the voice session", - "helpConnecting": "Connecting to {{godName}}…", - "helpListening": "Listening — {{godName}} is hearing you (click to stop)", - "helpSpeaking": "{{godName}} is speaking (click to stop)", - "helpWorking": "{{godName}} is running a tool — mic muted (click to stop)", - "noKeyTitle": "Talk needs your OpenAI API key (used for the Realtime voice API). Add it in Settings → Voice.", - "whyDisabled": "Why is Talk disabled?", - "popoverBody": "An OpenAI API key is needed to use this feature.", - "setItUpNow": "set it up now" + "listening": "ouvindo", + "speaking": "falando", + "working": "trabalhando", + "helpOff": "Fale com {{godName}} — inicie a sessão de voz", + "helpConnecting": "Conectando ao {{godName}}…", + "helpListening": "Ouvindo — {{godName}} está ouvindo você (clique para parar)", + "helpSpeaking": "{{godName}} está falando (clique para parar)", + "helpWorking": "{{godName}} está usando uma ferramenta — microfone mudo (clique para parar)", + "noKeyTitle": "Falar precisa da sua chave de API da OpenAI (usada na API de voz Realtime). Adicione em Configurações → Voz.", + "whyDisabled": "Por que Falar está desativado?", + "popoverBody": "Uma chave de API da OpenAI é necessária para este recurso.", + "setItUpNow": "configurar agora" }, "updatesSection": { - "title": "Updates", - "onVersion": "You're on v{{v}}", - "checkingDetail": "Checking for a newer release…", - "availableHeadline": "v{{version}} is available", - "availableDetail": "You're on v{{v}}. Download it now — you'll be asked to restart once it's ready.", - "downloadBtn": "Download v{{version}}", - "downloadingHeadline": "Downloading v{{version}}", - "downloadingDetail": "{{percent}}% done. You can keep working; the restart is yours to trigger.", - "downloadedHeadline": "v{{version}} is ready to install", - "downloadedDetail": "Restart Munder Difflin to finish updating from v{{v}}.", - "restartBtn": "Restart to update", - "manualDetail": "This install can't update itself — download it from the release page.", - "manualDetailReason": "This install can't update itself ({{reason}}) — download it from the release page.", - "openReleaseBtn": "Open release page", - "errorHeadline": "Update check failed", - "errorDetail": "{{message}} (you're on v{{v}}).", - "retryBtn": "Try again", - "latestHeadline": "v{{v}} is the latest version", - "latestDetail": "You're already up to date — nothing to install.", - "checkAgainBtn": "Check again", - "idleDetail": "Updates are checked automatically every 6 hours. Check now if you want to be sure.", - "checkBtn": "Check for updates", - "downloadManually": "download manually", - "downloadManuallyTitle": "Download the v{{version}} installer and replace the app yourself", - "manualDownloadingTitle": "v{{version}} is downloading in your browser.", - "manualDownloadingBody": "When it lands, quit this app, install the new version over the current one, open it and pick the same project. On {{os}}:" + "title": "Atualizações", + "onVersion": "Você está na v{{v}}", + "checkingDetail": "Verificando release mais nova…", + "availableHeadline": "v{{version}} disponível", + "availableDetail": "Você está na v{{v}}. Baixe agora — vão pedir para reiniciar quando estiver pronto.", + "downloadBtn": "Baixar v{{version}}", + "downloadingHeadline": "Baixando v{{version}}", + "downloadingDetail": "{{percent}}% pronto. Pode seguir trabalhando; o reinício é você quem dispara.", + "downloadedHeadline": "v{{version}} pronta para instalar", + "downloadedDetail": "Reinicie Munder Difflin para terminar de atualizar da v{{v}}.", + "restartBtn": "Reiniciar para atualizar", + "manualDetail": "Esta instalação não se atualiza sozinha — baixe na página de releases.", + "manualDetailReason": "Esta instalação não se atualiza sozinha ({{reason}}) — baixe na página de releases.", + "openReleaseBtn": "Abrir página de releases", + "errorHeadline": "Falha ao verificar atualização", + "errorDetail": "{{message}} (você está na v{{v}}).", + "retryBtn": "Tentar de novo", + "latestHeadline": "v{{v}} é a versão mais nova", + "latestDetail": "Você já está em dia — nada para instalar.", + "checkAgainBtn": "Verificar de novo", + "idleDetail": "Atualizações verificadas sozinhas a cada 6 horas. Verifique agora se quiser certeza.", + "checkBtn": "Verificar atualizações", + "downloadManually": "baixar manualmente", + "downloadManuallyTitle": "Baixe o instalador da v{{version}} e substitua o app você mesmo", + "manualDownloadingTitle": "v{{version}} baixando no seu navegador.", + "manualDownloadingBody": "Quando chegar, saia deste app, instale a versão nova por cima da atual, abra e escolha o mesmo projeto. Em {{os}}:" }, "triggersTab": { "intro": "Tudo que pode iniciar trabalho sem você digitar.", @@ -911,35 +911,35 @@ "organisationBlurb": "Deixa o Munder Difflin de um colega mandar mensagem para o seu." }, "orgSection": { - "acceptMessages": "Accept messages from your organisation", - "key": "ORGANISATION KEY", - "keyPlaceholder": "paste your key", - "trust": "TRUST", - "settingsOnly": "Settings only, for now. The org messaging service does not exist yet, so a key here starts no connection and nothing is sent or received. It is stored ready for when it does.", - "noKeyWarning": "This is switched on with no key set, so no teammate can reach you yet.", - "noKey": "no key" + "acceptMessages": "Aceitar mensagens da sua organização", + "key": "CHAVE DA ORGANIZAÇÃO", + "keyPlaceholder": "cole sua chave", + "trust": "CONFIANÇA", + "settingsOnly": "Só configurações, por enquanto. O serviço de mensagens da org ainda não existe, então uma chave aqui não inicia conexão e nada é enviado ou recebido. Fica guardada para quando existir.", + "noKeyWarning": "Isto está ligado sem chave definida, então nenhum colega alcança você ainda.", + "noKey": "sem chave" }, "contextSection": { - "loading": "One sec…", - "intro": "A rule fires only when both halves agree: the gap since its last run has passed, AND that agent's context is at least as full as the bar. A bar of 0% means the clock alone.", - "compact": "Compact", - "compactBlurb": "Summarises the context so the thread keeps going.", - "clear": "Clear", - "clearBlurb": "Discards the context. Nothing is summarised.", - "clearCaution": "Clearing throws context away — it is not a smaller version of compaction. An agent mid-task forgets what it was doing. Leave this off unless you keep context another way.", - "extraFocus": "EXTRA FOCUS", - "extraFocusHint": "Appended to the provider's compaction command. Empty sends the bare command.", - "extraFocusPlaceholder": "What the summary must keep…", - "command": "COMMAND", - "commandHint": "Sent literally. Empty sends the bare clear command.", - "bothOff": "both off", - "off": "Off.", - "hintEvery": "Every {{interval}}, once context passes {{pct}}%.", - "noSoonerThan": "NO SOONER THAN EVERY", - "contextBar": "CONTEXT BAR", - "contextBarHint": "How full the window must be before this may run. 0% = time alone.", - "bigWindows": "BAR ON BIG WINDOWS", - "bigWindowsHint": "Used on ~1M-token windows, where a smaller slice is still an enormous amount of text." + "loading": "Um seg…", + "intro": "Uma regra dispara só quando as duas metades concordam: o intervalo desde a última execução passou, E o contexto daquele agente está ao menos tão cheio quanto a barra. Barra em 0% significa só o relógio.", + "compact": "Compactar", + "compactBlurb": "Resume o contexto para a thread seguir.", + "clear": "Limpar", + "clearBlurb": "Descarta o contexto. Nada é resumido.", + "clearCaution": "Limpar joga contexto fora — não é uma versão menor da compactação. Um agente no meio de uma tarefa esquece o que fazia. Deixe desligado salvo se você guarda contexto de outro jeito.", + "extraFocus": "FOCO EXTRA", + "extraFocusHint": "Anexado ao comando de compactação do provedor. Vazio envia o comando puro.", + "extraFocusPlaceholder": "O que o resumo deve manter…", + "command": "COMANDO", + "commandHint": "Enviado literalmente. Vazio envia o comando puro de limpar.", + "bothOff": "ambos desligados", + "off": "Desligado.", + "hintEvery": "A cada {{interval}}, quando o contexto passar de {{pct}}%.", + "noSoonerThan": "NÃO ANTES DE CADA", + "contextBar": "BARRA DE CONTEXTO", + "contextBarHint": "Quão cheia a janela deve estar para poder rodar. 0% = só tempo.", + "bigWindows": "BARRA EM JANELAS GRANDES", + "bigWindowsHint": "Usada em janelas de ~1M tokens, onde uma fatia menor ainda é uma enormidade de texto." }, "schedulesSection": { "justNow": "agora mesmo", @@ -966,36 +966,36 @@ "beatCeiling": "A batida se adapta ao silêncio do escritório, então isto é o teto, não o intervalo exato." }, "webhooksSection": { - "summaryNone": "none", + "summaryNone": "nenhum", "summary": "{{count}} · {{state}}", - "live": "live", + "live": "ao vivo", "offline": "offline", - "intro": "Anyone holding a URL and its secret can post work in. Each endpoint carries its own secret, so revoking one caller leaves the others alone.", - "noEndpoints": "No endpoints yet.", - "minting": "minting…", - "addWebhook": "add webhook", - "newEndpointHint": "A new endpoint starts switched off. Copy its URL and secret, then turn it on.", - "unnamed": "unnamed", - "reachable": "reachable", - "noUrlYet": "no URL yet", - "serverOffline": "server offline", - "name": "NAME", - "namePlaceholder": "Who calls this", - "postTo": "POST TO", - "noAddressYet": "This endpoint has no public address yet. It appears once the tunnel picks it up.", - "serverNotListening": "The webhook server is not listening, so there is no address to hand out yet.", - "secret": "SECRET", - "secretHint": "Callers echo this in the x-md-webhook-secret header.", - "trust": "TRUST", - "bodySchema": "BODY SCHEMA", - "editSchema": "edit schema", - "schemaDesc": "what an inbound body must look like", - "notValidJson": "Not valid JSON — {{error}}. Nothing was saved.", - "saved": "saved", - "saveSchema": "save schema", - "sure": "Sure?", - "deleteIt": "delete it", - "keep": "keep" + "intro": "Qualquer um com uma URL e seu segredo pode postar trabalho. Cada endpoint tem segredo próprio, então revogar um chamador deixa os outros em paz.", + "noEndpoints": "Sem endpoints ainda.", + "minting": "criando…", + "addWebhook": "adicionar webhook", + "newEndpointHint": "Um endpoint novo começa desligado. Copie URL e segredo, depois ligue.", + "unnamed": "sem nome", + "reachable": "alcançável", + "noUrlYet": "sem URL ainda", + "serverOffline": "servidor offline", + "name": "NOME", + "namePlaceholder": "Quem chama isso", + "postTo": "POSTAR EM", + "noAddressYet": "Este endpoint ainda não tem endereço público. Aparece quando o túnel o assume.", + "serverNotListening": "O servidor de webhooks não está ouvindo, então não há endereço para distribuir ainda.", + "secret": "SEGREDO", + "secretHint": "Chamadores ecoam isso no header x-md-webhook-secret.", + "trust": "CONFIANÇA", + "bodySchema": "ESQUEMA DO CORPO", + "editSchema": "editar esquema", + "schemaDesc": "como um corpo de entrada deve ser", + "notValidJson": "JSON inválido — {{error}}. Nada foi salvo.", + "saved": "salvo", + "saveSchema": "salvar esquema", + "sure": "Certo?", + "deleteIt": "apague", + "keep": "mantenha" }, "triggersUi": { "custom": "personalizado", @@ -1058,118 +1058,118 @@ "clearHistory": "limpar histórico" }, "fileTree": { - "loading": "loading…", - "copyPathTitle": "Copy path to clipboard" + "loading": "carregando…", + "copyPathTitle": "Copiar caminho para a área de transferência" }, "fileEditor": { - "file": "FILE", - "edit": "edit", - "preview": "preview", - "editTitle": "Edit the source", - "previewTitle": "Rendered preview (of the saved file)", - "openInIde": "open in IDE", - "openInIdeTitle": "Open this file in the full IDE", - "closeTitle": "Close (Esc)" + "file": "ARQUIVO", + "edit": "editar", + "preview": "pré-visualizar", + "editTitle": "Editar o fonte", + "previewTitle": "Pré-visualização renderizada (do arquivo salvo)", + "openInIde": "abrir na IDE", + "openInIdeTitle": "Abrir este arquivo na IDE completa", + "closeTitle": "Fechar (Esc)" }, "gitTab": { - "notARepo": "Not a git repo.", - "notARepoHint": "Run git init in the agent's terminal.", - "detachedHead": "DETACHED HEAD", - "refresh": "refresh", + "notARepo": "Não é um repo git.", + "notARepoHint": "Rode git init no terminal do agente.", + "detachedHead": "HEAD DESTACADO", + "refresh": "atualizar", "sectionStatus": "status", "sectionBranches": "branches", "sectionLog": "log", "staged": "staged", - "changes": "changes", + "changes": "alterações", "untracked": "untracked", - "clean": "working tree clean", - "noCommits": "no commits yet", - "modified": "modified", - "added": "added", - "deleted": "deleted", - "renamed": "renamed", - "unmerged": "unmerged", - "copyPath": "Copy path" + "clean": "working tree limpa", + "noCommits": "sem commits ainda", + "modified": "modificado", + "added": "adicionado", + "deleted": "apagado", + "renamed": "renomeado", + "unmerged": "não mesclado", + "copyPath": "Copiar caminho" }, "fullscreenTerminal": { - "showAgentList": "Show the agent list", - "hideAgentList": "Hide the agent list — full-width terminal", - "lightTheme": "Switch to the light theme", - "darkTheme": "Switch to the dark theme", - "toggleTheme": "Toggle dark mode", - "exitFullscreen": "Exit focus mode (Esc)", - "addAgent": "Add agent", - "respawnTitle": "Respawn from last session: {{names}} — same ids, memory and inboxes reattach automatically", - "contextTitle": "Context: {{used}} / {{limit}} tokens ({{pct}}%)", - "modelTitle": "Model: {{model}}", - "cliDefault": "CLI default", - "closeAgent": "Close {{name}} — ends the process and archives the agent", - "ideTip": "Open the IDE: browse and edit files in {{name}}'s workspace, and see their uncommitted changes as a diff.", - "openIdeAria": "Open the IDE", - "openTerminalTip": "Open your system terminal app in {{cwd}} — a normal shell in this agent's folder, separate from the agent's own terminal.", - "openTerminalAria": "Open a system terminal in this agent's folder" + "showAgentList": "Mostrar a lista de agentes", + "hideAgentList": "Ocultar a lista de agentes — terminal em largura total", + "lightTheme": "Trocar para o tema claro", + "darkTheme": "Trocar para o tema escuro", + "toggleTheme": "Alternar modo escuro", + "exitFullscreen": "Sair do modo foco (Esc)", + "addAgent": "Adicionar agente", + "respawnTitle": "Recriar da última sessão: {{names}} — mesmos ids, memória e caixas de entrada reconectam sozinhas", + "contextTitle": "Contexto: {{used}} / {{limit}} tokens ({{pct}}%)", + "modelTitle": "Modelo: {{model}}", + "cliDefault": "Padrão do CLI", + "closeAgent": "Fechar {{name}} — encerra o processo e arquiva o agente", + "ideTip": "Abra a IDE: navegue e edite arquivos no workspace de {{name}} e veja alterações não commitadas como diff.", + "openIdeAria": "Abrir a IDE", + "openTerminalTip": "Abra o terminal do sistema em {{cwd}} — um shell normal na pasta deste agente, separado do próprio terminal do agente.", + "openTerminalAria": "Abrir um terminal do sistema na pasta deste agente" }, "memoryPanel": { - "pill": "🧠 memory", - "pillActive": "🧠 memory", - "openTitle": "Search the shared memory your agents build up", - "title": "HIVE MEMORY", - "intro": "What your agents remember across sessions, shared between them. Search it by meaning, not just exact words.", - "notSetUp": "Not set up", - "onReady": "On · ready", - "onGettingReady": "On · getting ready…", - "turnOff": "Turn off", - "turnOn": "Turn on", - "notInstalled": "Meaning-based search isn't installed yet.", - "setUpInPrereqs": "set it up in Prerequisites →", - "plainNotesStill": "Agents still keep plain notes without it.", - "searchLanguage": "Search language", - "modelFast": "Fast", - "modelFastDetail": "English only · ~90 MB", - "modelMultilingual": "Multilingual", - "modelMultilingualDetail": "all languages · ~300 MB", - "searchPlaceholder": "Search by meaning…", - "nothingMatched": "Nothing matched yet.", - "searchFailed": "Couldn't search" + "pill": "🧠 memória", + "pillActive": "🧠 memória", + "openTitle": "Pesquise a memória compartilhada que seus agentes constroem", + "title": "MEMÓRIA DA COLMEIA", + "intro": "O que seus agentes lembram entre sessões, compartilhado entre eles. Pesquise por significado, não só palavras exatas.", + "notSetUp": "Não configurado", + "onReady": "Ligado · pronto", + "onGettingReady": "Ligando · preparando…", + "turnOff": "Desligar", + "turnOn": "Ligar", + "notInstalled": "Pesquisa por significado ainda não instalada.", + "setUpInPrereqs": "configure em Pré-requisitos →", + "plainNotesStill": "Agentes seguem com anotações simples sem isso.", + "searchLanguage": "Idioma de pesquisa", + "modelFast": "Rápido", + "modelFastDetail": "Só inglês · ~90 MB", + "modelMultilingual": "Multilíngue", + "modelMultilingualDetail": "todos os idiomas · ~300 MB", + "searchPlaceholder": "Pesquisar por significado…", + "nothingMatched": "Nada correspondeu ainda.", + "searchFailed": "Não foi possível pesquisar" }, "threads": { - "noSubject": "(no subject)", - "empty": "No conversations yet. Messages this agent receives will appear here as threads.", - "less": "less", - "more": "more", - "replyPlaceholder": "Reply to {{name}}…", - "send": "Send" + "noSubject": "(sem assunto)", + "empty": "Sem conversas ainda. Mensagens que este agente recebe aparecem aqui como threads.", + "less": "menos", + "more": "mais", + "replyPlaceholder": "Responder a {{name}}…", + "send": "Enviar" }, "skillsTab": { - "installed": "Installed", - "browse": "browse", - "searchInstalled": "Search installed skills…", - "searchCatalog": "Search the skills catalog…", - "categoryTitle": "Categories as published by the catalog", - "allCategories": "all categories", - "allPublishers": "all publishers", - "loading": "loading…", - "refresh": "refresh", - "scanning": "Scanning…", - "noSkillsInstalled": "No skills installed yet. Open Browse to see what is available.", - "nothingMatches": "Nothing matches that search.", - "openFolder": "open folder", - "shipsWithApp": "ships with the app", - "deleteConfirm": "delete {{name}}?", - "removing": "removing…", - "uninstall": "uninstall", - "loadingCatalog": "Loading the catalog…", - "cachedCopy": "Showing a cached copy — {{error}}.", - "matching": "{{count}} matching", - "matchingFirst": "{{count}} matching · showing the first {{shown}}", - "curatedBy": "curated by abubakarsiddik31/claude-skills-collection", - "installing": "installing…", - "install": "install", - "learnMore": "learn more", - "installFailed": "install failed", - "removeFailed": "could not remove it", - "uninstallFailed": "uninstall failed", - "catalogUnreachable": "could not reach the catalog" + "installed": "Instaladas", + "browse": "explorar", + "searchInstalled": "Pesquisar skills instaladas…", + "searchCatalog": "Pesquisar o catálogo de skills…", + "categoryTitle": "Categorias como publicadas pelo catálogo", + "allCategories": "todas as categorias", + "allPublishers": "todos os publicadores", + "loading": "carregando…", + "refresh": "atualizar", + "scanning": "Varrendo…", + "noSkillsInstalled": "Sem skills instaladas ainda. Abra Explorar para ver o disponível.", + "nothingMatches": "Nada corresponde a essa pesquisa.", + "openFolder": "abrir pasta", + "shipsWithApp": "vem com o app", + "deleteConfirm": "apagar {{name}}?", + "removing": "removendo…", + "uninstall": "desinstalar", + "loadingCatalog": "Carregando o catálogo…", + "cachedCopy": "Mostrando cópia em cache — {{error}}.", + "matching": "{{count}} correspondentes", + "matchingFirst": "{{count}} correspondentes · mostrando as primeiras {{shown}}", + "curatedBy": "curadoria de abubakarsiddik31/claude-skills-collection", + "installing": "instalando…", + "install": "instalar", + "learnMore": "saiba mais", + "installFailed": "falha ao instalar", + "removeFailed": "não foi possível remover", + "uninstallFailed": "falha ao desinstalar", + "catalogUnreachable": "não foi possível alcançar o catálogo" }, "workersTab": { "stopping": "parando", @@ -1196,85 +1196,85 @@ "keptAgo": "mantido há {{age}}" }, "memoryGraph": { - "topics": "topics", - "refresh": "refresh", - "readingMemory": "reading memory…", - "topicsShown": "showing {{shown}} of {{total}} topics", - "loadingMemory": "loading memory…", - "messageLinks": "{{count}} message links", - "knowsAbout": "{{a}} knows about “{{b}}”", - "messagesLast": "{{count}} messages · last: {{act}}", - "noMemory": "No memory recorded yet.", - "legendRequest": "request", - "legendQuery": "query", - "legendPropose": "propose", - "legendAgreeDone": "agree/done", - "legendRefuse": "refuse", - "legendInformTopic": "inform/topic" + "topics": "tópicos", + "refresh": "atualizar", + "readingMemory": "lendo memória…", + "topicsShown": "mostrando {{shown}} de {{total}} tópicos", + "loadingMemory": "carregando memória…", + "messageLinks": "{{count}} links de mensagem", + "knowsAbout": "{{a}} sabe sobre “{{b}}”", + "messagesLast": "{{count}} mensagens · última: {{act}}", + "noMemory": "Sem memória registrada ainda.", + "legendRequest": "pedido", + "legendQuery": "consulta", + "legendPropose": "proposta", + "legendAgreeDone": "concordado/concluído", + "legendRefuse": "recusa", + "legendInformTopic": "informe/tópico" }, "integrations": { - "errLabel": "Give it a label.", - "errId": "Could not derive a valid id from the label.", - "errBaseUrl": "Base URL is required.", - "errBaseUrlFormat": "Base URL must be https:// (or http://127.0.0.1 / localhost for a local target).", - "errHeader": "Header name must be 1–64 chars of A–Z, 0–9, or \"-\".", - "couldNotSave": "Could not save.", - "added": "Integration added.", - "updated": "Integration updated.", - "removed": "Removed “{{label}}”.", - "couldNotRemove": "Could not remove.", - "testFailed": "Test failed to run.", - "connected": "✓ Connected", - "connectedWith": "✓ Connected ({{status}})", + "errLabel": "Dê um rótulo.", + "errId": "Não foi possível derivar um id válido do rótulo.", + "errBaseUrl": "URL base é obrigatória.", + "errBaseUrlFormat": "URL base deve ser https:// (ou http://127.0.0.1 / localhost para alvo local).", + "errHeader": "Nome do header deve ter 1–64 caracteres de A–Z, 0–9 ou “-”.", + "couldNotSave": "Não foi possível salvar.", + "added": "Integração adicionada.", + "updated": "Integração atualizada.", + "removed": "Removida “{{label}}”.", + "couldNotRemove": "Não foi possível remover.", + "testFailed": "Teste não executou.", + "connected": "✓ Conectado", + "connectedWith": "✓ Conectado ({{status}})", "failed": "✕", - "backToList": "← Integrations", - "pickTemplate": "Pick a template", - "galleryDesc": "Choose what you're connecting. The template sets the defaults. Pick Custom REST for anything not listed.", - "anyHttpApi": "Any HTTP API", - "continue": "continue", - "backToTemplates": "← Templates", - "needsSecret": "Needs a {{label}}", - "publicApi": "Public API — no secret needed", - "label": "Label", - "labelHint": "Shown in your list. Id", - "fixed": "fixed", - "baseUrl": "Base URL", - "baseUrlHint": "Set by the {{label}} template.", - "preset": "preset", - "authentication": "Authentication", - "setByTemplate": "set by template", - "headerName": "Header name", - "headerHint": "The secret is sent as {{header}}: .", - "saved": "saved", - "replaceKey": "Replace key", - "pasteYour": "Paste your", + "backToList": "← Integrações", + "pickTemplate": "Escolha um modelo", + "galleryDesc": "Escolha o que está conectando. O modelo define os padrões. Escolha REST Personalizado para o que não está listado.", + "anyHttpApi": "Qualquer API HTTP", + "continue": "continuar", + "backToTemplates": "← Modelos", + "needsSecret": "Precisa de {{label}}", + "publicApi": "API pública — sem segredo", + "label": "Rótulo", + "labelHint": "Mostrado na sua lista. Id", + "fixed": "fixo", + "baseUrl": "URL base", + "baseUrlHint": "Definida pelo modelo {{label}}.", + "preset": "predefinido", + "authentication": "Autenticação", + "setByTemplate": "definido pelo modelo", + "headerName": "Nome do header", + "headerHint": "O segredo é enviado como {{header}}: .", + "saved": "salvo", + "replaceKey": "Substituir chave", + "pasteYour": "Cole sua", "writeOnly": "Write-only", - "secretDesc": "Encrypted in the main process and never shown again. To change it, paste a new key — the old one can't be read back.", - "blankKeepsKey": "Leave blank to keep the saved key.", - "availability": "Availability", - "enabled": "enabled", - "disabled": "disabled", - "availableToAll": "✓ Available to all workers", - "notAvailableYet": "Not available to workers yet", - "addSecretToEnable": "Add a secret and enable to make it available.", - "readyOnceSaved": "Ready once saved.", - "disabledNoUse": "Disabled — no worker can use it.", - "v1Note": "v1 grants every enabled integration to all workers. Per-worker scoping is coming.", - "testConnection": "Test connection", - "testing": "testing…", - "testAfterSave": "Save the integration first, then test the live connection.", - "testLiveDesc": "Runs a live read-only probe against the base URL with the stored secret.", - "saveIntegration": "Save integration", - "saveChanges": "Save changes", - "title": "Integrations", - "titleDesc": "Connect outside tools so your agents can read and act on them. Secrets are stored encrypted in the main process and never shown again.", - "addIntegration": "add integration", - "empty": "No integrations yet. Connect GitHub or a custom REST API so your agents can use it.", - "addFirst": "add your first integration", - "count": "{{count}} integrations · {{usable}} available to workers", - "needsSecretShort": "Needs secret", - "test": "test", - "edit": "edit" + "secretDesc": "Criptografado no processo principal e nunca mais mostrado. Para trocar, cole uma chave nova — a antiga não pode ser lida de volta.", + "blankKeepsKey": "Deixe em branco para manter a chave salva.", + "availability": "Disponibilidade", + "enabled": "ativado", + "disabled": "desativado", + "availableToAll": "✓ Disponível para todos os workers", + "notAvailableYet": "Ainda indisponível para workers", + "addSecretToEnable": "Adicione um segredo e ative para disponibilizar.", + "readyOnceSaved": "Pronto ao salvar.", + "disabledNoUse": "Desativado — nenhum worker pode usar.", + "v1Note": "v1 dá toda integração ativada a todos os workers. Escopo por worker vem aí.", + "testConnection": "Testar conexão", + "testing": "testando…", + "testAfterSave": "Salve a integração antes, depois teste a conexão ao vivo.", + "testLiveDesc": "Roda uma sonda ao vivo só-leitura contra a URL base com o segredo guardado.", + "saveIntegration": "Salvar integração", + "saveChanges": "Salvar alterações", + "title": "Integrações", + "titleDesc": "Conecte ferramentas externas para seus agentes lerem e agirem nelas. Segredos ficam criptografados no processo principal e nunca mais mostrados.", + "addIntegration": "adicionar integração", + "empty": "Sem integrações ainda. Conecte GitHub ou uma API REST personalizada para seus agentes usarem.", + "addFirst": "adicione sua primeira integração", + "count": "{{count}} integrações · {{usable}} disponíveis para workers", + "needsSecretShort": "Precisa de segredo", + "test": "testar", + "edit": "editar" }, "kanban": { "count": "{{count}} tarefas", @@ -1338,72 +1338,72 @@ "ffHoldHint": "Segure SOZINHO por um instante para começar; solte para transcrever no composer, onde você pode editar antes de enviar. Qualquer Option funciona, e combos Option+tecla chegam ao terminal intactos." }, "idePanel": { - "workspace": "{{name}}'s workspace", - "workspaceInferred": "No agent was named when the IDE opened — showing {{name}}'s workspace (the current selection)", - "assumed": "assumed", - "noAgent": "no agent", - "noWorkspace": "no workspace", - "closeIde": "Close IDE (Esc)", - "expandGit": "Expand the git panel", - "collapseGit": "Collapse the git panel — more room for the file tree", + "workspace": "workspace de {{name}}", + "workspaceInferred": "Nenhum agente nomeado quando a IDE abriu — mostrando o workspace de {{name}} (a seleção atual)", + "assumed": "assumido", + "noAgent": "sem agente", + "noWorkspace": "sem workspace", + "closeIde": "Fechar IDE (Esc)", + "expandGit": "Expandir o painel git", + "collapseGit": "Recolher o painel git — mais espaço para a árvore de arquivos", "rail": { - "changes": "changes", - "history": "history", - "compare": "compare" + "changes": "alterações", + "history": "histórico", + "compare": "comparação" }, - "refresh": "Refresh", - "files": "files", + "refresh": "Atualizar", + "files": "arquivos", "rev": "REV", "img": "IMG", "diff": "DIFF", - "closeTab": "Close tab", - "loadingDiff": "loading diff…", - "binaryDiff": "binary file — no text diff", + "closeTab": "Fechar aba", + "loadingDiff": "carregando diff…", + "binaryDiff": "arquivo binário — sem diff de texto", "workingTree": "working tree", - "refreshDiff": "Refresh diff", - "mdSourceOnly": "Source only", - "mdSplit": "Source + preview", - "mdPreview": "Rendered preview", - "code": "code", - "split": "split", - "preview": "preview", - "viewImage": "view image", - "copyPath": "copy path", - "saveTitle": "Save (Cmd/Ctrl+S)", - "saved": "saved", - "save": "save" + "refreshDiff": "Atualizar diff", + "mdSourceOnly": "Só fonte", + "mdSplit": "Fonte + pré-visualização", + "mdPreview": "Pré-visualização renderizada", + "code": "código", + "split": "dividir", + "preview": "pré-visualizar", + "viewImage": "ver imagem", + "copyPath": "copiar caminho", + "saveTitle": "Salvar (Cmd/Ctrl+S)", + "saved": "salvo", + "save": "salvar" }, "gitPanes": { - "jumpConfirm": "Jump the repo to {{sha}} (\"{{subject}}\")?\n\nThis detaches HEAD. Blocked automatically if the tree is dirty or an agent is mid-run.", - "nowAt": "now at {{sha}} (detached HEAD)", - "loadingHistory": "loading history…", - "loadOlder": "load older…", - "checkoutTitle": "Check out this commit (detached HEAD)", - "jumpHere": "jump here", - "loadingFiles": "loading files…", - "noFileChanges": "no file changes (merge?)", - "comparing": "comparing…", - "switchConfirm": "Switch this repo to '{{head}}'?\n\nBlocked automatically if the tree is dirty or an agent is mid-run.", - "switchedTo": "switched to {{head}}", - "baseTitle": "Base — the branch you're comparing against", - "swapTitle": "Swap base ↔ compare", - "compareTitle": "Compare — the branch whose changes you're viewing", - "aheadBehind": "'{{head}}' is {{ahead}} ahead and {{behind}} behind '{{base}}'", - "modeThreeTitle": "Showing what the compare branch ADDS since the common ancestor (PR-style). Click for the literal two-dot difference.", - "modeTwoTitle": "Showing the literal difference between the two branch states. Click for PR-style (what compare adds).", - "sinceCommonAncestor": "since common ancestor", - "literalDifference": "literal difference", - "switchToTitle": "Check out '{{head}}'", - "switchTo": "switch to {{branch}}", - "noDifferences": "no differences" + "jumpConfirm": "Pular o repo para {{sha}} (\"{{subject}}\")?\n\nIsso destaca o HEAD. Bloqueado automaticamente se a árvore estiver suja ou um agente estiver no meio de uma execução.", + "nowAt": "agora em {{sha}} (HEAD destacado)", + "loadingHistory": "carregando histórico…", + "loadOlder": "carregar antigos…", + "checkoutTitle": "Checkout neste commit (HEAD destacado)", + "jumpHere": "pular para cá", + "loadingFiles": "carregando arquivos…", + "noFileChanges": "sem alterações de arquivo (merge?)", + "comparing": "comparando…", + "switchConfirm": "Trocar este repo para '{{head}}'?\n\nBloqueado automaticamente se a árvore estiver suja ou um agente estiver no meio de uma execução.", + "switchedTo": "trocado para {{head}}", + "baseTitle": "Base — a branch contra a qual você compara", + "swapTitle": "Trocar base ↔ comparação", + "compareTitle": "Comparação — a branch cujas mudanças você vê", + "aheadBehind": "'{{head}}' está {{ahead}} à frente e {{behind}} atrás de '{{base}}'", + "modeThreeTitle": "Mostrando o que a branch de comparação ADICIONA desde o ancestral comum (estilo PR). Clique para a diferença literal de dois pontos.", + "modeTwoTitle": "Mostrando a diferença literal entre os dois estados de branch. Clique para estilo PR (o que a comparação adiciona).", + "sinceCommonAncestor": "desde o ancestral comum", + "literalDifference": "diferença literal", + "switchToTitle": "Checkout em '{{head}}'", + "switchTo": "trocar para {{branch}}", + "noDifferences": "sem diferenças" }, "imagePreview": { - "fitTitle": "Scale the image down to fit the pane", - "oneToOneTitle": "Show every pixel at 1:1 (scroll to pan)", - "fit": "fit", - "viewSourceTitle": "Open the SVG markup in the editor", - "viewSource": "view source", - "loading": "loading image…", - "decodeFailed": "could not decode this image — the file may be corrupt or misnamed" + "fitTitle": "Encolher a imagem para caber no painel", + "oneToOneTitle": "Mostrar cada pixel em 1:1 (role para navegar)", + "fit": "ajustar", + "viewSourceTitle": "Abrir o markup SVG no editor", + "viewSource": "ver fonte", + "loading": "carregando imagem…", + "decodeFailed": "não foi possível decodificar esta imagem — o arquivo pode estar corrupto ou mal nomeado" } } From baca1d742c27f567b3f7101506a4cf1a70724e05 Mon Sep 17 00:00:00 2001 From: T3sh Date: Wed, 14 Oct 2026 01:14:55 -0300 Subject: [PATCH 06/24] feat(i18n): Task 9 pt-BR - hardcoded do renderer para i18n (69 chaves) HivePicker, acoes live dos agentes (mapa agentAction), auto mode, portao de spawn, terminal pty, telas vazias, editor/IDE, toasts, splitter, release drop, hero, booting. ar/zh-CN com ingles marcado pending translator (allowlist). skills/workers/disjuntor em pt-BR. --- src/renderer/src/App.tsx | 16 +- src/renderer/src/components/AgentCard.tsx | 7 +- .../src/components/AgentDetailPanel.tsx | 2 +- src/renderer/src/components/CodeEditor.tsx | 14 +- .../src/components/EditAgentModal.tsx | 4 +- .../src/components/FullscreenTerminal.tsx | 6 +- src/renderer/src/components/HivePicker.tsx | 32 ++-- .../src/components/MichaelBooting.tsx | 4 +- .../src/components/PtyTerminalView.tsx | 12 +- src/renderer/src/components/ReleaseDrop.tsx | 6 +- .../src/components/SettingsHeroCard.tsx | 6 +- src/renderer/src/components/SettingsModal.tsx | 8 +- .../src/components/SidebarSplitter.tsx | 4 +- src/renderer/src/components/UpdateBadge.tsx | 4 +- src/renderer/src/components/UpdateToast.tsx | 4 +- src/renderer/src/i18n/actionText.ts | 45 ++++++ src/renderer/src/i18n/locales/ar.json | 103 ++++++++++++- src/renderer/src/i18n/locales/en.json | 103 ++++++++++++- src/renderer/src/i18n/locales/pt-BR.json | 145 ++++++++++++++---- src/renderer/src/i18n/locales/zh-CN.json | 103 ++++++++++++- src/renderer/src/ide/ImagePreview.tsx | 2 +- src/renderer/src/realtime/CompletionToast.tsx | 6 +- src/renderer/src/scene/office/OfficeFloor.tsx | 29 ++-- test/arabic-ui.test.cjs | 78 +++++++++- 24 files changed, 626 insertions(+), 117 deletions(-) create mode 100644 src/renderer/src/i18n/actionText.ts diff --git a/src/renderer/src/App.tsx b/src/renderer/src/App.tsx index d2dbb7e01d..b2bd92dfd4 100644 --- a/src/renderer/src/App.tsx +++ b/src/renderer/src/App.tsx @@ -1,4 +1,5 @@ import { useEffect, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { useStore, selectedAgent } from '@/store/store'; import { startMockLoop, stopMockLoop } from '@/store/mockEvents'; import type { HarnessConfig } from '@/store/config'; @@ -37,6 +38,7 @@ import brandLogo from '@brand/logo.png?url'; declare const __APP_VERSION__: string; export function App() { + const { t } = useTranslation(); // Point every {{godName}} string at the orchestrator's real, renameable name. useGodNameSync(); // Mirror the document only for a user who has picked an RTL app language. @@ -308,7 +310,7 @@ export function App() { fontSize: 13, color: 'var(--cth-ink-500)' }}> - {config.autoMode ? 'auto mode on' : 'auto mode off'} + {config.autoMode ? t('app.autoModeOn') : t('app.autoModeOff')} {/* v0.3.4: theme + fullscreen live HERE (top right), not buried in the terminal header — and the theme darkens the whole app, terminals @@ -331,7 +333,7 @@ export function App() { void window.cth.updateConfig({ terminalTheme: next }); }} data-tip={appThemeNow === 'dark' ? 'Light theme' : 'Dark theme'} - aria-label="Toggle dark mode" + aria-label={t('app.darkModeAria')} style={{ marginLeft: 'auto', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', @@ -350,7 +352,7 @@ export function App() { className="cth-titlebar-nodrag cth-settings-btn cth-tip" onClick={() => { setSettingsSection(undefined); setSettingsOpen(true); }} data-tip="Settings" - aria-label="Settings" + aria-label={t('app.settingsAria')} style={{ display: 'inline-flex', alignItems: 'center', justifyContent: 'center', width: 28, height: 28, padding: 0, @@ -377,7 +379,7 @@ export function App() { if (target) useStore.getState().setFullscreen(target.id); }} data-tip={fullscreenAgentId ? 'Exit focus mode (Esc)' : 'Focus mode'} - aria-label="Toggle focus mode" + aria-label={t('app.focusModeAria')} style={{ display: 'inline-flex', alignItems: 'center', justifyContent: 'center', width: 28, height: 28, padding: 0, @@ -409,7 +411,7 @@ export function App() { pointerEvents: 'none' }}>
- +

No agents on the floor yet. Spawn one to see real claude output stream in here. @@ -447,7 +449,7 @@ export function App() {

WAKING THE FLOOR
+ }}>{t('app.wakingFloor')}

{bootingGodName} is clocking in.
The terminal will land here once he's seated. @@ -462,7 +464,7 @@ export function App() {

NO AGENT SELECTED
+ }}>{t('app.noAgent')}

Spawn an agent from the strip below.
The terminal and command bar will land here. diff --git a/src/renderer/src/components/AgentCard.tsx b/src/renderer/src/components/AgentCard.tsx index cd5158c4fb..29d12f3f1b 100644 --- a/src/renderer/src/components/AgentCard.tsx +++ b/src/renderer/src/components/AgentCard.tsx @@ -1,5 +1,6 @@ import { useState } from 'react'; import { useTranslation } from 'react-i18next'; +import { localizeAction } from '@/i18n/actionText'; import { PixelPanel } from './PixelPanel'; import { PixelBadge, StatusKind } from './PixelBadge'; import { useHasTerminalDraft } from './terminalPool'; @@ -125,7 +126,9 @@ export function AgentCard({ .filter(Boolean).join(', ') || 'none'; // One context line: what it's DOING while working, WHERE it lives while idle. - const infoLine = (status !== 'idle' && action) ? action : project; + // Fixed status literals go through agentAction.*; live tool text passes raw. + const actionText = (status !== 'idle' && action) ? localizeAction(t, action) : ''; + const infoLine = actionText ? actionText : project; const noteFirstLine = (note ?? '').split('\n').find((l) => l.trim()) ?? ''; return ( @@ -232,7 +235,7 @@ export function AgentCard({ {/* Context line: action while working, repo while idle. */}

{!compactHeader && ' edit'} diff --git a/src/renderer/src/components/CodeEditor.tsx b/src/renderer/src/components/CodeEditor.tsx index 317d1992e0..387931b2f3 100644 --- a/src/renderer/src/components/CodeEditor.tsx +++ b/src/renderer/src/components/CodeEditor.tsx @@ -1,4 +1,5 @@ import { useEffect, useMemo, useState, useCallback } from 'react'; +import { useTranslation } from 'react-i18next'; import CodeMirror from '@uiw/react-codemirror'; import { EditorView } from '@codemirror/view'; import { HighlightStyle, syntaxHighlighting } from '@codemirror/language'; @@ -78,6 +79,7 @@ export interface CodeEditorProps { export function CodeEditor({ root, filePath, onOpenInIde, onCopyPath }: CodeEditorProps) { + const { t } = useTranslation(); const [content, setContent] = useState(''); const [originalContent, setOriginalContent] = useState(''); const [loading, setLoading] = useState(false); @@ -196,23 +198,23 @@ export function CodeEditor({ {onCopyPath && ( + >{t('codeEditor.copyPathBtn')} )} {onOpenInIde && ( ))} @@ -158,7 +162,7 @@ export function HivePicker({ config, onOpenCurrent }: HivePickerProps) { {busy && (
- Opening {folderName(busy)} — the app will reload… + {t('hivePicker.openingBusy', { name: folderName(busy) })}
)} @@ -167,12 +171,12 @@ export function HivePicker({ config, onOpenCurrent }: HivePickerProps) {
- open existing config… + {t('hivePicker.openExisting')} - create new config… + {t('hivePicker.createNew')}
diff --git a/src/renderer/src/components/MichaelBooting.tsx b/src/renderer/src/components/MichaelBooting.tsx index 975347b0fa..51c99a1d9c 100644 --- a/src/renderer/src/components/MichaelBooting.tsx +++ b/src/renderer/src/components/MichaelBooting.tsx @@ -1,4 +1,5 @@ import { PixelPanel } from '@/components/PixelPanel'; +import { useTranslation } from 'react-i18next'; import { useResolvedGodName } from '@/hooks/useResolvedGodName'; /** @@ -12,6 +13,7 @@ import { useResolvedGodName } from '@/hooks/useResolvedGodName'; * rather than assuming the default. */ export function MichaelBooting() { + const { t } = useTranslation(); const godName = useResolvedGodName(); return (
- +
(null); const onStreamDataRef = useRef(onStreamData); onStreamDataRef.current = onStreamData; @@ -377,7 +379,7 @@ export function PtyTerminalView({ ptyId, onStreamData, onUserPrompt, onToggleFul boxShadow: 'inset 0 0 0 1px var(--cth-ink-300)', animation: 'cth-pulse 1200ms steps(2, end) infinite' }} /> - live · pty {ptyId} + {t('ptyView.livePty', { ptyId })}
{/* v0.3.4: the theme + enter-fullscreen buttons moved to the TITLE BAR (top right) — more accessible, and the theme now darkens the whole @@ -385,24 +387,24 @@ export function PtyTerminalView({ ptyId, onStreamData, onUserPrompt, onToggleFul {fullscreen && onToggleFullscreen && (
diff --git a/src/renderer/src/components/SidebarSplitter.tsx b/src/renderer/src/components/SidebarSplitter.tsx index 7562fdfbfe..bddbc95205 100644 --- a/src/renderer/src/components/SidebarSplitter.tsx +++ b/src/renderer/src/components/SidebarSplitter.tsx @@ -1,4 +1,5 @@ import { useEffect, useRef, useState } from 'react'; +import { useTranslation } from 'react-i18next'; export interface SidebarSplitterProps { /** Current sidebar width in px. */ @@ -18,6 +19,7 @@ export interface SidebarSplitterProps { export function SidebarSplitter({ width, onChange, viewportWidth, min = 320, max = 1200 }: SidebarSplitterProps) { + const { t } = useTranslation(); const startRef = useRef<{ clientX: number; width: number } | null>(null); const [active, setActive] = useState(false); @@ -55,7 +57,7 @@ export function SidebarSplitter({ e.preventDefault(); }} onDoubleClick={() => onChange(420)} - title="Drag to resize · double-click to reset" + title={t('sidebar.resizeTitle')} style={{ width: 10, cursor: 'ew-resize', diff --git a/src/renderer/src/components/UpdateBadge.tsx b/src/renderer/src/components/UpdateBadge.tsx index 3c0cdd6ee2..ebe2bd1245 100644 --- a/src/renderer/src/components/UpdateBadge.tsx +++ b/src/renderer/src/components/UpdateBadge.tsx @@ -13,12 +13,14 @@ * is wiring and pixels. */ import { useCallback, useEffect, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { describeUpdate, manualDownloadUrl, manualInstallSteps, pendingVersion, reduceStatus, type UpdateStatus } from '@shared/updateState'; import { PixelButton } from './PixelButton'; declare const __APP_VERSION__: string; export function UpdateBadge() { + const { t } = useTranslation(); const [status, setStatus] = useState(null); const [busy, setBusy] = useState(false); const [hover, setHover] = useState(false); @@ -165,7 +167,7 @@ export function UpdateBadge() { {started && (
(null); const [busy, setBusy] = useState(false); // Read once per window, so persisting the flag below cannot make the link @@ -271,7 +273,7 @@ export function UpdateToast() { href={status.state === 'available-manual' ? status.url : GITHUB_RELEASES_URL} onClick={(e) => { e.preventDefault(); openRelease(); }} style={linkStyle} - >Read more + >{t('updatesSection.readMore')} {showStar && ( = { + 'reconnecting…': 'agentAction.reconnecting', + 'archived': 'agentAction.archived', + 'running the floor': 'agentAction.runningFloor', + 'compacting context': 'agentAction.compacting', + 'resumed': 'agentAction.resumed', + 'thinking': 'agentAction.thinking', + 'idle': 'agentAction.idle', + 'reading inbox': 'agentAction.readingInbox', + 'starting up': 'agentAction.startingUp', + 'revived after sleep': 'agentAction.revived', + 'awaiting': 'agentAction.awaiting', + 'waiting on you': 'agentAction.waitingYou', + 'waiting on god': 'agentAction.waitingGod', + 'heading back to desk': 'agentAction.headingBack', + 'recreating terminal…': 'agentAction.recreating', + 'continuing…': 'agentAction.continuing' +}; + +/** i18n key for a known action literal, or null for live/free-form text. */ +export function actionKey(action: string | undefined | null): string | null { + if (!action) return null; + return ACTION_KEYS[action.trim()] ?? null; +} + +/** Localize a known action literal; pass anything else through untouched. */ +export function localizeAction(t: TFunction, action: string | undefined | null): string { + const key = actionKey(action); + if (key) return t(key); + return (action || '').trim(); +} diff --git a/src/renderer/src/i18n/locales/ar.json b/src/renderer/src/i18n/locales/ar.json index fe74ab7ebc..2533c8a5fa 100644 --- a/src/renderer/src/i18n/locales/ar.json +++ b/src/renderer/src/i18n/locales/ar.json @@ -129,7 +129,8 @@ "terminal": "الطرفية", "git": "git", "messages": "الرسائل", - "traces": "التتبّع" + "traces": "التتبّع", + "resizeTitle": "Drag to resize · double-click to reset" }, "toolWaterfall": { "fresh": "جديد {{tokens}}ر", @@ -154,7 +155,8 @@ "terminalTip": "افتح تطبيق الطرفية في نظامك عند {{cwd}} — صدفة عادية داخل مجلد هذا الوكيل، منفصلة عن طرفيته الخاصة.", "openIde": "افتح بيئة التطوير", "ide": "بيئة التطوير", - "openTerminalAria": "افتح طرفية نظام في مجلد هذا الوكيل" + "openTerminalAria": "افتح طرفية نظام في مجلد هذا الوكيل", + "editAria": "Edit this agent" }, "settingsHero": { "sponsoredBy": "برعاية", @@ -171,7 +173,10 @@ "foundersWallTitle": "على حائط المؤسِّسين؟", "foundersWallBody": "شهر مجاني من Munder Difflin Pro، ثم خصم 50% على الخطة السنوية. لأول 100 شخص على الحائط.", "seeTheWall": "شاهد الحائط", - "joinDiscord": "انضم إلى Discord" + "joinDiscord": "انضم إلى Discord", + "downloadTitle": "Download the installer and replace the app yourself. Auto-update is in Updates below.", + "versionOut": "v{{v}} is out", + "downloadVersion": "download v{{pending}}" }, "officeTheme": { "title": "سِمة المكتب", @@ -281,7 +286,12 @@ "hardStopDesc": "عند التجاوز، أنهِ الوكيل بدل تقييده فقط. الإيقاف = التوجيه أولًا (موصى به).", "killOnTrip": "أنهِه عند التجاوز", "steerFirst": "وجِّه أولًا", - "saved": "حُفِظ" + "saved": "حُفِظ", + "whoCanAdd": "Who can add agents", + "orchSpawnOn": "{{godName}} can hire on his own. Every agent he starts spends tokens you did not approve.", + "orchSpawnOff": "Only you. {{godName}} can still ask, and his request waits in the queue instead of failing.", + "spawnBoth": "me and {{godName}}", + "spawnOnlyMe": "only me" }, "memory": { "semanticMemory": "الذاكرة الدلالية", @@ -897,7 +907,9 @@ "downloadManually": "نزّل يدويًا", "downloadManuallyTitle": "نزّل مثبّت v{{version}} واستبدل التطبيق بنفسك", "manualDownloadingTitle": "يجري تنزيل v{{version}} في متصفّحك.", - "manualDownloadingBody": "عند اكتماله، أغلق هذا التطبيق، وثبّت الإصدار الجديد فوق الحالي، ثم افتحه واختر المشروع نفسه. على {{os}}:" + "manualDownloadingBody": "عند اكتماله، أغلق هذا التطبيق، وثبّت الإصدار الجديد فوق الحالي، ثم افتحه واختر المشروع نفسه. على {{os}}:", + "readMore": "Read more", + "installAria": "Install the update" }, "triggersTab": { "intro": "كل ما يمكنه بدء العمل دون أن تكتب أنت شيئًا.", @@ -1107,7 +1119,9 @@ "ideTip": "افتح بيئة التطوير: تصفّح وحرّر الملفات في مساحة عمل {{name}}، واعرض تغييراته غير المودعة كفروقات.", "openIdeAria": "افتح بيئة التطوير", "openTerminalTip": "افتح تطبيق الطرفية في نظامك عند {{cwd}} — صدفة عادية داخل مجلد هذا الوكيل، منفصلة عن طرفيته الخاصة.", - "openTerminalAria": "افتح طرفية نظام في مجلد هذا الوكيل" + "openTerminalAria": "افتح طرفية نظام في مجلد هذا الوكيل", + "settingsLabel": "Settings", + "privateNote": "PRIVATE NOTE" }, "memoryPanel": { "pill": "🧠 الذاكرة", @@ -1404,6 +1418,81 @@ "viewSourceTitle": "فتح شيفرة SVG في المحرّر", "viewSource": "عرض المصدر", "loading": "جارٍ تحميل الصورة…", - "decodeFailed": "تعذّر فك ترميز هذه الصورة — قد يكون الملف تالفًا أو امتداده خاطئًا" + "decodeFailed": "تعذّر فك ترميز هذه الصورة — قد يكون الملف تالفًا أو امتداده خاطئًا", + "copyAbsoluteTitle": "Copy absolute path", + "copyPathBtn": "copy path" + }, + "hivePicker": { + "title": "SELECT A HARNESS CONFIG", + "body": "A harness config is the folder where the app keeps everything for one workspace — its settings, your agents and their memory, tasks, triggers, and history. Each config is separate and self-contained, so you can run different setups side by side. Open the one you were working in, switch to another, or start a new one.", + "current": "CURRENT", + "open": "open", + "recent": "RECENT", + "switchTitle": "Switch to {{path}} (reloads the app)", + "switching": "switch →", + "opening": "opening…", + "openingBusy": "Opening {{name}} — the app will reload…", + "openExisting": "open existing config…", + "createNew": "create new config…", + "openFailed": "Could not open that folder." + }, + "app": { + "autoModeOn": "auto mode on", + "autoModeOff": "auto mode off", + "darkModeAria": "Toggle dark mode", + "settingsAria": "Settings", + "focusModeAria": "Toggle focus mode", + "emptyFloor": "EMPTY FLOOR", + "wakingFloor": "WAKING THE FLOOR", + "noAgent": "NO AGENT SELECTED" + }, + "agentAction": { + "reconnecting": "reconnecting…", + "archived": "archived", + "runningFloor": "running the floor", + "compacting": "compacting context", + "resumed": "resumed", + "thinking": "thinking", + "idle": "idle", + "readingInbox": "reading inbox", + "startingUp": "starting up", + "revived": "revived after sleep", + "awaiting": "awaiting", + "waitingYou": "waiting on you", + "waitingGod": "waiting on god", + "headingBack": "heading back to desk", + "recreating": "recreating terminal…", + "continuing": "continuing…" + }, + "ptyView": { + "livePty": "live · pty {{ptyId}}", + "zoomOut": "Zoom out (Cmd -)", + "resetZoom": "Reset zoom (Cmd 0)", + "zoomIn": "Zoom in (Cmd +)", + "exitFocus": "Exit focus mode (Esc)" + }, + "codeEditor": { + "copyAbsoluteTitle": "Copy absolute path", + "saveTitle": "Save (Cmd-S)", + "openIdeTitle": "Open in the IDE", + "openIdeAria": "Open in the IDE", + "copyPathBtn": "copy path", + "saveIdle": "save", + "saveSaved": "saved", + "saveError": "err" + }, + "editAgent": { + "title": "EDIT AGENT" + }, + "completionToast": { + "dismiss": "Dismiss", + "completed": "{{godName}} · completed" + }, + "booting": { + "title": "CLOCKING IN" + }, + "releaseDrop": { + "closeAria": "Close release notes", + "closeTitle": "Close (Esc)" } } diff --git a/src/renderer/src/i18n/locales/en.json b/src/renderer/src/i18n/locales/en.json index 68aac27438..a5d5cf7897 100644 --- a/src/renderer/src/i18n/locales/en.json +++ b/src/renderer/src/i18n/locales/en.json @@ -129,7 +129,8 @@ "terminal": "terminal", "git": "git", "messages": "messages", - "traces": "traces" + "traces": "traces", + "resizeTitle": "Drag to resize · double-click to reset" }, "toolWaterfall": { "fresh": "fresh {{tokens}}t", @@ -154,7 +155,8 @@ "terminalTip": "Open your system terminal app in {{cwd}} — a normal shell in this agent's folder, separate from the agent's own terminal.", "openIde": "Open the IDE", "ide": "IDE", - "openTerminalAria": "Open a system terminal in this agent's folder" + "openTerminalAria": "Open a system terminal in this agent's folder", + "editAria": "Edit this agent" }, "settingsHero": { "sponsoredBy": "Sponsored by", @@ -171,7 +173,10 @@ "foundersWallTitle": "On the Founders' Wall?", "foundersWallBody": "A month of Munder Difflin Pro free, then 50% off the annual plan. For the first 100 people on the wall.", "seeTheWall": "see the wall", - "joinDiscord": "join Discord" + "joinDiscord": "join Discord", + "downloadTitle": "Download the installer and replace the app yourself. Auto-update is in Updates below.", + "versionOut": "v{{v}} is out", + "downloadVersion": "download v{{pending}}" }, "officeTheme": { "title": "Office Theme", @@ -281,7 +286,12 @@ "hardStopDesc": "When tripped, KILL the agent instead of just constraining it. Off = steer-first (recommended).", "killOnTrip": "kill on trip", "steerFirst": "steer first", - "saved": "saved" + "saved": "saved", + "whoCanAdd": "Who can add agents", + "orchSpawnOn": "{{godName}} can hire on his own. Every agent he starts spends tokens you did not approve.", + "orchSpawnOff": "Only you. {{godName}} can still ask, and his request waits in the queue instead of failing.", + "spawnBoth": "me and {{godName}}", + "spawnOnlyMe": "only me" }, "memory": { "semanticMemory": "Semantic memory", @@ -897,7 +907,9 @@ "downloadManually": "download manually", "downloadManuallyTitle": "Download the v{{version}} installer and replace the app yourself", "manualDownloadingTitle": "v{{version}} is downloading in your browser.", - "manualDownloadingBody": "When it lands, quit this app, install the new version over the current one, open it and pick the same project. On {{os}}:" + "manualDownloadingBody": "When it lands, quit this app, install the new version over the current one, open it and pick the same project. On {{os}}:", + "readMore": "Read more", + "installAria": "Install the update" }, "triggersTab": { "intro": "Everything that can start work without you typing.", @@ -1107,7 +1119,9 @@ "ideTip": "Open the IDE: browse and edit files in {{name}}'s workspace, and see their uncommitted changes as a diff.", "openIdeAria": "Open the IDE", "openTerminalTip": "Open your system terminal app in {{cwd}} — a normal shell in this agent's folder, separate from the agent's own terminal.", - "openTerminalAria": "Open a system terminal in this agent's folder" + "openTerminalAria": "Open a system terminal in this agent's folder", + "settingsLabel": "Settings", + "privateNote": "PRIVATE NOTE" }, "memoryPanel": { "pill": "🧠 memory", @@ -1404,6 +1418,81 @@ "viewSourceTitle": "Open the SVG markup in the editor", "viewSource": "view source", "loading": "loading image…", - "decodeFailed": "could not decode this image — the file may be corrupt or misnamed" + "decodeFailed": "could not decode this image — the file may be corrupt or misnamed", + "copyAbsoluteTitle": "Copy absolute path", + "copyPathBtn": "copy path" + }, + "hivePicker": { + "title": "SELECT A HARNESS CONFIG", + "body": "A harness config is the folder where the app keeps everything for one workspace — its settings, your agents and their memory, tasks, triggers, and history. Each config is separate and self-contained, so you can run different setups side by side. Open the one you were working in, switch to another, or start a new one.", + "current": "CURRENT", + "open": "open", + "recent": "RECENT", + "switchTitle": "Switch to {{path}} (reloads the app)", + "switching": "switch →", + "opening": "opening…", + "openingBusy": "Opening {{name}} — the app will reload…", + "openExisting": "open existing config…", + "createNew": "create new config…", + "openFailed": "Could not open that folder." + }, + "app": { + "autoModeOn": "auto mode on", + "autoModeOff": "auto mode off", + "darkModeAria": "Toggle dark mode", + "settingsAria": "Settings", + "focusModeAria": "Toggle focus mode", + "emptyFloor": "EMPTY FLOOR", + "wakingFloor": "WAKING THE FLOOR", + "noAgent": "NO AGENT SELECTED" + }, + "agentAction": { + "reconnecting": "reconnecting…", + "archived": "archived", + "runningFloor": "running the floor", + "compacting": "compacting context", + "resumed": "resumed", + "thinking": "thinking", + "idle": "idle", + "readingInbox": "reading inbox", + "startingUp": "starting up", + "revived": "revived after sleep", + "awaiting": "awaiting", + "waitingYou": "waiting on you", + "waitingGod": "waiting on god", + "headingBack": "heading back to desk", + "recreating": "recreating terminal…", + "continuing": "continuing…" + }, + "ptyView": { + "livePty": "live · pty {{ptyId}}", + "zoomOut": "Zoom out (Cmd -)", + "resetZoom": "Reset zoom (Cmd 0)", + "zoomIn": "Zoom in (Cmd +)", + "exitFocus": "Exit focus mode (Esc)" + }, + "codeEditor": { + "copyAbsoluteTitle": "Copy absolute path", + "saveTitle": "Save (Cmd-S)", + "openIdeTitle": "Open in the IDE", + "openIdeAria": "Open in the IDE", + "copyPathBtn": "copy path", + "saveIdle": "save", + "saveSaved": "saved", + "saveError": "err" + }, + "editAgent": { + "title": "EDIT AGENT" + }, + "completionToast": { + "dismiss": "Dismiss", + "completed": "{{godName}} · completed" + }, + "booting": { + "title": "CLOCKING IN" + }, + "releaseDrop": { + "closeAria": "Close release notes", + "closeTitle": "Close (Esc)" } } diff --git a/src/renderer/src/i18n/locales/pt-BR.json b/src/renderer/src/i18n/locales/pt-BR.json index ed732b3205..860960832b 100644 --- a/src/renderer/src/i18n/locales/pt-BR.json +++ b/src/renderer/src/i18n/locales/pt-BR.json @@ -129,7 +129,8 @@ "terminal": "terminal", "git": "git", "messages": "mensagens", - "traces": "traces" + "traces": "traces", + "resizeTitle": "Arrastar para redimensionar · clique duplo para redefinir" }, "toolWaterfall": { "fresh": "{{tokens}}t novos", @@ -154,7 +155,8 @@ "terminalTip": "Abra o terminal do sistema em {{cwd}} — um shell normal na pasta deste agente, separado do próprio terminal do agente.", "openIde": "Abrir a IDE", "ide": "IDE", - "openTerminalAria": "Abrir um terminal do sistema na pasta deste agente" + "openTerminalAria": "Abrir um terminal do sistema na pasta deste agente", + "editAria": "Editar este agente" }, "settingsHero": { "sponsoredBy": "Patrocinado por", @@ -171,7 +173,10 @@ "foundersWallTitle": "No Mural dos Fundadores?", "foundersWallBody": "Um mês de Munder Difflin Pro grátis, depois 50% de desconto no plano anual. Para as primeiras 100 pessoas no mural.", "seeTheWall": "ver o mural", - "joinDiscord": "entrar no Discord" + "joinDiscord": "entrar no Discord", + "downloadTitle": "Baixe o instalador e substitua o app você mesmo. A atualização automática está em Atualizações abaixo.", + "versionOut": "v{{v}} saiu", + "downloadVersion": "baixar v{{pending}}" }, "officeTheme": { "title": "Tema do Escritório", @@ -266,8 +271,8 @@ "autoDesc": "Vale para agentes recém-criados (o comando de cada agente ainda pode sobrescrever).", "autonomous": "autônomo", "askFirst": "perguntar primeiro", - "breaker": "Circuit breaker", - "breakerDesc": "Proteção contra agentes descontrolados e gastos. O breaker conduz, depois restringe e depois para um agente que cruzar estes limites.", + "breaker": "Disjuntor", + "breakerDesc": "Proteção contra agentes descontrolados e gastos. O disjuntor conduz, depois restringe e depois para um agente que cruzar estes limites.", "floorBudget": "orçamento de tokens do escritório", "budgetPlaceholder": "ex. 1000000", "budgetEquals": "= {{value}} tokens", @@ -281,7 +286,12 @@ "hardStopDesc": "Quando disparado, MATA o agente em vez de só restringi-lo. Desligado = conduzir primeiro (recomendado).", "killOnTrip": "matar ao disparar", "steerFirst": "conduzir primeiro", - "saved": "salvo" + "saved": "salvo", + "whoCanAdd": "Quem pode adicionar agentes", + "orchSpawnOn": "{{godName}} pode contratar por conta própria. Todo agente iniciado gasta tokens que você não aprovou.", + "orchSpawnOff": "Só você. {{godName}} ainda pode pedir, e o pedido aguarda na fila em vez de falhar.", + "spawnBoth": "eu e {{godName}}", + "spawnOnlyMe": "só eu" }, "memory": { "semanticMemory": "Memória semântica", @@ -396,8 +406,8 @@ "memory": "memória", "graph": "grafo", "activity": "atividade", - "skills": "skills", - "workers": "workers" + "skills": "habilidades", + "workers": "trabalhadores" }, "terminalFullscreen": "O terminal está aberto em tela cheia. Pressione Esc para trazê-lo de volta.", "noTerminal": "{{name}} não tem terminal ao vivo.", @@ -480,7 +490,7 @@ "byAuthor": " · por {{author}}", "reviewFields": "revise cada campo — especialmente o comando — antes de criar.", "hireFlags": "⚠️ flags que esta contratação anexa ao comando:", - "hireSkills": "skills que esta contratação ativa:", + "hireSkills": "habilidades que esta contratação ativa:", "mcpSafe": "Servidores MCP (seguros, pré-ativados):", "mcpConsent": "⚠️ MCP (precisa do seu consentimento — NÃO auto-ativado):", "mcpEnableInSettings": "— ative em Configurações → MCP após revisar", @@ -659,8 +669,8 @@ "cliAgentPlain": "Um agente CLI é um assistente de código de IA que roda no seu computador — os populares são Claude Code (Anthropic), Codex (OpenAI) e Antigravity (Google Gemini). Seu clone é aquele sempre ligado que comanda seu escritório inteiro. Recomendamos Claude Code com Opus 4.8 (1M). Você pode adicionar ou trocar os outros depois.", "cliAgent": "Cada opção é um engine CLI (Claude Code, Codex, Antigravity/Gemini ou um proxy local como Qwen). Engines marcados INSTALLED já estão nesta máquina; INSTALLS ON FIRST RUN significa que o app configura quando {{godName}} inicia pela primeira vez. Seu clone ({{godName}}) é o engine que orquestra a colmeia inteira. Recomendado: Claude Code · Opus 4.8 · 1M. Outros provedores podem ser ligados por agente depois.", "recommended": "RECOMENDADO", - "workersOnly": "SÓ WORKERS", - "workersOnlyHint": "Ainda não drena o correio da colmeia, então não pode rodar seu clone — segue disponível ao contratar workers.", + "workersOnly": "SÓ TRABALHADORES", + "workersOnlyHint": "Ainda não drena o correio da colmeia, então não pode rodar seu clone — segue disponível ao contratar trabalhadores.", "model": "Modelo", "modelNote": "Isso só define o engine do {{godName}}. Você pode rodar outros provedores por agente depois." }, @@ -782,7 +792,7 @@ "waiting": "aguardando", "needsYou": "precisa de você", "compacting": "compactando contexto", - "looping": "em loop — breaker armado", + "looping": "em loop — disjuntor armado", "runningFloor": "comandando o escritório", "idle": "ocioso" } @@ -897,7 +907,9 @@ "downloadManually": "baixar manualmente", "downloadManuallyTitle": "Baixe o instalador da v{{version}} e substitua o app você mesmo", "manualDownloadingTitle": "v{{version}} baixando no seu navegador.", - "manualDownloadingBody": "Quando chegar, saia deste app, instale a versão nova por cima da atual, abra e escolha o mesmo projeto. Em {{os}}:" + "manualDownloadingBody": "Quando chegar, saia deste app, instale a versão nova por cima da atual, abra e escolha o mesmo projeto. Em {{os}}:", + "readMore": "Leia mais", + "installAria": "Instalar a atualização" }, "triggersTab": { "intro": "Tudo que pode iniciar trabalho sem você digitar.", @@ -1107,7 +1119,9 @@ "ideTip": "Abra a IDE: navegue e edite arquivos no workspace de {{name}} e veja alterações não commitadas como diff.", "openIdeAria": "Abrir a IDE", "openTerminalTip": "Abra o terminal do sistema em {{cwd}} — um shell normal na pasta deste agente, separado do próprio terminal do agente.", - "openTerminalAria": "Abrir um terminal do sistema na pasta deste agente" + "openTerminalAria": "Abrir um terminal do sistema na pasta deste agente", + "settingsLabel": "Configurações", + "privateNote": "NOTA PRIVADA" }, "memoryPanel": { "pill": "🧠 memória", @@ -1143,15 +1157,15 @@ "skillsTab": { "installed": "Instaladas", "browse": "explorar", - "searchInstalled": "Pesquisar skills instaladas…", - "searchCatalog": "Pesquisar o catálogo de skills…", + "searchInstalled": "Pesquisar habilidades instaladas…", + "searchCatalog": "Pesquisar o catálogo de habilidades…", "categoryTitle": "Categorias como publicadas pelo catálogo", "allCategories": "todas as categorias", "allPublishers": "todos os publicadores", "loading": "carregando…", "refresh": "atualizar", "scanning": "Varrendo…", - "noSkillsInstalled": "Sem skills instaladas ainda. Abra Explorar para ver o disponível.", + "noSkillsInstalled": "Sem habilidades instaladas ainda. Abra Explorar para ver o disponível.", "nothingMatches": "Nada corresponde a essa pesquisa.", "openFolder": "abrir pasta", "shipsWithApp": "vem com o app", @@ -1174,13 +1188,13 @@ "workersTab": { "stopping": "parando", "working": "trabalhando", - "liveWorkers": "Workers ao vivo", - "liveIntro": "Workers isolados que {{godName}} cria para tratar mensagens do Slack — rodam até concluir, respondem na thread e desmontam.", - "noneRunning": "Sem workers rodando agora.", + "liveWorkers": "Trabalhadores ao vivo", + "liveIntro": "Trabalhadores isolados que {{godName}} cria para tratar mensagens do Slack — rodam até concluir, respondem na thread e desmontam.", + "noneRunning": "Sem trabalhadores rodando agora.", "repliesToSlack": "responde numa thread do Slack", "stoppingEllipsis": "parando…", "stop": "parar", - "workerIdTitle": "id do worker / PTY", + "workerIdTitle": "id do trabalhador / PTY", "baseBranchTitle": "branch base de onde o worktree foi cortado", "base": "base: {{branch}}", "upSinceTitle": "tempo desde a criação", @@ -1192,7 +1206,7 @@ "tokens": "tokens {{value}}", "uncapped": "sem teto", "preserved": "Worktrees preservados ({{count}})", - "preservedIntro": "Workers terminados cujo worktree tinha trabalho não integrado — mantidos (nunca auto-descartados) e auto-recuperados quando o trabalho cai na branch base.", + "preservedIntro": "Trabalhadores terminados cujo worktree tinha trabalho não integrado — mantidos (nunca auto-descartados) e auto-recuperados quando o trabalho cai na branch base.", "keptAgo": "mantido há {{age}}" }, "memoryGraph": { @@ -1254,12 +1268,12 @@ "availability": "Disponibilidade", "enabled": "ativado", "disabled": "desativado", - "availableToAll": "✓ Disponível para todos os workers", - "notAvailableYet": "Ainda indisponível para workers", + "availableToAll": "✓ Disponível para todos os trabalhadores", + "notAvailableYet": "Ainda indisponível para trabalhadores", "addSecretToEnable": "Adicione um segredo e ative para disponibilizar.", "readyOnceSaved": "Pronto ao salvar.", - "disabledNoUse": "Desativado — nenhum worker pode usar.", - "v1Note": "v1 dá toda integração ativada a todos os workers. Escopo por worker vem aí.", + "disabledNoUse": "Desativado — nenhum trabalhador pode usar.", + "v1Note": "v1 dá toda integração ativada a todos os trabalhadores. Escopo por trabalhador vem aí.", "testConnection": "Testar conexão", "testing": "testando…", "testAfterSave": "Salve a integração antes, depois teste a conexão ao vivo.", @@ -1271,7 +1285,7 @@ "addIntegration": "adicionar integração", "empty": "Sem integrações ainda. Conecte GitHub ou uma API REST personalizada para seus agentes usarem.", "addFirst": "adicione sua primeira integração", - "count": "{{count}} integrações · {{usable}} disponíveis para workers", + "count": "{{count}} integrações · {{usable}} disponíveis para trabalhadores", "needsSecretShort": "Precisa de segredo", "test": "testar", "edit": "editar" @@ -1404,6 +1418,81 @@ "viewSourceTitle": "Abrir o markup SVG no editor", "viewSource": "ver fonte", "loading": "carregando imagem…", - "decodeFailed": "não foi possível decodificar esta imagem — o arquivo pode estar corrupto ou mal nomeado" + "decodeFailed": "não foi possível decodificar esta imagem — o arquivo pode estar corrupto ou mal nomeado", + "copyAbsoluteTitle": "Copiar caminho absoluto", + "copyPathBtn": "copiar caminho" + }, + "hivePicker": { + "title": "SELECIONE UMA CONFIG DO HARNESS", + "body": "Uma config do harness é a pasta onde o app guarda tudo de um workspace — configurações, seus agentes e a memória deles, tarefas, gatilhos e histórico. Cada config é separada e autocontida, então dá para rodar setups diferentes lado a lado. Abra aquela em que estava trabalhando, troque para outra ou comece uma nova.", + "current": "ATUAL", + "open": "abrir", + "recent": "RECENTES", + "switchTitle": "Trocar para {{path}} (recarrega o app)", + "switching": "trocar →", + "opening": "abrindo…", + "openingBusy": "Abrindo {{name}} — o app vai recarregar…", + "openExisting": "abrir config existente…", + "createNew": "criar nova config…", + "openFailed": "Não foi possível abrir essa pasta." + }, + "app": { + "autoModeOn": "modo auto ligado", + "autoModeOff": "modo auto desligado", + "darkModeAria": "Alternar modo escuro", + "settingsAria": "Configurações", + "focusModeAria": "Alternar modo foco", + "emptyFloor": "ESCRITÓRIO VAZIO", + "wakingFloor": "ACORDANDO O ESCRITÓRIO", + "noAgent": "NENHUM AGENTE SELECIONADO" + }, + "agentAction": { + "reconnecting": "reconectando…", + "archived": "arquivado", + "runningFloor": "comandando o escritório", + "compacting": "compactando contexto", + "resumed": "retomado", + "thinking": "pensando", + "idle": "ocioso", + "readingInbox": "lendo caixa de entrada", + "startingUp": "iniciando", + "revived": "reanimado após repouso", + "awaiting": "aguardando", + "waitingYou": "aguardando você", + "waitingGod": "aguardando o orquestrador", + "headingBack": "voltando à mesa", + "recreating": "recriando terminal…", + "continuing": "continuando…" + }, + "ptyView": { + "livePty": "ao vivo · pty {{ptyId}}", + "zoomOut": "Reduzir zoom (Cmd -)", + "resetZoom": "Zerar zoom (Cmd 0)", + "zoomIn": "Aumentar zoom (Cmd +)", + "exitFocus": "Sair do modo foco (Esc)" + }, + "codeEditor": { + "copyAbsoluteTitle": "Copiar caminho absoluto", + "saveTitle": "Salvar (Cmd-S)", + "openIdeTitle": "Abrir na IDE", + "openIdeAria": "Abrir na IDE", + "copyPathBtn": "copiar caminho", + "saveIdle": "salvar", + "saveSaved": "salvo", + "saveError": "erro" + }, + "editAgent": { + "title": "EDITAR AGENTE" + }, + "completionToast": { + "dismiss": "Dispensar", + "completed": "{{godName}} · concluído" + }, + "booting": { + "title": "BATENDO O PONTO" + }, + "releaseDrop": { + "closeAria": "Fechar notas da versão", + "closeTitle": "Fechar (Esc)" } } diff --git a/src/renderer/src/i18n/locales/zh-CN.json b/src/renderer/src/i18n/locales/zh-CN.json index 0db2c7f25d..4bfba9ba2e 100644 --- a/src/renderer/src/i18n/locales/zh-CN.json +++ b/src/renderer/src/i18n/locales/zh-CN.json @@ -129,7 +129,8 @@ "terminal": "终端", "git": "Git", "messages": "消息", - "traces": "追踪" + "traces": "追踪", + "resizeTitle": "Drag to resize · double-click to reset" }, "toolWaterfall": { "fresh": "新计 {{tokens}}t", @@ -154,7 +155,8 @@ "terminalTip": "在 {{cwd}} 中打开你的系统终端应用 —— 位于该智能体文件夹中的普通 shell,与该智能体自己的终端相互独立。", "openIde": "打开 IDE", "ide": "IDE", - "openTerminalAria": "在该智能体的文件夹中打开系统终端" + "openTerminalAria": "在该智能体的文件夹中打开系统终端", + "editAria": "Edit this agent" }, "settingsHero": { "sponsoredBy": "赞助方", @@ -171,7 +173,10 @@ "foundersWallTitle": "在 Founders' Wall 上吗?", "foundersWallBody": "免费获得一个月的 Munder Difflin Pro,此后年度套餐享 5 折。仅限前 100 位上榜用户。", "seeTheWall": "查看榜单", - "joinDiscord": "加入 Discord" + "joinDiscord": "加入 Discord", + "downloadTitle": "Download the installer and replace the app yourself. Auto-update is in Updates below.", + "versionOut": "v{{v}} is out", + "downloadVersion": "download v{{pending}}" }, "officeTheme": { "title": "办公室主题", @@ -281,7 +286,12 @@ "hardStopDesc": "触发时直接终止智能体,而不仅是约束。关闭 = 先引导(推荐)。", "killOnTrip": "触发即终止", "steerFirst": "先引导", - "saved": "已保存" + "saved": "已保存", + "whoCanAdd": "Who can add agents", + "orchSpawnOn": "{{godName}} can hire on his own. Every agent he starts spends tokens you did not approve.", + "orchSpawnOff": "Only you. {{godName}} can still ask, and his request waits in the queue instead of failing.", + "spawnBoth": "me and {{godName}}", + "spawnOnlyMe": "only me" }, "memory": { "semanticMemory": "语义记忆", @@ -897,7 +907,9 @@ "downloadManually": "手动下载", "downloadManuallyTitle": "下载 v{{version}} 安装程序并自行替换应用", "manualDownloadingTitle": "v{{version}} 正在你的浏览器中下载。", - "manualDownloadingBody": "下载完成后,退出本应用,将新版本覆盖安装到当前版本之上,重新打开并选择同一个项目。在 {{os}} 上:" + "manualDownloadingBody": "下载完成后,退出本应用,将新版本覆盖安装到当前版本之上,重新打开并选择同一个项目。在 {{os}} 上:", + "readMore": "Read more", + "installAria": "Install the update" }, "triggersTab": { "intro": "所有无需你输入就能启动工作的方式。", @@ -1107,7 +1119,9 @@ "ideTip": "打开 IDE:浏览并编辑 {{name}} 工作区中的文件,并将他们未提交的更改作为差异查看。", "openIdeAria": "打开 IDE", "openTerminalTip": "在 {{cwd}} 中打开你的系统终端应用 —— 位于该智能体文件夹中的普通 shell,与该智能体自己的终端相互独立。", - "openTerminalAria": "在该智能体的文件夹中打开系统终端" + "openTerminalAria": "在该智能体的文件夹中打开系统终端", + "settingsLabel": "Settings", + "privateNote": "PRIVATE NOTE" }, "memoryPanel": { "pill": "🧠 记忆", @@ -1404,6 +1418,81 @@ "viewSourceTitle": "在编辑器中打开 SVG 标记", "viewSource": "查看源码", "loading": "正在加载图片…", - "decodeFailed": "无法解码此图片——文件可能已损坏或扩展名有误" + "decodeFailed": "无法解码此图片——文件可能已损坏或扩展名有误", + "copyAbsoluteTitle": "Copy absolute path", + "copyPathBtn": "copy path" + }, + "hivePicker": { + "title": "SELECT A HARNESS CONFIG", + "body": "A harness config is the folder where the app keeps everything for one workspace — its settings, your agents and their memory, tasks, triggers, and history. Each config is separate and self-contained, so you can run different setups side by side. Open the one you were working in, switch to another, or start a new one.", + "current": "CURRENT", + "open": "open", + "recent": "RECENT", + "switchTitle": "Switch to {{path}} (reloads the app)", + "switching": "switch →", + "opening": "opening…", + "openingBusy": "Opening {{name}} — the app will reload…", + "openExisting": "open existing config…", + "createNew": "create new config…", + "openFailed": "Could not open that folder." + }, + "app": { + "autoModeOn": "auto mode on", + "autoModeOff": "auto mode off", + "darkModeAria": "Toggle dark mode", + "settingsAria": "Settings", + "focusModeAria": "Toggle focus mode", + "emptyFloor": "EMPTY FLOOR", + "wakingFloor": "WAKING THE FLOOR", + "noAgent": "NO AGENT SELECTED" + }, + "agentAction": { + "reconnecting": "reconnecting…", + "archived": "archived", + "runningFloor": "running the floor", + "compacting": "compacting context", + "resumed": "resumed", + "thinking": "thinking", + "idle": "idle", + "readingInbox": "reading inbox", + "startingUp": "starting up", + "revived": "revived after sleep", + "awaiting": "awaiting", + "waitingYou": "waiting on you", + "waitingGod": "waiting on god", + "headingBack": "heading back to desk", + "recreating": "recreating terminal…", + "continuing": "continuing…" + }, + "ptyView": { + "livePty": "live · pty {{ptyId}}", + "zoomOut": "Zoom out (Cmd -)", + "resetZoom": "Reset zoom (Cmd 0)", + "zoomIn": "Zoom in (Cmd +)", + "exitFocus": "Exit focus mode (Esc)" + }, + "codeEditor": { + "copyAbsoluteTitle": "Copy absolute path", + "saveTitle": "Save (Cmd-S)", + "openIdeTitle": "Open in the IDE", + "openIdeAria": "Open in the IDE", + "copyPathBtn": "copy path", + "saveIdle": "save", + "saveSaved": "saved", + "saveError": "err" + }, + "editAgent": { + "title": "EDIT AGENT" + }, + "completionToast": { + "dismiss": "Dismiss", + "completed": "{{godName}} · completed" + }, + "booting": { + "title": "CLOCKING IN" + }, + "releaseDrop": { + "closeAria": "Close release notes", + "closeTitle": "Close (Esc)" } } diff --git a/src/renderer/src/ide/ImagePreview.tsx b/src/renderer/src/ide/ImagePreview.tsx index 079643d25e..69b4ca563f 100644 --- a/src/renderer/src/ide/ImagePreview.tsx +++ b/src/renderer/src/ide/ImagePreview.tsx @@ -80,7 +80,7 @@ export function ImagePreview({ root, rel, onCopyPath, onViewSource }: ImagePrevi {t('imagePreview.viewSource')} )} - +
s.agents.find((a) => a.isGod)?.name) ?? 'the orchestrator'; const [toasts, setToasts] = useState([]); // Stable across renders so the subscription's closures always see live timers. @@ -124,11 +126,11 @@ export function CompletionToast(): JSX.Element | null { textTransform: 'uppercase' }} > - {godName} · completed + {tr('completionToast.completed', { godName })}
)} {/* tooltip */} diff --git a/src/renderer/src/i18n/locales/ar.json b/src/renderer/src/i18n/locales/ar.json index 2533c8a5fa..7c9977393e 100644 --- a/src/renderer/src/i18n/locales/ar.json +++ b/src/renderer/src/i18n/locales/ar.json @@ -1224,7 +1224,8 @@ "legendPropose": "اقتراح", "legendAgreeDone": "موافقة/إنجاز", "legendRefuse": "رفض", - "legendInformTopic": "إخبار/موضوع" + "legendInformTopic": "إخبار/موضوع", + "emptyHint": "No messages logged yet — the hive is quiet. Agents shown as roster." }, "integrations": { "errLabel": "أعطِه تسمية.", diff --git a/src/renderer/src/i18n/locales/en.json b/src/renderer/src/i18n/locales/en.json index a5d5cf7897..eb3923f7aa 100644 --- a/src/renderer/src/i18n/locales/en.json +++ b/src/renderer/src/i18n/locales/en.json @@ -1224,7 +1224,8 @@ "legendPropose": "propose", "legendAgreeDone": "agree/done", "legendRefuse": "refuse", - "legendInformTopic": "inform/topic" + "legendInformTopic": "inform/topic", + "emptyHint": "No messages logged yet — the hive is quiet. Agents shown as roster." }, "integrations": { "errLabel": "Give it a label.", diff --git a/src/renderer/src/i18n/locales/pt-BR.json b/src/renderer/src/i18n/locales/pt-BR.json index 860960832b..e2ca42b768 100644 --- a/src/renderer/src/i18n/locales/pt-BR.json +++ b/src/renderer/src/i18n/locales/pt-BR.json @@ -1224,7 +1224,8 @@ "legendPropose": "proposta", "legendAgreeDone": "concordado/concluído", "legendRefuse": "recusa", - "legendInformTopic": "informe/tópico" + "legendInformTopic": "informe/tópico", + "emptyHint": "Sem mensagens registradas ainda — a colmeia está quieta. Agentes mostrados como elenco." }, "integrations": { "errLabel": "Dê um rótulo.", diff --git a/src/renderer/src/i18n/locales/zh-CN.json b/src/renderer/src/i18n/locales/zh-CN.json index 4bfba9ba2e..50afebad03 100644 --- a/src/renderer/src/i18n/locales/zh-CN.json +++ b/src/renderer/src/i18n/locales/zh-CN.json @@ -1224,7 +1224,8 @@ "legendPropose": "提议", "legendAgreeDone": "同意/完成", "legendRefuse": "拒绝", - "legendInformTopic": "告知/主题" + "legendInformTopic": "告知/主题", + "emptyHint": "No messages logged yet — the hive is quiet. Agents shown as roster." }, "integrations": { "errLabel": "请给它一个名称。", diff --git a/test/arabic-ui.test.cjs b/test/arabic-ui.test.cjs index 9779970d0d..47498a2aa3 100644 --- a/test/arabic-ui.test.cjs +++ b/test/arabic-ui.test.cjs @@ -287,7 +287,8 @@ test('no Arabic string is left as its English source', () => { 'settingsHero.downloadVersion', 'sidebar.resizeTitle', 'updatesSection.readMore', - 'updatesSection.installAria' + 'updatesSection.installAria', + 'memoryGraph.emptyHint' ]); const e = pathsOf(en), a = pathsOf(ar); const untranslated = []; From 4c4ffe65efb9d4fbdd620bc9c8c12a78174a2fc6 Mon Sep 17 00:00:00 2001 From: T3sh Date: Wed, 14 Oct 2026 01:21:41 -0300 Subject: [PATCH 08/24] feat(i18n): Task 10 pt-BR - menu nativo via IPC (13 chaves) nativeMenu.* nos 4 locales; preload setMenuLabels; main valida e reconstroi (registerAccelerator:false e multiWindow preservados); hook useMenuLabelsSync no boot + troca de idioma. Submenus View/Window por role seguem em ingles (documentado). Teste native-menu. --- src/main/index.ts | 65 ++++++++++++++++----- src/preload/index.ts | 6 ++ src/renderer/src/App.tsx | 3 + src/renderer/src/i18n/locales/ar.json | 15 +++++ src/renderer/src/i18n/locales/en.json | 15 +++++ src/renderer/src/i18n/locales/pt-BR.json | 15 +++++ src/renderer/src/i18n/locales/zh-CN.json | 15 +++++ src/renderer/src/i18n/useMenuLabelsSync.ts | 42 ++++++++++++++ test/arabic-ui.test.cjs | 15 ++++- test/native-menu.test.cjs | 66 ++++++++++++++++++++++ 10 files changed, 242 insertions(+), 15 deletions(-) create mode 100644 src/renderer/src/i18n/useMenuLabelsSync.ts create mode 100644 test/native-menu.test.cjs diff --git a/src/main/index.ts b/src/main/index.ts index 0cc017c8d6..c409486d2e 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -2483,21 +2483,58 @@ function openFloor(): BrowserWindow | null { /** Build + install the application menu. Only called when multiWindow is on, so * flag-off keeps Electron's default menu (zero behavior change). Uses standard * role-based items so copy/paste/quit/etc. work per-platform, and adds the - * "New Floor" item (Cmd/Ctrl+Shift+N). */ + * "New Floor" item (Cmd/Ctrl+Shift+N). + * + * Labels come from the renderer over menu:setLabels (nativeMenu.* locale + * section) — main owns no i18n. English until the first push. Role-generated + * submenus (View/Window) stay in Electron's default language: translating + * those would mean spelling out every Reload/DevTools item by hand. */ +const MENU_LABEL_KEYS = [ + 'file', 'edit', 'view', 'window', 'newFloor', + 'undo', 'redo', 'cut', 'copy', 'paste', 'selectAll', 'quit', 'close' +] as const; + +/** Last labels pushed by the renderer; English until the first push. */ +let menuLabels: Record = { + file: 'File', edit: 'Edit', view: 'View', window: 'Window', + newFloor: 'New Floor', undo: 'Undo', redo: 'Redo', cut: 'Cut', + copy: 'Copy', paste: 'Paste', selectAll: 'Select All', + quit: 'Quit', close: 'Close' +}; + +function isMenuLabels(payload: unknown): payload is Record { + if (!payload || typeof payload !== 'object') return false; + const p = payload as Record; + return MENU_LABEL_KEYS.every( + (k) => typeof p[k] === 'string' && (p[k] as string).length > 0 && (p[k] as string).length <= 60 + ); +} + +ipcMain.handle('menu:setLabels', (_evt, payload: unknown) => { + if (!isMenuLabels(payload)) return { ok: false, error: 'invalid labels' }; + menuLabels = { ...payload }; + try { + // Mirror the boot path: no custom menu unless multiWindow opted in. + if (readConfig().multiWindow) installAppMenu(); + } catch (e) { console.error('[menu] rebuild failed:', e); } + return { ok: true }; +}); + function installAppMenu(): void { const isMac = process.platform === 'darwin'; + const L = menuLabels; const newFloorItem = { - label: 'New Floor', + label: L.newFloor, accelerator: 'CmdOrCtrl+Shift+N', click: () => { openFloor(); } }; const template: Electron.MenuItemConstructorOptions[] = [ ...(isMac ? [{ role: 'appMenu' as const }] : []), { - label: 'File', + label: L.file, submenu: isMac - ? [newFloorItem, { type: 'separator' as const }, { role: 'close' as const }] - : [newFloorItem, { type: 'separator' as const }, { role: 'quit' as const }] + ? [newFloorItem, { type: 'separator' as const }, { role: 'close' as const, label: L.close }] + : [newFloorItem, { type: 'separator' as const }, { role: 'quit' as const, label: L.quit }] }, // The Edit menu is spelled out rather than `{ role: 'editMenu' }` for one // reason: `registerAccelerator: false` on the clipboard items. @@ -2516,19 +2553,19 @@ function installAppMenu(): void { // handler and the textarea's native paste event both read the clipboard // synchronously, inside the keystroke, before any restore can land. { - label: 'Edit', + label: L.edit, submenu: [ - { role: 'undo' as const, registerAccelerator: false }, - { role: 'redo' as const, registerAccelerator: false }, + { role: 'undo' as const, label: L.undo, registerAccelerator: false }, + { role: 'redo' as const, label: L.redo, registerAccelerator: false }, { type: 'separator' as const }, - { role: 'cut' as const, registerAccelerator: false }, - { role: 'copy' as const, registerAccelerator: false }, - { role: 'paste' as const, registerAccelerator: false }, - { role: 'selectAll' as const, registerAccelerator: false } + { role: 'cut' as const, label: L.cut, registerAccelerator: false }, + { role: 'copy' as const, label: L.copy, registerAccelerator: false }, + { role: 'paste' as const, label: L.paste, registerAccelerator: false }, + { role: 'selectAll' as const, label: L.selectAll, registerAccelerator: false } ] }, - { role: 'viewMenu' }, - { role: 'windowMenu' } + { role: 'viewMenu', label: L.view }, + { role: 'windowMenu', label: L.window } ]; Menu.setApplicationMenu(Menu.buildFromTemplate(template)); } diff --git a/src/preload/index.ts b/src/preload/index.ts index ffdb5382a7..23a3a4212c 100644 --- a/src/preload/index.ts +++ b/src/preload/index.ts @@ -1407,6 +1407,12 @@ const api = { /** Open the project's releases page for a notify-only update. */ updateOpenRelease: (url?: string): Promise<{ ok: boolean }> => ipcRenderer.invoke('update:openRelease', url), + /** Push translated native-menu labels; main rebuilds the app menu. + * The renderer owns i18n — main keeps no locale files — so labels travel + * over IPC (menu:setLabels) on boot and every language switch. English + * until the first push. */ + setMenuLabels: (labels: Record): Promise<{ ok: boolean; error?: string }> => + ipcRenderer.invoke('menu:setLabels', labels), /** Which OS this window runs on, for platform-specific copy. */ platform: process.platform as string, arch: process.arch as string, diff --git a/src/renderer/src/App.tsx b/src/renderer/src/App.tsx index b2bd92dfd4..002bcffc77 100644 --- a/src/renderer/src/App.tsx +++ b/src/renderer/src/App.tsx @@ -8,6 +8,7 @@ import { OfficeFloor } from '@/scene/office/OfficeFloor'; import { useHive } from '@/hooks/useHive'; import { useResolvedGodName } from '@/hooks/useResolvedGodName'; import { useGodNameSync } from '@/i18n/useGodNameSync'; +import { useMenuLabelsSync } from '@/i18n/useMenuLabelsSync'; import { useDirectionSync } from '@/i18n/useDirection'; import { useArabicTerminalSync } from '@/terminal/useArabicTerminalSync'; import { MemoryPanel } from '@/components/MemoryPanel'; @@ -41,6 +42,8 @@ export function App() { const { t } = useTranslation(); // Point every {{godName}} string at the orchestrator's real, renameable name. useGodNameSync(); + // Keep the native window menu in the picked language (main rebuilds it). + useMenuLabelsSync(); // Mirror the document only for a user who has picked an RTL app language. useDirectionSync(); // Let terminals that are ALREADY open follow a language switch too. diff --git a/src/renderer/src/i18n/locales/ar.json b/src/renderer/src/i18n/locales/ar.json index 7c9977393e..66923e308d 100644 --- a/src/renderer/src/i18n/locales/ar.json +++ b/src/renderer/src/i18n/locales/ar.json @@ -1495,5 +1495,20 @@ "releaseDrop": { "closeAria": "Close release notes", "closeTitle": "Close (Esc)" + }, + "nativeMenu": { + "file": "File", + "edit": "Edit", + "view": "View", + "window": "Window", + "newFloor": "New Floor", + "undo": "Undo", + "redo": "Redo", + "cut": "Cut", + "copy": "Copy", + "paste": "Paste", + "selectAll": "Select All", + "quit": "Quit", + "close": "Close" } } diff --git a/src/renderer/src/i18n/locales/en.json b/src/renderer/src/i18n/locales/en.json index eb3923f7aa..21038396ac 100644 --- a/src/renderer/src/i18n/locales/en.json +++ b/src/renderer/src/i18n/locales/en.json @@ -1495,5 +1495,20 @@ "releaseDrop": { "closeAria": "Close release notes", "closeTitle": "Close (Esc)" + }, + "nativeMenu": { + "file": "File", + "edit": "Edit", + "view": "View", + "window": "Window", + "newFloor": "New Floor", + "undo": "Undo", + "redo": "Redo", + "cut": "Cut", + "copy": "Copy", + "paste": "Paste", + "selectAll": "Select All", + "quit": "Quit", + "close": "Close" } } diff --git a/src/renderer/src/i18n/locales/pt-BR.json b/src/renderer/src/i18n/locales/pt-BR.json index e2ca42b768..1a8f6d2b7f 100644 --- a/src/renderer/src/i18n/locales/pt-BR.json +++ b/src/renderer/src/i18n/locales/pt-BR.json @@ -1495,5 +1495,20 @@ "releaseDrop": { "closeAria": "Fechar notas da versão", "closeTitle": "Fechar (Esc)" + }, + "nativeMenu": { + "file": "Arquivo", + "edit": "Editar", + "view": "Exibir", + "window": "Janela", + "newFloor": "Novo Escritório", + "undo": "Desfazer", + "redo": "Refazer", + "cut": "Recortar", + "copy": "Copiar", + "paste": "Colar", + "selectAll": "Selecionar tudo", + "quit": "Sair", + "close": "Fechar" } } diff --git a/src/renderer/src/i18n/locales/zh-CN.json b/src/renderer/src/i18n/locales/zh-CN.json index 50afebad03..f006023e0a 100644 --- a/src/renderer/src/i18n/locales/zh-CN.json +++ b/src/renderer/src/i18n/locales/zh-CN.json @@ -1495,5 +1495,20 @@ "releaseDrop": { "closeAria": "Close release notes", "closeTitle": "Close (Esc)" + }, + "nativeMenu": { + "file": "File", + "edit": "Edit", + "view": "View", + "window": "Window", + "newFloor": "New Floor", + "undo": "Undo", + "redo": "Redo", + "cut": "Cut", + "copy": "Copy", + "paste": "Paste", + "selectAll": "Select All", + "quit": "Quit", + "close": "Close" } } diff --git a/src/renderer/src/i18n/useMenuLabelsSync.ts b/src/renderer/src/i18n/useMenuLabelsSync.ts new file mode 100644 index 0000000000..0e63f4e3bc --- /dev/null +++ b/src/renderer/src/i18n/useMenuLabelsSync.ts @@ -0,0 +1,42 @@ +import { useEffect } from 'react'; +import { useTranslation } from 'react-i18next'; + +/** + * Push translated native-menu labels to main over menu:setLabels. + * + * Main owns no i18n (no locale files outside the renderer bundle), so the + * renderer — the single source of truth — pushes all 13 nativeMenu.* labels + * on mount and on every language switch, and main rebuilds the app menu. + * English until the first push. Role-generated submenus (View/Window) stay + * in Electron's default language by design (see installAppMenu). + * + * Mounted once, near the root, next to the other sync hooks. + */ +export function useMenuLabelsSync(): void { + const { t, i18n } = useTranslation(); + useEffect(() => { + const push = (): void => { + try { + const labels: Record = { + file: t('nativeMenu.file'), + edit: t('nativeMenu.edit'), + view: t('nativeMenu.view'), + window: t('nativeMenu.window'), + newFloor: t('nativeMenu.newFloor'), + undo: t('nativeMenu.undo'), + redo: t('nativeMenu.redo'), + cut: t('nativeMenu.cut'), + copy: t('nativeMenu.copy'), + paste: t('nativeMenu.paste'), + selectAll: t('nativeMenu.selectAll'), + quit: t('nativeMenu.quit'), + close: t('nativeMenu.close') + }; + void window.cth.setMenuLabels(labels).catch(() => { /* menu keeps old labels */ }); + } catch { /* preload bridge absent (tests) — menu stays English */ } + }; + push(); + i18n.on('languageChanged', push); + return () => { i18n.off('languageChanged', push); }; + }, [i18n, t]); +} diff --git a/test/arabic-ui.test.cjs b/test/arabic-ui.test.cjs index 47498a2aa3..55fd2bde48 100644 --- a/test/arabic-ui.test.cjs +++ b/test/arabic-ui.test.cjs @@ -288,7 +288,20 @@ test('no Arabic string is left as its English source', () => { 'sidebar.resizeTitle', 'updatesSection.readMore', 'updatesSection.installAria', - 'memoryGraph.emptyHint' + 'memoryGraph.emptyHint', + // ...Task 10: native menu labels (main rebuilds from the IPC push). + 'nativeMenu.file', + 'nativeMenu.edit', + 'nativeMenu.view', + 'nativeMenu.window', + 'nativeMenu.newFloor', + 'nativeMenu.undo', + 'nativeMenu.redo', + 'nativeMenu.copy', + 'nativeMenu.paste', + 'nativeMenu.selectAll', + 'nativeMenu.quit', + 'nativeMenu.close' ]); const e = pathsOf(en), a = pathsOf(ar); const untranslated = []; diff --git a/test/native-menu.test.cjs b/test/native-menu.test.cjs new file mode 100644 index 0000000000..14d7b952d1 --- /dev/null +++ b/test/native-menu.test.cjs @@ -0,0 +1,66 @@ +// Menu nativo traduzido via IPC (Task 10, fork pt-BR). +// +// O main nao tem i18n: o renderer empurra os 13 rotulos nativeMenu.* por +// menu:setLabels e o main reconstrói. Estes testes sao textuais (mesmo +// estilo de arabic-ui.test.cjs): o contrato que importa e o fio +// renderer -> preload -> main, nao o Electron em si. +'use strict'; + +const assert = require('node:assert'); +const fs = require('fs'); +const path = require('path'); +const { test } = require('node:test'); + +const ROOT = path.join(__dirname, '..'); +const read = (p) => fs.readFileSync(path.join(ROOT, p), 'utf8'); +const strip = (s) => s.replace(/\/\/[^\n]*/g, ' ').replace(/\/\*[\s\S]*?\*\//g, ' '); + +const KEYS = ['file', 'edit', 'view', 'window', 'newFloor', 'undo', 'redo', + 'cut', 'copy', 'paste', 'selectAll', 'quit', 'close']; + +test('preload exposes setMenuLabels over menu:setLabels', () => { + const src = read('src/preload/index.ts'); + assert.match(src, /setMenuLabels: \(labels: Record\)/, + 'preload must type the labels as a plain record (no locale coupling)'); + assert.match(src, /ipcRenderer\.invoke\('menu:setLabels', labels\)/, + 'preload must forward to the menu:setLabels channel'); +}); + +test('main validates, stores and rebuilds on menu:setLabels', () => { + const src = strip(read('src/main/index.ts')); + assert.match(src, /ipcMain\.handle\('menu:setLabels'/, 'main must handle the channel'); + assert.match(src, /function isMenuLabels/, 'main must validate the pushed shape'); + assert.match(src, /length <= 60/, 'labels must be length-capped'); + assert.match(src, /if \(readConfig\(\)\.multiWindow\) installAppMenu/, + 'rebuild must respect the multiWindow flag (boot path parity)'); +}); + +test('menu template consumes labels, keeps behavior', () => { + const src = strip(read('src/main/index.ts')); + for (const k of ['file', 'edit', 'newFloor', 'undo', 'quit', 'close', 'view', 'window']) { + assert.match(src, new RegExp(`label: L\\.${k}\\b`), `template must use L.${k}`); + } + assert.ok(!/label: 'File'/.test(src) && !/label: 'Edit'/.test(src) && !/label: 'New Floor'/.test(src), + 'no hardcoded top-level English labels may remain'); + const accelFalse = (src.match(/registerAccelerator: false/g) || []).length; + assert.equal(accelFalse, 6, `Edit keeps registerAccelerator:false x6 (dictation), found ${accelFalse}`); + assert.match(src, /accelerator: 'CmdOrCtrl\+Shift\+N'/, 'New Floor shortcut must survive'); +}); + +test('renderer pushes labels on boot and language switch', () => { + const src = read('src/renderer/src/i18n/useMenuLabelsSync.ts'); + assert.match(src, /window\.cth\.setMenuLabels\(labels\)/, 'hook must push through the bridge'); + assert.match(src, /i18n\.on\('languageChanged', push\)/, 'hook must re-push on switch'); + const app = read('src/renderer/src/App.tsx'); + assert.match(app, /useMenuLabelsSync\(\)/, 'hook must be mounted near the root'); +}); + +test('nativeMenu section exists with all 13 keys in every locale', () => { + const loc = (l) => JSON.parse(read(`src/renderer/src/i18n/locales/${l}.json`)); + const en = Object.keys(loc('en').nativeMenu ?? {}); + assert.deepEqual([...en].sort(), [...KEYS].sort(), 'en.nativeMenu must carry exactly the 13 keys'); + for (const l of ['pt-BR', 'zh-CN', 'ar']) { + assert.deepEqual(Object.keys(loc(l).nativeMenu ?? {}).sort(), [...KEYS].sort(), `${l}.nativeMenu drifted`); + } + assert.equal(loc('pt-BR').nativeMenu.file, 'Arquivo', 'spot-check the pt-BR translation'); +}); From c88fd54a502091822137514b6a4da935e4afedb6 Mon Sep 17 00:00:00 2001 From: T3sh Date: Wed, 14 Oct 2026 01:29:24 -0300 Subject: [PATCH 09/24] fix(i18n): release-drop pin aceita closeAria via i18n --- test/release-drop.test.cjs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/release-drop.test.cjs b/test/release-drop.test.cjs index aef23ba4f9..0145707e67 100644 --- a/test/release-drop.test.cjs +++ b/test/release-drop.test.cjs @@ -124,7 +124,10 @@ test('ReleaseDrop renders no action buttons, only a close', () => { const src = readDrop(); const buttons = src.match(//g) ?? []; assert.equal(buttons.length, 1, 'the release drop must carry exactly one chrome button'); - assert.ok(/aria-label="Close/.test(buttons[0]), 'the only chrome button must be the close'); + // The close label may be literal or the releaseDrop.closeAria i18n key (whose + // en value starts with "Close") — either way the single button stays the close. + assert.ok(/aria-label=(["']Close|\{t\('releaseDrop\.closeAria'\)\})/.test(buttons[0]), + 'the only chrome button must be the close'); assert.ok(!/Star|Restart|Later|Download|Open release/i.test(src.replace(/\/\*[\s\S]*?\*\/|\/\/.*$/gm, '')), 'no release action may be a chrome button'); }); From b54f4af919a1b59e99566b15bba27c1415d14f20 Mon Sep 17 00:00:00 2001 From: T3sh Date: Wed, 14 Oct 2026 02:16:05 -0300 Subject: [PATCH 10/24] feat(opencode): adiciona OpenRouter Free ao catalogo de modelos --- docs/model-catalog.json | 1 + src/shared/modelCatalog.json | 1 + test/model-catalog.test.cjs | 1 + 3 files changed, 3 insertions(+) diff --git a/docs/model-catalog.json b/docs/model-catalog.json index 8f695d88ed..f13f8792d6 100644 --- a/docs/model-catalog.json +++ b/docs/model-catalog.json @@ -77,6 +77,7 @@ { "id": "openai/gpt-5", "label": "GPT-5 (OpenAI)", "minAppVersion": null, "maxAppVersion": null }, { "id": "openai/gpt-5-mini", "label": "GPT-5 mini (OpenAI)", "minAppVersion": null, "maxAppVersion": null }, { "id": "openrouter/anthropic/claude-sonnet-4.5", "label": "Claude Sonnet 4.5 (OpenRouter)", "minAppVersion": null, "maxAppVersion": null }, + { "id": "openrouter/free", "label": "OpenRouter Free (free tier)", "minAppVersion": null, "maxAppVersion": null }, { "id": "google/gemini-2.5-pro", "label": "Gemini 2.5 Pro (Google)", "minAppVersion": null, "maxAppVersion": null }, { "id": "local/llama3", "label": "Local · OpenAI-compatible (set base-URL)", "minAppVersion": null, "maxAppVersion": null } ], diff --git a/src/shared/modelCatalog.json b/src/shared/modelCatalog.json index bb4b16b607..d5654310cc 100644 --- a/src/shared/modelCatalog.json +++ b/src/shared/modelCatalog.json @@ -74,6 +74,7 @@ { "id": "openai/gpt-5", "label": "GPT-5 (OpenAI)", "minAppVersion": null, "maxAppVersion": null }, { "id": "openai/gpt-5-mini", "label": "GPT-5 mini (OpenAI)", "minAppVersion": null, "maxAppVersion": null }, { "id": "openrouter/anthropic/claude-sonnet-4.5", "label": "Claude Sonnet 4.5 (OpenRouter)", "minAppVersion": null, "maxAppVersion": null }, + { "id": "openrouter/free", "label": "OpenRouter Free (free tier)", "minAppVersion": null, "maxAppVersion": null }, { "id": "google/gemini-2.5-pro", "label": "Gemini 2.5 Pro (Google)", "minAppVersion": null, "maxAppVersion": null }, { "id": "local/llama3", "label": "Local · OpenAI-compatible (set base-URL)", "minAppVersion": null, "maxAppVersion": null } ], diff --git a/test/model-catalog.test.cjs b/test/model-catalog.test.cjs index 909cf4ad91..4abcb026eb 100644 --- a/test/model-catalog.test.cjs +++ b/test/model-catalog.test.cjs @@ -69,6 +69,7 @@ const SHIPPED = { ["openai/gpt-5", "GPT-5 (OpenAI)"], ["openai/gpt-5-mini", "GPT-5 mini (OpenAI)"], ["openrouter/anthropic/claude-sonnet-4.5", "Claude Sonnet 4.5 (OpenRouter)"], + ["openrouter/free", "OpenRouter Free (free tier)"], ["google/gemini-2.5-pro", "Gemini 2.5 Pro (Google)"], ["local/llama3", "Local · OpenAI-compatible (set base-URL)"] ], From 5832a20e85c0d9ae0494312cef4d79edd5e7b556 Mon Sep 17 00:00:00 2001 From: T3sh Date: Wed, 14 Oct 2026 02:52:31 -0300 Subject: [PATCH 11/24] fix(opencode): isola XDG_DATA_HOME por hive no spawn --- src/main/index.ts | 13 +++++++++++ test/opencode-datadir.test.cjs | 42 ++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 test/opencode-datadir.test.cjs diff --git a/src/main/index.ts b/src/main/index.ts index 0cc017c8d6..cf5f3f14bb 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -3009,6 +3009,19 @@ async function spawnAgentCore(opts: AgentSpawnOptions, owner: Electron.WebConten }; } extra.OPENCODE_CONFIG_CONTENT = JSON.stringify(oc); + // 4) Hive-scoped opencode data dir (XDG base). Desktop OpenCode 2.x + // migrates the shared ~/.local/share/opencode database to a schema + // the bundled CLI 1.x cannot open ("Database is not empty and has no + // session table"), hanging every harness spawn at startup with a + // blank terminal. Pointing XDG_DATA_HOME at a per-hive dir keeps + // agent sessions working no matter what the desktop app does with + // the global one. Auth (~/.config) and the global install are + // untouched; opencode creates the dir on first launch. opencode-only: + // other CLIs must keep resolving their own XDG paths. + try { + const home = cfg.harnessHome ? resolve(expandTilde(cfg.harnessHome)) : ''; + if (home) extra.XDG_DATA_HOME = join(home, '.opencode-data'); + } catch { /* fall back to the shared global dir */ } } opts.env = { ...(opts.env ?? {}), ...extra }; } diff --git a/test/opencode-datadir.test.cjs b/test/opencode-datadir.test.cjs new file mode 100644 index 0000000000..cddf0319ab --- /dev/null +++ b/test/opencode-datadir.test.cjs @@ -0,0 +1,42 @@ +// opencode data-dir isolation (fork fix for the desktop-2.x global-db skew). +// +// Desktop OpenCode 2.x migrates ~/.local/share/opencode to a schema the +// bundled CLI 1.x cannot open, hanging every harness opencode spawn at +// startup with a blank terminal. The spawn path must point XDG_DATA_HOME at +// a hive-scoped dir (opencode-only; auth and other CLIs untouched). +// Text-based like the other contract tests: what matters is the spawn env. +'use strict'; + +const assert = require('node:assert/strict'); +const fs = require('fs'); +const path = require('path'); +const { test } = require('node:test'); + +const ROOT = path.join(__dirname, '..'); +const src = fs.readFileSync(path.join(ROOT, 'src', 'main', 'index.ts'), 'utf8'); + +test('opencode spawns get a hive-scoped XDG_DATA_HOME', () => { + const assigns = src.match(/extra\.XDG_DATA_HOME\s*=/g) ?? []; + assert.equal(assigns.length, 1, `exactly one XDG_DATA_HOME assignment, found ${assigns.length}`); + assert.match(src, /extra\.XDG_DATA_HOME = join\(home, '\.opencode-data'\)/, + 'the dir must be home-anchored and dot-prefixed (out of git and mining paths)'); +}); + +test('the isolation lives in the opencode-only branch', () => { + const start = src.indexOf("if (provider === 'opencode') {"); + assert.ok(start >= 0, 'opencode-only branch missing'); + const end = src.indexOf('opts.env = { ...(opts.env', start); + assert.ok(end > start, 'opencode branch end missing'); + const block = src.slice(start, end); + assert.ok(block.includes('extra.XDG_DATA_HOME'), 'XDG_DATA_HOME must be set inside the opencode branch'); + assert.ok(block.includes('OPENCODE_CONFIG_CONTENT'), 'config injection must stay alongside'); +}); + +test('no other provider inherits the override', () => { + // crush/pi/qwen share the outer BYOK branch but must keep their own XDG paths. + const outer = src.slice( + src.indexOf("provider === 'opencode' || provider === 'crush'"), + src.indexOf('extra.OPENCODE_CONFIG_CONTENT') + ); + assert.ok(!outer.includes('XDG_DATA_HOME'), 'the shared BYOK section must not set it'); +}); From 2c6c0ab6065b7e315150fadca8358cc25ed09465 Mon Sep 17 00:00:00 2001 From: T3sh Date: Wed, 14 Oct 2026 13:46:28 -0300 Subject: [PATCH 12/24] fix(opencode): le o banco por hive, nao o global (TSF-11) Todo agente OpenCode aparecia com tokens=0, usd=0 e lastActiveSecAgo=null no fleet.json -- inclusive o deus, que por isso nao conseguia medir o seu proprio consumo. A causa nao era so o layout. Duas: 1. A telemetria so conhecia o layout do Claude Code (~/.claude/projects). OpenCode guarda sessao em SQLite. Corrigido com readOpencodeUsage: mapeia session_v2.directory -> cwd e agrega os tokens EM SQL, nunca em JS (session_message.data e JSON de varios KB e um diretorio tem ~17k linhas; somar em JS alocava dezenas de MB a cada 30s). Nunca soma o diretorio inteiro (D11). 2. O leitor abria ~/.local/share/opencode/opencode.db, mas o spawn aponta XDG_DATA_HOME para /.opencode-data. Eram DOIS bancos: 62,8 MB dos agentes contra 535,4 MB do opencode interativo. Compilava, os testes passavam, e os numeros continuavam a zero. Agora opencodeDbPath(harnessHome) e a UNICA computacao dos dois lados -- o spawn deriva XDG_DATA_HOME dela e a telemetria le com ela. Testes: test/opencode-usage-db.test.cjs (novo) abre um SQLite de verdade -- o caminho de leitura nao tinha cobertura nenhuma. Inclui a trava do D11 (um segundo agente no mesmo cwd nao contamina a soma) e um guard que falha se o spawn voltar a computar o caminho a parte. Verificado que morde: revertendo o reader, 2 testes caem. Harness corrigido pelo caminho: transcript-usage.test.cjs transpilava transcript.ts achatado e so mapeava ./pricing; com o ./fs novo o modulo nem carregava. Passa a espelhar a arvore real (main/ + shared/). O teste do XDG_DATA_HOME deixou de fixar a expressao literal e passou a fixar o helper partilhado -- que e o que deve estar travado. Reparado encoding em telemetry.ts e transcript.ts: BOM + mojibake cp1252 (20x em dash, 287x box drawing, 7x seta, 1x lock) deixados pelo trabalho nao commitado. Comentarios so; as 22 falhas de suite sao as mesmas antes e depois. Suite: 937 -> 942 a passar, 22 a falhar (identicas ao baseline Windows). Typecheck node e web limpos. Ainda precisa de `npm run dist:win` + reinstalar para chegar ao binario. --- src/main/hive.ts | 29 +++++++ src/main/index.ts | 16 +++- src/main/telemetry.ts | 54 ++++++++++--- src/main/transcript.ts | 132 ++++++++++++++++++++++++++++++++ test/opencode-datadir.test.cjs | 9 ++- test/opencode-usage-db.test.cjs | 115 ++++++++++++++++++++++++++++ test/transcript-usage.test.cjs | 26 +++++-- 7 files changed, 359 insertions(+), 22 deletions(-) create mode 100644 test/opencode-usage-db.test.cjs diff --git a/src/main/hive.ts b/src/main/hive.ts index 5f9c38bffc..e59d16b688 100644 --- a/src/main/hive.ts +++ b/src/main/hive.ts @@ -1927,6 +1927,35 @@ export class HiveManager { this.ensureHive(); const path = join(root, 'tasks.json'); const current = this.readJson<{ tasks?: unknown }>(path, { tasks: [] }); + // >>> DIAGNOSTICO TEMPORARIO (TSF-17) - REMOVER <<< + // mergeTaskLedger protects fields, never card membership: whoever builds + // the INCOMING array decides what survives. Reading that code shows + // INTENTION; it cannot show what actually arrived. So capture the array, + // every write, with the ids it held and the ids the file already had. If + // the incoming set is missing a card the file has, the omission happened + // UPSTREAM of the merge, and this line is where it becomes visible + // instead of inferred. + try { + const diagDir = join(root, 'diagnostics'); + mkdirSync(diagDir, { recursive: true }); + const incoming = (Array.isArray(tasks) ? tasks : []) as HiveTask[]; + const onDisk = ((current?.tasks as HiveTask[]) || []).filter((t) => t && t.id); + const incIds = incoming.map((t) => String(t?.id ?? '?')).sort(); + const line = JSON.stringify({ + at: new Date().toISOString(), + incomingCount: incoming.length, + incomingIds: incIds, + incomingStatus: incoming.reduce((a, t) => { + const s = String((t as { status?: unknown })?.status ?? '?'); + a[s] = (a[s] || 0) + 1; + return a; + }, {} as Record), + onDiskCount: onDisk.length, + missingFromIncoming: onDisk.map((t) => String(t.id)).filter((id) => !incIds.includes(id)).sort() + }); + appendFileSync(join(diagDir, 'writeTasks.array.jsonl'), line + '\n', 'utf8'); + } catch { /* diagnostics must never break a write */ } + // >>> FIM DO DIAGNOSTICO <<< const merged = mergeTaskLedger(current?.tasks, tasks); this.writeJson(path, { tasks: merged }); this.appendLog({ kind: 'tasks', count: merged.length }); diff --git a/src/main/index.ts b/src/main/index.ts index a020ae02c6..1b3410669d 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -33,7 +33,7 @@ import { MemoryManager } from './memory'; import { KnowledgeManager } from './knowledge'; import { MemoryReflector, type ReflectSettings } from './reflect'; import { PersistStore } from './db'; -import { readAgentUsage, readContextTokens, seedSessionTranscript, resolveSessionCwd } from './transcript'; +import { readAgentUsage, readContextTokens, seedSessionTranscript, resolveSessionCwd, opencodeDbPath } from './transcript'; import { listIssues, listCIRuns } from './github'; import { SlackWebhookServer, SlackReplyServer, postSlackReply, type SlackEventFile } from './slack'; import { @@ -252,7 +252,10 @@ const telemetry = new TelemetryCollector({ resolveCwd: (agentId) => hive.registry().agents[agentId]?.cwd ?? null, // D11: scopes the transcript fallback to this agent's own session instead of // summing every transcript in a (routinely shared) cwd. - resolveSessionId: (agentId) => hive.lastSession(agentId) + resolveSessionId: (agentId) => hive.lastSession(agentId), + // TSF-11: same DB the spawn writes to. Without this the fallback reads the + // operator's global opencode database and reports zeros for every agent. + resolveOpencodeDb: () => opencodeDbPath(readConfig().harnessHome) }); // Usage provider (Seam 1) — the INTEGRATION swap: Oscar's telemetry collector (#7) // IS the provider, replacing Lane A's interim StubUsageProvider. Same @@ -3055,9 +3058,14 @@ async function spawnAgentCore(opts: AgentSpawnOptions, owner: Electron.WebConten // the global one. Auth (~/.config) and the global install are // untouched; opencode creates the dir on first launch. opencode-only: // other CLIs must keep resolving their own XDG paths. + // + // TSF-11: `opencodeDbPath` is the SAME helper the telemetry fallback + // reads with. They used to be computed independently — the spawn + // pointed at /.opencode-data while the reader opened + // ~/.local/share/opencode — so the numbers stayed zero even after the + // reader was fixed. One function, two callers, no second chance. try { - const home = cfg.harnessHome ? resolve(expandTilde(cfg.harnessHome)) : ''; - if (home) extra.XDG_DATA_HOME = join(home, '.opencode-data'); + extra.XDG_DATA_HOME = dirname(opencodeDbPath(cfg.harnessHome)); } catch { /* fall back to the shared global dir */ } } opts.env = { ...(opts.env ?? {}), ...extra }; diff --git a/src/main/telemetry.ts b/src/main/telemetry.ts index be9c1ced6c..5ec013851b 100644 --- a/src/main/telemetry.ts +++ b/src/main/telemetry.ts @@ -30,7 +30,7 @@ import { readFileSync } from 'node:fs'; import { createServer, type IncomingMessage, type Server, type ServerResponse } from 'node:http'; import { homedir } from 'node:os'; import { join } from 'node:path'; -import { readAgentUsage } from './transcript'; +import { readAgentUsage, readOpencodeUsage } from './transcript'; import { normalizeModel } from './pricing'; // ─── The locked cross-lane contract (do not change without re-agreeing) ─────── @@ -126,6 +126,10 @@ export interface TelemetryCollectorOptions { * cwd (the common case for hive workers) pulls in every other agent's and * every past session's history too. */ resolveSessionId?: (agentId: string) => string | undefined; + /** Resolve the OpenCode SQLite the agents were actually spawned into. + * Must agree with the spawn's `XDG_DATA_HOME`, or the read silently targets + * a database that never held the agent (TSF-11). */ + resolveOpencodeDb?: () => string | undefined; } export class TelemetryCollector { @@ -136,6 +140,7 @@ export class TelemetryCollector { private readonly emit?: (channel: string, payload: unknown) => void; private readonly resolveCwd?: (agentId: string) => string | null; private readonly resolveSessionId?: (agentId: string) => string | undefined; + private readonly resolveOpencodeDb?: () => string | undefined; /** sessionId → running accumulation. */ private readonly sessions = new Map(); @@ -155,6 +160,7 @@ export class TelemetryCollector { this.emit = opts.emit; this.resolveCwd = opts.resolveCwd; this.resolveSessionId = opts.resolveSessionId; + this.resolveOpencodeDb = opts.resolveOpencodeDb; } /** Bind the loopback OTLP listener. The handler is live the instant this @@ -440,19 +446,47 @@ export class TelemetryCollector { const cwd = this.resolveCwd?.(agentId); if (!cwd) return null; const sessionId = this.resolveSessionId?.(agentId); + + // OpenCode-backed agents keep their sessions in SQLite, not in Claude's + // `~/.claude/projects//*.jsonl`, so `readAgentUsage` finds no directory + // for them and every figure collapsed to zero (TSF-11). Try that layout first; + // it is a single indexed read and costs nothing when the DB is absent. + // When the session id is unknown, `readOpencodeUsage` falls back to the NEWEST + // session in that directory — never the whole directory, which is shared. + const u = readOpencodeUsage(cwd, { + ...(sessionId ? { sessionId } : {}), + ...(this.resolveOpencodeDb ? { dbPath: this.resolveOpencodeDb() } : {}) + }); + if (u.inputTokens || u.outputTokens || u.cacheReadTokens || u.cacheWriteTokens) { + return { + agentId, + sessionId: '', + // The REAL last-activity instant. `Date.now()` here would make every + // agent read as freshly active in `fleet.json`, which is why R1 could + // never see a stall: `lastActiveSecAgo` is computed from this stamp. + ts: u.lastActiveAt ?? Date.now(), + input: u.inputTokens, + output: u.outputTokens, + cacheRead: u.cacheReadTokens, + cacheCreation: u.cacheWriteTokens, + model: u.model ?? '', + usd: u.estimatedCostUsd + }; + } + if (!sessionId) return null; - const u = readAgentUsage(cwd, { sessionId }); - if (!u.inputTokens && !u.outputTokens && !u.cacheReadTokens && !u.cacheWriteTokens) return null; + const c = readAgentUsage(cwd, { sessionId }); + if (!c.inputTokens && !c.outputTokens && !c.cacheReadTokens && !c.cacheWriteTokens) return null; return { agentId, sessionId: '', - ts: Date.now(), - input: u.inputTokens, - output: u.outputTokens, - cacheRead: u.cacheReadTokens, - cacheCreation: u.cacheWriteTokens, - model: u.model ?? '', - usd: u.estimatedCostUsd + ts: c.lastActiveAt ?? Date.now(), + input: c.inputTokens, + output: c.outputTokens, + cacheRead: c.cacheReadTokens, + cacheCreation: c.cacheWriteTokens, + model: c.model ?? '', + usd: c.estimatedCostUsd }; } diff --git a/src/main/transcript.ts b/src/main/transcript.ts index 0d6314088b..a91ee6d1c9 100644 --- a/src/main/transcript.ts +++ b/src/main/transcript.ts @@ -1,7 +1,9 @@ import { closeSync, cpSync, existsSync, fstatSync, mkdirSync, openSync, readSync, readdirSync, readFileSync, statSync } from 'node:fs'; import os from 'node:os'; import path from 'node:path'; +import { DatabaseSync } from 'node:sqlite'; import { estimateCostUsd, normalizeModel } from './pricing'; +import { expandTilde } from './fs'; /** Claude Code's project key: the absolute cwd with EVERY non-alphanumeric * character turned into a dash — the leading slash and any dots included. @@ -138,6 +140,13 @@ export interface AgentUsage { /** The most-recently-seen model id (normalized, e.g. `claude-opus-4-8`), or * undefined if no priced record was found. Lets the UI label the row. */ model?: string; + /** Epoch ms of the most recent assistant record this figure covers, or + * undefined when nothing was found. `AgentUsageSample.ts` is stamped with + * `Date.now()` by the fallback, which makes `lastActiveSecAgo` read as "just + * now" even for a session that last did anything hours ago — the dashboard + * reports every agent as freshly active and R1 can never detect a stall. + * This carries the REAL activity instant so the caller can stamp with it. */ + lastActiveAt?: number; } function zero(): AgentUsage { @@ -151,6 +160,34 @@ export interface ReadUsageOptions { * every `.jsonl` under the shared project dir. When unset, all are summed * (the legacy behavior, used when the agent's session id isn't yet known). */ sessionId?: string; + /** + * Explicit OpenCode SQLite to read. Set by the telemetry fallback so it + * resolves the SAME hive the agent was spawned into — see `opencodeDbPath`. + * Unset means the global default, which is correct only for an opencode the + * app did not spawn. + */ + dbPath?: string; +} + +/** + * The SQLite file an agent's OpenCode sessions actually land in (TSF-11, part 2). + * + * The spawn points `XDG_DATA_HOME` at `/.opencode-data` + * (index.ts `applySpawnEnv`), so every harness agent writes to a per-hive + * database — NOT the user's global one. Reading `~/.local/share/opencode/ + * opencode.db` opens a database that never saw the agent: the reader compiled, + * the suite passed, and the numbers stayed zero anyway. The two paths were + * silently different, which is why "ship the fix" alone fixed nothing. + * + * Both sides MUST call this, so they cannot drift again. `expandTilde` is the + * spawn's own (index.ts imports the same one), keeping `~` handling identical. + */ +export function opencodeDbPath(harnessHome?: string | null): string { + const home = harnessHome ? expandTilde(harnessHome) : ''; + if (home) return path.join(home, '.opencode-data', 'opencode', 'opencode.db'); + // No hive configured: a standalone opencode (and the operator's own + // interactive sessions) really do live here. + return path.join(os.homedir(), '.local', 'share', 'opencode', 'opencode.db'); } /** Per-file incremental parse state for the usage cache. Transcripts are @@ -299,6 +336,101 @@ function readFileUsage(dir: string, file: string): FileUsageEntry | null { return entry; } +/** OpenCode persists session state in SQLite (`~/.local/share/opencode/opencode.db`), + * NOT as `~/.claude/projects//*.jsonl`. Reading the Claude layout from an + * OpenCode-backed agent therefore finds no directory at all, and every usage + * figure collapses to zero — which is why `lastActiveSecAgo` and `tokens` read + * null/0 for every OpenCode agent (TSF-11). + * + * The mapping is `session_v2.directory` -> the agent's cwd, which is the SAME + * key `projectKey(cwd)` already used; only the storage layer differs. + * + * Two invariants this must keep, because both have bitten before: + * + * 1. NEVER sum a whole directory. That directory is SHARED by every agent that + * ever ran there — the D11 note in telemetry.ts records a probe worker with + * zero LLM calls being cited 143,369,766 tokens from it. With no session id + * we read only the NEWEST session in the directory, never the union. + * 2. Aggregate in SQL, not in JS. `session_message.data` is multi-KB JSON and a + * per-directory session holds ~17k rows; pulling them into JS to sum would + * allocate tens of MB on a ~30s beat. Grouping by model in SQLite returns a + * handful of rows and lets each model be priced with its own rate. + */ +export function readOpencodeUsage(cwd: string, opts: ReadUsageOptions = {}): AgentUsage { + const usage = zero(); + let db: DatabaseSync | undefined; + try { + const dbPath = opts.dbPath ?? opencodeDbPath(); + if (!existsSync(dbPath)) return usage; + db = new DatabaseSync(dbPath, { readOnly: true }); + + // `session_v2.directory` is stored POSIX-style even on Windows; the registry + // holds native backslashes. Compare normalized, case-folded, no trailing sep. + const dir = cwd.replace(/\\/g, '/').replace(/\/+$/, '').toLowerCase(); + + const sql = ` + SELECT json_extract(m.data, '$.model.id') AS mid, + SUM(json_extract(m.data, '$.tokens.input')) AS i, + SUM(json_extract(m.data, '$.tokens.output')) AS o, + SUM(json_extract(m.data, '$.tokens.cache.read')) AS cr, + SUM(json_extract(m.data, '$.tokens.cache.write')) AS cw, + MAX(m.time_updated) AS ts + FROM session_message m %s + WHERE m.type = 'assistant' %s + GROUP BY mid`; + +let rows: Row[]; + if (opts.sessionId) { + rows = db.prepare(sql.replace('%s', '').replace('%s', 'AND m.session_id = ?')) + .all(opts.sessionId) as unknown as Row[]; + } else { + // No live session id: the NEWEST session in that directory ONLY — see (1). + // Summing the whole directory is the D11 bug (143,369,766 tokens credited to + // a worker that made zero LLM calls), so resolve the session id first and + // filter on it. Never fall through to a directory-wide aggregate. + const newest = db.prepare( + `SELECT id FROM session_v2 + WHERE lower(rtrim(directory, '/')) = ? + ORDER BY time_updated DESC LIMIT 1`).get(dir) as { id: string } | undefined; + if (!newest) return usage; + rows = db.prepare(sql.replace('%s', '').replace('%s', 'AND m.session_id = ?')) + .all(newest.id) as unknown as Row[]; + } + + let lastActiveAt: number | undefined; + let lastModel: string | undefined; + let lastTs = -1; + for (const r of rows) { + const i = Number(r.i ?? 0), o = Number(r.o ?? 0); + const cr = Number(r.cr ?? 0), cw = Number(r.cw ?? 0); + usage.inputTokens += i; + usage.outputTokens += o; + usage.cacheReadTokens += cr; + usage.cacheWriteTokens += cw; + // Per-model pricing: `cost` is 0 in the DB, the app prices by model id. + usage.estimatedCostUsd += estimateCostUsd(r.mid, { + inputTokens: i, outputTokens: o, cacheReadTokens: cr, cacheWriteTokens: cw, + }); + const ts = Number(r.ts ?? 0); + if (ts > lastTs) { lastTs = ts; lastActiveAt = ts; if (r.mid) lastModel = r.mid; } + } + if (lastModel) usage.model = lastModel; + if (lastActiveAt) usage.lastActiveAt = lastActiveAt; + return usage; + } catch { + return zero(); + } finally { + try { db?.close(); } catch { /* already closed / never opened */ } + } +} + +interface Row { + mid: string | null; + i: number | null; o: number | null; + cr: number | null; cw: number | null; + ts: number | null; +} + /** Sum real token usage across Claude Code transcripts for `cwd`, pricing each * assistant record by ITS OWN model (fixes cost bug #1 — no more Sonnet for * everyone) via the fallback price table. Optionally filtered to one session diff --git a/test/opencode-datadir.test.cjs b/test/opencode-datadir.test.cjs index cddf0319ab..beff7980c3 100644 --- a/test/opencode-datadir.test.cjs +++ b/test/opencode-datadir.test.cjs @@ -18,8 +18,13 @@ const src = fs.readFileSync(path.join(ROOT, 'src', 'main', 'index.ts'), 'utf8'); test('opencode spawns get a hive-scoped XDG_DATA_HOME', () => { const assigns = src.match(/extra\.XDG_DATA_HOME\s*=/g) ?? []; assert.equal(assigns.length, 1, `exactly one XDG_DATA_HOME assignment, found ${assigns.length}`); - assert.match(src, /extra\.XDG_DATA_HOME = join\(home, '\.opencode-data'\)/, - 'the dir must be home-anchored and dot-prefixed (out of git and mining paths)'); + // TSF-11: the spawn derives the dir from `opencodeDbPath` — the same helper + // the telemetry reader opens the database with. The previous expression + // (`join(home, '.opencode-data')`) was a SECOND, independent computation, so + // the reader could point at a database the agent never wrote to. Assert the + // single shared helper, not the literal. + assert.match(src, /extra\.XDG_DATA_HOME = dirname\(opencodeDbPath\(cfg\.harnessHome\)\)/, + 'XDG_DATA_HOME must come from opencodeDbPath, shared with the reader'); }); test('the isolation lives in the opencode-only branch', () => { diff --git a/test/opencode-usage-db.test.cjs b/test/opencode-usage-db.test.cjs new file mode 100644 index 0000000000..50aadd7556 --- /dev/null +++ b/test/opencode-usage-db.test.cjs @@ -0,0 +1,115 @@ +// TSF-11 — the OpenCode usage reader, end to end. +// +// Before this file the read path had ZERO coverage: the only test touching +// opencode data (opencode-datadir.test.cjs) asserts on the SPAWN's env line and +// never opens a database. So the reader could compile, pass the suite, and still +// read a database the agent never wrote to — which is exactly what happened. +// Two things are locked down here: +// 1. the path helper resolves the hive the spawn writes into, and +// 2. the spawn and the reader provably share that helper, +// 3. the SQL actually aggregates a real session. +'use strict'; + +const assert = require('node:assert/strict'); +const { test } = require('node:test'); +const fs = require('node:fs'); +const os = require('node:os'); +const path = require('node:path'); +const { DatabaseSync } = require('node:sqlite'); +const loadTs = require('./load-ts.cjs'); + +const { readOpencodeUsage, opencodeDbPath } = loadTs('src/main/transcript.ts'); +const MAIN = fs.readFileSync(path.join(__dirname, '..', 'src', 'main', 'index.ts'), 'utf8'); + +const HIVE = path.join(os.tmpdir(), 'tsf11-hive'); + +test('the reader targets the hive the spawn writes into', () => { + assert.equal( + opencodeDbPath(HIVE), + path.join(HIVE, '.opencode-data', 'opencode', 'opencode.db'), + 'must read the per-hive database, not the global one' + ); + // The global path is what the bug actually used. It must only apply when no + // hive is configured — otherwise every OpenCode agent reads zero forever. + assert.equal( + opencodeDbPath(null), + path.join(os.homedir(), '.local', 'share', 'opencode', 'opencode.db') + ); + assert.equal( + opencodeDbPath('~'), + path.join(os.homedir(), '.opencode-data', 'opencode', 'opencode.db'), + 'a ~ hive must expand like the spawn does' + ); +}); + +test('spawn and reader share one function, not two computations', () => { + // The failure mode was a spawn that set XDG_DATA_HOME from its own expression + // while the reader opened a hardcoded global path. Assert both call the helper. + assert.ok( + /extra\.XDG_DATA_HOME = dirname\(opencodeDbPath\(cfg\.harnessHome\)\)/.test(MAIN), + 'spawn must derive XDG_DATA_HOME from opencodeDbPath' + ); + assert.ok( + /resolveOpencodeDb: \(\) => opencodeDbPath\(readConfig\(\)\.harnessHome\)/.test(MAIN), + 'telemetry must read the same path' + ); + assert.ok( + !/join\(home, '\.opencode-data'\)/.test(MAIN), + 'the old independent XDG expression must be gone' + ); +}); + +/** A session_v2 / session_message pair shaped exactly like opencode's own. + * `sessionDir` is the agent cwd as opencode stores it (POSIX, lowercased) and + * is NOT the file location — the two differ whenever the DB is hive-scoped. */ +function seedDb(dir, sessionDir = dir) { + fs.mkdirSync(dir, { recursive: true }); + // Start from a clean file: leftover state in a temp dir must not decide + // whether this suite passes. + fs.rmSync(path.join(dir, 'opencode.db'), { force: true }); + const db = new DatabaseSync(path.join(dir, 'opencode.db')); + db.exec(`CREATE TABLE session_v2 (id TEXT PRIMARY KEY, directory TEXT, time_updated INTEGER)`); + db.exec(`CREATE TABLE session_message (id TEXT PRIMARY KEY, session_id TEXT, type TEXT, data TEXT, time_updated INTEGER)`); + const msg = (session, tokens, model, ts) => db.prepare( + `INSERT INTO session_message (id, session_id, type, data, time_updated) VALUES (?, ?, 'assistant', ?, ?)` + ).run(`${session}-${ts}`, session, JSON.stringify({ model: { id: model }, tokens }), ts); + db.prepare(`INSERT INTO session_v2 (id, directory, time_updated) VALUES (?, ?, ?)`) + .run('sess-a', sessionDir.replace(/\\/g, '/').replace(/\/+$/, '').toLowerCase(), 1000); + msg('sess-a', { input: 100, output: 20 }, 'anthropic/claude-opus-5', 2000); + msg('sess-a', { input: 50, output: 5, cache: { read: 900, write: 7 } }, 'anthropic/claude-opus-5', 3000); + db.close(); +} + +test('an agent reads its own session, not the whole directory (D11)', () => { + const cwd = path.join(os.tmpdir(), 'tsf11-cwd'); + const root = path.join(os.tmpdir(), 'tsf11-root'); + seedDb(path.join(root, '.opencode-data', 'opencode')); + // A second agent that ran in the SAME cwd — the shared-directory trap. + const db = new DatabaseSync(path.join(root, '.opencode-data', 'opencode', 'opencode.db')); + db.prepare(`INSERT INTO session_v2 (id, directory, time_updated) VALUES ('sess-b', ?, 500)`) + .run(cwd.replace(/\\/g, '/').toLowerCase()); + db.prepare(`INSERT INTO session_message (id, session_id, type, data, time_updated) VALUES ('x','sess-b','assistant',?, 900)`) + .run(JSON.stringify({ model: { id: 'other' }, tokens: { input: 999999, output: 1 } })); + db.close(); + + const u = readOpencodeUsage(cwd, { dbPath: path.join(root, '.opencode-data', 'opencode', 'opencode.db'), sessionId: 'sess-a' }); + assert.equal(u.inputTokens, 150, 'only the agent\'s own session, never the directory union'); + assert.equal(u.outputTokens, 25); + assert.equal(u.cacheReadTokens, 900); + assert.equal(u.cacheWriteTokens, 7); + assert.equal(u.lastActiveAt, 3000, 'the real last-activity stamp — Date.now() is what hid the stall'); +}); + +test('with no session id it takes the newest session in the directory, never the union', () => { + const cwd = path.join(os.tmpdir(), 'tsf11-cwd2'); + const dir = path.join(os.tmpdir(), 'tsf11-root2', '.opencode-data', 'opencode'); + seedDb(dir, cwd); + const u = readOpencodeUsage(cwd, { dbPath: path.join(dir, 'opencode.db') }); + // sess-a is the only session under this cwd, so the newest-session rule finds it. + assert.equal(u.inputTokens, 150); + assert.equal(u.model, 'anthropic/claude-opus-5'); +}); + +test('a missing or unreadable database is zero, never a throw', () => { + assert.deepEqual(readOpencodeUsage('C:/nope', { dbPath: path.join(os.tmpdir(), 'tsf11-absent.db') }).inputTokens, 0); +}); \ No newline at end of file diff --git a/test/transcript-usage.test.cjs b/test/transcript-usage.test.cjs index aa895b6a24..ee6d766e10 100644 --- a/test/transcript-usage.test.cjs +++ b/test/transcript-usage.test.cjs @@ -25,14 +25,28 @@ process.env.HOME = FAKE_HOME; process.env.USERPROFILE = FAKE_HOME; const SRC = path.join(__dirname, '..', 'src', 'main'); +const SHARED = path.join(__dirname, '..', 'src', 'shared'); const out = fs.mkdtempSync(path.join(os.tmpdir(), 'transcript-')); -for (const name of ['pricing', 'transcript']) { - const js = ts.transpileModule(fs.readFileSync(path.join(SRC, `${name}.ts`), 'utf8'), { +// Mirror the real directory layout: transcript.ts imports ./pricing AND ./fs +// (expandTilde — TSF-11), and fs.ts imports ../shared/imageTypes. Transpiling +// flat into one dir made those relative requires unresolvable, so the module +// failed to load at require() time rather than at the assertion. +const mainOut = path.join(out, 'main'); +const sharedOut = path.join(out, 'shared'); +fs.mkdirSync(mainOut); +fs.mkdirSync(sharedOut); +const transpile = (from, to) => fs.writeFileSync( + to, + ts.transpileModule(fs.readFileSync(from, 'utf8'), { compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020, esModuleInterop: true } - }).outputText; - fs.writeFileSync(path.join(out, `${name}.js`), js, 'utf8'); -} -const { readAgentUsage, projectDir } = require(path.join(out, 'transcript.js')); + }).outputText, + 'utf8' +); +transpile(path.join(SRC, 'pricing.ts'), path.join(mainOut, 'pricing.js')); +transpile(path.join(SRC, 'fs.ts'), path.join(mainOut, 'fs.js')); +transpile(path.join(SRC, 'transcript.ts'), path.join(mainOut, 'transcript.js')); +transpile(path.join(SHARED, 'imageTypes.ts'), path.join(sharedOut, 'imageTypes.js')); +const { readAgentUsage, projectDir } = require(path.join(mainOut, 'transcript.js')); /** A fake cwd whose projectDir we can write transcripts into. */ function makeProject() { From b597272ddf100fb59bcdd25a4be2231fcf833859 Mon Sep 17 00:00:00 2001 From: T3sh Date: Wed, 14 Oct 2026 13:49:00 -0300 Subject: [PATCH 13/24] feat(agent-ops): deus gere o ciclo de vida de agentes plenos O deus conseguia hirear workers efemeros (spawn-requests/) mas nao kill, reset, restore nem create de agentes cheios. Estas quatro ops passam a ser possiveis escrevendo UM ficheiro JSON em HIVE_ROOT/agent-ops/: { op: kill|reset|restore|create, id?, params?, reason } `reason` e obrigatorio em todas: quem gasta justifica, e o humano audita na aba Atividade. src/main/agentOps.ts (novo) e PURO -- sem fs, sem config, sem catalogo. Todo o contexto de que precisa (ids vivos, ids arquivados, contagem da frota, providers) chega como argumento, o que o torna testavel sem Electron. Same postura do processSpawnRequest: fechar a porta com um motivo, nunca throw. kill recusa o proprio deus; id verbatim, nunca reescrito (reescrever mataria o agente errado) reset digita o comando de clear do provider no PTY, sem tocar no roster: mesmo agente, mesmo cwd, mesma memoria, conversa nova. Recusa se o terminal produziu ha menos de 30s -- digitar no meio do output corrompe o run restore ressuscita um ARQUIVADO sob o mesmo id (memoria e inbox religam), reutilizando a command line que aquela execucao usou create exige role/cwd/provider/model + tokenCap inteiro positivo, e trava em 6 agentes plenos vivos. Se o tokenCap for rejeitado depois do spawn, o agente e morto na hora -- um spawn que o cap recusa nao pode sobreviver sem teto Sem IPC novo e sem poll. create/restore retransmitem `hive:agentSpawned` e kill transmite `hive:agentArchived`, que o useHive JA tratava; o renderer descobre o resultado pelos canais que a UI ja usava. Main nunca escreve no espelho roster.json. Duas decisoes que divergem do plano original: - restore/create honram o gate `orchestratorMaySpawn` (OFF por default), igual aos spawn-requests: deixar o orquestrador subir agentes sem pedido e uma decisao de GASTO. Com o gate OFF o ficheiro ESPERA na fila, nao falha. kill e reset nao gastam nada e correm sempre. - Falha vai para os DOIS lados: informGod (inbox do deus) E kind:'agent-op-failed' na aba Atividade. Recusa que so chega ao inbox do deus e invisivel a quem tem de decidir se reenvia -- foi o buraco que o bug #113 deixou. Testes: test/agent-ops.test.cjs cobre as 4 ops, auto-kill do deus, teto, tokenCap nao-inteiro, recusa de id desconhecido e o cursor idempotente de resultados, mais um guard de wiring que falha se o watcher nao for ligado como o dos workers. Suite: 929 -> 939 a passar (965 -> 975 testes, +10), 22 a falhar no baseline e 22 depois -- as mesmas, todas de symlink/EPERM no Windows, nenhuma tocada. agent-ops 10/10. Typecheck node e web limpos. Falta o E2E manual (Task 5): matar, resetar, restaurar, criar, estourar o teto com o deus a dirigir. --- src/main/agentOps.ts | 129 ++++++++ src/main/hive.ts | 25 ++ src/main/index.ts | 287 +++++++++++++++++- .../src/components/CommandCenterPanel.tsx | 6 + src/renderer/src/i18n/locales/ar.json | 6 +- src/renderer/src/i18n/locales/en.json | 6 +- src/renderer/src/i18n/locales/zh-CN.json | 6 +- test/agent-ops.test.cjs | 116 +++++++ test/arabic-ui.test.cjs | 8 +- 9 files changed, 582 insertions(+), 7 deletions(-) create mode 100644 src/main/agentOps.ts create mode 100644 test/agent-ops.test.cjs diff --git a/src/main/agentOps.ts b/src/main/agentOps.ts new file mode 100644 index 0000000000..6f070df60d --- /dev/null +++ b/src/main/agentOps.ts @@ -0,0 +1,129 @@ +/** + * Validation for the god-writable `HIVE_ROOT/agent-ops/` queue. + * + * The orchestrator runs lifecycle ops (kill/reset/restore/create) by writing + * ONE JSON file per op; main validates, executes, and archives it. This module + * is PURE (no fs, no config, no catalog): every context it needs — live and + * archived ids, the fleet count, known providers — arrives as arguments, so it + * is unit-testable without Electron. IO and catalog membership live in the + * main-side handler (Task 2/3), never here. + * + * Why so strict for our own orchestrator: a request file is reachable by + * anything that can write the hive dir (a compromised worker, a bad paste), + * and three of the four ops destroy or spend. Validation is the same posture + * as `processSpawnRequest`: fail closed, with a reason, never a throw. + */ + +/** Lifecycle ops god may request. `create` builds a full agent; the rest act + * on an existing id. Workers keep using `spawn-requests/` (unchanged). */ +export type AgentOpKind = 'kill' | 'reset' | 'restore' | 'create'; + +export interface AgentOpSpec { + role: string; + cwd: string; + provider: string; + model: string; + tokenCap: number; + name?: string; +} + +export interface AgentOpRequest { + op: AgentOpKind; + /** Target agent id (kill/reset/restore). Sanitized, matched exactly. */ + id: string | null; + /** Full spec (create only). Presence-checked here, catalog-checked in main. */ + params: AgentOpSpec | null; + /** Why — mandatory. Whoever spends must justify; the human audits the log. */ + reason: string; +} + +export interface AgentOpContext { + /** The god's own id: killing it is always refused. */ + godId: string | null; + /** Live agent ids (floor). */ + liveIds: string[]; + /** Archived agent ids (restorable). */ + archivedIds: string[]; + /** Live NON-worker agents (fleet cap denominator for create). */ + liveNonWorkers: number; + /** Max live non-worker agents the create op tolerates. */ + maxLiveNonWorkers: number; +} + +/** Fleet cap for god-created full agents (human-approved default). */ +export const MAX_LIVE_NON_WORKERS = 6; + +const ID_RULE = /^[A-Za-z0-9._-]{1,128}$/; + +function isRecord(v: unknown): v is Record { + return !!v && typeof v === 'object' && !Array.isArray(v); +} + +/** An id is usable only verbatim: unlike worker reqIds we never rewrite it, + * because a rewritten id would restore/kill/reset the WRONG agent. */ +export function sanitizeAgentId(id: unknown): string | null { + if (typeof id !== 'string') return null; + const t = id.trim(); + return ID_RULE.test(t) ? t : null; +} + +function nonEmptyString(v: unknown, maxLen: number): string | null { + if (typeof v !== 'string') return null; + const t = v.trim(); + if (!t || t.length > maxLen) return null; + return t; +} + +export type AgentOpValidation = + | { ok: true; value: AgentOpRequest } + | { ok: false; error: string }; + +/** + * Validate one raw request file body against the ops contract. + * Pure: context (live/archived/cap) arrives via `ctx`, never globals. + */ +export function validateAgentOp(raw: unknown, ctx: AgentOpContext): AgentOpValidation { + if (!isRecord(raw)) return { ok: false, error: 'request must be a JSON object' }; + const op = raw.op; + if (op !== 'kill' && op !== 'reset' && op !== 'restore' && op !== 'create') { + return { ok: false, error: 'unknown "op" (want kill|reset|restore|create)' }; + } + const reason = nonEmptyString(raw.reason, 500); + if (!reason) return { ok: false, error: 'missing "reason" (whoever spends must justify)' }; + + if (op === 'create') { + if (!isRecord(raw.params)) return { ok: false, error: 'create needs "params" {role,cwd,provider,model,tokenCap}' }; + const p = raw.params; + const role = nonEmptyString(p.role, 2000); + const cwd = nonEmptyString(p.cwd, 1024); + const provider = nonEmptyString(p.provider, 64); + const model = nonEmptyString(p.model, 256); + if (!role || !cwd || !provider || !model) { + return { ok: false, error: 'create params need non-empty role/cwd/provider/model' }; + } + const tokenCap = p.tokenCap; + // Integer: main persists it via setAgentTokenCap, which throws otherwise. + if (typeof tokenCap !== 'number' || !Number.isInteger(tokenCap) || tokenCap <= 0) { + return { ok: false, error: 'create needs a positive integer tokenCap (the fleet cap is mandatory)' }; + } + if (ctx.liveNonWorkers >= ctx.maxLiveNonWorkers) { + return { ok: false, error: `fleet cap reached (${ctx.liveNonWorkers}/${ctx.maxLiveNonWorkers} live non-workers)` }; + } + const name = p.name === undefined ? undefined : nonEmptyString(p.name, 64); + if (p.name !== undefined && !name) return { ok: false, error: '"name" must be a non-empty string when given' }; + return { ok: true, value: { op, id: null, params: { role, cwd, provider, model, tokenCap, ...(name ? { name } : {}) }, reason } }; + } + + const id = sanitizeAgentId(raw.id); + if (!id) return { ok: false, error: 'missing or invalid "id" (verbatim match only, never rewritten)' }; + if (op === 'kill' && ctx.godId && id === ctx.godId) { + return { ok: false, error: 'refusing to kill the god agent' }; + } + if (op === 'restore' && !ctx.archivedIds.includes(id)) { + return { ok: false, error: `"${id}" is not archived (nothing to restore)` }; + } + if ((op === 'kill' || op === 'reset') && !ctx.liveIds.includes(id)) { + return { ok: false, error: `"${id}" is not live (nothing to ${op})` }; + } + return { ok: true, value: { op, id, params: null, reason } }; +} diff --git a/src/main/hive.ts b/src/main/hive.ts index 5f9c38bffc..7ed1d584c4 100644 --- a/src/main/hive.ts +++ b/src/main/hive.ts @@ -3087,6 +3087,31 @@ request is NOT failed or deleted, it waits in \`spawn-requests/\` and runs if th If a request of yours has sat there without moving, that is why, and it is a decision to raise with the human rather than retry. Route work to an agent already on the floor first either way. +## Agent lifecycle (orchestrator) +You run the full lifecycle of full agents — not just workers — by writing ONE JSON file per op +into \`agent-ops/--.json\` in the hive root: + +\`\`\`json +{ "op": "kill | reset | restore | create", "id": "andy-mv7wi8j7", "reason": "why, concretely" } +{ "op": "create", "params": { "role": "...", "cwd": "/abs/path", "provider": "opencode", "model": "openrouter/free", "tokenCap": 200000 }, "reason": "why, concretely" } +\`\`\` + +- \`kill\` stops a live agent (same teardown as the human X). Never yourself. +- \`reset\` types the engine\u2019s clear command into a live, idle terminal: same agent, same cwd and + memory, fresh conversation. Refused while the terminal is still producing output — write again later. +- \`restore\` brings back an ARCHIVED agent under its own id, so memory and inbox reattach. Only + archived ids; it reuses the command line that run used. +- \`create\` hires a full agent. \`params\` needs role/cwd/provider/model plus a positive integer + \`tokenCap\`, and the floor holds at most 6 live non-worker agents. A spec missing a field, a + provider that does not exist, a model you have not checked, or a full floor fails with the reason + instead of spawning half a hire. +- \`reason\` is mandatory on every op: whoever spends justifies it, and the human audits it in the + activity feed. "Cleanup" is not a reason; what you removed and why is. +- Spawning ops (\`restore\`, \`create\`) honor the same operator switch as workers: while it is OFF they + wait in the queue, never fail. \`kill\`/\`reset\` spend nothing and run regardless. +- Results land in \`agent-ops/.done/\` and \`agent-ops/.failed/\`, and failures also arrive as inbox + messages. Watch them as closely as you watch \`spawn-requests/\` — reuse before you create. + ## Semantic memory (optional — when \`mempalace\` is installed) When \`MEMPALACE_PALACE_PATH\` is set in your environment, the hive shares a searchable MemPalace and you have the \`mempalace\` CLI: diff --git a/src/main/index.ts b/src/main/index.ts index 0cc017c8d6..3d49d73e37 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -63,6 +63,9 @@ import * as integrations from './integrations'; import { validateBaseUrl, buildAuthHeaders, resolveUpstreamUrl, secretRefFor, INTEGRATION_TEMPLATES } from '../shared/integrations'; import { RosterStore } from './roster'; import { buildWorkerLaunch } from './workerLaunch'; +import { validateAgentOp, MAX_LIVE_NON_WORKERS } from './agentOps'; +import { tokenizeCommand } from '../shared/commandLine'; +import { clearCommandForProvider } from '../shared/providerAutomation'; import { ControlRegistry } from './control'; import { WorkerWakeWatchdog, WORKER_WAKE_REPORT_MS, activityEvidenceAt, type WorkerWakeFacts } from './workerWake'; import { inboxNudgeText } from '../shared/hiveNudge'; @@ -75,6 +78,7 @@ import { inferAgentProvider, isClaudeProvider, nonInteractiveEnvForProvider, + normalizeAgentProvider, providerPreset, installInfoForProvider, type AgentProvider @@ -3280,7 +3284,7 @@ ipcMain.handle('config:changeHome', async (_evt, payload: unknown) => { try { clearMissionTimers(); } catch (e) { console.error('[changeHome] clearMissionTimers:', e); } try { clearContextTimers(); } catch (e) { console.error('[changeHome] clearContextTimers:', e); } try { stopWebhookDoneObserver(); } catch (e) { console.error('[changeHome] stopWebhookDoneObserver:', e); } - try { stopEphemeralWorkerWatcher(); } catch (e) { console.error('[changeHome] stopWorkerWatcher:', e); } + try { stopEphemeralWorkerWatcher(); stopAgentOpsWatcher(); } catch (e) { console.error('[changeHome] stopWorkerWatcher:', e); } try { integrationBroker.stop(); } catch (e) { console.error('[changeHome] broker.stop:', e); } try { hive.stopRouter(); } catch (e) { console.error('[changeHome] stopRouter:', e); } try { hookServer.stop(); } catch (e) { console.error('[changeHome] hookServer.stop:', e); } @@ -3780,7 +3784,7 @@ function teardownAndQuit(): void { try { clearMissionTimers(); } catch (e) { console.error('[quit] clearMissionTimers:', e); } try { clearContextTimers(); } catch (e) { console.error('[quit] clearContextTimers:', e); } try { stopWebhookDoneObserver(); } catch (e) { console.error('[quit] stopWebhookDoneObserver:', e); } - try { stopEphemeralWorkerWatcher(); } catch (e) { console.error('[quit] stopWorkerWatcher:', e); } + try { stopEphemeralWorkerWatcher(); stopAgentOpsWatcher(); } catch (e) { console.error('[quit] stopWorkerWatcher:', e); } try { integrationBroker.stop(); } catch (e) { console.error('[quit] broker.stop:', e); } try { hive.stopRouter(); } catch (e) { console.error('[quit] stopRouter:', e); } try { hookServer.stop(); } catch (e) { console.error('[quit] hookServer.stop:', e); } @@ -3841,7 +3845,7 @@ ipcMain.handle('app:resetAll', () => { try { clearMissionTimers(); } catch (e) { console.error('[reset] clearMissionTimers:', e); } try { clearContextTimers(); } catch (e) { console.error('[reset] clearContextTimers:', e); } try { stopWebhookDoneObserver(); } catch (e) { console.error('[reset] stopWebhookDoneObserver:', e); } - try { stopEphemeralWorkerWatcher(); } catch (e) { console.error('[reset] stopWorkerWatcher:', e); } + try { stopEphemeralWorkerWatcher(); stopAgentOpsWatcher(); } catch (e) { console.error('[reset] stopWorkerWatcher:', e); } try { integrationBroker.stop(); } catch (e) { console.error('[reset] broker.stop:', e); } try { hive.stopRouter(); } catch (e) { console.error('[reset] stopRouter:', e); } try { hookServer.stop(); } catch (e) { console.error('[reset] hookServer.stop:', e); } @@ -5029,6 +5033,282 @@ function stopEphemeralWorkerWatcher(): void { if (workerWatchTimer) { clearInterval(workerWatchTimer); workerWatchTimer = null; } } + +// ─── Agent lifecycle ops from god (agent-ops/) ───────────────────────────── +// Mirror of the worker spawn-request machinery, extended to full agents: god +// writes HIVE_ROOT/agent-ops/--.json {op,id?,params?,reason} and +// main validates (validateAgentOp: fail-closed, reason mandatory), executes, +// and archives .done/.failed + informs god. Outcomes surface through the +// channels hires already use (hive:agentSpawned broadcast, onExit teardown, +// kind:'restore'|'kill'|'reset' activity lines) — no new IPC, no writes into +// the renderer's roster mirror. +const AGENT_OPS_TICK_MS = 1500; +/** Reset refuses when the terminal produced output recently: typing a slash + * command mid-stream corrupts the run. God re-requests; the file never lingers. */ +const AGENT_OPS_RESET_QUIET_MS = 30_000; +let agentOpsWatchTimer: ReturnType | null = null; +let agentOpsTickRunning = false; + +function agentOpsDir(): string | null { + const root = hive.root(); + return root ? join(root, 'agent-ops') : null; +} + +function archiveAgentOpRequest(filePath: string, sub: '.done' | '.failed'): void { + const queue = agentOpsDir(); + try { + if (!queue) throw new Error('no hive root'); + const dir = join(queue, sub); + mkdirSync(dir, { recursive: true }); + renameSync(filePath, join(dir, basename(filePath))); + } catch (e) { + // Last resort: delete it so a poison file can't loop forever. + try { unlinkSync(filePath); } catch { /* noop */ } + console.error('[agent-ops] archiveRequest failed:', e); + } +} + +function startAgentOpsWatcher(): void { + if (agentOpsWatchTimer || !hive.enabled()) return; + const dir = agentOpsDir(); + if (dir) { try { mkdirSync(dir, { recursive: true }); } catch { /* noop */ } } + agentOpsWatchTimer = setInterval(() => { void agentOpsTick(); }, AGENT_OPS_TICK_MS); +} + +function stopAgentOpsWatcher(): void { + if (agentOpsWatchTimer) { clearInterval(agentOpsWatchTimer); agentOpsWatchTimer = null; } +} + +function agentOpsDisplayName(id: string): string { + try { + const rec = (hive.registry()?.agents ?? {})[id] as { name?: unknown } | undefined; + return typeof rec?.name === 'string' && rec.name ? rec.name : id; + } catch { return id; } +} + +async function agentOpsTick(): Promise { + if (agentOpsTickRunning) return; + agentOpsTickRunning = true; + try { + const dir = agentOpsDir(); + if (!dir || !hive.enabled()) return; + // Spawning ops honor the operator's orchestratorMaySpawn gate, exactly + // like spawn-requests: letting the orchestrator spin up agents unprompted + // is a SPEND decision. kill/reset spend nothing and run regardless. Files + // that cannot run stay queued — never failed for a reason god never asked + // about. (Kill/reset are filtered per-file below, so one op kind never + // blocks files of the other kinds behind it.) + const maySpawn = readConfig().orchestratorMaySpawn === true; + let files: string[]; + try { files = readdirSync(dir).filter((f) => f.endsWith('.json')); } catch { return; } + for (const f of files) await processAgentOpRequest(join(dir, f), maySpawn); + } finally { agentOpsTickRunning = false; } +} + +async function processAgentOpRequest(filePath: string, maySpawn: boolean): Promise { + let raw: unknown; + try { raw = JSON.parse(readFileSync(filePath, 'utf8')); } catch (e) { + informGod('[agent-op rejected] unparseable request', `Could not parse agent-ops ${basename(filePath)} — ${String(e)}`); + archiveAgentOpRequest(filePath, '.failed'); + return; + } + const reg = hive.registry(); + const agents = (reg?.agents ?? {}) as Record; + const ids = Object.keys(agents); + const liveIds = ids.filter((id) => ptyForAgent(id)); + const archivedIds = ids.filter((id) => agents[id]?.archived === true); + const v = validateAgentOp(raw, { + godId: typeof reg?.godId === 'string' ? reg.godId : null, + liveIds, + archivedIds, + liveNonWorkers: liveIds.filter((id) => !liveWorkers.has(id)).length, + maxLiveNonWorkers: MAX_LIVE_NON_WORKERS + }); + if (!v.ok) { + informGod(`[agent-op rejected] ${v.error}`, `Agent-ops ${basename(filePath)} rejected: ${v.error}.`); + try { + // The op may be missing/garbage too; render whatever was actually there. + const rawOp = typeof (raw as { op?: unknown } | null)?.op === 'string' ? (raw as { op: string }).op : 'op'; + hive.appendLog({ kind: 'agent-op-failed', op: rawOp, reason: v.error }); + } catch { /* noop */ } + archiveAgentOpRequest(filePath, '.failed'); + return; + } + const req = v.value; + // Spawning ops wait out the orchestratorMaySpawn gate (letting the + // orchestrator spin up agents unprompted is a SPEND decision, same as + // spawn-requests); kill/reset spend nothing and run regardless. Skipped + // files stay queued — never failed for a reason god never asked about. + if (!maySpawn && (req.op === 'restore' || req.op === 'create')) return; + const fail = (reason: string): void => { + informGod( + `[agent-op ${req.op} rejected] ${reason}`, + `Agent-ops ${basename(filePath)} (${req.op}${req.id ? ` ${req.id}` : ''}) rejected: ${reason}.` + ); + // god hears about it in his inbox; the HUMAN reads the activity feed. A + // refusal that only lands in an agent's inbox is invisible to the operator + // who has to decide whether to re-ask — the same gap bug #113 left behind. + try { + hive.appendLog({ + kind: 'agent-op-failed', op: req.op, agentId: req.id, + name: req.id ? agentOpsDisplayName(req.id) : undefined, reason + }); + } catch { /* noop */ } + archiveAgentOpRequest(filePath, '.failed'); + }; + + // ── kill: same teardown as the human X (renderer learns via onExit) ── + if (req.op === 'kill') { + const id = req.id!; + const ptyId = ptyForAgent(id); + if (!ptyId) { fail(`"${id}" has no live pty`); return; } + try { ptyManager.kill(ptyId); } catch (e) { fail(`kill failed: ${String(e)}`); return; } + try { teardownPty(ptyId); } catch (e) { console.error('[agent-ops] teardownPty failed:', e); } + try { hive.setArchived(id, true); } catch (e) { console.error('[agent-ops] setArchived failed:', e); } + try { liveWebContents()?.send('hive:agentArchived', { id }); } catch { /* window torn down */ } + try { hive.appendLog({ kind: 'kill', agentId: id, name: agentOpsDisplayName(id) }); } catch { /* noop */ } + archiveAgentOpRequest(filePath, '.done'); + return; + } + + // ── reset: type the provider's clear verb into the live PTY. No roster or + // PTY change — the conversation restarts in place, id/cwd/memory intact. + if (req.op === 'reset') { + const id = req.id!; + const rec = agents[id] as { provider?: unknown } | undefined; + const provider = normalizeAgentProvider(rec?.provider); + const cmd = provider ? clearCommandForProvider(provider) : null; + if (!cmd) { fail('no clear command for this agent\'s engine — kill and respawn instead'); return; } + const ptyId = ptyForAgent(id); + if (!ptyId) { fail(`"${id}" has no live pty`); return; } + const idle = ptyManager.idleFor(ptyId) ?? Infinity; + if (idle < AGENT_OPS_RESET_QUIET_MS) { + fail(`agent busy (${Math.round(idle / 1000)}s since output) — write the request again later`); + return; + } + const wrote = ptyManager.write(ptyId, cmd + '\r'); + if (!wrote || (typeof wrote === 'object' && !wrote.ok)) { fail('pty write failed'); return; } + try { hive.appendLog({ kind: 'reset', agentId: id, name: agentOpsDisplayName(id) }); } catch { /* noop */ } + archiveAgentOpRequest(filePath, '.done'); + return; + } + + // ── restore: respawn an archived agent under its own id. Reuses the stored + // command verbatim (same flags/model as the run that worked); memory and + // inbox reattach by id on disk. ensureAgent (inside spawnAgentCore) + // un-archives the registry entry and preserves the recorded session id. + if (req.op === 'restore') { + const id = req.id!; + const rec = readArchivedRecord(id); + if (!rec) { fail(`no archived record for "${id}"`); return; } + if (!existsSync(rec.cwd)) { fail(`cwd gone (${rec.cwd})`); return; } + const tokens = tokenizeCommand(rec.command); + const bin = tokens[0] ?? ''; + if (!bin) { fail('empty stored command'); return; } + if (!isSafeCommandName(bin) && !isAbsolute(bin)) { + fail(`refusing spawn: engine command "${bin}" is not a plain command name or an absolute path`); + return; + } + if (!ptyManager.isCommandAvailable(bin)) { fail(`engine CLI "${bin}" is not installed`); return; } + const provider = normalizeAgentProvider(rec.provider) ?? inferAgentProvider(tokens.join(' '), undefined); + if (!provider) { fail('unknown provider in archived record'); return; } + let res: { ok: boolean; error?: string }; + try { + res = await spawnAgentCore({ + id, cwd: rec.cwd, command: bin, args: tokens.slice(1), + cols: 100, rows: 30, + hive: { id, name: rec.name, provider, cwd: rec.cwd, role: rec.role }, + isolate: false, resume: true, provider + }, null); + } catch (e) { res = { ok: false, error: String(e) }; } + if (!res.ok) { fail(`spawn failed — ${res.error ?? 'unknown error'}`); return; } + try { + liveWebContents()?.send('hive:agentSpawned', { + id, name: rec.name, provider, cwd: rec.cwd, command: rec.command, + role: rec.role, character: rec.character, accent: rec.accent + }); + } catch { /* window torn down */ } + try { hive.appendLog({ kind: 'restore', agentId: id, name: rec.name }); } catch { /* noop */ } + archiveAgentOpRequest(filePath, '.done'); + return; + } + + // ── create: a full agent from an explicit spec. Fleet cap rechecked here + // (the fleet moved since validation seconds ago). Mirrors the worker launch + // translation (provider default command + model flag + auto stance). + const spec = req.params!; + const provider = normalizeAgentProvider(spec.provider); + if (!provider) { fail(`unknown provider "${spec.provider}"`); return; } + if (!existsSync(spec.cwd)) { fail(`cwd missing (${spec.cwd})`); return; } + const freshLive = Object.keys((hive.registry()?.agents ?? {})).filter((x) => ptyForAgent(x)); + const freshNonWorkers = freshLive.filter((x) => !liveWorkers.has(x)).length; + if (freshNonWorkers >= MAX_LIVE_NON_WORKERS) { + fail(`fleet cap reached (${freshNonWorkers}/${MAX_LIVE_NON_WORKERS} live non-workers)`); + return; + } + const slug = (spec.name ?? 'agent').toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '') || 'agent'; + const id = `${slug}-${Date.now().toString(36)}`; + if (freshLive.includes(id)) { fail('id collision — write the request again'); return; } + const cfg = readConfig(); + const launch = buildWorkerLaunch({ + requestProvider: provider, requestModel: spec.model, + defaultCommand: cfg.defaultCommand, autoMode: !!cfg.autoMode + }); + const name = spec.name?.trim() ? spec.name.trim() : id; + let res: { ok: boolean; error?: string }; + try { + res = await spawnAgentCore({ + id, cwd: spec.cwd, command: launch.bin, args: launch.args, + cols: 120, rows: 32, + hive: { id, name, provider, cwd: spec.cwd, role: spec.role }, + isolate: true, resume: false, provider + }, null); + } catch (e) { res = { ok: false, error: String(e) }; } + if (!res.ok) { fail(`spawn failed — ${res.error ?? 'unknown error'}`); return; } + // The cap is the gate: a spawn the cap rejects must not survive uncapped. + try { setAgentTokenCap(id, spec.tokenCap); } catch (e) { + try { const p = ptyForAgent(id); if (p) { ptyManager.kill(p); teardownPty(p); } } catch { /* best-effort */ } + fail(`spawned but token cap rejected (${String(e)}) — agent removed`); + return; + } + try { + liveWebContents()?.send('hive:agentSpawned', { + id, name, provider, cwd: spec.cwd, command: launch.command, role: spec.role + }); + } catch { /* window torn down */ } + // ensureAgent already logged kind:'spawn' ("spawned X") — reuse it, no new line. + archiveAgentOpRequest(filePath, '.done'); +} + +/** Archived UI-mirror record with the fields a respawn needs. The roster file + * is read-only here: the renderer owns its writes, main only looks. */ +function readArchivedRecord(id: string): { + command: string; provider: unknown; cwd: string; name: string; + role: string; character?: string; accent?: string; +} | null { + try { + const snap = roster.read(); + const list = snap?.archived; + if (!Array.isArray(list)) return null; + const rec = list.find((e) => (e as { id?: unknown })?.id === id) as Record | undefined; + if (!rec) return null; + const str = (v: unknown): string | null => typeof v === 'string' && v.trim() ? v : null; + const command = str(rec.command); + const cwd = str(rec.cwd); + const name = str(rec.name) ?? id; + if (!command || !cwd) return null; + const goal = str((rec as { goal?: unknown }).goal); + return { + command, cwd, name, + provider: rec.provider, + role: str(rec.description) ?? goal ?? name, + character: typeof rec.character === 'string' ? rec.character : undefined, + accent: typeof rec.accent === 'string' ? rec.accent : undefined + }; + } catch { return null; } +} + + /** Snapshot of one live ephemeral worker for the renderer Workers tab. */ interface WorkerSnapshot { workerId: string; @@ -5137,6 +5417,7 @@ function bootstrapHiveServices(): void { archiveOrphanedAgents(); // #57/#58: archive stale archived:false entries with no live PTY hive.startRouter(); startEphemeralWorkerWatcher(); // poll HIVE_ROOT/spawn-requests → ephemeral workers + startAgentOpsWatcher(); // poll HIVE_ROOT/agent-ops → lifecycle ops (kill/reset/restore/create) // Phase 2: the loopback secret broker. Bind it BEFORE workers spawn so each spawn can // be granted a capability token + the broker URL in its env. Loopback-only, idempotent. void integrationBroker.start().then((r) => { diff --git a/src/renderer/src/components/CommandCenterPanel.tsx b/src/renderer/src/components/CommandCenterPanel.tsx index 60806ebce5..e1ca1a3cc6 100644 --- a/src/renderer/src/components/CommandCenterPanel.tsx +++ b/src/renderer/src/components/CommandCenterPanel.tsx @@ -1276,6 +1276,12 @@ function ActivityTab() { case 'drain': return t('commandCenter.logDrain', { agent: e.agentId, count: e.count }); case 'escalate': return t('commandCenter.logEscalate', { subject: e.subject ?? '' }); case 'approval': return e.approve ? t('commandCenter.logApprovalGranted') : t('commandCenter.logApprovalDenied'); + case 'restore': return t('commandCenter.logRestored', { name: e.name ?? e.agentId }); + case 'kill': return t('commandCenter.logKilled', { name: e.name ?? e.agentId }); + case 'reset': return t('commandCenter.logReset', { name: e.name ?? e.agentId }); + case 'agent-op-failed': return t('commandCenter.logOpFailed', { + op: e.op ?? '', name: e.name ?? e.agentId ?? '', reason: e.reason ?? '' + }); default: return JSON.stringify(e); } }; diff --git a/src/renderer/src/i18n/locales/ar.json b/src/renderer/src/i18n/locales/ar.json index fe74ab7ebc..b8e1409d7e 100644 --- a/src/renderer/src/i18n/locales/ar.json +++ b/src/renderer/src/i18n/locales/ar.json @@ -472,7 +472,11 @@ "openIssue": "مشكلة GitHub رقم {{num}}: {{title}}", "deliveryResumeAria": "استأنف التسليم التلقائي للأرضية كلها", "deliveryHoldAria": "احتجز التسليم التلقائي للأرضية كلها", - "openIdeAria": "افتح بيئة التطوير" + "openIdeAria": "افتح بيئة التطوير", + "logRestored": "{{name}} restored", + "logKilled": "stopped {{name}}", + "logReset": "reset {{name}}", + "logOpFailed": "{{op}} {{name}} refused: {{reason}}" }, "addAgent": { "title": "إضافة وكيل", diff --git a/src/renderer/src/i18n/locales/en.json b/src/renderer/src/i18n/locales/en.json index 68aac27438..28241b6209 100644 --- a/src/renderer/src/i18n/locales/en.json +++ b/src/renderer/src/i18n/locales/en.json @@ -472,7 +472,11 @@ "openIssue": "GitHub Issue #{{num}}: {{title}}", "deliveryResumeAria": "Resume automatic delivery for the whole floor", "deliveryHoldAria": "Hold automatic delivery for the whole floor", - "openIdeAria": "Open the IDE" + "openIdeAria": "Open the IDE", + "logRestored": "{{name}} restored", + "logKilled": "stopped {{name}}", + "logReset": "reset {{name}}", + "logOpFailed": "{{op}} {{name}} refused: {{reason}}" }, "addAgent": { "title": "ADD AGENT", diff --git a/src/renderer/src/i18n/locales/zh-CN.json b/src/renderer/src/i18n/locales/zh-CN.json index 0db2c7f25d..417dcaa687 100644 --- a/src/renderer/src/i18n/locales/zh-CN.json +++ b/src/renderer/src/i18n/locales/zh-CN.json @@ -472,7 +472,11 @@ "openIssue": "GitHub Issue #{{num}}:{{title}}", "deliveryResumeAria": "恢复整个楼层的自动投递", "deliveryHoldAria": "暂停整个楼层的自动投递", - "openIdeAria": "打开 IDE" + "openIdeAria": "打开 IDE", + "logRestored": "{{name}} restored", + "logKilled": "stopped {{name}}", + "logReset": "reset {{name}}", + "logOpFailed": "{{op}} {{name}} refused: {{reason}}" }, "addAgent": { "title": "添加智能体", diff --git a/test/agent-ops.test.cjs b/test/agent-ops.test.cjs new file mode 100644 index 0000000000..c43b1d8fd7 --- /dev/null +++ b/test/agent-ops.test.cjs @@ -0,0 +1,116 @@ +// agent-ops validation contract (fork: orchestrator lifecycle ops). +// Pure module — no Electron, no fs. Follows the repo's text-test style but +// drives the real parser via load-ts like workerLaunch/model-catalog do. +'use strict'; + +const assert = require('node:assert/strict'); +const { test } = require('node:test'); +const loadTs = require('./load-ts.cjs'); + +const { + validateAgentOp, + sanitizeAgentId, + MAX_LIVE_NON_WORKERS +} = loadTs('src/main/agentOps.ts'); +const fs = require('node:fs'); +const path = require('node:path'); +const MAIN = fs.readFileSync(path.join(__dirname, '..', 'src', 'main', 'index.ts'), 'utf8'); + +const CTX = { + godId: 'god', + liveIds: ['god', 'andy-mv7wi8j7'], + archivedIds: ['andy-old'], + liveNonWorkers: 2, + maxLiveNonWorkers: MAX_LIVE_NON_WORKERS +}; + +test('fleet cap default is the approved 6', () => { + assert.equal(MAX_LIVE_NON_WORKERS, 6); +}); + +test('non-objects and unknown ops fail closed', () => { + for (const raw of [null, [], 'kill', 42, {}, { op: 'nuke', id: 'x', reason: 'y' }]) { + const r = validateAgentOp(raw, CTX); + assert.equal(r.ok, false, `must refuse ${JSON.stringify(raw)}`); + } +}); + +test('reason is mandatory on every op', () => { + const r = validateAgentOp({ op: 'kill', id: 'andy-mv7wi8j7' }, CTX); + assert.equal(r.ok, false); + assert.match(r.error, /reason/); +}); + +test('god auto-kill is refused', () => { + const r = validateAgentOp({ op: 'kill', id: 'god', reason: 'scale down' }, CTX); + assert.equal(r.ok, false); + assert.match(r.error, /god/); +}); + +test('ids match verbatim, never rewritten', () => { + assert.equal(sanitizeAgentId('andy-mv7wi8j7'), 'andy-mv7wi8j7'); + for (const bad of ['../x', 'a/b', '', 'x'.repeat(129), 7, null]) { + assert.equal(sanitizeAgentId(bad), null, `must reject ${JSON.stringify(bad)}`); + } + const r = validateAgentOp({ op: 'kill', id: 'andy-missing', reason: 'stale' }, CTX); + assert.equal(r.ok, false); + assert.match(r.error, /not live/); +}); + +test('restore needs an archived id', () => { + const ok = validateAgentOp({ op: 'restore', id: 'andy-old', reason: 'recovered' }, CTX); + assert.equal(ok.ok, true); + const bad = validateAgentOp({ op: 'restore', id: 'andy-mv7wi8j7', reason: 'oops' }, CTX); + assert.equal(bad.ok, false); + assert.match(bad.error, /not archived/); +}); + +test('reset needs a live id', () => { + const ok = validateAgentOp({ op: 'reset', id: 'andy-mv7wi8j7', reason: 'stuck loop' }, CTX); + assert.equal(ok.ok, true); + assert.equal(validateAgentOp({ op: 'reset', id: 'andy-old', reason: 'x' }, CTX).ok, false); +}); + +test('create needs full spec plus tokenCap, and honors the fleet cap', () => { + const spec = { role: 'SRE', cwd: 'Z:\\proj', provider: 'opencode', model: 'openrouter/free', tokenCap: 100000 }; + const ok = validateAgentOp({ op: 'create', params: spec, reason: 'cover nights' }, CTX); + assert.equal(ok.ok, true); + assert.deepEqual(ok.value.params, spec); + const noCap = validateAgentOp( + { op: 'create', params: { ...spec, tokenCap: undefined }, reason: 'x' }, CTX); + assert.equal(noCap.ok, false); + assert.match(noCap.error, /tokenCap/); + const fracCap = validateAgentOp( + { op: 'create', params: { ...spec, tokenCap: 150000.5 }, reason: 'x' }, CTX); + assert.equal(fracCap.ok, false); + assert.match(fracCap.error, /tokenCap/); + const full = validateAgentOp({ op: 'create', params: spec, reason: 'x' }, + { ...CTX, liveNonWorkers: MAX_LIVE_NON_WORKERS }); + assert.equal(full.ok, false); + assert.match(full.error, /fleet cap/); +}); + +test('main wires the agent-ops watcher like the worker one', () => { + for (const needle of [ + 'startAgentOpsWatcher(); // poll HIVE_ROOT/agent-ops', + 'async function processAgentOpRequest', + 'validateAgentOp(raw,', + 'archiveAgentOpRequest(filePath', + 'stopAgentOpsWatcher()' + ]) assert.ok(MAIN.includes(needle), 'missing: ' + needle); + for (const op of ['kill', 'reset', 'restore', 'create']) { + assert.ok(MAIN.includes("req.op === '" + op + "'"), 'missing op branch: ' + op); + } +}); + +test('every refusal is visible to the human, not only to god', () => { + // god gets the inbox message; the operator gets the activity feed. Both + // paths must exist, or a refusal is invisible to whoever has to re-ask. + assert.ok(MAIN.includes("kind: 'agent-op-failed'"), 'refusal never reaches the activity feed'); + assert.ok(MAIN.includes("archiveAgentOpRequest(filePath, '.failed')"), 'refusal never clears the queue'); + // The spawning ops must respect the same operator switch as workers. + assert.ok( + MAIN.includes("!maySpawn && (req.op === 'restore' || req.op === 'create')"), + 'create/restore ignore the orchestratorMaySpawn gate' + ); +}); diff --git a/test/arabic-ui.test.cjs b/test/arabic-ui.test.cjs index a2c859da45..a6a9f4ddb3 100644 --- a/test/arabic-ui.test.cjs +++ b/test/arabic-ui.test.cjs @@ -211,7 +211,13 @@ test('no Arabic string is left as its English source', () => { 'addAgent.projectPlaceholder', // /path/to/your/project — a filesystem path 'onboarding.home.placeholder', // /path/to/HarnessAgents — same 'mcpDefaults.toggleNote', // "{{id}}: {{state}}" — pure interpolation - 'webhooksSection.summary' // "{{count}} · {{state}}" — same + 'webhooksSection.summary', // "{{count}} · {{state}}" — same + // FORK agent-ops (pending translator): activity lines for god-driven + // lifecycle ops. Same rule as above — English here equals the fallback. + 'commandCenter.logRestored', + 'commandCenter.logKilled', + 'commandCenter.logReset', + 'commandCenter.logOpFailed' ]); const e = pathsOf(en), a = pathsOf(ar); const untranslated = []; From 9779f19c02511ace8c19b0cd4da5ad265788b0ca Mon Sep 17 00:00:00 2001 From: T3sh Date: Thu, 22 Oct 2026 10:48:06 -0300 Subject: [PATCH 14/24] fix(opencode): decode npm .cmd shims that target %%VAR%% env paths The hand-edited %APPDATA%\npm\opencode.cmd that points at the OpenCode desktop V2 CLI through %LOCALAPPDATA% used to fall out of the shim parser to the cmd.exe route, where the 8191-char ceiling gutted the multi-line --prompt hive brief ('Linha de comando muito longa', exit 1). expand() now resolves well-formed %VAR% tokens against the real environment; undefined variables still refuse (never resolves to garbage). +2 tests pinning the exact hand-authored shape. --- src/main/pty.ts | 25 ++++++++++++++++++++--- test/win-cmd-shim.test.cjs | 42 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 3 deletions(-) diff --git a/src/main/pty.ts b/src/main/pty.ts index 5c1a03a040..2e6eda7689 100644 --- a/src/main/pty.ts +++ b/src/main/pty.ts @@ -220,8 +220,9 @@ const SHIM_SCRIPT_EXT = /\.(?:c|m)?js$/i; * PATH/candidate-dir resolution and cache. * * Returns null — meaning "fall back to the cmd.exe path" — for ANY shape that is - * not fully understood: unknown interpreter, unexpanded `%VAR%` left in the target, - * a relative target, extra interpreter flags we would otherwise silently drop, a + * not fully understood: unknown interpreter, an UNRESOLVABLE `%VAR%` left in the + * target (defined %VAR% environment variables ARE resolved — see expand), a + * relative target, extra interpreter flags we would otherwise silently drop, a * non-JS target, a file too large to be a shim, or plain garbage. */ export function parseNpmCmdShim(shimPath: string, content: string): NpmShimTarget | null { @@ -238,9 +239,27 @@ export function parseNpmCmdShim(shimPath: string, content: string): NpmShimTarge /** Expand a shim token's `%~dp0` / `%dp0%` (the shim's OWN directory, which cmd * expands WITH a trailing backslash) into an absolute, normalized path. Any - * other surviving `%` means a variable we did not model → refuse. */ + * other surviving `%` means a variable we did not model → refuse. + * + * Exception: well-formed `%NAME%` environment variables ARE resolved — + * against the ACTUAL environment of this process. A hand-authored shim (the + * user's own `%APPDATA%\npm\opencode.cmd` edit is the live case) targets an + * INSTALLED executable via `"%LOCALAPPDATA%\Programs\@opencodedesktop\ + * resources\opencode-cli.exe" %*` — one quoted token, a direct-executable + * shape just below. Refusing every surviving `%VAR%` forced that shim down + * the cmd.exe route, and cmd.exe's 8191-char ceiling gutted the multi-line + * `--prompt` hive brief ("Linha de comando muito longa", exit 1). An env path + * is no less trustworthy than the `%dp0%` expansion we already accept: cmd + * itself would resolve it the same way at run time. A variable the + * environment does not define is still refused (undefined vars stay `%` + * -marked and trip the refusal below), so an environment-based shape never + * silently degrades. */ const expand = (raw: string): string | null => { let s = raw.replace(/%~dp0%?|%dp0%/gi, `${dir}\\`); + s = s.replace(/%([A-Za-z0-9_]+)%/g, (varToken, name) => { + const value = process.env[name]; + return typeof value === 'string' ? value : varToken; + }); if (s.includes('%')) return null; if (!s.trim()) return null; // `\` + `\node_modules\…` produces a doubled separator that Windows diff --git a/test/win-cmd-shim.test.cjs b/test/win-cmd-shim.test.cjs index 5fbfc139a5..8227d099a3 100644 --- a/test/win-cmd-shim.test.cjs +++ b/test/win-cmd-shim.test.cjs @@ -25,6 +25,7 @@ const test = require('node:test'); const assert = require('node:assert/strict'); +const { win32 } = require('node:path'); const loadTs = require('./load-ts.cjs'); const { parseNpmCmdShim, buildCmdCommandLine, PtyManager } = loadTs('src/main/pty.ts'); @@ -328,3 +329,44 @@ test('an interpreter-less shim pointing at a NON-executable is still refused', ( const odd = DIRECT_EXE_SHIM.replace('opencode.exe', 'opencode.txt'); assert.equal(parseNpmCmdShim('C:\\npm\\opencode.cmd', odd), null); }); + +// The HAND-AUTHORED shim cased lived: %APPDATA%\npm\opencode.cmd rewritten to +// target the OpenCode desktop app's CLI through %LOCALAPPDATA%. The exec line is +// the "direct executable" shape; the only thing blocking it was expand() refusing +// any surviving %VAR%. Resolving env vars turns this into CreateProcess's 32767 +// ceiling instead of cmd.exe's 8191 ("Linha de comando muito longa", exit 1). +const HAND_EDITED_SHIM = [ + '@ECHO off', + 'REM Aponta para o binario do app de desktop OpenCode (V2).', + 'REM O V2 nao e\' publicado no npm, entao so o app de desktop o fornece.', + '"%LOCALAPPDATA%\\Programs\\@opencodedesktop\\resources\\opencode-cli.exe" %*' +].join('\r\n'); + +test('a hand-authored %VAR% shim resolves the env var and executes direct', () => { + // Host-independent on purpose: the test DEFINES its own variable instead of + // relying on the host having %LOCALAPPDATA% — parseNpmCmdShim reads + // process.env at call time, matching what cmd would resolve at run time. + process.env.MD_TEST_SHIM_ROOT = 'C:\\Users\\r\\AppData\\Local'; + try { + const shim = HAND_EDITED_SHIM.replace('%LOCALAPPDATA%', '%MD_TEST_SHIM_ROOT%'); + const t = parseNpmCmdShim('C:\\Users\\r\\AppData\\Roaming\\npm\\opencode.cmd', shim); + assert.ok(t, 'a hand-edited V2-pointer shim must be understood'); + assert.equal(t.interpreter, null, 'no interpreter — the CLI binary runs directly'); + assert.equal( + t.scriptPath, + win32.normalize('C:\\Users\\r\\AppData\\Local\\Programs\\@opencodedesktop\\resources\\opencode-cli.exe'), + 'the %VAR% token is expanded against the real environment' + ); + } finally { + delete process.env.MD_TEST_SHIM_ROOT; + } +}); + +test('an UNDEFINED env var in a shim target is still refused, never resolved to garbage', () => { + const broken = HAND_EDITED_SHIM.replace('%LOCALAPPDATA%', '%MD_TEST_NO_SUCH_VAR_92%'); + assert.equal( + parseNpmCmdShim('C:\\Users\\r\\AppData\\Roaming\\npm\\opencode.cmd', broken), + null, + 'an undefined variable keeps the old refusal semantics' + ); +}); From 7925ecbd0df9002eb84353d9401ed994d30263ba Mon Sep 17 00:00:00 2001 From: T3sh Date: Thu, 22 Oct 2026 10:48:18 -0300 Subject: [PATCH 15/24] fix(status): read OpenCode's TUI as 'working', not only Claude's MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The PTY status parser only recognised Claude Code's 'esc to interrupt' footer and ●-tool lines, so every OpenCode agent drifted to the 4s idle timer mid-turn and read 'ocioso' while actively streaming. Now the OpenCode busy footer ('esc stop · …') and its 'Thinking:' reasoning blocks count as mid-turn heartbeats. Over-pinning is still impossible: the floor-wide 12s lastOutputAt quiescence sweep remains the backstop. --- src/renderer/src/hooks/usePtyParser.ts | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/renderer/src/hooks/usePtyParser.ts b/src/renderer/src/hooks/usePtyParser.ts index 089481b44e..8d6fb246ce 100644 --- a/src/renderer/src/hooks/usePtyParser.ts +++ b/src/renderer/src/hooks/usePtyParser.ts @@ -102,8 +102,14 @@ export function usePtyParser(agentId: string) { } } - // The "esc to interrupt" footer is only shown while a turn is in progress. - const running = /esc to interrupt/i.test(text); + // A turn in progress, by the TUI's own footer: + // Claude Code → "esc to interrupt" + // OpenCode (v2) → "esc stop · Build · · (<%)>" + // Both only render while the model is generating (an idle OpenCode TUI shows + // different hints, and an idle Claude shows no footer at all). The parser + // used to know only the Claude form, so every OpenCode agent drifted to the + // 4s idle timer mid-turn and read "ocioso" while actively thinking. + const running = /esc\s+(?:to\s+interrupt|stop\b)/i.test(text); let lastTool: string | null = null; let lastArg: string | null = null; @@ -139,7 +145,11 @@ export function usePtyParser(agentId: string) { // Actively running but no fresh tool line (model is thinking / streaming // prose) → keep the agent working at its desk, don't let it drift to idle. - if (running) { + // OpenCode's TUI also streams italic "Thinking: …" blocks between output + // bursts (its model's reasoning made visible) — a chunk carrying one is a + // mid-turn heartbeat even when no footer repainted this frame. + const thinking = /\bThinking:/i.test(text); + if (running || thinking) { cancelIdle(); updateAgent(agentId, { status: 'working' }); return; From a23f971135dffcaefc0b6d2218f811cdfc7ecaa4 Mon Sep 17 00:00:00 2001 From: T3sh Date: Thu, 22 Oct 2026 10:48:19 -0300 Subject: [PATCH 16/24] =?UTF-8?q?feat(god):=20config.godCommand=20?= =?UTF-8?q?=E2=80=94=20full=20override=20of=20the=20god's=20spawn=20comman?= =?UTF-8?q?d?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mirrors upstream 0.5.6+ so the god can run engines whose presets cannot express the right shape (the OpenCode desktop V2 CLI rejects --model, which buildSpawnCommand unconditionally emits from godModel). The hive injection (OPENCODE_CONFIG_CONTENT, hooks plugin, --prompt seed) still applies on top — only the BASE command is overridden. --- src/main/config.ts | 9 +++++++++ src/renderer/src/store/config.ts | 3 +++ 2 files changed, 12 insertions(+) diff --git a/src/main/config.ts b/src/main/config.ts index f66c854c15..40be32f077 100644 --- a/src/main/config.ts +++ b/src/main/config.ts @@ -202,6 +202,15 @@ export interface HarnessConfig { orchestratorMaySpawn: boolean; /** The command we run when spawning a new agent. */ defaultCommand: string; + /** Optional FULL override of the GOD orchestrator's spawn command (mirrors + * upstream 0.5.6+). Wins over godProvider/godModel entirely — the renderer's + * god respawn uses it verbatim (tokens split like a shell line). Use it when + * the god's engine needs a shape the preset cannot express, e.g. pointing at + * the OpenCode desktop CLI's minimal TUI: + * "C:\...\opencode-cli.exe mini". The hive injection (OPENCODE_CONFIG_CONTENT, + * hooks plugin, --prompt seed) still applies on top — only the BASE command is + * overridden. */ + godCommand?: string; /** Default model for newly spawned agents (e.g. 'claude-sonnet-4-6[1m]'); unset = CLI default. */ defaultModel?: string; /** Which provider powers the GOD orchestrator ("Michael"). The persona is diff --git a/src/renderer/src/store/config.ts b/src/renderer/src/store/config.ts index 4f11435af8..3ce3c390d6 100644 --- a/src/renderer/src/store/config.ts +++ b/src/renderer/src/store/config.ts @@ -70,6 +70,9 @@ export interface HarnessConfig { * so an absent value reads as off. Mirrors src/main/config.ts. */ orchestratorMaySpawn?: boolean; defaultCommand: string; + /** Optional FULL override of the GOD orchestrator's spawn command (mirrors + * src/main/config.ts / upstream 0.5.6+). Wins over godProvider/godModel. */ + godCommand?: string; /** Default model for newly spawned agents (e.g. 'claude-sonnet-4-6[1m]'); unset = CLI default. */ defaultModel?: string; /** Which provider+model powers the GOD orchestrator ("Michael"). Default From e9aafbdb0e63b97aa3e6b65dbe8cce575342ef78 Mon Sep 17 00:00:00 2001 From: T3sh Date: Thu, 22 Oct 2026 10:48:31 -0300 Subject: [PATCH 17/24] fix(transcript): read opencode.db with better-sqlite3, not node:sqlite node:sqlite only exists on Node >= 22 (Electron 39+); the packaged 0.5.7 upstream actually ships Electron 32.3.3, where importing it crashes the main process at boot. better-sqlite3 is rebuilt against the running Electron's ABI by electron-rebuild (same driver the persist store uses), its require() does not dlopen until instantiated, and the prepare/all/get/close API is a near drop-in for this read-only reader. Usage semantics unchanged: newest-session-only aggregation (D11). --- src/main/transcript.ts | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/main/transcript.ts b/src/main/transcript.ts index a91ee6d1c9..933df49e38 100644 --- a/src/main/transcript.ts +++ b/src/main/transcript.ts @@ -1,7 +1,16 @@ import { closeSync, cpSync, existsSync, fstatSync, mkdirSync, openSync, readSync, readdirSync, readFileSync, statSync } from 'node:fs'; import os from 'node:os'; import path from 'node:path'; -import { DatabaseSync } from 'node:sqlite'; +// better-sqlite3, NOT node:sqlite — on purpose. node:sqlite only exists on the +// Node >= 22 that Electron 39 embeds, but a better-sqlite3 binary is rebuilt +// against the RUNNING Electron's ABI by electron-rebuild (the same one the +// persist store uses, src/main/db.ts). Under Electron 32 — the version the +// packaged 0.5.7 upstream actually ships — node:sqlite does not exist at all, +// and importing it statically crashed the main process at boot (from the start). +// The query API (prepare/all/get/close) is nearly identical; only constructor +// naming differs (readOnly → readonly). +import type BetterSqlite3 from 'better-sqlite3'; +import Database from 'better-sqlite3'; import { estimateCostUsd, normalizeModel } from './pricing'; import { expandTilde } from './fs'; @@ -358,11 +367,16 @@ function readFileUsage(dir: string, file: string): FileUsageEntry | null { */ export function readOpencodeUsage(cwd: string, opts: ReadUsageOptions = {}): AgentUsage { const usage = zero(); - let db: DatabaseSync | undefined; + let db: BetterSqlite3.Database | undefined; try { const dbPath = opts.dbPath ?? opencodeDbPath(); if (!existsSync(dbPath)) return usage; - db = new DatabaseSync(dbPath, { readOnly: true }); + // better-sqlite3's `readonly` (vs node:sqlite's `readOnly`) — a genuinely + // read-only handle: an opencode.db (or WAL) we must never mutate from here. + // The require() itself does NOT dlopen (only `new Database()` does), so a + // broken native module here degrades to zeroed usage — the same resilience + // the code already shows for a missing db file. + db = new Database(dbPath, { readonly: true }); // `session_v2.directory` is stored POSIX-style even on Windows; the registry // holds native backslashes. Compare normalized, case-folded, no trailing sep. From df8e4c641f48b749214d88bb5b482c417272673a Mon Sep 17 00:00:00 2001 From: T3sh Date: Thu, 22 Oct 2026 10:48:31 -0300 Subject: [PATCH 18/24] build(electron): pin the runtime Electron 0.5.7 actually ships (32.3.3) The asar's package.json declares 39.8.5 as a devDependency, but the bundled exe runtime reports 32.3.3. Align the fork's dev runtime to the executed version: node:sqlite is absent on 32 (the transcript reader now uses better-sqlite3, see previous commit), the ABI-locked native modules (better-sqlite3) already target 32, and node-pty is NAPI-stable. --- package-lock.json | 31 ++++--------------------------- package.json | 2 +- 2 files changed, 5 insertions(+), 28 deletions(-) diff --git a/package-lock.json b/package-lock.json index af7455c814..33ea318642 100644 --- a/package-lock.json +++ b/package-lock.json @@ -53,7 +53,7 @@ "@types/react": "^18.3.11", "@types/react-dom": "^18.3.0", "@vitejs/plugin-react": "^4.3.2", - "electron": "^32.2.0", + "electron": "32.3.3", "electron-builder": "^25.1.8", "electron-vite": "^2.3.0", "typescript": "^5.6.3", @@ -2008,29 +2008,6 @@ } } }, - "node_modules/@openai/agents-core/node_modules/ws": { - "version": "8.21.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.3.tgz", - "integrity": "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==", - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, "node_modules/@openai/agents-realtime": { "version": "0.11.8", "resolved": "https://registry.npmjs.org/@openai/agents-realtime/-/agents-realtime-0.11.8.tgz", @@ -5533,9 +5510,9 @@ } }, "node_modules/electron/node_modules/@types/node": { - "version": "20.19.41", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.41.tgz", - "integrity": "sha512-ECymXOukMnOoVkC2bb1Vc/w/836DXncOg5m8Xj1RH7xSHZJWNYY6Zh7EH477vcnD5egKNNfy2RpNOmuChhFPgQ==", + "version": "20.19.43", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.43.tgz", + "integrity": "sha512-6oYBAi5ikg4Pl+kGsoYtawUMBT2zZMCvPNF7pVLnHZfd1zf38DRiWn/gT01RYCdUqkv7Fhr+C9ot4/tb+2sVvA==", "dev": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 706152bc6e..86c4de5723 100644 --- a/package.json +++ b/package.json @@ -72,7 +72,7 @@ "@types/react": "^18.3.11", "@types/react-dom": "^18.3.0", "@vitejs/plugin-react": "^4.3.2", - "electron": "^32.2.0", + "electron": "32.3.3", "electron-builder": "^25.1.8", "electron-vite": "^2.3.0", "typescript": "^5.6.3", From ace80fe47b80b56376a8379936ca53648f171196 Mon Sep 17 00:00:00 2001 From: T3sh Date: Thu, 22 Oct 2026 10:48:43 -0300 Subject: [PATCH 19/24] =?UTF-8?q?feat(office):=20per-agent=20desk=20pins?= =?UTF-8?q?=20=E2=80=94=20Edit=20Agent=20picks=20the=20seat?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Today the floor seats everyone automatically (god → 0, workers → first free in add order). Edit Agent now exposes a Desk picker; a pin beats every auto rule — including the god's reserved seat 0 — and NEVER evicts the agent already sitting on a pinned seat (out-of-range/taken pins degrade to auto with a console warning). Pins persist in the roster (durable Agent.seat): the god's pin is captured from the stale entry before respawn re-creates him, workers survive via their restore spread. A pin change re-seats the avatar live (removeCharacter releases the old seat, addCharacter re-claims under the new pin). OfficeFloor publishes seatCount for the picker; +6 tests pin the claim semantics. --- .../src/components/EditAgentModal.tsx | 33 ++++++- src/renderer/src/hooks/useHive.ts | 19 +++- src/renderer/src/scene/office/OfficeFloor.tsx | 33 +++++++ src/renderer/src/store/store.ts | 11 +++ test/office-desk-pins.test.cjs | 90 +++++++++++++++++++ 5 files changed, 184 insertions(+), 2 deletions(-) create mode 100644 test/office-desk-pins.test.cjs diff --git a/src/renderer/src/components/EditAgentModal.tsx b/src/renderer/src/components/EditAgentModal.tsx index e905dc69a6..50077bad15 100644 --- a/src/renderer/src/components/EditAgentModal.tsx +++ b/src/renderer/src/components/EditAgentModal.tsx @@ -44,6 +44,8 @@ export function EditAgentModal({ agent, onClose }: EditAgentModalProps) { const [model, setModel] = useState(agent.model); const [description, setDescription] = useState(agent.description); const [goal, setGoal] = useState(agent.goal ?? ''); + const [seat, setSeat] = useState(agent.seat); + const seatCount = useStore((s) => s.seatCount); useEffect(() => { void window.cth.getConfig().then(setConfig).catch(() => setConfig(null)); @@ -58,6 +60,7 @@ export function EditAgentModal({ agent, onClose }: EditAgentModalProps) { setModel(agent.model); setDescription(agent.description); setGoal(agent.goal ?? ''); + setSeat(agent.seat); }, [agent.id]); const pickProvider = (id: AgentProvider) => { @@ -88,7 +91,8 @@ export function EditAgentModal({ agent, onClose }: EditAgentModalProps) { model, command, description: trimmedDescription, - goal: trimmedGoal || undefined + goal: trimmedGoal || undefined, + seat }); onClose(); }; @@ -186,6 +190,33 @@ export function EditAgentModal({ agent, onClose }: EditAgentModalProps) { ))}
+ + +
+ + + Pick a seat · blank = automatic. A pinned desk beats the first-free rule — even for Michael (desk 0). A pin on a taken desk falls back to automatic. + +
+
diff --git a/src/renderer/src/hooks/useHive.ts b/src/renderer/src/hooks/useHive.ts index cd97975220..f75f1d3c82 100644 --- a/src/renderer/src/hooks/useHive.ts +++ b/src/renderer/src/hooks/useHive.ts @@ -387,6 +387,12 @@ export function useHive(config: HarnessConfig | null): void { // Synchronous guard (no await between check and set) → exactly one spawn. if (cancelled || godSpawning.current) return; godSpawning.current = true; + // Capture the stale restored entry's DESK PIN before clearing it — the + // god object is rebuilt from scratch below, and without this his Edit + // Agent → Desk pin (persisted only in the renderer roster) would be + // lost on every respawn. + const prevGod = useStore.getState().agents.find((a) => a.id === GOD_ID); + const godSeat = prevGod?.seat; useStore.getState().removeAgent(GOD_ID); // clear any stale restored entry // A prior rename (Edit Agent panel → renameAgent() → hive.ts's renameAgent()) @@ -398,7 +404,15 @@ export function useHive(config: HarnessConfig | null): void { const godProvider = config.godProvider ?? 'claude'; const godModel = config.godModel; - const command = buildSpawnCommand(config, godModel, godProvider); + // config.godCommand is a FULL override of the god's base spawn command + // (mirrors upstream 0.5.6+): it wins over godProvider/godModel entirely. + // Needed when the god's engine cannot take the preset's flags at all — + // e.g. the OpenCode desktop V2 CLI rejects `--model`, so + // buildSpawnCommand(config, godModel, 'opencode') emits an arg the CLI + // treats as fatal ("Unrecognized flag: --model"). The hive injection + // (OPENCODE_CONFIG_CONTENT, hooks plugin, --prompt seed) still applies on + // top — only the BASE command is overridden here. + const command = (config.godCommand ?? '').trim() || buildSpawnCommand(config, godModel, godProvider); const [exe, ...args] = tokenizeCommand(command.trim()); const res = await window.cth.spawnPty({ id: GOD_PTY, @@ -435,6 +449,9 @@ export function useHive(config: HarnessConfig | null): void { command: command.trim(), provider: godProvider, model: godModel, + // Preserve the desk pin captured from the stale entry above; without + // it Michael's Edit Agent → Desk choice is dropped on every respawn. + seat: godSeat, isGod: true, recentTextTs: Date.now() }; diff --git a/src/renderer/src/scene/office/OfficeFloor.tsx b/src/renderer/src/scene/office/OfficeFloor.tsx index 52c231b848..605fd4d60e 100644 --- a/src/renderer/src/scene/office/OfficeFloor.tsx +++ b/src/renderer/src/scene/office/OfficeFloor.tsx @@ -59,6 +59,11 @@ interface CoffeeRun { interface Runtime { character: Character; seatIndex: number | null; + /** The desk PIN this seat was claimed under (equal to agent.seat when the + * pin won the claim, undefined for auto seating). Drives the re-seat check + * in syncAgents: pin set/changed/cleared → the avatar drops and re-adds so + * claimSeat re-runs with the new pin. */ + pinnedSeat?: number; waitTile: Tile; charName: string; prevStatus?: string; @@ -357,6 +362,9 @@ export function OfficeFloor() { } }; addZoneSeats('boardroom'); // conference room overflow + // Publish how many desks this theme exposes — Edit Agent's desk picker + // ranges over this (0-based; seat 0 is Michael's room). + useStore.getState().setSeatCount(seatTiles.length); // The bottom-right open area is the cafeteria (break room) — see the // coffee-break director below. It is deliberately NOT added as overflow // desk seating, so the café tables stay free for breaks. @@ -384,6 +392,20 @@ export function OfficeFloor() { // All other workers claim seats from 1 onward. const GOD_SEAT = 0; const claimSeat = (agent: Agent): number | null => { + // A per-agent DESK PIN (Edit Agent → Desk) beats every auto rule — + // including the god's reserved seat 0 — when the pinned seat is free + // and in range. An out-of-range or already-claimed pin degrades to the + // auto rules (loudly, so a typo'd pin is visible in devtools): a pin + // must never evict the agent currently sitting there. + const pin = agent.seat; + if (typeof pin === 'number' && Number.isInteger(pin) + && pin >= 0 && pin < seatTiles.length && !seatClaims.has(pin)) { + seatClaims.add(pin); + return pin; + } + if (pin != null) { + console.warn(`[office] desk pin ${pin} for ${agent.name} is out of range or taken — falling back to auto seating`); + } if (agent.isGod) { seatClaims.add(GOD_SEAT); return GOD_SEAT; } for (let i = 1; i < seatTiles.length; i++) { if (!seatClaims.has(i)) { seatClaims.add(i); return i; } @@ -1410,6 +1432,9 @@ export function OfficeFloor() { }); character.show(charLayer); const rt: Runtime = { character, seatIndex, waitTile, charName }; + // Record WHICH desk pin this seat was claimed under, so a later pin + // change (set / moved / cleared) is detectable in syncAgents. + rt.pinnedSeat = typeof agent.seat === 'number' && agent.seat === seatIndex ? agent.seat : undefined; // Standard desks paint the 2×2 PC monitor two rows above the seat — // give those a DeskScreen (lights up while seated) and a cup spot // beside the monitor, exactly where the tileset's baked-in mug used @@ -1586,6 +1611,14 @@ export function OfficeFloor() { for (const agent of agents) { const rt = runtimes.get(agent.id); if (!rt) void addCharacter(agent); + else if (agent.seat !== rt.pinnedSeat) { + // Desk pin set/changed/cleared → drop and re-add so claimSeat + // re-runs under the new pin (removeCharacter releases the old + // seat; addCharacter honours the new one). Nothing else in the + // avatar state depends on seat continuity, so the swap is safe. + removeCharacter(agent.id); + void addCharacter(agent); + } else { rt.character.setName(agent.name); applyState(agent, rt); diff --git a/src/renderer/src/store/store.ts b/src/renderer/src/store/store.ts index aa5fc452c1..7885c36345 100644 --- a/src/renderer/src/store/store.ts +++ b/src/renderer/src/store/store.ts @@ -54,6 +54,11 @@ export interface Agent { goal?: string; /** User-authored private note shown and edited from the roster-card hover. */ note?: string; + /** Desk PIN — which floor seat this agent sits at (0 = Michael's room). + * Set from Edit Agent; a pin beats every auto rule (first-free claim, the + * god's reserved seat). Cleared = automatic first-free seat again. Durable + * roster field: survives restarts, so a team keeps its desk layout. */ + seat?: number; status: StatusKind; action: string; progress: number; @@ -218,6 +223,10 @@ interface State { toolCounts: Record; bumpToolCount: (id: string) => void; setGodStatus: (status: GodStatus) => void; + /** How many floor seats the live office map exposes — fed by OfficeFloor once + * the theme's seat tiles are discovered, read by Edit Agent's desk picker. */ + seatCount: number; + setSeatCount: (n: number) => void; select: (id: string) => void; updateAgent: (id: string, patch: Partial) => void; /** Copy durable hive roles onto roster descriptions (and the reverse is a @@ -695,6 +704,8 @@ export const useStore = create((set, get) => ({ bumpToolCount: (id) => set((s) => ({ toolCounts: { ...s.toolCounts, [id]: (s.toolCounts[id] ?? 0) + 1 } })), setGodStatus: (status) => set({ godStatus: status }), + seatCount: 0, + setSeatCount: (n) => set((s) => s.seatCount === n ? s : { seatCount: Math.max(0, Math.floor(n)) }), select: (id) => set((s) => { persistAgents(s.agents, id); return { selectedId: id, ccTabRequest: null }; }), updateAgent: (id, patch) => set((s) => { diff --git a/test/office-desk-pins.test.cjs b/test/office-desk-pins.test.cjs new file mode 100644 index 0000000000..ff8d4e9eaf --- /dev/null +++ b/test/office-desk-pins.test.cjs @@ -0,0 +1,90 @@ +const test = require('node:test'); +const assert = require('node:assert/strict'); + +// DESK PINS — the pure claim rule, extracted from OfficeFloor. These tests pin +// the semantics the floor's claimSeat() implements: +// 1. a pin beats every auto rule (even the god's reserved seat 0) +// 2. a pin is honoured ONLY when free and in range — it must never evict +// whoever already sits there (out-of-range/taken pin degrades to auto) +// 3. an unpinned god keeps seat 0 (Michael's room) +// 4. unpinned workers claim the first free seat from 1 onward +function claimSeat(agent, seatClaims, seatCount /* e.g. 12 */) { + const GOD_SEAT = 0; + const pin = agent.seat; + if (typeof pin === 'number' && Number.isInteger(pin) + && pin >= 0 && pin < seatCount && !seatClaims.has(pin)) { + seatClaims.add(pin); + return pin; + } + if (pin != null) return undefined; // degraded → caller falls back (see below) + if (agent.isGod) { seatClaims.add(GOD_SEAT); return GOD_SEAT; } + for (let i = 1; i < seatCount; i++) { + if (!seatClaims.has(i)) { seatClaims.add(i); return i; } + } + return null; +} + +/** The floor's actual fallback after a degraded/taken pin: god → 0, else first free. */ +function claimSeatFull(agent, seatClaims, seatCount) { + const idx = claimSeat(agent, seatClaims, seatCount); + if (idx !== undefined) return idx; + if (agent.isGod) { seatClaims.add(0); return 0; } + for (let i = 1; i < seatCount; i++) { + if (!seatClaims.has(i)) { seatClaims.add(i); return i; } + } + return null; +} + +const SEATS = 4; // 0..3 + +test('unpinned god keeps Michael\'s room (seat 0)', () => { + const claims = new Set(); + assert.equal(claimSeatFull({ isGod: true }, claims, SEATS), 0); +}); + +test('unpinned workers claim the first free seat from 1', () => { + const claims = new Set(); + assert.equal(claimSeatFull({}, claims, SEATS), 1); + assert.equal(claimSeatFull({}, claims, SEATS), 2); + assert.equal(claimSeatFull({}, claims, SEATS), 3); + assert.equal(claimSeatFull({}, claims, SEATS), null, 'full floor seats nobody'); +}); + +test('a pin on a free seat wins — even out of order and for the god', () => { + const claims = new Set(); + const taken = claimSeatFull({}, claims, SEATS); // worker #1 auto → seat 1 + assert.equal(taken, 1); + assert.equal(claimSeatFull({ isGod: true, seat: 2 }, claims, SEATS), 2, + 'god with a pin sits where the owner says, not in seat 0'); + assert.ok(claims.has(0) === false, 'seat 0 stays free for whoever'); + + const claims2 = new Set(); + assert.equal(claimSeatFull({ seat: 3 }, claims2, SEATS), 3, 'later hire with a pin still wins'); + const next = claimSeatFull({}, claims2, SEATS); + assert.equal(next, 1, 'auto agents (non-god) fill the first free seat from 1, around pins'); +}); + +test('a pin on a TAKEN seat degrades to auto instead of evicting', () => { + const claims = new Set(); + assert.equal(claimSeatFull({}, claims, SEATS), 1); // someone is at 1 + const claimsCopy = new Set(claims); + const got = claimSeatFull({ seat: 1 }, claims, SEATS); + assert.notEqual(got, 1, 'no eviction'); + assert.ok([0, 2].includes(got) || got === null); + assert.deepEqual([...claims].sort(), [...claimsCopy, got].sort()); +}); + +test('a pin out of range (or negative/non-integer) degrades to auto', () => { + assert.equal(claimSeatFull({ seat: SEATS }, new Set(), SEATS), 1, 'seat >= count → auto'); + assert.equal(claimSeatFull({ seat: -2 }, new Set(), SEATS), 0 === 0 ? 1 : 1, 'negative → auto'); + assert.equal(claimSeatFull({ seat: 1.5 }, new Set(), SEATS), 1, 'fractional → auto'); +}); + +test('membership is exactly one seat: pin claim is idempotent for the owner', () => { + const claims = new Set(); + const s = claimSeatFull({ seat: 2 }, claims, SEATS); + assert.equal(s, 2); + // A re-claim attempt for the same agent would find its pin taken and fall + // back — but the floor releases BEFORE re-claiming (removeCharacter first), + // which is what these tests encode. +}); From 686725b5b879366c9fe699ce1a9902f03cfc15fb Mon Sep 17 00:00:00 2001 From: T3sh Date: Thu, 22 Oct 2026 19:18:14 -0300 Subject: [PATCH 20/24] fix(deps/landing): bump remotion/@remotion-cli a 4.0.538 (TSF-8) --- landing-remotion/package-lock.json | 2797 +++++++++++++++++++++------- landing-remotion/package.json | 4 +- 2 files changed, 2092 insertions(+), 709 deletions(-) diff --git a/landing-remotion/package-lock.json b/landing-remotion/package-lock.json index 08fd5d6da3..4d6c01629c 100644 --- a/landing-remotion/package-lock.json +++ b/landing-remotion/package-lock.json @@ -8,16 +8,280 @@ "name": "munder-difflin-landing-remotion", "version": "0.1.0", "dependencies": { - "@remotion/cli": "4.0.286", + "@remotion/cli": "4.0.538", "react": "^18.3.1", "react-dom": "^18.3.1", - "remotion": "4.0.286" + "remotion": "4.0.538" }, "devDependencies": { "@types/react": "^18.3.11", "typescript": "^5.6.3" } }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/@babel/parser": { + "version": "7.29.9", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.9.tgz", + "integrity": "sha512-CjXrNHTnvqBVqHgdBysY3vk2T8tpJHb5/RMeHJBTyVa9xgugCB0CJTx/3oO8RV2QRQP391RWpB7D6hLjm8V9uA==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.8" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/core/node_modules/@babel/types": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz", + "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.8.tgz", + "integrity": "sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.8", + "@babel/types": "^7.29.8", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/generator/node_modules/@babel/parser": { + "version": "7.29.9", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.9.tgz", + "integrity": "sha512-CjXrNHTnvqBVqHgdBysY3vk2T8tpJHb5/RMeHJBTyVa9xgugCB0CJTx/3oO8RV2QRQP391RWpB7D6hLjm8V9uA==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.8" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/generator/node_modules/@babel/types": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz", + "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports/node_modules/@babel/types": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz", + "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.10", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.10.tgz", + "integrity": "sha512-EMCx3AGZ3WfAl6ht7AyQoPm2Lh+BGYEMdc4Q6Hf7uSCDOZFuLq44qNwL+iaim8VlyYhRAo4X43+weadK8ZB4Yg==", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.8" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers/node_modules/@babel/types": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz", + "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/parser": { "version": "7.24.1", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.1.tgz", @@ -30,10 +294,143 @@ "node": ">=6.0.0" } }, + "node_modules/@babel/template": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template/node_modules/@babel/parser": { + "version": "7.29.9", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.9.tgz", + "integrity": "sha512-CjXrNHTnvqBVqHgdBysY3vk2T8tpJHb5/RMeHJBTyVa9xgugCB0CJTx/3oO8RV2QRQP391RWpB7D6hLjm8V9uA==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.8" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/template/node_modules/@babel/types": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz", + "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.10", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.10.tgz", + "integrity": "sha512-B3lYAs2nkKskbgQ1nfy8Ma9ao9Q1rntTAQHrzzyDuj+TSO+X3le6PfWwqDvodsb+OumE10eMFfuMCTQSQ5iuIQ==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.8", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.9", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.8", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/@babel/parser": { + "version": "7.29.9", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.9.tgz", + "integrity": "sha512-CjXrNHTnvqBVqHgdBysY3vk2T8tpJHb5/RMeHJBTyVa9xgugCB0CJTx/3oO8RV2QRQP391RWpB7D6hLjm8V9uA==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.8" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/traverse/node_modules/@babel/types": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz", + "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz", + "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@emnapi/core": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.3.tgz", + "integrity": "sha512-zLpS5asjEb7lq8jYLq37N6XKaE41DIexlY1rF/z4/tIl3wo13Sqm28fRyfIsKZD+NZ8mM5RoKkpW/rBcuoSZSg==", + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.3", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.3.tgz", + "integrity": "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.3.tgz", + "integrity": "sha512-ELEBe8PsLvvJ6QMr0zLt8ffvOHW/dc1m3CEzNMg7aJUv3bMaoDtw2TXyDAwkYBuroxxuHEwhRTLJSe5sya547g==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.0.tgz", - "integrity": "sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz", + "integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==", "cpu": [ "ppc64" ], @@ -47,9 +444,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.0.tgz", - "integrity": "sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz", + "integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==", "cpu": [ "arm" ], @@ -63,9 +460,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.0.tgz", - "integrity": "sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz", + "integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==", "cpu": [ "arm64" ], @@ -79,9 +476,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.0.tgz", - "integrity": "sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz", + "integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==", "cpu": [ "x64" ], @@ -95,9 +492,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.0.tgz", - "integrity": "sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz", + "integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==", "cpu": [ "arm64" ], @@ -111,9 +508,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.0.tgz", - "integrity": "sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz", + "integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==", "cpu": [ "x64" ], @@ -127,9 +524,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.0.tgz", - "integrity": "sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz", + "integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==", "cpu": [ "arm64" ], @@ -143,9 +540,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.0.tgz", - "integrity": "sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz", + "integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==", "cpu": [ "x64" ], @@ -159,9 +556,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.0.tgz", - "integrity": "sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz", + "integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==", "cpu": [ "arm" ], @@ -175,9 +572,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.0.tgz", - "integrity": "sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz", + "integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==", "cpu": [ "arm64" ], @@ -191,9 +588,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.0.tgz", - "integrity": "sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz", + "integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==", "cpu": [ "ia32" ], @@ -207,9 +604,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.0.tgz", - "integrity": "sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz", + "integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==", "cpu": [ "loong64" ], @@ -223,9 +620,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.0.tgz", - "integrity": "sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz", + "integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==", "cpu": [ "mips64el" ], @@ -239,9 +636,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.0.tgz", - "integrity": "sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz", + "integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==", "cpu": [ "ppc64" ], @@ -255,9 +652,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.0.tgz", - "integrity": "sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz", + "integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==", "cpu": [ "riscv64" ], @@ -271,9 +668,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.0.tgz", - "integrity": "sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz", + "integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==", "cpu": [ "s390x" ], @@ -287,9 +684,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.0.tgz", - "integrity": "sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz", + "integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==", "cpu": [ "x64" ], @@ -303,9 +700,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.0.tgz", - "integrity": "sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz", + "integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==", "cpu": [ "arm64" ], @@ -319,9 +716,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.0.tgz", - "integrity": "sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz", + "integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==", "cpu": [ "x64" ], @@ -335,9 +732,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.0.tgz", - "integrity": "sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz", + "integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==", "cpu": [ "arm64" ], @@ -351,9 +748,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.0.tgz", - "integrity": "sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz", + "integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==", "cpu": [ "x64" ], @@ -366,10 +763,26 @@ "node": ">=18" } }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz", + "integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/sunos-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.0.tgz", - "integrity": "sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz", + "integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==", "cpu": [ "x64" ], @@ -383,9 +796,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.0.tgz", - "integrity": "sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz", + "integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==", "cpu": [ "arm64" ], @@ -399,9 +812,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.0.tgz", - "integrity": "sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz", + "integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==", "cpu": [ "ia32" ], @@ -415,9 +828,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.0.tgz", - "integrity": "sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz", + "integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==", "cpu": [ "x64" ], @@ -440,6 +853,16 @@ "@jridgewell/trace-mapping": "^0.3.24" } }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", @@ -460,9 +883,9 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", + "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { @@ -475,131 +898,322 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@remotion/bundler": { - "version": "4.0.286", - "resolved": "https://registry.npmjs.org/@remotion/bundler/-/bundler-4.0.286.tgz", - "integrity": "sha512-wqPYs7kVnMGm+fC6HNaAMhxgJuiTCuYt6apxJK3SBzEVn6oRGS1HpbSLom8R4peY9nJ7ROiuCVRVtnsQ9+0sRg==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@remotion/studio": "4.0.286", - "@remotion/studio-shared": "4.0.286", - "css-loader": "5.2.7", - "esbuild": "0.25.0", - "react-refresh": "0.9.0", - "remotion": "4.0.286", - "source-map": "0.7.3", - "style-loader": "4.0.0", - "webpack": "5.96.1" + "node_modules/@mediabunny/aac-encoder": { + "version": "1.62.0", + "resolved": "https://registry.npmjs.org/@mediabunny/aac-encoder/-/aac-encoder-1.62.0.tgz", + "integrity": "sha512-BtGaX3GVGgfQzbqeuqeKAOvHF2lhV70FO3T2orAr4Lr6YklRBOaggfRsKEp93cd6Y7DQab9GFYAuURa1DksCYw==", + "license": "MPL-2.0", + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/Vanilagy" }, "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" + "mediabunny": "^1.0.0" } }, - "node_modules/@remotion/cli": { - "version": "4.0.286", - "resolved": "https://registry.npmjs.org/@remotion/cli/-/cli-4.0.286.tgz", - "integrity": "sha512-omJZWTxiOcttkvoosyiyB777nlKg94DqPidrnc1VcT/eeX3Q3CFW4nfkW2NZbb7wgVjgoEdUE0WGNCOShB7IzA==", - "license": "SEE LICENSE IN LICENSE.md", - "dependencies": { - "@remotion/bundler": "4.0.286", - "@remotion/media-utils": "4.0.286", - "@remotion/player": "4.0.286", - "@remotion/renderer": "4.0.286", - "@remotion/studio": "4.0.286", - "@remotion/studio-server": "4.0.286", - "@remotion/studio-shared": "4.0.286", - "dotenv": "9.0.2", - "minimist": "1.2.6", - "prompts": "2.4.2", - "remotion": "4.0.286" + "node_modules/@mediabunny/flac-encoder": { + "version": "1.62.0", + "resolved": "https://registry.npmjs.org/@mediabunny/flac-encoder/-/flac-encoder-1.62.0.tgz", + "integrity": "sha512-ZxyElacW8o61mydIXVzYClv6E0ULkXcq9Aup+GQGpuaHKaZPF1y8S5gGrs4rFkr1s0bZ7iYGYPxHeGrg7J1yjg==", + "license": "MPL-2.0", + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/Vanilagy" }, - "bin": { - "remotion": "remotion-cli.js", - "remotionb": "remotionb-cli.js", - "remotiond": "remotiond-cli.js" + "peerDependencies": { + "mediabunny": "^1.0.0" + } + }, + "node_modules/@mediabunny/mp3-encoder": { + "version": "1.62.0", + "resolved": "https://registry.npmjs.org/@mediabunny/mp3-encoder/-/mp3-encoder-1.62.0.tgz", + "integrity": "sha512-72yrJXFO+qkFurWzVpkTu7e5yVF6qFB0mmyaMcg7Ztwz5a+bSvuitkaIY82FBk5vM7euCKzFuqVwOzH0YUCcLg==", + "license": "MPL-2.0", + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/Vanilagy" }, "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" + "mediabunny": "^1.0.0" } }, - "node_modules/@remotion/compositor-darwin-arm64": { - "version": "4.0.286", - "resolved": "https://registry.npmjs.org/@remotion/compositor-darwin-arm64/-/compositor-darwin-arm64-4.0.286.tgz", - "integrity": "sha512-0v1crc+65Yo2qRqRS8XeiISkAs+fyhoXQtBe0r+yDtJQMLhTHGkvwGVAFJpeOBo2WpfNkhpKqN8wB/1pPB/llw==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ] + "node_modules/@module-federation/error-codes": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@module-federation/error-codes/-/error-codes-0.22.0.tgz", + "integrity": "sha512-xF9SjnEy7vTdx+xekjPCV5cIHOGCkdn3pIxo9vU7gEZMIw0SvAEdsy6Uh17xaCpm8V0FWvR0SZoK9Ik6jGOaug==", + "license": "MIT" }, - "node_modules/@remotion/compositor-darwin-x64": { - "version": "4.0.286", - "resolved": "https://registry.npmjs.org/@remotion/compositor-darwin-x64/-/compositor-darwin-x64-4.0.286.tgz", - "integrity": "sha512-1OoApxncp/yQ+0IlyDE0QnCEQY5phruYbvC7B3O7GQvx/cwZyAPUq8Vix3HQEFKDzu0yBsg9+SbnG+hs3AI9VQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ] + "node_modules/@module-federation/runtime": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@module-federation/runtime/-/runtime-0.22.0.tgz", + "integrity": "sha512-38g5iPju2tPC3KHMPxRKmy4k4onNp6ypFPS1eKGsNLUkXgHsPMBFqAjDw96iEcjri91BrahG4XcdyKi97xZzlA==", + "license": "MIT", + "dependencies": { + "@module-federation/error-codes": "0.22.0", + "@module-federation/runtime-core": "0.22.0", + "@module-federation/sdk": "0.22.0" + } }, - "node_modules/@remotion/compositor-linux-arm64-gnu": { - "version": "4.0.286", - "resolved": "https://registry.npmjs.org/@remotion/compositor-linux-arm64-gnu/-/compositor-linux-arm64-gnu-4.0.286.tgz", - "integrity": "sha512-hJNE2d7p4a0o+W8hmw1PM0ShXYnmiPnHvfVAUplKbP2HR9vvHQCQiTolucUt2A7Abqp9Nzci9nSid3+EJAPWhw==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" + "node_modules/@module-federation/runtime-core": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@module-federation/runtime-core/-/runtime-core-0.22.0.tgz", + "integrity": "sha512-GR1TcD6/s7zqItfhC87zAp30PqzvceoeDGYTgF3Vx2TXvsfDrhP6Qw9T4vudDQL3uJRne6t7CzdT29YyVxlgIA==", + "license": "MIT", + "dependencies": { + "@module-federation/error-codes": "0.22.0", + "@module-federation/sdk": "0.22.0" + } + }, + "node_modules/@module-federation/runtime-tools": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@module-federation/runtime-tools/-/runtime-tools-0.22.0.tgz", + "integrity": "sha512-4ScUJ/aUfEernb+4PbLdhM/c60VHl698Gn1gY21m9vyC1Ucn69fPCA1y2EwcCB7IItseRMoNhdcWQnzt/OPCNA==", + "license": "MIT", + "dependencies": { + "@module-federation/runtime": "0.22.0", + "@module-federation/webpack-bundler-runtime": "0.22.0" + } + }, + "node_modules/@module-federation/sdk": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@module-federation/sdk/-/sdk-0.22.0.tgz", + "integrity": "sha512-x4aFNBKn2KVQRuNVC5A7SnrSCSqyfIWmm1DvubjbO9iKFe7ith5niw8dqSFBekYBg2Fwy+eMg4sEFNVvCAdo6g==", + "license": "MIT" + }, + "node_modules/@module-federation/webpack-bundler-runtime": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@module-federation/webpack-bundler-runtime/-/webpack-bundler-runtime-0.22.0.tgz", + "integrity": "sha512-aM8gCqXu+/4wBmJtVeMeeMN5guw3chf+2i6HajKtQv7SJfxV/f4IyNQJUeUQu9HfiAZHjqtMV5Lvq/Lvh8LdyA==", + "license": "MIT", + "dependencies": { + "@module-federation/runtime": "0.22.0", + "@module-federation/sdk": "0.22.0" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.0.7.tgz", + "integrity": "sha512-SeDnOO0Tk7Okiq6DbXmmBODgOAb9dp9gjlphokTUxmt8U3liIP1ZsozBahH69j/RJv+Rfs6IwUKHTgQYJ/HBAw==", + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.5.0", + "@emnapi/runtime": "^1.5.0", + "@tybys/wasm-util": "^0.10.1" + } + }, + "node_modules/@remotion/bundler": { + "version": "4.0.538", + "resolved": "https://registry.npmjs.org/@remotion/bundler/-/bundler-4.0.538.tgz", + "integrity": "sha512-8chqxvsKXhh3Wo0UQufKr54lVp5NsJRm0PhFHcKv5CzLSyWASQD1wG4w9jWOMDCT1A7YPulFGqoDGlFWYaFR0A==", + "license": "SEE LICENSE IN LICENSE.md", + "dependencies": { + "@remotion/studio": "4.0.538", + "@remotion/studio-shared": "4.0.538", + "@remotion/timeline-utils": "4.0.538", + "@rspack/core": "1.7.11", + "@rspack/plugin-react-refresh": "1.6.1", + "css-loader": "7.1.4", + "esbuild": "0.28.1", + "react-refresh": "0.18.0", + "remotion": "4.0.538", + "style-loader": "4.0.0", + "webpack": "5.105.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@remotion/bundler/node_modules/webpack": { + "version": "5.105.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.105.0.tgz", + "integrity": "sha512-gX/dMkRQc7QOMzgTe6KsYFM7DxeIONQSui1s0n/0xht36HvrgbxtM1xBlgx596NbpHuQU8P7QpKwrZYwUX48nw==", + "license": "MIT", + "dependencies": { + "@types/eslint-scope": "^3.7.7", + "@types/estree": "^1.0.8", + "@types/json-schema": "^7.0.15", + "@webassemblyjs/ast": "^1.14.1", + "@webassemblyjs/wasm-edit": "^1.14.1", + "@webassemblyjs/wasm-parser": "^1.14.1", + "acorn": "^8.15.0", + "acorn-import-phases": "^1.0.3", + "browserslist": "^4.28.1", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.19.0", + "es-module-lexer": "^2.0.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.11", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.3.1", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^4.3.3", + "tapable": "^2.3.0", + "terser-webpack-plugin": "^5.3.16", + "watchpack": "^2.5.1", + "webpack-sources": "^3.3.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/@remotion/captions": { + "version": "4.0.538", + "resolved": "https://registry.npmjs.org/@remotion/captions/-/captions-4.0.538.tgz", + "integrity": "sha512-ADDnP8QxU7hDtjaE2PuS6UeyHRtfvkomXBKmK8M9LlC98+iuNEAeMGw02T4p15wDzEER44QDPG09K9kKBnWqUw==", + "license": "MIT" + }, + "node_modules/@remotion/cli": { + "version": "4.0.538", + "resolved": "https://registry.npmjs.org/@remotion/cli/-/cli-4.0.538.tgz", + "integrity": "sha512-4JN4ywRT2gj+HrpFrFvl7SdyUoRBZgN61jnvxvaLUdWZClchIvx5/Fwk9/dXahxf//yMd5d6vEdJcOFsyZw90w==", + "license": "SEE LICENSE IN LICENSE.md", + "dependencies": { + "@babel/parser": "7.24.1", + "@remotion/bundler": "4.0.538", + "@remotion/codemods": "4.0.538", + "@remotion/media-utils": "4.0.538", + "@remotion/player": "4.0.538", + "@remotion/renderer": "4.0.538", + "@remotion/studio": "4.0.538", + "@remotion/studio-server": "4.0.538", + "@remotion/studio-shared": "4.0.538", + "dotenv": "17.3.1", + "mediabunny": "1.62.0", + "minimist": "1.2.6", + "prompts": "2.4.2", + "remotion": "4.0.538", + "semver": "7.5.3" + }, + "bin": { + "remotion": "remotion-cli.js", + "remotionb": "remotionb-cli.js", + "remotiond": "remotiond-cli.js" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@remotion/codemods": { + "version": "4.0.538", + "resolved": "https://registry.npmjs.org/@remotion/codemods/-/codemods-4.0.538.tgz", + "integrity": "sha512-m+oASCDQa1+22cANXp97ZwZ+ZvnuWZaSFqEFPpVF6RajssJRcn+npr9UCFleTJrx7Fm2bOVVdmFtPTuXdT8+Bw==", + "license": "MIT", + "dependencies": { + "@babel/parser": "7.24.1", + "@babel/types": "7.24.0", + "@remotion/studio-protocol": "4.0.538", + "@remotion/studio-shared": "4.0.538", + "ast-types": "0.16.1", + "recast": "0.23.21", + "remotion": "4.0.538" + } + }, + "node_modules/@remotion/compositor-darwin-arm64": { + "version": "4.0.538", + "resolved": "https://registry.npmjs.org/@remotion/compositor-darwin-arm64/-/compositor-darwin-arm64-4.0.538.tgz", + "integrity": "sha512-VV4f68T9UGLjuumo1BycjKwgPFr5b6yLkznFp5NufScK8wIe+w34rRQ6ZMO2SEEwr+q97FkgMXHu0fgB8UTQmg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@remotion/compositor-darwin-x64": { + "version": "4.0.538", + "resolved": "https://registry.npmjs.org/@remotion/compositor-darwin-x64/-/compositor-darwin-x64-4.0.538.tgz", + "integrity": "sha512-PSKUGDfZuvkpUsxlrUAeXz49gwJ8DIlArIIxldO35h5aPF10s8IY92vVz4EXuT/ETfGDsb9X9lgmlsy51bbb6g==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@remotion/compositor-linux-arm64-gnu": { + "version": "4.0.538", + "resolved": "https://registry.npmjs.org/@remotion/compositor-linux-arm64-gnu/-/compositor-linux-arm64-gnu-4.0.538.tgz", + "integrity": "sha512-QSGe7eoL6r4ksOYYWrt6iypGLwtT25fuMMuZtcdl5ij/IgQQuYkeD6TE8/Nvy3qhCJc/tNazcuC8OonBtLiXvQ==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "optional": true, + "os": [ + "linux" ] }, "node_modules/@remotion/compositor-linux-arm64-musl": { - "version": "4.0.286", - "resolved": "https://registry.npmjs.org/@remotion/compositor-linux-arm64-musl/-/compositor-linux-arm64-musl-4.0.286.tgz", - "integrity": "sha512-ix0Aa9wB95Rqr5z+HfmdjWctv4OfALs2NJgGZvdGUInjvZJiyvrachkF/ek15zBsinx6PDiJC8dhwfI/+ZhG8g==", + "version": "4.0.538", + "resolved": "https://registry.npmjs.org/@remotion/compositor-linux-arm64-musl/-/compositor-linux-arm64-musl-4.0.538.tgz", + "integrity": "sha512-ALEWbRQeKYXBYCA4d8mjuyahRBziTgZFnkWjINfat2N0YxH1zOOxKqdHevcYFgBYAS4KgVd5PZ/+zCUGSyRb3A==", "cpu": [ "arm64" ], + "libc": [ + "musl" + ], "optional": true, "os": [ "linux" ] }, "node_modules/@remotion/compositor-linux-x64-gnu": { - "version": "4.0.286", - "resolved": "https://registry.npmjs.org/@remotion/compositor-linux-x64-gnu/-/compositor-linux-x64-gnu-4.0.286.tgz", - "integrity": "sha512-RXGgst6AfDQya4ym3chpKN42AedNt42yKxN59wvE5VMtKNfkgtDGvSj64NUcGNidJtduPei2/poZgtOcOAfLSQ==", + "version": "4.0.538", + "resolved": "https://registry.npmjs.org/@remotion/compositor-linux-x64-gnu/-/compositor-linux-x64-gnu-4.0.538.tgz", + "integrity": "sha512-i+u3ea1MN1BkBSp5BK1YGqVBEJPS9AxxszHeUSJ4zYtldlu1lEAnATLPWO0zs5jA6P0Vtap+2rDcFuKKAlDxyA==", "cpu": [ "x64" ], + "libc": [ + "glibc" + ], "optional": true, "os": [ "linux" ] }, "node_modules/@remotion/compositor-linux-x64-musl": { - "version": "4.0.286", - "resolved": "https://registry.npmjs.org/@remotion/compositor-linux-x64-musl/-/compositor-linux-x64-musl-4.0.286.tgz", - "integrity": "sha512-PljI4b8YBGiR7lh2oyi5AwhHgXGHb0zt2ABbQsI0iQGyUyt9yYd0eUo6W+2rEZHVWZFLNZpovQhNIm2tEdABxQ==", + "version": "4.0.538", + "resolved": "https://registry.npmjs.org/@remotion/compositor-linux-x64-musl/-/compositor-linux-x64-musl-4.0.538.tgz", + "integrity": "sha512-ickPY224j3K3f2WiooleExbMtE/G/upt3c4tA5xqVu09STUE3fEBMqZly7PoFa/byfVk8ifVUVs0BuyGaG1oVA==", "cpu": [ "x64" ], + "libc": [ + "musl" + ], "optional": true, "os": [ "linux" ] }, "node_modules/@remotion/compositor-win32-x64-msvc": { - "version": "4.0.286", - "resolved": "https://registry.npmjs.org/@remotion/compositor-win32-x64-msvc/-/compositor-win32-x64-msvc-4.0.286.tgz", - "integrity": "sha512-PsR5fyZhu9JOqTsbVb4nyi8/7aa7vDFAdo0LgRXl/G26ioEyF03pWQdWQjdbwC1hRmXy72AtVQfU1WCkAEfGPg==", + "version": "4.0.538", + "resolved": "https://registry.npmjs.org/@remotion/compositor-win32-x64-msvc/-/compositor-win32-x64-msvc-4.0.538.tgz", + "integrity": "sha512-eQdKMPAPBodquLi/QbHP7irvIFstHkksh6in3jaJ0w397qeIHiRUCB3DWA8foRqyGPykibt+B2kQg9l3xxIcog==", "cpu": [ "x64" ], @@ -608,32 +1222,76 @@ "win32" ] }, - "node_modules/@remotion/media-parser": { - "version": "4.0.286", - "resolved": "https://registry.npmjs.org/@remotion/media-parser/-/media-parser-4.0.286.tgz", - "integrity": "sha512-Xl4zt5qCgFktpUM6HaMd15uUZecZ1nDnCTn+j8hBHT7kN9dJwwNYz7AZM7q3+C5NKbomVAJW2hs5ELiyAZwvqQ==", - "license": "Remotion License https://remotion.dev/license" + "node_modules/@remotion/elevenlabs": { + "version": "4.0.538", + "resolved": "https://registry.npmjs.org/@remotion/elevenlabs/-/elevenlabs-4.0.538.tgz", + "integrity": "sha512-K06HrD+dKz25i31sRbxniNzIjGgzPEeiLLwmCyuVZuat+PQ9stb5EmIuWue/n++YnisT4bgFt6QNyoSdQEbByw==", + "license": "MIT", + "dependencies": { + "@remotion/captions": "4.0.538", + "zod": "4.5.4" + } + }, + "node_modules/@remotion/licensing": { + "version": "4.0.538", + "resolved": "https://registry.npmjs.org/@remotion/licensing/-/licensing-4.0.538.tgz", + "integrity": "sha512-vm8mpeZCowrn0OI/Y7KRmeAVuXiK6ylj0xk0utMbwlsLNB3ywLg3nyO0H4pD+a7fDn9FId3y283xFkJ6XymtfQ==", + "license": "MIT" + }, + "node_modules/@remotion/media": { + "version": "4.0.538", + "resolved": "https://registry.npmjs.org/@remotion/media/-/media-4.0.538.tgz", + "integrity": "sha512-+TViwM5SWbj0nPLHgCNcuvatnlezOZHHV8BcTG+uFKwMHTxxmEcj40Ow0vM0H5/MAP54B7i/qlmV74YZqLXfDw==", + "dependencies": { + "mediabunny": "1.62.0", + "remotion": "4.0.538", + "zod": "4.5.4" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } }, "node_modules/@remotion/media-utils": { - "version": "4.0.286", - "resolved": "https://registry.npmjs.org/@remotion/media-utils/-/media-utils-4.0.286.tgz", - "integrity": "sha512-QOoRB5VaclGRPBlQWtTCy/W9uuFJ7N3htSawB3fPeMpIDZ401FOaqXSeqbmtoLwi4v9dMsz8ec406lv67enQAw==", + "version": "4.0.538", + "resolved": "https://registry.npmjs.org/@remotion/media-utils/-/media-utils-4.0.538.tgz", + "integrity": "sha512-Rfjg5P+lkioXz4ip+0SQlzzaOspu4/jP8NWOwVi7ICeJPJ3m0ZaU7TKjLTVA1pzX9bWV4vwoigALNWn+cMiHHg==", "license": "MIT", "dependencies": { - "remotion": "4.0.286" + "mediabunny": "1.62.0", + "remotion": "4.0.538" }, "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" } }, + "node_modules/@remotion/openai-whisper": { + "version": "4.0.538", + "resolved": "https://registry.npmjs.org/@remotion/openai-whisper/-/openai-whisper-4.0.538.tgz", + "integrity": "sha512-+AVrT5WwkRhN1er2fd4cR52EZDfGx+riiw65mnOf8oQKnbAT+1OhmoH6WIwPKX1qOZxhTwvGY5m2xthlAOSW1w==", + "license": "MIT", + "dependencies": { + "@remotion/captions": "4.0.538", + "zod": "4.5.4" + } + }, + "node_modules/@remotion/paths": { + "version": "4.0.538", + "resolved": "https://registry.npmjs.org/@remotion/paths/-/paths-4.0.538.tgz", + "integrity": "sha512-GN/6cpxQn6ssvhb4Ph1RRQLrhQTtZYmJysZ+PjHi1Zn4WzC07akkgNj+BTqtdGWsUKFj1cyGvzzcZswbPLLc6w==", + "license": "MIT", + "dependencies": { + "remotion": "4.0.538" + } + }, "node_modules/@remotion/player": { - "version": "4.0.286", - "resolved": "https://registry.npmjs.org/@remotion/player/-/player-4.0.286.tgz", - "integrity": "sha512-T+DRPoMEqZajc7ITU6/46R4EcufpL7vKKWPJLxEmqikkluaFe3uL0Ms3qOI1DddvhfJyHPnJt6NS+J31rp81kw==", + "version": "4.0.538", + "resolved": "https://registry.npmjs.org/@remotion/player/-/player-4.0.538.tgz", + "integrity": "sha512-HYvGtDD2cG8/EICy8kleIqZJIHqRXNsJjETv0BS4n+Yrlo95oZvrzbfhGn0GbP8b3ucO4EkehNkw+qpVqG9M7Q==", "license": "SEE LICENSE IN LICENSE.md", "dependencies": { - "remotion": "4.0.286" + "remotion": "4.0.538" }, "peerDependencies": { "react": ">=16.8.0", @@ -641,114 +1299,650 @@ } }, "node_modules/@remotion/renderer": { - "version": "4.0.286", - "resolved": "https://registry.npmjs.org/@remotion/renderer/-/renderer-4.0.286.tgz", - "integrity": "sha512-VtKPjYofNDLEIQimVUppzD18Q48eu1zrG9nMnd9Xy4GEO6FKenGkt9bkH8N+X6K7S+KSJiVy7nTR5S6qr8Xgjg==", + "version": "4.0.538", + "resolved": "https://registry.npmjs.org/@remotion/renderer/-/renderer-4.0.538.tgz", + "integrity": "sha512-d4xzVMHqw/ajV0WEjyuFNt3UY6Tg5Aj0iABSxcwBiVI7YwsJQ9RGoB80VS95Sa9choYQfSSRJGFSQT53X/qjRg==", "license": "SEE LICENSE IN LICENSE.md", "dependencies": { - "@remotion/streaming": "4.0.286", + "@remotion/licensing": "4.0.538", + "@remotion/streaming": "4.0.538", "execa": "5.1.1", - "extract-zip": "2.0.1", - "remotion": "4.0.286", - "source-map": "^0.8.0-beta.0", - "ws": "8.17.1" + "remotion": "4.0.538", + "source-map": "0.8.0", + "ws": "8.21.0" }, "optionalDependencies": { - "@remotion/compositor-darwin-arm64": "4.0.286", - "@remotion/compositor-darwin-x64": "4.0.286", - "@remotion/compositor-linux-arm64-gnu": "4.0.286", - "@remotion/compositor-linux-arm64-musl": "4.0.286", - "@remotion/compositor-linux-x64-gnu": "4.0.286", - "@remotion/compositor-linux-x64-musl": "4.0.286", - "@remotion/compositor-win32-x64-msvc": "4.0.286" + "@remotion/compositor-darwin-arm64": "4.0.538", + "@remotion/compositor-darwin-x64": "4.0.538", + "@remotion/compositor-linux-arm64-gnu": "4.0.538", + "@remotion/compositor-linux-arm64-musl": "4.0.538", + "@remotion/compositor-linux-x64-gnu": "4.0.538", + "@remotion/compositor-linux-x64-musl": "4.0.538", + "@remotion/compositor-win32-x64-msvc": "4.0.538" }, "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" } }, - "node_modules/@remotion/renderer/node_modules/source-map": { - "version": "0.8.0-beta.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", - "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==", - "deprecated": "The work that was done in this beta branch won't be included in future versions", - "license": "BSD-3-Clause", + "node_modules/@remotion/sdk": { + "version": "4.0.538", + "resolved": "https://registry.npmjs.org/@remotion/sdk/-/sdk-4.0.538.tgz", + "integrity": "sha512-ypTWi4pwWFlb/ZETuSMn6YYFpAfUmbJa6bUmqZlj2iQ3V5W2Pfi1lYl/El4xOl3GEYVErJutIf0JJYI3AE7McQ==", + "license": "Remotion License", "dependencies": { - "whatwg-url": "^7.0.0" + "@remotion/player": "4.0.538", + "@remotion/studio-shared": "4.0.538", + "remotion": "4.0.538" }, - "engines": { - "node": ">= 8" + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" } }, "node_modules/@remotion/streaming": { - "version": "4.0.286", - "resolved": "https://registry.npmjs.org/@remotion/streaming/-/streaming-4.0.286.tgz", - "integrity": "sha512-os52J+Ci1Twrn1a+LNqPkz3TuAV/qxEHmGsGuhdRfHDJ+fnZws1VebDm+Tdlk8BGdvCbL/h0NUeEdpBcMOWrsA==", + "version": "4.0.538", + "resolved": "https://registry.npmjs.org/@remotion/streaming/-/streaming-4.0.538.tgz", + "integrity": "sha512-9zoJ59eBMRwufh9eXp4R1i8X+J6BZ4xIfjGFUmiDKPBYh6N1GMRlOwFPZAKyW/QLJZMVtUkz0jTqyYrrAGrWhg==", "license": "MIT" }, "node_modules/@remotion/studio": { - "version": "4.0.286", - "resolved": "https://registry.npmjs.org/@remotion/studio/-/studio-4.0.286.tgz", - "integrity": "sha512-2yCdXxKAZzP3EC9dgwsAbteZoh1bRW84Zki0BeMb1OCflqtTJG5rI8EfIsEMz/OntIwW3kGtbkV8LuVv86oOrA==", - "license": "MIT", - "dependencies": { - "@remotion/media-parser": "4.0.286", - "@remotion/media-utils": "4.0.286", - "@remotion/player": "4.0.286", - "@remotion/renderer": "4.0.286", - "@remotion/studio-shared": "4.0.286", - "@remotion/zod-types": "4.0.286", + "version": "4.0.538", + "resolved": "https://registry.npmjs.org/@remotion/studio/-/studio-4.0.538.tgz", + "integrity": "sha512-lO+rEYRuS+0yKW65pqy8szDTjmy23x4RImXR3JAiHOfv7KLDY8NoB3XY+lLiDHAVseL2bZHAG2ZIjTotCQvyQQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.31", + "@remotion/captions": "4.0.538", + "@remotion/codemods": "4.0.538", + "@remotion/elevenlabs": "4.0.538", + "@remotion/media": "4.0.538", + "@remotion/media-utils": "4.0.538", + "@remotion/openai-whisper": "4.0.538", + "@remotion/paths": "4.0.538", + "@remotion/player": "4.0.538", + "@remotion/renderer": "4.0.538", + "@remotion/sdk": "4.0.538", + "@remotion/studio-protocol": "4.0.538", + "@remotion/studio-shared": "4.0.538", + "@remotion/timeline-utils": "4.0.538", + "@remotion/web-renderer": "4.0.538", + "@remotion/zod-types": "4.0.538", + "@tanstack/react-virtual": "3.14.9", + "mediabunny": "1.62.0", "memfs": "3.4.3", - "open": "^8.4.2", - "remotion": "4.0.286", + "open": "8.4.2", + "prismjs": "1.30.0", + "remotion": "4.0.538", "semver": "7.5.3", - "source-map": "0.7.3", - "zod": "3.22.3" + "zod": "4.5.4" }, "peerDependencies": { + "@remotion/video-matting": "4.0.538", + "@remotion/whisper-webgpu": "4.0.538", "react": ">=16.8.0", "react-dom": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@remotion/video-matting": { + "optional": true + }, + "@remotion/whisper-webgpu": { + "optional": true + } + } + }, + "node_modules/@remotion/studio-protocol": { + "version": "4.0.538", + "resolved": "https://registry.npmjs.org/@remotion/studio-protocol/-/studio-protocol-4.0.538.tgz", + "integrity": "sha512-QycNTOjcnUD6MPFlkJ0N6ZAw6kq450aAKSqKSHlsLjuMEGDF3yZEzIaDnF2QTuJc02WnNEBV2o8mx4XRNda9Zw==", + "license": "Remotion License", + "dependencies": { + "zod": "4.5.4" + } + }, + "node_modules/@remotion/studio-server": { + "version": "4.0.538", + "resolved": "https://registry.npmjs.org/@remotion/studio-server/-/studio-server-4.0.538.tgz", + "integrity": "sha512-skvVMWsGJZNXFFagAY+jq4/7QNN/UlcfSMdaF1wDQSyZ7Bb6KL/R6udApikrPkHLFeExVmQiB8dHkSjaSwp+1g==", + "license": "MIT", + "dependencies": { + "@babel/parser": "7.24.1", + "@babel/types": "7.24.0", + "@remotion/bundler": "4.0.538", + "@remotion/codemods": "4.0.538", + "@remotion/renderer": "4.0.538", + "@remotion/studio-protocol": "4.0.538", + "@remotion/studio-shared": "4.0.538", + "@svgr/core": "8.1.0", + "@svgr/plugin-jsx": "8.1.0", + "kiwi-schema": "0.5.0", + "memfs": "3.4.3", + "open": "8.4.2", + "recast": "0.23.21", + "remotion": "4.0.538", + "semver": "7.5.3", + "zod": "4.5.4" + } + }, + "node_modules/@remotion/studio-shared": { + "version": "4.0.538", + "resolved": "https://registry.npmjs.org/@remotion/studio-shared/-/studio-shared-4.0.538.tgz", + "integrity": "sha512-FpKJ/43J86ay/4ZhEFa2SAu8bmrzN8IMDjAD0qFPgf3SNkgd9RX2vhzth6RH+RyOggOFGpHrdcPlI6EYpv6ByQ==", + "license": "MIT", + "dependencies": { + "remotion": "4.0.538" + } + }, + "node_modules/@remotion/timeline-utils": { + "version": "4.0.538", + "resolved": "https://registry.npmjs.org/@remotion/timeline-utils/-/timeline-utils-4.0.538.tgz", + "integrity": "sha512-sGRUxrXSdxkd78C8ChQNApoEiYKgOPFO6+cezOLB+gqk2updtreR3sjau9RzmsPO/2C5r7x8x1vDyTSb3U/geQ==", + "license": "MIT", + "dependencies": { + "mediabunny": "1.62.0", + "remotion": "4.0.538" + } + }, + "node_modules/@remotion/web-renderer": { + "version": "4.0.538", + "resolved": "https://registry.npmjs.org/@remotion/web-renderer/-/web-renderer-4.0.538.tgz", + "integrity": "sha512-dIpIHPrVCiy9Nz5FvUWOejn3ZYgcAVdQzkdVL64R0aCEqx8BnGxTNYmKz+xm3H3fQE+q2HKCJoR6dYMgTayS2Q==", + "license": "SEE LICENSE IN LICENSE.md", + "dependencies": { + "@mediabunny/aac-encoder": "1.62.0", + "@mediabunny/flac-encoder": "1.62.0", + "@mediabunny/mp3-encoder": "1.62.0", + "@remotion/licensing": "4.0.538", + "mediabunny": "1.62.0", + "remotion": "4.0.538" + }, + "peerDependencies": { + "react": ">=18.0.0", + "react-dom": ">=18.0.0" + } + }, + "node_modules/@remotion/zod-types": { + "version": "4.0.538", + "resolved": "https://registry.npmjs.org/@remotion/zod-types/-/zod-types-4.0.538.tgz", + "integrity": "sha512-/2+zn7/QGGMFhr30ccEwhc1GYpyMa+TsVOMdjS9+7SylfXm2ULAxIHHhJDJYrxTES/ROx5EI4UdD+ugoEHQXEg==", + "license": "MIT", + "dependencies": { + "remotion": "4.0.538" + } + }, + "node_modules/@rspack/binding": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@rspack/binding/-/binding-1.7.11.tgz", + "integrity": "sha512-2MGdy2s2HimsDT444Bp5XnALzNRxuBNc7y0JzyuqKbHBywd4x2NeXyhWXXoxufaCFu5PBc9Qq9jyfjW2Aeh06Q==", + "license": "MIT", + "optionalDependencies": { + "@rspack/binding-darwin-arm64": "1.7.11", + "@rspack/binding-darwin-x64": "1.7.11", + "@rspack/binding-linux-arm64-gnu": "1.7.11", + "@rspack/binding-linux-arm64-musl": "1.7.11", + "@rspack/binding-linux-x64-gnu": "1.7.11", + "@rspack/binding-linux-x64-musl": "1.7.11", + "@rspack/binding-wasm32-wasi": "1.7.11", + "@rspack/binding-win32-arm64-msvc": "1.7.11", + "@rspack/binding-win32-ia32-msvc": "1.7.11", + "@rspack/binding-win32-x64-msvc": "1.7.11" + } + }, + "node_modules/@rspack/binding-darwin-arm64": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@rspack/binding-darwin-arm64/-/binding-darwin-arm64-1.7.11.tgz", + "integrity": "sha512-oduECiZVqbO5zlVw+q7Vy65sJFth99fWPTyucwvLJJtJkPL5n17Uiql2cYP6Ijn0pkqtf1SXgK8WjiKLG5bIig==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rspack/binding-darwin-x64": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@rspack/binding-darwin-x64/-/binding-darwin-x64-1.7.11.tgz", + "integrity": "sha512-a1+TtTE9ap6RalgFi7FGIgkJP6O4Vy6ctv+9WGJy53E4kuqHR0RygzaiVxCI/GMc/vBT9vY23hyrpWb3d1vtXA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rspack/binding-linux-arm64-gnu": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.7.11.tgz", + "integrity": "sha512-P0QrGRPbTWu6RKWfN0bDtbnEps3rXH0MWIMreZABoUrVmNQKtXR6e73J3ub6a+di5s2+K0M2LJ9Bh2/H4UsDUA==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rspack/binding-linux-arm64-musl": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.7.11.tgz", + "integrity": "sha512-6ky7R43VMjWwmx3Yx7Jl7faLBBMAgMDt+/bN35RgwjiPgsIByz65EwytUVuW9rikB43BGHvA/eqlnjLrUzNBqw==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rspack/binding-linux-x64-gnu": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.7.11.tgz", + "integrity": "sha512-cuOJMfCOvb2Wgsry5enXJ3iT1FGUjdPqtGUBVupQlEG4ntSYsQ2PtF4wIDVasR3wdxC5nQbipOrDiN/u6fYsdQ==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rspack/binding-linux-x64-musl": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-musl/-/binding-linux-x64-musl-1.7.11.tgz", + "integrity": "sha512-CoK37hva4AmHGh3VCsQXmGr40L36m1/AdnN5LEjUX6kx5rEH7/1nEBN6Ii72pejqDVvk9anEROmPDiPw10tpFg==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rspack/binding-wasm32-wasi": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@rspack/binding-wasm32-wasi/-/binding-wasm32-wasi-1.7.11.tgz", + "integrity": "sha512-OtrmnPUVJMxjNa3eDMfHyPdtlLRmmp/aIm0fQHlAOATbZvlGm12q7rhPW5BXTu1yh+1rQ1/uqvz+SzKEZXuJaQ==", + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "1.0.7" + } + }, + "node_modules/@rspack/binding-win32-arm64-msvc": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@rspack/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.7.11.tgz", + "integrity": "sha512-lObFW6e5lCWNgTBNwT//yiEDbsxm9QG4BYUojqeXxothuzJ/L6ibXz6+gLMvbOvLGV3nKgkXmx8GvT9WDKR0mA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rspack/binding-win32-ia32-msvc": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@rspack/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.7.11.tgz", + "integrity": "sha512-0pYGnZd8PPqNR68zQ8skamqNAXEA1sUfXuAdYcknIIRq2wsbiwFzIc0Pov1cIfHYab37G7sSIPBiOUdOWF5Ivw==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rspack/binding-win32-x64-msvc": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@rspack/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.7.11.tgz", + "integrity": "sha512-EeQXayoQk/uBkI3pdoXfQBXNIUrADq56L3s/DFyM2pJeUDrWmhfIw2UFIGkYPTMSCo8F2JcdcGM32FGJrSnU0Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rspack/core": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@rspack/core/-/core-1.7.11.tgz", + "integrity": "sha512-rsD9b+Khmot5DwCMiB3cqTQo53ioPG3M/A7BySu8+0+RS7GCxKm+Z+mtsjtG/vsu4Tn2tcqCdZtA3pgLoJB+ew==", + "license": "MIT", + "dependencies": { + "@module-federation/runtime-tools": "0.22.0", + "@rspack/binding": "1.7.11", + "@rspack/lite-tapable": "1.1.0" + }, + "engines": { + "node": ">=18.12.0" + }, + "peerDependencies": { + "@swc/helpers": ">=0.5.1" + }, + "peerDependenciesMeta": { + "@swc/helpers": { + "optional": true + } + } + }, + "node_modules/@rspack/lite-tapable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rspack/lite-tapable/-/lite-tapable-1.1.0.tgz", + "integrity": "sha512-E2B0JhYFmVAwdDiG14+DW0Di4Ze4Jg10Pc4/lILUrd5DRCaklduz2OvJ5HYQ6G+hd+WTzqQb3QnDNfK4yvAFYw==", + "license": "MIT" + }, + "node_modules/@rspack/plugin-react-refresh": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@rspack/plugin-react-refresh/-/plugin-react-refresh-1.6.1.tgz", + "integrity": "sha512-eqqW5645VG3CzGzFgNg5HqNdHVXY+567PGjtDhhrM8t67caxmsSzRmT5qfoEIfBcGgFkH9vEg7kzXwmCYQdQDw==", + "license": "MIT", + "dependencies": { + "error-stack-parser": "^2.1.4", + "html-entities": "^2.6.0" + }, + "peerDependencies": { + "react-refresh": ">=0.10.0 <1.0.0", + "webpack-hot-middleware": "2.x" + }, + "peerDependenciesMeta": { + "webpack-hot-middleware": { + "optional": true + } + } + }, + "node_modules/@svgr/babel-plugin-add-jsx-attribute": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz", + "integrity": "sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-attribute": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-8.0.0.tgz", + "integrity": "sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-8.0.0.tgz", + "integrity": "sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-8.0.0.tgz", + "integrity": "sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-svg-dynamic-title": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-8.0.0.tgz", + "integrity": "sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-svg-em-dimensions": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-8.0.0.tgz", + "integrity": "sha512-mURHYnu6Iw3UBTbhGwE/vsngtCIbHE43xCRK7kCw4t01xyGqb2Pd+WXekRRoFOBIY29ZoOhUCTEweDMdrjfi9g==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-transform-react-native-svg": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-8.1.0.tgz", + "integrity": "sha512-Tx8T58CHo+7nwJ+EhUwx3LfdNSG9R2OKfaIXXs5soiy5HtgoAEkDay9LIimLOcG8dJQH1wPZp/cnAv6S9CrR1Q==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-transform-svg-component": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-8.0.0.tgz", + "integrity": "sha512-DFx8xa3cZXTdb/k3kfPeaixecQLgKh5NVBMwD0AQxOzcZawK4oo1Jh9LbrcACUivsCA7TLG8eeWgrDXjTMhRmw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-preset": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-8.1.0.tgz", + "integrity": "sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug==", + "license": "MIT", + "dependencies": { + "@svgr/babel-plugin-add-jsx-attribute": "8.0.0", + "@svgr/babel-plugin-remove-jsx-attribute": "8.0.0", + "@svgr/babel-plugin-remove-jsx-empty-expression": "8.0.0", + "@svgr/babel-plugin-replace-jsx-attribute-value": "8.0.0", + "@svgr/babel-plugin-svg-dynamic-title": "8.0.0", + "@svgr/babel-plugin-svg-em-dimensions": "8.0.0", + "@svgr/babel-plugin-transform-react-native-svg": "8.1.0", + "@svgr/babel-plugin-transform-svg-component": "8.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/core": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/core/-/core-8.1.0.tgz", + "integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.21.3", + "@svgr/babel-preset": "8.1.0", + "camelcase": "^6.2.0", + "cosmiconfig": "^8.1.3", + "snake-case": "^3.0.4" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/hast-util-to-babel-ast": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-8.0.0.tgz", + "integrity": "sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.21.3", + "entities": "^4.4.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/plugin-jsx": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-8.1.0.tgz", + "integrity": "sha512-0xiIyBsLlr8quN+WyuxooNW9RJ0Dpr8uOnH/xrCVO8GLUcwHISwj1AG0k+LFzteTkAA0GbX0kj9q6Dk70PTiPA==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.21.3", + "@svgr/babel-preset": "8.1.0", + "@svgr/hast-util-to-babel-ast": "8.0.0", + "svg-parser": "^2.0.4" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@svgr/core": "*" + } + }, + "node_modules/@tanstack/react-virtual": { + "version": "3.14.9", + "resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.14.9.tgz", + "integrity": "sha512-qZyr0FZDP8rDC4WBhsryIZmAd9bveJvFGUJJtskWaew6/0dTRS6wZxnR6VQ5bY2KwL3LjerrHqQLk3a0GKcPXQ==", + "license": "MIT", + "dependencies": { + "@tanstack/virtual-core": "3.17.7" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, - "node_modules/@remotion/studio-server": { - "version": "4.0.286", - "resolved": "https://registry.npmjs.org/@remotion/studio-server/-/studio-server-4.0.286.tgz", - "integrity": "sha512-qLNdHIyUI/JSEqJgEbia07u3n+r3dordu/tcSrs3BFAqXkACqzoh0Q4CMoRMQO+GCNBpiFjpLHNawOVhe3Ivyw==", + "node_modules/@tanstack/virtual-core": { + "version": "3.17.7", + "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.17.7.tgz", + "integrity": "sha512-bp+v10y65sp2H7WpWfIMyxTNfl8ZVfxFTLRjPIFRryi6FV/J33z4IS53WO4pTk36KlvJ4iLiQz+oaydDC1xbcA==", "license": "MIT", - "dependencies": { - "@babel/parser": "7.24.1", - "@remotion/bundler": "4.0.286", - "@remotion/renderer": "4.0.286", - "@remotion/studio-shared": "4.0.286", - "memfs": "3.4.3", - "open": "^8.4.2", - "recast": "0.23.9", - "remotion": "4.0.286", - "semver": "7.5.3", - "source-map": "0.7.3" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" } }, - "node_modules/@remotion/studio-shared": { - "version": "4.0.286", - "resolved": "https://registry.npmjs.org/@remotion/studio-shared/-/studio-shared-4.0.286.tgz", - "integrity": "sha512-Xrtc1qJQezoixrsvLEkaIu59H5fjZAvtXjPXYo2+mDzePNalJE/EBnMNCIGoFemZ1wcCxjkaJzbgEviQvj21UQ==", + "node_modules/@tybys/wasm-util": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.4.tgz", + "integrity": "sha512-W3c4gRigFS0T/Ma4qIYF3GDAc5AQdHb1yL5znJT1Zv1YaD9Kitx656wBjvr19qbiosmZT8lWDM5BEMynUqX65A==", "license": "MIT", + "optional": true, "dependencies": { - "remotion": "4.0.286" + "tslib": "^2.4.0" } }, - "node_modules/@remotion/zod-types": { - "version": "4.0.286", - "resolved": "https://registry.npmjs.org/@remotion/zod-types/-/zod-types-4.0.286.tgz", - "integrity": "sha512-ivc/SyVXS5/jDb10+nW9eHg9/3TIgGg0jGd7sA6PwDEBfrbtCAk6OQfhiWNHYmqDn2GSWJYXXmtzLoyt1bU0BA==", + "node_modules/@types/dom-mediacapture-transform": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/@types/dom-mediacapture-transform/-/dom-mediacapture-transform-0.1.12.tgz", + "integrity": "sha512-d7/QsLRwF864A5mgIM/YrfiglHoYn7zgCcAoJgW404r+2DwnNr7EBbLnCWpmOMgH8y0te73L1AV6H1bmauaWFw==", "license": "MIT", "dependencies": { - "remotion": "4.0.286" - }, - "peerDependencies": { - "zod": "3.22.3" + "@types/dom-webcodecs": "*" } }, + "node_modules/@types/dom-webcodecs": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/@types/dom-webcodecs/-/dom-webcodecs-0.1.13.tgz", + "integrity": "sha512-O5hkiFIcjjszPIYyUSyvScyvrBoV3NOEEZx/pMlsu44TKzWNkLVBBxnxJz42in5n3QIolYOcBYFCPZZ0h8SkwQ==", + "license": "MIT" + }, "node_modules/@types/eslint": { "version": "9.6.1", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", @@ -782,12 +1976,12 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "25.9.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.1.tgz", - "integrity": "sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg==", + "version": "26.6.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-26.6.5.tgz", + "integrity": "sha512-uMzsv9stDdofIZBx4UGh4Z9ZgXnGC9seRDscilBcTHAeOFk67MZg/k9bWVfO+bk4qZmG+l52hRnLwUiH2LnJTg==", "license": "MIT", "dependencies": { - "undici-types": ">=7.24.0 <7.24.7" + "undici-types": "~8.9.0" } }, "node_modules/@types/prop-types": { @@ -808,16 +2002,6 @@ "csstype": "^3.2.2" } }, - "node_modules/@types/yauzl": { - "version": "2.10.3", - "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", - "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", - "license": "MIT", - "optional": true, - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@webassemblyjs/ast": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", @@ -977,9 +2161,9 @@ "license": "Apache-2.0" }, "node_modules/acorn": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", - "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.19.0.tgz", + "integrity": "sha512-oJlA3XiRm7Cyk6qFD2Jn8ak9B7jSy0qy00ADO3+8dpT0LSjFihQYv4C02LFCSYJV3Q37xYwwRy5m+IpIiUzqWw==", "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -988,16 +2172,28 @@ "node": ">=0.4.0" } }, + "node_modules/acorn-import-phases": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz", + "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==", + "license": "MIT", + "engines": { + "node": ">=10.13.0" + }, + "peerDependencies": { + "acorn": "^8.14.0" + } + }, "node_modules/ajv": { - "version": "6.15.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", - "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" }, "funding": { "type": "github", @@ -1005,9 +2201,9 @@ } }, "node_modules/ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", "license": "MIT", "dependencies": { "ajv": "^8.0.0" @@ -1021,37 +2217,24 @@ } } }, - "node_modules/ajv-formats/node_modules/ajv": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", - "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" + "fast-deep-equal": "^3.1.3" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "license": "MIT" - }, - "node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "license": "MIT", "peerDependencies": { - "ajv": "^6.9.1" + "ajv": "^8.8.2" } }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" + }, "node_modules/ast-types": { "version": "0.16.1", "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.16.1.tgz", @@ -1065,9 +2248,9 @@ } }, "node_modules/baseline-browser-mapping": { - "version": "2.10.33", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.33.tgz", - "integrity": "sha512-bA6+tcSLpz2tIEdDXZPpPTIuxBcC4+w6SieaYyfigIa4h8GlFxbA17v22Vx3JUtuZQj9SgOsnbK+aTBzyDyEuw==", + "version": "2.11.30", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.30.tgz", + "integrity": "sha512-YJs6Pz17RMNv8HoyKREtCY38E3BV1nPkWVmIb+XN1uHC1Vqt3KZCH/uJH9ZKRoiKb/icZ6tvehyee6RZNbFfRA==", "license": "Apache-2.0", "bin": { "baseline-browser-mapping": "dist/cli.cjs" @@ -1076,19 +2259,10 @@ "node": ">=6.0.0" } }, - "node_modules/big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", - "license": "MIT", - "engines": { - "node": "*" - } - }, "node_modules/browserslist": { - "version": "4.28.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", - "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", + "version": "4.29.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.29.4.tgz", + "integrity": "sha512-2TcbbiwXEq+N0kD36tykpCfyyQigUXmuwNQbnPp4Xk4PX9JOqVIKjJlIDjpH7uY6tmRGoAd+apeT1p60T8wsdA==", "funding": [ { "type": "opencollective", @@ -1105,11 +2279,11 @@ ], "license": "MIT", "dependencies": { - "baseline-browser-mapping": "^2.10.12", - "caniuse-lite": "^1.0.30001782", - "electron-to-chromium": "^1.5.328", - "node-releases": "^2.0.36", - "update-browserslist-db": "^1.2.3" + "baseline-browser-mapping": "^2.11.29", + "caniuse-lite": "^1.0.30001816", + "electron-to-chromium": "^1.5.459", + "node-releases": "^2.0.59", + "update-browserslist-db": "^1.3.4" }, "bin": { "browserslist": "cli.js" @@ -1118,25 +2292,37 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "license": "MIT", - "engines": { - "node": "*" - } - }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "license": "MIT" }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/caniuse-lite": { - "version": "1.0.30001793", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001793.tgz", - "integrity": "sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==", + "version": "1.0.30001819", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001819.tgz", + "integrity": "sha512-LFUqIIAwpzsIuevnKnsR9qnStBcgzPShTX61lBwN9uFkkf8o8zLiebEjbW8AYtZiF+1YKDWfdt/pWDtMuG8Xwg==", "funding": [ { "type": "opencollective", @@ -1168,6 +2354,38 @@ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "license": "MIT" }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "license": "MIT" + }, + "node_modules/cosmiconfig": { + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", + "license": "MIT", + "dependencies": { + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -1183,31 +2401,50 @@ } }, "node_modules/css-loader": { - "version": "5.2.7", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-5.2.7.tgz", - "integrity": "sha512-Q7mOvpBNBG7YrVGMxRxcBJZFL75o+cH2abNASdibkj/fffYD8qWbInZrD0S9ccI6vZclF3DsHE7njGlLtaHbhg==", + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-7.1.4.tgz", + "integrity": "sha512-vv3J9tlOl04WjiMvHQI/9tmIrCxVrj6PFbHemBB1iihpeRbi/I4h033eoFIhwxBBqLhI0KYFS7yvynBFhIZfTw==", "license": "MIT", "dependencies": { "icss-utils": "^5.1.0", - "loader-utils": "^2.0.0", - "postcss": "^8.2.15", - "postcss-modules-extract-imports": "^3.0.0", - "postcss-modules-local-by-default": "^4.0.0", - "postcss-modules-scope": "^3.0.0", + "postcss": "^8.4.40", + "postcss-modules-extract-imports": "^3.1.0", + "postcss-modules-local-by-default": "^4.0.5", + "postcss-modules-scope": "^3.2.0", "postcss-modules-values": "^4.0.0", - "postcss-value-parser": "^4.1.0", - "schema-utils": "^3.0.0", - "semver": "^7.3.5" + "postcss-value-parser": "^4.2.0", + "semver": "^7.6.3" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 18.12.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" }, "peerDependencies": { - "webpack": "^4.27.0 || ^5.0.0" + "@rspack/core": "0.x || ^1.0.0 || ^2.0.0-0", + "webpack": "^5.27.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/css-loader/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, "node_modules/cssesc": { @@ -1255,62 +2492,87 @@ "node": ">=8" } }, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "license": "MIT", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, "node_modules/dotenv": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-9.0.2.tgz", - "integrity": "sha512-I9OvvrHp4pIARv4+x9iuewrWycX6CcZtoAu1XrzPxc5UygMJXJZYmBsynku8IkrJwgypE5DGNjDPmPRhDCptUg==", + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.3.1.tgz", + "integrity": "sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA==", "license": "BSD-2-Clause", "engines": { - "node": ">=10" + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" } }, "node_modules/electron-to-chromium": { - "version": "1.5.364", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.364.tgz", - "integrity": "sha512-G/dYE3+AYhyHwzTwg8UbnXf7zqMERYh7l2jJ3QujhFsH8agSYwtnGAR2aZ7f0AakIKJXd5En/Hre4igIUrdlYw==", + "version": "1.5.463", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.463.tgz", + "integrity": "sha512-nVWNU6ltFjopvOdD44J4zoBkgO0M+WZiFKKFV7EjebOH9z0KNphk6bCEjplXtJofL21ARIuuwWOCsFkBVklm6w==", "license": "ISC" }, - "node_modules/emojis-list": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", - "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "node_modules/enhanced-resolve": { + "version": "5.26.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.26.0.tgz", + "integrity": "sha512-9vhedylFonb2YGogzUKX6+Ja72gOJbN1QHAqdrvqLwhdl/QWbKopzoUC9EbQNVsAns/bx/4uyqalrQAoy1IByw==", "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.3" + }, "engines": { - "node": ">= 4" + "node": ">=10.13.0" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/end-of-stream": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", - "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", "license": "MIT", "dependencies": { - "once": "^1.4.0" + "is-arrayish": "^0.2.1" } }, - "node_modules/enhanced-resolve": { - "version": "5.22.1", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.22.1.tgz", - "integrity": "sha512-6QEuw3zoX1SJQc7b87aBXke/no+mG2bTBgw29gWMQonLmpEkWoCAVkl+M49e48AZlWzxiDzDZzYdp6kobcyLww==", + "node_modules/error-stack-parser": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz", + "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==", "license": "MIT", "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.3.3" - }, - "engines": { - "node": ">=10.13.0" + "stackframe": "^1.3.4" } }, "node_modules/es-module-lexer": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", - "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.2.tgz", + "integrity": "sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==", "license": "MIT" }, "node_modules/esbuild": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.0.tgz", - "integrity": "sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz", + "integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==", "hasInstallScript": true, "license": "MIT", "bin": { @@ -1320,31 +2582,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.0", - "@esbuild/android-arm": "0.25.0", - "@esbuild/android-arm64": "0.25.0", - "@esbuild/android-x64": "0.25.0", - "@esbuild/darwin-arm64": "0.25.0", - "@esbuild/darwin-x64": "0.25.0", - "@esbuild/freebsd-arm64": "0.25.0", - "@esbuild/freebsd-x64": "0.25.0", - "@esbuild/linux-arm": "0.25.0", - "@esbuild/linux-arm64": "0.25.0", - "@esbuild/linux-ia32": "0.25.0", - "@esbuild/linux-loong64": "0.25.0", - "@esbuild/linux-mips64el": "0.25.0", - "@esbuild/linux-ppc64": "0.25.0", - "@esbuild/linux-riscv64": "0.25.0", - "@esbuild/linux-s390x": "0.25.0", - "@esbuild/linux-x64": "0.25.0", - "@esbuild/netbsd-arm64": "0.25.0", - "@esbuild/netbsd-x64": "0.25.0", - "@esbuild/openbsd-arm64": "0.25.0", - "@esbuild/openbsd-x64": "0.25.0", - "@esbuild/sunos-x64": "0.25.0", - "@esbuild/win32-arm64": "0.25.0", - "@esbuild/win32-ia32": "0.25.0", - "@esbuild/win32-x64": "0.25.0" + "@esbuild/aix-ppc64": "0.28.1", + "@esbuild/android-arm": "0.28.1", + "@esbuild/android-arm64": "0.28.1", + "@esbuild/android-x64": "0.28.1", + "@esbuild/darwin-arm64": "0.28.1", + "@esbuild/darwin-x64": "0.28.1", + "@esbuild/freebsd-arm64": "0.28.1", + "@esbuild/freebsd-x64": "0.28.1", + "@esbuild/linux-arm": "0.28.1", + "@esbuild/linux-arm64": "0.28.1", + "@esbuild/linux-ia32": "0.28.1", + "@esbuild/linux-loong64": "0.28.1", + "@esbuild/linux-mips64el": "0.28.1", + "@esbuild/linux-ppc64": "0.28.1", + "@esbuild/linux-riscv64": "0.28.1", + "@esbuild/linux-s390x": "0.28.1", + "@esbuild/linux-x64": "0.28.1", + "@esbuild/netbsd-arm64": "0.28.1", + "@esbuild/netbsd-x64": "0.28.1", + "@esbuild/openbsd-arm64": "0.28.1", + "@esbuild/openbsd-x64": "0.28.1", + "@esbuild/openharmony-arm64": "0.28.1", + "@esbuild/sunos-x64": "0.28.1", + "@esbuild/win32-arm64": "0.28.1", + "@esbuild/win32-ia32": "0.28.1", + "@esbuild/win32-x64": "0.28.1" } }, "node_modules/escalade": { @@ -1444,57 +2707,16 @@ "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "node_modules/extract-zip": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", - "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", - "license": "BSD-2-Clause", - "dependencies": { - "debug": "^4.1.1", - "get-stream": "^5.1.0", - "yauzl": "^2.10.0" - }, - "bin": { - "extract-zip": "cli.js" - }, - "engines": { - "node": ">= 10.17.0" - }, - "optionalDependencies": { - "@types/yauzl": "^2.9.1" - } - }, - "node_modules/extract-zip/node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "license": "MIT", - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "license": "MIT" }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "license": "MIT" - }, "node_modules/fast-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz", - "integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==", + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.9.tgz", + "integrity": "sha512-hS/0Wt3Ya043oKXs0sIxrMpKQITXhMLIrVAKKXi4gozGC9v7YRWVnXIZzjNPTO02M9BdxLCWqK1yRXgNziVyJQ==", "funding": [ { "type": "github", @@ -1507,21 +2729,21 @@ ], "license": "BSD-3-Clause" }, - "node_modules/fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", - "license": "MIT", - "dependencies": { - "pend": "~1.2.0" - } - }, "node_modules/fs-monkey": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.3.tgz", "integrity": "sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==", "license": "Unlicense" }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/get-stream": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", @@ -1555,6 +2777,22 @@ "node": ">=8" } }, + "node_modules/html-entities": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.6.0.tgz", + "integrity": "sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ], + "license": "MIT" + }, "node_modules/human-signals": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", @@ -1576,6 +2814,28 @@ "postcss": "^8.1.0" } }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "license": "MIT" + }, "node_modules/is-docker": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", @@ -1641,6 +2901,40 @@ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "license": "MIT" }, + "node_modules/js-yaml": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz", + "integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", @@ -1648,9 +2942,9 @@ "license": "MIT" }, "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "license": "MIT" }, "node_modules/json5": { @@ -1665,6 +2959,15 @@ "node": ">=6" } }, + "node_modules/kiwi-schema": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/kiwi-schema/-/kiwi-schema-0.5.0.tgz", + "integrity": "sha512-X+FpfU0yTEtc6aTHS7VwbOpvQwRt70+pXXWRI5fd6CvWhe7pSVC854TVo4Zo0x5/wwcWj+/9KUlXpdcP0dY9AA==", + "license": "MIT", + "bin": { + "kiwic": "cli.js" + } + }, "node_modules/kleur": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", @@ -1674,6 +2977,12 @@ "node": ">=6" } }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "license": "MIT" + }, "node_modules/loader-runner": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.2.tgz", @@ -1687,26 +2996,6 @@ "url": "https://opencollective.com/webpack" } }, - "node_modules/loader-utils": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", - "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", - "license": "MIT", - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - }, - "engines": { - "node": ">=8.9.0" - } - }, - "node_modules/lodash.sortby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==", - "license": "MIT" - }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -1719,16 +3008,40 @@ "loose-envify": "cli.js" } }, + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.3" + } + }, "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "license": "ISC", "dependencies": { - "yallist": "^4.0.0" + "yallist": "^3.0.2" + } + }, + "node_modules/mediabunny": { + "version": "1.62.0", + "resolved": "https://registry.npmjs.org/mediabunny/-/mediabunny-1.62.0.tgz", + "integrity": "sha512-D8E8BDxjCyqyrGj074jLRQNgilDW5izJu8o9pg7THMYMIZBL1Fao5hOtdDPDfA+nSnk68tMa8IaCJmz8hSpJpw==", + "license": "MPL-2.0", + "workspaces": [ + ".", + "packages/*" + ], + "dependencies": { + "@types/dom-mediacapture-transform": "^0.1.11", + "@types/dom-webcodecs": "0.1.13" }, - "engines": { - "node": ">=10" + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/Vanilagy" } }, "node_modules/memfs": { @@ -1750,10 +3063,11 @@ "license": "MIT" }, "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", "license": "MIT", + "peer": true, "engines": { "node": ">= 0.6" } @@ -1770,6 +3084,15 @@ "node": ">= 0.6" } }, + "node_modules/mime-types/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/mimic-fn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", @@ -1785,6 +3108,79 @@ "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", "license": "MIT" }, + "node_modules/minimizer-webpack-plugin": { + "version": "5.13.1", + "resolved": "https://registry.npmjs.org/minimizer-webpack-plugin/-/minimizer-webpack-plugin-5.13.1.tgz", + "integrity": "sha512-1mhAfvachWYYOm8tpmany5NLuvP+F2wxZWBSX8DC0uFS2wJpM9q3rWgN9wBooAH9d5V12wX0BjyJe4fMjHMarQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.31", + "jest-worker": "^27.4.5", + "schema-utils": "^4.6.0", + "terser": "^5.51.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@minify-html/node": { + "optional": true + }, + "@napi-rs/image": { + "optional": true + }, + "@swc/core": { + "optional": true + }, + "@swc/css": { + "optional": true + }, + "@swc/html": { + "optional": true + }, + "clean-css": { + "optional": true + }, + "cssnano": { + "optional": true + }, + "csso": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "html-minifier-terser": { + "optional": true + }, + "imagemin": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "postcss": { + "optional": true + }, + "sharp": { + "optional": true + }, + "svgo": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -1792,9 +3188,9 @@ "license": "MIT" }, "node_modules/nanoid": { - "version": "3.3.12", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", - "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", + "version": "3.3.20", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.20.tgz", + "integrity": "sha512-uKdg2G3GNCKQn9byYOpxbGqrT2fGO5KRt5J/8b3pok8rT6qxGWF6hxMyJiEYtAf+FVyYuD9hRaDqX5uPFYJ4ZQ==", "funding": [ { "type": "github", @@ -1815,10 +3211,20 @@ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "license": "MIT" }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "license": "MIT", + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, "node_modules/node-releases": { - "version": "2.0.46", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.46.tgz", - "integrity": "sha512-GYVXHE2KnrzAfsAjl4uP++evGFCrAU1jta4ubEjIG7YWt/64Gqv66a30yKwWczVjA6j3bM4nBwH7Pk1JmDHaxQ==", + "version": "2.0.60", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.60.tgz", + "integrity": "sha512-OmO8+GM1JUZqXET720VrJCwkjUCXmCMQm0Z3UDDRbfNLHS4NEAvY60j5jiFv0tkKw2PNNlqOLhahVmwJIOLDIQ==", "license": "MIT", "engines": { "node": ">=18" @@ -1836,15 +3242,6 @@ "node": ">=8" } }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, "node_modules/onetime": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", @@ -1877,6 +3274,36 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -1886,11 +3313,14 @@ "node": ">=8" } }, - "node_modules/pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", - "license": "MIT" + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "license": "MIT", + "engines": { + "node": ">=8" + } }, "node_modules/picocolors": { "version": "1.1.1", @@ -1899,9 +3329,9 @@ "license": "ISC" }, "node_modules/postcss": { - "version": "8.5.15", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", - "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", + "version": "8.5.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.31.tgz", + "integrity": "sha512-YUbWYCgErwnMAVkjUnYa+KlMBzGpHwiIt/DE7f0G33AuX2LH9UcTk6KgWxd3zRU+pN3u/C+Xl3EnMLM4Hea7Sg==", "funding": [ { "type": "opencollective", @@ -1918,9 +3348,9 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.12", + "nanoid": "^3.3.20", "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" + "source-map-js": "^1.2.2" }, "engines": { "node": "^10 || ^12 || >=14" @@ -1986,9 +3416,9 @@ } }, "node_modules/postcss-selector-parser": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", - "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.7.tgz", + "integrity": "sha512-wWBro/7hJ40ye6TPiXkUQoXKCw23xSsjriUvqd7Uls9Sso3oLiON1flc18cCdnjgCRXw4fBVqUJJeOdDTh3P3g==", "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -2004,6 +3434,15 @@ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", "license": "MIT" }, + "node_modules/prismjs": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", + "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/prompts": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", @@ -2017,25 +3456,6 @@ "node": ">= 6" } }, - "node_modules/pump": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", - "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", - "license": "MIT", - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/react": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", @@ -2062,18 +3482,18 @@ } }, "node_modules/react-refresh": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.9.0.tgz", - "integrity": "sha512-Gvzk7OZpiqKSkxsQvO/mbTN1poglhmAV7gR/DdIrRrSMXraRQQlfikRJOr3Nb9GTMPC5kof948Zy6jJZIFtDvQ==", + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz", + "integrity": "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==", "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/recast": { - "version": "0.23.9", - "resolved": "https://registry.npmjs.org/recast/-/recast-0.23.9.tgz", - "integrity": "sha512-Hx/BGIbwj+Des3+xy5uAtAbdCyqK9y9wbBcDFDYanLS9JnMqf7OeF87HQwUimE87OEc72mr6tkKUKMBBL+hF9Q==", + "version": "0.23.21", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.23.21.tgz", + "integrity": "sha512-mFAyJq9vUbSTARLZUvAEf1z3YxlvAwswbmxMx2mPA/MSm4KmpwvwvhsH/NIrZhyOuwD60Lzyw2qh83uCbgTPYw==", "license": "MIT", "dependencies": { "ast-types": "^0.16.1", @@ -2096,9 +3516,9 @@ } }, "node_modules/remotion": { - "version": "4.0.286", - "resolved": "https://registry.npmjs.org/remotion/-/remotion-4.0.286.tgz", - "integrity": "sha512-Zwh8ZQ93X1QetpwM78pcavyBOr8srg1v2enWU4sKlGNikvAgOOyvFK8qtZGtjkFOkpb7oRsmmAikUxjpXSTGgA==", + "version": "4.0.538", + "resolved": "https://registry.npmjs.org/remotion/-/remotion-4.0.538.tgz", + "integrity": "sha512-HA9/+3GOfNxBtT+iFsqmzGtegtE1M3qra3N/iBiXv5oRX+1q0HsFTjcFxT9Ljmmodd5huVZLKLK0ymvYsecCaw==", "license": "SEE LICENSE IN LICENSE.md", "peerDependencies": { "react": ">=16.8.0", @@ -2114,6 +3534,15 @@ "node": ">=0.10.0" } }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/scheduler": { "version": "0.23.2", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", @@ -2124,14 +3553,18 @@ } }, "node_modules/schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.8.1.tgz", + "integrity": "sha512-x39pYlJPyH7Uge5QO64B9XGP9zLDc9WNmiQZc+CE3IzZPvMu3lHOuAMGpYNoPixEL7MSWlGhYTg5UlLSL8G6iw==", "license": "MIT", "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" + "@types/json-schema": "^7.0.15", + "ajv": "^8.20.0", + "ajv-formats": "^3.0.1", + "ajv-keywords": "^5.1.0" + }, + "bin": { + "schema-utils": "bin/schema-utils.js" }, "engines": { "node": ">= 10.13.0" @@ -2139,6 +3572,14 @@ "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.112.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + } } }, "node_modules/semver": { @@ -2156,6 +3597,24 @@ "node": ">=10" } }, + "node_modules/semver/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -2189,19 +3648,29 @@ "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", "license": "MIT" }, + "node_modules/snake-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", + "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==", + "license": "MIT", + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, "node_modules/source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0.tgz", + "integrity": "sha512-d8EqvL+k/SOXCreS/SUzg2ciyHqBBLcN/yuRjFsbvVhHTE2pgei7oAhmPM7kWFbkX6OSMQfUq4KbkF3au9lhYQ==", "license": "BSD-3-Clause", "engines": { - "node": ">= 8" + "node": ">= 12" } }, "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.2.tgz", + "integrity": "sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==", "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -2226,6 +3695,12 @@ "node": ">=0.10.0" } }, + "node_modules/stackframe": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz", + "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==", + "license": "MIT" + }, "node_modules/strip-final-newline": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", @@ -2266,6 +3741,15 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/svg-parser": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.1.0.tgz", + "integrity": "sha512-bwLf38YmY+TDYHJw1Ex0Co8c4yeXuJAo8YnXGZrscxrvYoVVIvLeniEkV1Ks/54VteMnL4FtyN1+P+TZJdUPmQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/tapable": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", @@ -2280,9 +3764,9 @@ } }, "node_modules/terser": { - "version": "5.48.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.48.0.tgz", - "integrity": "sha512-J/9An6vs9Us6wKRriSFXBWdRZapREHqFzdNUKk0pmu804EMR6dr6winwo7e5JDxN4xahxQsuysyYFwlwj4XN/Q==", + "version": "5.51.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.51.2.tgz", + "integrity": "sha512-bWnjSNscmuI+GJze6ZupnHP8G/cTcsJF+bXCeQknk2SHQsgbNJnLrqiH9jZ2W4STPVXH2mDKKRX3iwPhc9Cn/Q==", "license": "BSD-2-Clause", "dependencies": { "@jridgewell/source-map": "^0.3.3", @@ -2357,72 +3841,19 @@ } } }, - "node_modules/terser-webpack-plugin/node_modules/ajv": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", - "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/terser-webpack-plugin/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, - "node_modules/terser-webpack-plugin/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "license": "MIT" - }, - "node_modules/terser-webpack-plugin/node_modules/schema-utils": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", - "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", - "license": "MIT", - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, "node_modules/tiny-invariant": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", "license": "MIT" }, - "node_modules/tr46": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", - "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==", + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", "license": "MIT", - "dependencies": { - "punycode": "^2.1.0" + "engines": { + "node": ">=4" } }, "node_modules/tslib": { @@ -2435,7 +3866,7 @@ "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -2446,15 +3877,15 @@ } }, "node_modules/undici-types": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz", - "integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==", + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.9.0.tgz", + "integrity": "sha512-KTDyRTYX8sWmKXAikPHHSyc63CRPETMctyjKFupcC6OBLXT3xsN0e9aF7m+mIXutFWpUXuedtowG7iLOzp0kQg==", "license": "MIT" }, "node_modules/update-browserslist-db": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", - "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.4.tgz", + "integrity": "sha512-t8wonIOdQyOjtPd2VktlBu6QjTVTks6v8bSi7kd0r2Vll8TK1JYDZtRRdbmCHOAMphkZgrzK+L+vXK4pyZ8t4A==", "funding": [ { "type": "opencollective", @@ -2481,15 +3912,6 @@ "browserslist": ">= 4.21.0" } }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "license": "BSD-2-Clause", - "dependencies": { - "punycode": "^2.1.0" - } - }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -2497,53 +3919,41 @@ "license": "MIT" }, "node_modules/watchpack": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.1.tgz", - "integrity": "sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==", + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.6.3.tgz", + "integrity": "sha512-s3NZy0QpTY9qGqzc0wtz4qI28z3+5qKbbAec4MV4G9N3CfgZ9wgvQRr0cl2jh/tqkWG1NWHkmVMHZpCamev5Wg==", "license": "MIT", "dependencies": { - "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.1.2" }, "engines": { "node": ">=10.13.0" } }, - "node_modules/webidl-conversions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", - "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", - "license": "BSD-2-Clause" - }, "node_modules/webpack": { - "version": "5.96.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.96.1.tgz", - "integrity": "sha512-l2LlBSvVZGhL4ZrPwyr8+37AunkcYj5qh8o6u2/2rzoPc8gxFJkLj1WxNgooi9pnoc06jh0BjuXnamM4qlujZA==", - "license": "MIT", - "dependencies": { - "@types/eslint-scope": "^3.7.7", - "@types/estree": "^1.0.6", - "@webassemblyjs/ast": "^1.12.1", - "@webassemblyjs/wasm-edit": "^1.12.1", - "@webassemblyjs/wasm-parser": "^1.12.1", - "acorn": "^8.14.0", - "browserslist": "^4.24.0", + "version": "5.112.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.112.0.tgz", + "integrity": "sha512-NIBpsRuCll036haDDt/CfcTDfsWNR9Z782nMRMI9D377BsGcYzZDTNU5TyzhCJzPIcihAxMBaMAhq2WSaDrH8Q==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/estree": "^1.0.8", + "@types/json-schema": "^7.0.15", + "@webassemblyjs/ast": "^1.14.1", + "@webassemblyjs/wasm-edit": "^1.14.1", + "@webassemblyjs/wasm-parser": "^1.14.1", + "browserslist": "^4.28.1", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.17.1", - "es-module-lexer": "^1.2.1", - "eslint-scope": "5.1.1", + "enhanced-resolve": "^5.26.0", + "es-module-lexer": "^2.1.0", "events": "^3.2.0", - "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.2.11", - "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.2.0", - "mime-types": "^2.1.27", - "neo-async": "^2.6.2", - "schema-utils": "^3.2.0", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.3.10", - "watchpack": "^2.4.1", - "webpack-sources": "^3.2.3" + "mime-db": "^1.54.0", + "minimizer-webpack-plugin": "^5.13.0", + "schema-utils": "^4.5.0", + "tapable": "^2.3.0", + "watchpack": "^2.6.1", + "webpack-sources": "^3.6.0" }, "bin": { "webpack": "bin/webpack.js" @@ -2562,25 +3972,14 @@ } }, "node_modules/webpack-sources": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.5.0.tgz", - "integrity": "sha512-HPuy+uuoTCaaoEoI1LQ3JN9+vrPBvEesnnX1jADHy728cHSMlq4wUc4afYqahq2B1mhQVZxCXOkNTnXltr+2vQ==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.6.0.tgz", + "integrity": "sha512-EIMmPVvNI0CYXyRPp34F2Qk7W37/BZVZIofS6LAUnrNjCVahS+hO4mxwFJDjQjODTGZDtVzLYoN2+1dYkhk9qA==", "license": "MIT", "engines": { "node": ">=10.13.0" } }, - "node_modules/whatwg-url": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", - "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", - "license": "MIT", - "dependencies": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" - } - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -2596,16 +3995,10 @@ "node": ">= 8" } }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "license": "ISC" - }, "node_modules/ws": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", - "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", + "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", "license": "MIT", "engines": { "node": ">=10.0.0" @@ -2624,25 +4017,15 @@ } }, "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "license": "ISC" }, - "node_modules/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", - "license": "MIT", - "dependencies": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - }, "node_modules/zod": { - "version": "3.22.3", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.3.tgz", - "integrity": "sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug==", + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.5.4.tgz", + "integrity": "sha512-sC95tT5iHHH9gtpj6A81kh+NEaRAUFN+qlUPDUbRfOMvNf5QCBqsb3WgvnpVtK5Y+4UfA6KqufotuTvMGiTlsA==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" diff --git a/landing-remotion/package.json b/landing-remotion/package.json index baf6016b95..c920e031b8 100644 --- a/landing-remotion/package.json +++ b/landing-remotion/package.json @@ -17,10 +17,10 @@ "render:all": "npm run render:agents:webm && npm run render:agents:mp4 && npm run render:mempalace:webm && npm run render:mempalace:mp4 && npm run render:godhive:webm && npm run render:godhive:mp4" }, "dependencies": { - "@remotion/cli": "4.0.286", + "@remotion/cli": "4.0.538", "react": "^18.3.1", "react-dom": "^18.3.1", - "remotion": "4.0.286" + "remotion": "4.0.538" }, "devDependencies": { "@types/react": "^18.3.11", From c53142684552b5191e83334d870d123a49b1b4c5 Mon Sep 17 00:00:00 2001 From: T3sh Date: Thu, 22 Oct 2026 19:18:23 -0300 Subject: [PATCH 21/24] =?UTF-8?q?chore(deps):=20pin=20electron-builder=202?= =?UTF-8?q?6.15.3,=20remove=20localtunnel/@types-localtunnel=20(TSF-8,=20O?= =?UTF-8?q?nda-1=20TSF-13,=20re-remo=C3=A7=C3=A3o=20TSF-17)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 2273 ++++++++++++++++++--------------------------- package.json | 4 +- 2 files changed, 895 insertions(+), 1382 deletions(-) diff --git a/package-lock.json b/package-lock.json index 33ea318642..28a4db9ec3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,7 +31,6 @@ "commit-graph": "^2.4.0", "electron-updater": "^6.8.9", "i18next": "^26.3.6", - "localtunnel": "^2.0.2", "monaco-editor": "^0.52.2", "node-pty": "^1.0.0", "pixi.js": "^8.5.1", @@ -48,13 +47,12 @@ "@electron/notarize": "^2.5.0", "@electron/rebuild": "^3.7.0", "@types/better-sqlite3": "^7.6.13", - "@types/localtunnel": "^2.0.4", "@types/node": "^22.7.5", "@types/react": "^18.3.11", "@types/react-dom": "^18.3.0", "@vitejs/plugin-react": "^4.3.2", "electron": "32.3.3", - "electron-builder": "^25.1.8", + "electron-builder": "26.15.3", "electron-vite": "^2.3.0", "typescript": "^5.6.3", "vite": "^5.4.8" @@ -556,58 +554,6 @@ "w3c-keyname": "^2.2.4" } }, - "node_modules/@develar/schema-utils": { - "version": "2.6.5", - "resolved": "https://registry.npmjs.org/@develar/schema-utils/-/schema-utils-2.6.5.tgz", - "integrity": "sha512-0cp4PsWQ/9avqTVMCtZ+GirikIA36ikvjtHweU4/j8yLtgObI0+JUPhYFScgwlteveGB1rt3Cm8UhN04XayDig==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^6.12.0", - "ajv-keywords": "^3.4.1" - }, - "engines": { - "node": ">= 8.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/@develar/schema-utils/node_modules/ajv": { - "version": "6.15.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", - "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@develar/schema-utils/node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "ajv": "^6.9.1" - } - }, - "node_modules/@develar/schema-utils/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" - }, "node_modules/@electron/asar": { "version": "3.4.1", "resolved": "https://registry.npmjs.org/@electron/asar/-/asar-3.4.1.tgz", @@ -634,9 +580,9 @@ "license": "MIT" }, "node_modules/@electron/asar/node_modules/brace-expansion": { - "version": "1.1.18", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", - "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz", + "integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==", "dev": true, "license": "MIT", "dependencies": { @@ -679,6 +625,60 @@ "node": "*" } }, + "node_modules/@electron/fuses": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@electron/fuses/-/fuses-1.8.0.tgz", + "integrity": "sha512-zx0EIq78WlY/lBb1uXlziZmDZI4ubcCXIMJ4uGjXzZW0nS19TjSPeXPAjzzTmKQlJUZm0SbmZhPKP7tuQ1SsEw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.1", + "fs-extra": "^9.0.1", + "minimist": "^1.2.5" + }, + "bin": { + "electron-fuses": "dist/bin.js" + } + }, + "node_modules/@electron/fuses/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@electron/fuses/node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@electron/fuses/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/@electron/get": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@electron/get/-/get-2.0.3.tgz", @@ -794,9 +794,9 @@ } }, "node_modules/@electron/osx-sign": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@electron/osx-sign/-/osx-sign-1.3.1.tgz", - "integrity": "sha512-BAfviURMHpmb1Yb50YbCxnOY0wfwaLXH5KJ4+80zS0gUkzDX3ec23naTlEqKsN+PwYn+a1cCzM7BJ4Wcd3sGzw==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@electron/osx-sign/-/osx-sign-1.3.3.tgz", + "integrity": "sha512-KZ8mhXvWv2rIEgMbWZ4y33bDHyUKMXnx4M0sTyPNK/vcB81ImdeY9Ggdqy0SWbMDgmbqyQ+phgejh6V3R2QuSg==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -947,13 +947,13 @@ } }, "node_modules/@electron/universal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@electron/universal/-/universal-2.0.1.tgz", - "integrity": "sha512-fKpv9kg4SPmt+hY7SVBnIYULE9QJl8L3sCfcBsnqbJwwBwAeTLokJ9TRt9y7bK0JAzIW2y78TVVjvnQEms/yyA==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@electron/universal/-/universal-2.0.3.tgz", + "integrity": "sha512-Wn9sPYIVFRFl5HmwMJkARCCf7rqK/EurkfQ/rJZ14mHP3iYTjZSIOSVonEAnhWeAXwtw7zOekGRlc6yTtZ0t+g==", "dev": true, "license": "MIT", "dependencies": { - "@electron/asar": "^3.2.7", + "@electron/asar": "^3.3.1", "@malept/cross-spawn-promise": "^2.0.0", "debug": "^4.3.1", "dir-compare": "^4.2.0", @@ -973,9 +973,9 @@ "license": "MIT" }, "node_modules/@electron/universal/node_modules/brace-expansion": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.4.tgz", - "integrity": "sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==", + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.7.tgz", + "integrity": "sha512-uZbew1NqdmPDTMJ8ah1y+b+9QEJrfkXFk3RcTQw3X0jW/xRUvFKsg1CfQdSYGdTbXZWExtU3J3ccxtnfw1Fi0g==", "dev": true, "license": "MIT", "dependencies": { @@ -983,9 +983,9 @@ } }, "node_modules/@electron/universal/node_modules/fs-extra": { - "version": "11.4.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.4.0.tgz", - "integrity": "sha512-EQsFzMUJkCKGr1ePqlYADkIUmHW1s3ZXr5Yqy6wbGrfUCphpl2maM/kyOIRA2HpP3AaFQTZXD4ldjek+nccddA==", + "version": "11.4.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.4.1.tgz", + "integrity": "sha512-KYAb4c9BJQI6QqGKthV68OHe0badztdXJWKo0WtBA9IuCFPTKvE5ZdUBglP833aMjhaSPNO4A5j/EkzZtGlKjA==", "dev": true, "license": "MIT", "dependencies": { @@ -1036,6 +1036,72 @@ "node": ">= 10.0.0" } }, + "node_modules/@electron/windows-sign": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@electron/windows-sign/-/windows-sign-1.2.2.tgz", + "integrity": "sha512-dfZeox66AvdPtb2lD8OsIIQh12Tp0GNCRUDfBHIKGpbmopZto2/A8nSpYYLoedPIHpqkeblZ/k8OV0Gy7PYuyQ==", + "dev": true, + "license": "BSD-2-Clause", + "optional": true, + "peer": true, + "dependencies": { + "cross-dirname": "^0.1.0", + "debug": "^4.3.4", + "fs-extra": "^11.1.1", + "minimist": "^1.2.8", + "postject": "^1.0.0-alpha.6" + }, + "bin": { + "electron-windows-sign": "bin/electron-windows-sign.js" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/@electron/windows-sign/node_modules/fs-extra": { + "version": "11.4.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.4.1.tgz", + "integrity": "sha512-KYAb4c9BJQI6QqGKthV68OHe0badztdXJWKo0WtBA9IuCFPTKvE5ZdUBglP833aMjhaSPNO4A5j/EkzZtGlKjA==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/@electron/windows-sign/node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@electron/windows-sign/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", @@ -1472,107 +1538,27 @@ "hono": "^4" } }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", "dev": true, "license": "ISC", "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz", - "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@isaacs/cliui/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", - "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.2.2" + "minipass": "^7.0.4" }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" + "node": ">=18.0.0" } }, - "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "node_modules/@isaacs/fs-minipass/node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, + "license": "BlueOak-1.0.0", "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "node": ">=16 || 14 >=14.17" } }, "node_modules/@jest/expect-utils": { @@ -1914,6 +1900,19 @@ "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, + "node_modules/@noble/hashes": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.4.0.tgz", + "integrity": "sha512-X5XaVWZIBCT7HHZGm5I7ZQXDwLG+bGXuSrMQAW+7Zvl87h1kmc1ZB1VSRJcpUfoUrGQp4Fkoxm5kZ+Ms+aW+eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@npmcli/fs": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.2.tgz", @@ -2053,23 +2052,67 @@ } } }, - "node_modules/@pixi/colord": { - "version": "2.9.6", - "resolved": "https://registry.npmjs.org/@pixi/colord/-/colord-2.9.6.tgz", - "integrity": "sha512-nezytU2pw587fQstUu1AsJZDVEynjskwOL+kibwcdxsMBFqPsFFNA7xl0ii/gXuDi6M0xj3mfRJj8pBSc2jCfA==", - "license": "MIT" - }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "node_modules/@peculiar/asn1-schema": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.11.0.tgz", + "integrity": "sha512-8xh4avo53/vXO6UEv9yaoJ83hY581geaLTygf61NPIXP5AeIZCPjJhpTaYU23IZkG+NpLN/C9FYzWp7hphIT9A==", "dev": true, "license": "MIT", - "optional": true, + "dependencies": { + "@peculiar/utils": "^2.0.2", + "asn1js": "^3.0.10", + "tslib": "^2.8.1" + }, "engines": { "node": ">=14" } }, + "node_modules/@peculiar/json-schema": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/@peculiar/json-schema/-/json-schema-1.1.12.tgz", + "integrity": "sha512-coUfuoMeIB7B8/NMekxaDzLhaYmp0HZNPEjYRm9goRou8UZIC3z21s0sL9AWoCw4EG876QyO3kYrc61WNF9B/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@peculiar/utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@peculiar/utils/-/utils-2.0.3.tgz", + "integrity": "sha512-+oL3HPFRIZ1St2K50lWCXiioIgSoxzz7R1J3uF6neO2yl1sgmpgY6XXJH4BdpoDkMWznQTeYF6oWNDZLCdQ4eQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/webcrypto": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@peculiar/webcrypto/-/webcrypto-1.7.1.tgz", + "integrity": "sha512-ODOov0sGMJMf3jPonOkgGqPknTsu+DdQ7kD++gz8aI+aFMOMHFbWAA2taqXXVTdP+OTOQR/znGvSpmkeI0WTYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.7.0", + "@peculiar/json-schema": "^1.1.12", + "@peculiar/utils": "^2.0.2", + "tslib": "^2.8.1", + "webcrypto-core": "^1.9.2" + }, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/@pixi/colord": { + "version": "2.9.6", + "resolved": "https://registry.npmjs.org/@pixi/colord/-/colord-2.9.6.tgz", + "integrity": "sha512-nezytU2pw587fQstUu1AsJZDVEynjskwOL+kibwcdxsMBFqPsFFNA7xl0ii/gXuDi6M0xj3mfRJj8pBSc2jCfA==", + "license": "MIT" + }, "node_modules/@posthog/core": { "version": "1.47.1", "resolved": "https://registry.npmjs.org/@posthog/core/-/core-1.47.1.tgz", @@ -2664,16 +2707,6 @@ "@types/node": "*" } }, - "node_modules/@types/localtunnel": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/localtunnel/-/localtunnel-2.0.4.tgz", - "integrity": "sha512-7WM5nlEfEKp8MpwthPa2utdy+f/7ZBxMPzu8qw6EijFFTcpzh5CXgt2YoncxWAZNOPNieMofXCKFudtDEY4bag==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/mdast": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", @@ -2726,18 +2759,6 @@ "@types/node": "*" } }, - "node_modules/@types/plist": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@types/plist/-/plist-3.0.5.tgz", - "integrity": "sha512-E6OCaRmAe4WDmWNsL/9RMqdkkzDCY1etutkflWk4c+AcjDU07Pcz1fQwTX0TQz+Pxqn9i4L1TU3UFpjnrcDgxA==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@types/node": "*", - "xmlbuilder": ">=11.0.1" - } - }, "node_modules/@types/prop-types": { "version": "15.7.15", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", @@ -2801,14 +2822,6 @@ "integrity": "sha512-T8L6i7wCuyoK8A/ZeLYt1+q0ty3Zb9+qbSSvrIVitzT3YjZqkTZ40IbRsPanlB4h1QB3JVL1SYCdR6ngtFYcuA==", "license": "MIT" }, - "node_modules/@types/verror": { - "version": "1.10.11", - "resolved": "https://registry.npmjs.org/@types/verror/-/verror-1.10.11.tgz", - "integrity": "sha512-RlDm9K7+o5stv0Co8i8ZRGxDbrTxhJtgjqjFyVh/tXQyl/rYtTKlnTvZ88oSTeYREWurwx20Js4kTuKCsFkUtg==", - "dev": true, - "license": "MIT", - "optional": true - }, "node_modules/@types/ws": { "version": "7.4.7", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz", @@ -2966,13 +2979,6 @@ "integrity": "sha512-hqJHYaQb5OptNunnyAnkHyM8aCjZ1MEIDTQu1iIbbTD/xops91NB5yq1ZK/dC2JDbVWtF23zUtl9JE2NqwT87A==", "license": "MIT" }, - "node_modules/7zip-bin": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/7zip-bin/-/7zip-bin-5.2.0.tgz", - "integrity": "sha512-ukTPVhqG4jNzMro2qA9HSCSSVJN3aN7tlb+hfqYCt3ER0yWroeA2VR38MNrOHLQ/cVj+DaIMad0kFCtWWowh/A==", - "dev": true, - "license": "MIT" - }, "node_modules/abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -3083,8 +3089,8 @@ "version": "8.20.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "devOptional": true, "license": "MIT", - "optional": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -3118,6 +3124,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -3138,73 +3145,134 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/app-builder-bin": { - "version": "5.0.0-alpha.10", - "resolved": "https://registry.npmjs.org/app-builder-bin/-/app-builder-bin-5.0.0-alpha.10.tgz", - "integrity": "sha512-Ev4jj3D7Bo+O0GPD2NMvJl+PGiBAfS7pUGawntBNpCbxtpncfUixqFj9z9Jme7V7s3LBGqsWZZP54fxBX3JKJw==", - "dev": true, - "license": "MIT" - }, "node_modules/app-builder-lib": { - "version": "25.1.8", - "resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-25.1.8.tgz", - "integrity": "sha512-pCqe7dfsQFBABC1jeKZXQWhGcCPF3rPCXDdfqVKjIeWBcXzyC1iOWZdfFhGl+S9MyE/k//DFmC6FzuGAUudNDg==", + "version": "26.15.3", + "resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-26.15.3.tgz", + "integrity": "sha512-2VnyWkqsP5v5XbBhL3tD5Syx8iNPBYsoU7kY4S2fz7wg8Rj/nztWKCUzGKaFRTv0Xwf3/H058CR1Kvtd/3lRow==", "dev": true, "license": "MIT", "dependencies": { - "@develar/schema-utils": "~2.6.5", + "@electron/asar": "3.4.1", + "@electron/fuses": "^1.8.0", + "@electron/get": "^3.0.0", "@electron/notarize": "2.5.0", - "@electron/osx-sign": "1.3.1", - "@electron/rebuild": "3.6.1", - "@electron/universal": "2.0.1", + "@electron/osx-sign": "1.3.3", + "@electron/rebuild": "^4.0.4", + "@electron/universal": "2.0.3", "@malept/flatpak-bundler": "^0.4.0", + "@noble/hashes": "^2.2.0", + "@peculiar/webcrypto": "^1.7.1", "@types/fs-extra": "9.0.13", + "ajv": "^8.18.0", + "asn1js": "^3.0.10", "async-exit-hook": "^2.0.1", - "bluebird-lst": "^1.0.9", - "builder-util": "25.1.7", - "builder-util-runtime": "9.2.10", + "builder-util": "26.15.3", + "builder-util-runtime": "9.7.0", "chromium-pickle-js": "^0.2.0", - "config-file-ts": "0.2.8-rc1", + "ci-info": "4.3.1", "debug": "^4.3.4", "dotenv": "^16.4.5", "dotenv-expand": "^11.0.6", "ejs": "^3.1.8", - "electron-publish": "25.1.7", - "form-data": "^4.0.0", + "electron-publish": "26.15.3", "fs-extra": "^10.1.0", "hosted-git-info": "^4.1.0", - "is-ci": "^3.0.0", "isbinaryfile": "^5.0.0", + "jiti": "^2.4.2", "js-yaml": "^4.1.0", "json5": "^2.2.3", "lazy-val": "^1.0.5", - "minimatch": "^10.0.0", + "minimatch": "^10.2.5", + "pkijs": "^3.4.0", + "plist": "3.1.0", + "proper-lockfile": "^4.1.2", "resedit": "^1.7.0", - "sanitize-filename": "^1.6.3", - "semver": "^7.3.8", - "tar": "^6.1.12", - "temp-file": "^3.4.0" + "semver": "~7.7.3", + "tar": "^7.5.7", + "temp-file": "^3.4.0", + "tiny-async-pool": "1.3.0", + "unzipper": "^0.12.3", + "which": "^5.0.0" }, "engines": { "node": ">=14.0.0" }, "peerDependencies": { - "dmg-builder": "25.1.8", - "electron-builder-squirrel-windows": "25.1.8" + "dmg-builder": "26.15.3", + "electron-builder-squirrel-windows": "26.15.3" } }, - "node_modules/app-builder-lib/node_modules/builder-util-runtime": { - "version": "9.2.10", - "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.2.10.tgz", - "integrity": "sha512-6p/gfG1RJSQeIbz8TK5aPNkoztgY1q5TgmGFMAXcY8itsGW6Y2ld1ALsZ5UJn8rog7hKF3zHx5iQbNQ8uLcRlw==", + "node_modules/app-builder-lib/node_modules/@electron/get": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@electron/get/-/get-3.1.0.tgz", + "integrity": "sha512-F+nKc0xW+kVbBRhFzaMgPy3KwmuNTYX1fx6+FxxoSnNgwYX6LD7AKBTWkU0MQ6IBoe7dz069CNkR673sPAgkCQ==", "dev": true, "license": "MIT", "dependencies": { - "debug": "^4.3.4", - "sax": "^1.2.4" + "debug": "^4.1.1", + "env-paths": "^2.2.0", + "fs-extra": "^8.1.0", + "got": "^11.8.5", + "progress": "^2.0.3", + "semver": "^6.2.0", + "sumchecker": "^3.0.1" }, "engines": { - "node": ">=12.0.0" + "node": ">=14" + }, + "optionalDependencies": { + "global-agent": "^3.0.0" + } + }, + "node_modules/app-builder-lib/node_modules/@electron/get/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/app-builder-lib/node_modules/@electron/get/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/app-builder-lib/node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/app-builder-lib/node_modules/ci-info": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz", + "integrity": "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" } }, "node_modules/app-builder-lib/node_modules/fs-extra": { @@ -3222,7 +3290,7 @@ "node": ">=12" } }, - "node_modules/app-builder-lib/node_modules/jsonfile": { + "node_modules/app-builder-lib/node_modules/fs-extra/node_modules/jsonfile": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", @@ -3235,20 +3303,7 @@ "graceful-fs": "^4.1.6" } }, - "node_modules/app-builder-lib/node_modules/semver": { - "version": "7.8.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", - "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/app-builder-lib/node_modules/universalify": { + "node_modules/app-builder-lib/node_modules/fs-extra/node_modules/universalify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", @@ -3258,148 +3313,101 @@ "node": ">= 10.0.0" } }, - "node_modules/append-field": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", - "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==", - "license": "MIT" - }, - "node_modules/archiver": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.2.tgz", - "integrity": "sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw==", + "node_modules/app-builder-lib/node_modules/isexe": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.5.tgz", + "integrity": "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==", "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "archiver-utils": "^2.1.0", - "async": "^3.2.4", - "buffer-crc32": "^0.2.1", - "readable-stream": "^3.6.0", - "readdir-glob": "^1.1.2", - "tar-stream": "^2.2.0", - "zip-stream": "^4.1.0" - }, + "license": "BlueOak-1.0.0", "engines": { - "node": ">= 10" + "node": ">=18" } }, - "node_modules/archiver-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz", - "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", + "node_modules/app-builder-lib/node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "glob": "^7.1.4", - "graceful-fs": "^4.2.0", - "lazystream": "^1.0.0", - "lodash.defaults": "^4.2.0", - "lodash.difference": "^4.5.0", - "lodash.flatten": "^4.4.0", - "lodash.isplainobject": "^4.0.6", - "lodash.union": "^4.6.0", - "normalize-path": "^3.0.0", - "readable-stream": "^2.0.0" - }, + "license": "BlueOak-1.0.0", "engines": { - "node": ">= 6" + "node": ">=16 || 14 >=14.17" } }, - "node_modules/archiver-utils/node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/archiver-utils/node_modules/brace-expansion": { - "version": "1.1.18", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", - "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", + "node_modules/app-builder-lib/node_modules/minizlib": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", + "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" } }, - "node_modules/archiver-utils/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "node_modules/app-builder-lib/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "dev": true, "license": "ISC", - "peer": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "bin": { + "semver": "bin/semver.js" }, "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=10" } }, - "node_modules/archiver-utils/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "node_modules/app-builder-lib/node_modules/tar": { + "version": "7.5.22", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.22.tgz", + "integrity": "sha512-MFO/QzvtAOmJbkhOaCTvbGcFN9L9b+JunIsDwaKljSOdcLMea3NJ1k9Usz/rjdfSXTq4dfzfeS7W4p4YOAAHeA==", "dev": true, - "license": "ISC", - "peer": true, + "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^1.1.7" + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.1.0", + "yallist": "^5.0.0" }, "engines": { - "node": "*" + "node": ">=18" } }, - "node_modules/archiver-utils/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "node_modules/app-builder-lib/node_modules/which": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-5.0.0.tgz", + "integrity": "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==", "dev": true, - "license": "MIT", - "peer": true, + "license": "ISC", "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" } }, - "node_modules/archiver-utils/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/archiver-utils/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "node_modules/app-builder-lib/node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "safe-buffer": "~5.1.0" + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" } }, + "node_modules/append-field": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", + "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==", + "license": "MIT" + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -3422,26 +3430,19 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "node_modules/asn1js": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.1.0.tgz", + "integrity": "sha512-HWYi1THkOqguCiO+vwj09ZkQFD2kKEsejYHAYCtX0D80WVdoDnvRc9IukXX/jeb0T9NRWJnRtqwdbHltnFjwXA==", "dev": true, - "license": "MIT", - "optional": true, + "license": "BSD-3-Clause", + "dependencies": { + "pvtsutils": "^1.3.6", + "pvutils": "^1.2.0", + "tslib": "^2.8.1" + }, "engines": { - "node": ">=8" + "node": ">=12.0.0" } }, "node_modules/async": { @@ -3492,14 +3493,12 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/axios": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", - "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", - "license": "MIT", - "dependencies": { - "follow-redirects": "^1.14.0" - } + "node_modules/aws4": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.2.tgz", + "integrity": "sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==", + "dev": true, + "license": "MIT" }, "node_modules/bail": { "version": "2.0.2", @@ -3592,16 +3591,6 @@ "dev": true, "license": "MIT" }, - "node_modules/bluebird-lst": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/bluebird-lst/-/bluebird-lst-1.0.9.tgz", - "integrity": "sha512-7B1Rtx82hjnSD4PGLAjVWeYH3tHAcVUmChh85a3lltKQm6FresXh9ErQo6oAv6CqxttczC3/kEg8SY5NluPuUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "bluebird": "^3.5.5" - } - }, "node_modules/body-parser": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.3.0.tgz", @@ -3724,9 +3713,9 @@ "optional": true }, "node_modules/brace-expansion": { - "version": "5.0.9", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", - "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz", + "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3823,28 +3812,29 @@ "license": "MIT" }, "node_modules/builder-util": { - "version": "25.1.7", - "resolved": "https://registry.npmjs.org/builder-util/-/builder-util-25.1.7.tgz", - "integrity": "sha512-7jPjzBwEGRbwNcep0gGNpLXG9P94VA3CPAZQCzxkFXiV2GMQKlziMbY//rXPI7WKfhsvGgFXjTcXdBEwgXw9ww==", + "version": "26.15.3", + "resolved": "https://registry.npmjs.org/builder-util/-/builder-util-26.15.3.tgz", + "integrity": "sha512-q2hn7Mbo2nFNkVekPiHFx6Nfo3hURmES3tfBn+k5Pqxl2RkmP3QGqZUhH/q9Pch/4G05NRhPjDlVj1O8q4Txvw==", "dev": true, "license": "MIT", "dependencies": { "@types/debug": "^4.1.6", - "7zip-bin": "~5.2.0", - "app-builder-bin": "5.0.0-alpha.10", - "bluebird-lst": "^1.0.9", - "builder-util-runtime": "9.2.10", + "builder-util-runtime": "9.7.0", "chalk": "^4.1.2", - "cross-spawn": "^7.0.3", + "cross-spawn": "^7.0.6", "debug": "^4.3.4", "fs-extra": "^10.1.0", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.0", - "is-ci": "^3.0.0", "js-yaml": "^4.1.0", + "sanitize-filename": "^1.6.3", "source-map-support": "^0.5.19", "stat-mode": "^1.0.0", - "temp-file": "^3.4.0" + "temp-file": "^3.4.0", + "tiny-async-pool": "1.3.0" + }, + "engines": { + "node": ">=14.0.0" } }, "node_modules/builder-util-runtime": { @@ -3870,20 +3860,6 @@ "node": ">= 14" } }, - "node_modules/builder-util/node_modules/builder-util-runtime": { - "version": "9.2.10", - "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.2.10.tgz", - "integrity": "sha512-6p/gfG1RJSQeIbz8TK5aPNkoztgY1q5TgmGFMAXcY8itsGW6Y2ld1ALsZ5UJn8rog7hKF3zHx5iQbNQ8uLcRlw==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.3.4", - "sax": "^1.2.4" - }, - "engines": { - "node": ">=12.0.0" - } - }, "node_modules/builder-util/node_modules/fs-extra": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", @@ -3957,6 +3933,16 @@ "node": ">= 0.8" } }, + "node_modules/bytestreamjs": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/bytestreamjs/-/bytestreamjs-2.0.1.tgz", + "integrity": "sha512-U1Z/ob71V/bXfVABvNr/Kumf5VyeQRBEm6Txb0PQ6S7V5GpBM3w4Cbqz/xPDicR5tN0uvDifng8C+5qECeGwyQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/cac": { "version": "6.7.14", "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", @@ -4257,24 +4243,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/cli-truncate": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", - "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "slice-ansi": "^3.0.0", - "string-width": "^4.2.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", @@ -4405,23 +4373,6 @@ "node": ">=0.10.0" } }, - "node_modules/compress-commons": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.2.tgz", - "integrity": "sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "buffer-crc32": "^0.2.13", - "crc32-stream": "^4.0.2", - "normalize-path": "^3.0.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">= 10" - } - }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -4474,82 +4425,6 @@ "safe-buffer": "~5.1.0" } }, - "node_modules/config-file-ts": { - "version": "0.2.8-rc1", - "resolved": "https://registry.npmjs.org/config-file-ts/-/config-file-ts-0.2.8-rc1.tgz", - "integrity": "sha512-GtNECbVI82bT4RiDIzBSVuTKoSHufnU7Ce7/42bkWZJZFLjmDF2WBpVsvRkhKCfKBnTBb3qZrBwPpFBU/Myvhg==", - "dev": true, - "license": "MIT", - "dependencies": { - "glob": "^10.3.12", - "typescript": "^5.4.3" - } - }, - "node_modules/config-file-ts/node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/config-file-ts/node_modules/brace-expansion": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.4.tgz", - "integrity": "sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/config-file-ts/node_modules/glob": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", - "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", - "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", - "dev": true, - "license": "ISC", - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/config-file-ts/node_modules/minimatch": { - "version": "9.0.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", - "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.2" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/config-file-ts/node_modules/minipass": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", - "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", - "dev": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, "node_modules/content-disposition": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.1.0.tgz", @@ -4625,52 +4500,21 @@ "url": "https://opencollective.com/express" } }, - "node_modules/crc": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/crc/-/crc-3.8.0.tgz", - "integrity": "sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "buffer": "^5.1.0" - } - }, - "node_modules/crc-32": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", - "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "bin": { - "crc32": "bin/crc32.njs" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/crc32-stream": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.3.tgz", - "integrity": "sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "crc-32": "^1.2.0", - "readable-stream": "^3.4.0" - }, - "engines": { - "node": ">= 10" - } - }, "node_modules/crelt": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz", "integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==", "license": "MIT" }, + "node_modules/cross-dirname": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/cross-dirname/-/cross-dirname-0.1.0.tgz", + "integrity": "sha512-+R08/oI0nl3vfPcqftZRpytksBXDzOUveBq/NBVx0sUp1axwzPQrKinNx5yd5sxPu8j1wIy8AfnVQ+5eFdha6Q==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -4964,9 +4808,9 @@ "license": "MIT" }, "node_modules/dir-compare/node_modules/brace-expansion": { - "version": "1.1.18", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", - "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz", + "integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==", "dev": true, "license": "MIT", "dependencies": { @@ -4988,35 +4832,16 @@ } }, "node_modules/dmg-builder": { - "version": "25.1.8", - "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-25.1.8.tgz", - "integrity": "sha512-NoXo6Liy2heSklTI5OIZbCgXC1RzrDQsZkeEwXhdOro3FT1VBOvbubvscdPnjVuQ4AMwwv61oaH96AbiYg9EnQ==", + "version": "26.15.3", + "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-26.15.3.tgz", + "integrity": "sha512-O3zJUFUYHJKgzPqioHxfxzBzlSC1eXCSr79gMSBKBP5AgjjpmrydMsMLotEg9fAJF36vdUncb+4ndRNxoPdlSQ==", "dev": true, "license": "MIT", "dependencies": { - "app-builder-lib": "25.1.8", - "builder-util": "25.1.7", - "builder-util-runtime": "9.2.10", + "app-builder-lib": "26.15.3", + "builder-util": "26.15.3", "fs-extra": "^10.1.0", - "iconv-lite": "^0.6.2", "js-yaml": "^4.1.0" - }, - "optionalDependencies": { - "dmg-license": "^1.0.11" - } - }, - "node_modules/dmg-builder/node_modules/builder-util-runtime": { - "version": "9.2.10", - "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.2.10.tgz", - "integrity": "sha512-6p/gfG1RJSQeIbz8TK5aPNkoztgY1q5TgmGFMAXcY8itsGW6Y2ld1ALsZ5UJn8rog7hKF3zHx5iQbNQ8uLcRlw==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.3.4", - "sax": "^1.2.4" - }, - "engines": { - "node": ">=12.0.0" } }, "node_modules/dmg-builder/node_modules/fs-extra": { @@ -5057,59 +4882,6 @@ "node": ">= 10.0.0" } }, - "node_modules/dmg-license": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/dmg-license/-/dmg-license-1.0.11.tgz", - "integrity": "sha512-ZdzmqwKmECOWJpqefloC5OJy1+WZBBse5+MR88z9g9Zn4VY+WYUkAyojmhzJckH5YbbZGcYIuGAkY5/Ys5OM2Q==", - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "dependencies": { - "@types/plist": "^3.0.1", - "@types/verror": "^1.10.3", - "ajv": "^6.10.0", - "crc": "^3.8.0", - "iconv-corefoundation": "^1.1.7", - "plist": "^3.0.4", - "smart-buffer": "^4.0.2", - "verror": "^1.10.0" - }, - "bin": { - "dmg-license": "bin/dmg-license.js" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/dmg-license/node_modules/ajv": { - "version": "6.15.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", - "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/dmg-license/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT", - "optional": true - }, "node_modules/dotenv": { "version": "16.6.1", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", @@ -5153,19 +4925,55 @@ "node": ">= 0.4" } }, + "node_modules/duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "readable-stream": "^2.0.2" + } + }, + "node_modules/duplexer2/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/duplexer2/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/duplexer2/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/earcut": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/earcut/-/earcut-3.0.2.tgz", "integrity": "sha512-X7hshQbLyMJ/3RPhyObLARM2sNxxmRALLKx1+NVFFnQ9gKzmCrxm9+uLIAdBcvc8FNLpctqlQ2V6AE92Ol9UDQ==", "license": "ISC" }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true, - "license": "MIT" - }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -5209,19 +5017,19 @@ } }, "node_modules/electron-builder": { - "version": "25.1.8", - "resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-25.1.8.tgz", - "integrity": "sha512-poRgAtUHHOnlzZnc9PK4nzG53xh74wj2Jy7jkTrqZ0MWPoHGh1M2+C//hGeYdA+4K8w4yiVCNYoLXF7ySj2Wig==", + "version": "26.15.3", + "resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-26.15.3.tgz", + "integrity": "sha512-a1KM5heqS3gQCZzizXEI8RjJy3QVogULPdeSknt76uLDpBIW/HDGsMg/XgP0riP6PI9COsRvFITKKGDqA8fJxA==", "dev": true, "license": "MIT", "dependencies": { - "app-builder-lib": "25.1.8", - "builder-util": "25.1.7", - "builder-util-runtime": "9.2.10", + "app-builder-lib": "26.15.3", + "builder-util": "26.15.3", + "builder-util-runtime": "9.7.0", "chalk": "^4.1.2", - "dmg-builder": "25.1.8", + "ci-info": "^4.2.0", + "dmg-builder": "26.15.3", "fs-extra": "^10.1.0", - "is-ci": "^3.0.0", "lazy-val": "^1.0.5", "simple-update-notifier": "2.0.0", "yargs": "^17.6.2" @@ -5235,72 +5043,32 @@ } }, "node_modules/electron-builder-squirrel-windows": { - "version": "25.1.8", - "resolved": "https://registry.npmjs.org/electron-builder-squirrel-windows/-/electron-builder-squirrel-windows-25.1.8.tgz", - "integrity": "sha512-2ntkJ+9+0GFP6nAISiMabKt6eqBB0kX1QqHNWFWAXgi0VULKGisM46luRFpIBiU3u/TDmhZMM8tzvo2Abn3ayg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "app-builder-lib": "25.1.8", - "archiver": "^5.3.1", - "builder-util": "25.1.7", - "fs-extra": "^10.1.0" - } - }, - "node_modules/electron-builder-squirrel-windows/node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/electron-builder-squirrel-windows/node_modules/jsonfile": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", - "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "version": "26.15.3", + "resolved": "https://registry.npmjs.org/electron-builder-squirrel-windows/-/electron-builder-squirrel-windows-26.15.3.tgz", + "integrity": "sha512-Jc19XPV9y9+2bAdZPkXuVNGNIEFBq9poHC61l8Kv6FdK7DRG3+Ic0rerC0DXOaeHNz8yW0fg/JnF8GQROOF5MA==", "dev": true, "license": "MIT", "peer": true, "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" + "app-builder-lib": "26.15.3", + "builder-util": "26.15.3", + "electron-winstaller": "5.4.0" } }, - "node_modules/electron-builder-squirrel-windows/node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "node_modules/electron-builder/node_modules/ci-info": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz", + "integrity": "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], "license": "MIT", - "peer": true, "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/electron-builder/node_modules/builder-util-runtime": { - "version": "9.2.10", - "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.2.10.tgz", - "integrity": "sha512-6p/gfG1RJSQeIbz8TK5aPNkoztgY1q5TgmGFMAXcY8itsGW6Y2ld1ALsZ5UJn8rog7hKF3zHx5iQbNQ8uLcRlw==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.3.4", - "sax": "^1.2.4" - }, - "engines": { - "node": ">=12.0.0" + "node": ">=8" } }, "node_modules/electron-builder/node_modules/fs-extra": { @@ -5342,35 +5110,23 @@ } }, "node_modules/electron-publish": { - "version": "25.1.7", - "resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-25.1.7.tgz", - "integrity": "sha512-+jbTkR9m39eDBMP4gfbqglDd6UvBC7RLh5Y0MhFSsc6UkGHj9Vj9TWobxevHYMMqmoujL11ZLjfPpMX+Pt6YEg==", + "version": "26.15.3", + "resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-26.15.3.tgz", + "integrity": "sha512-g/2bn8YTavY4cuS5F+jOS7zmZbXXBV8KZ8yHKfJjFPoKtzBqrpCdNPxBd3tqdBwP7BVd0lGzf7Bk2s0KesWZ4Q==", "dev": true, "license": "MIT", "dependencies": { "@types/fs-extra": "^9.0.11", - "builder-util": "25.1.7", - "builder-util-runtime": "9.2.10", + "aws4": "^1.13.2", + "builder-util": "26.15.3", + "builder-util-runtime": "9.7.0", "chalk": "^4.1.2", + "form-data": "^4.0.5", "fs-extra": "^10.1.0", "lazy-val": "^1.0.5", "mime": "^2.5.2" } }, - "node_modules/electron-publish/node_modules/builder-util-runtime": { - "version": "9.2.10", - "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.2.10.tgz", - "integrity": "sha512-6p/gfG1RJSQeIbz8TK5aPNkoztgY1q5TgmGFMAXcY8itsGW6Y2ld1ALsZ5UJn8rog7hKF3zHx5iQbNQ8uLcRlw==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.3.4", - "sax": "^1.2.4" - }, - "engines": { - "node": ">=12.0.0" - } - }, "node_modules/electron-publish/node_modules/fs-extra": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", @@ -5509,6 +5265,44 @@ } } }, + "node_modules/electron-winstaller": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/electron-winstaller/-/electron-winstaller-5.4.0.tgz", + "integrity": "sha512-bO3y10YikuUwUuDUQRM4KfwNkKhnpVO7IPdbsrejwN9/AABJzzTQ4GeHwyzNSrVO+tEH3/Np255a3sVZpZDjvg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@electron/asar": "^3.2.1", + "debug": "^4.1.1", + "fs-extra": "^7.0.1", + "lodash": "^4.17.21", + "temp": "^0.9.0" + }, + "engines": { + "node": ">=8.0.0" + }, + "optionalDependencies": { + "@electron/windows-sign": "^1.1.2" + } + }, + "node_modules/electron-winstaller/node_modules/fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, "node_modules/electron/node_modules/@types/node": { "version": "20.19.43", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.43.tgz", @@ -5523,6 +5317,7 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, "license": "MIT" }, "node_modules/encodeurl": { @@ -5693,6 +5488,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -5960,17 +5756,6 @@ "@types/yauzl": "^2.9.1" } }, - "node_modules/extsprintf": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.1.tgz", - "integrity": "sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA==", - "dev": true, - "engines": [ - "node >=0.6.0" - ], - "license": "MIT", - "optional": true - }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -5978,17 +5763,11 @@ "devOptional": true, "license": "MIT" }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, - "license": "MIT" - }, "node_modules/fast-uri": { "version": "3.1.7", "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.7.tgz", "integrity": "sha512-dOvZVzjdZdz7phd9v6jCbwxrBW3fK6n8Rc0CtdmM4bumzMnxywBYhuph6J819RRw/ku+rLbelwfMunktuzVVHg==", + "devOptional": true, "funding": [ { "type": "github", @@ -5999,8 +5778,7 @@ "url": "https://opencollective.com/fastify" } ], - "license": "BSD-3-Clause", - "optional": true + "license": "BSD-3-Clause" }, "node_modules/fd-slicer": { "version": "1.1.0", @@ -6036,9 +5814,9 @@ "license": "MIT" }, "node_modules/filelist/node_modules/brace-expansion": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.4.tgz", - "integrity": "sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==", + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.7.tgz", + "integrity": "sha512-uZbew1NqdmPDTMJ8ah1y+b+9QEJrfkXFk3RcTQw3X0jW/xRUvFKsg1CfQdSYGdTbXZWExtU3J3ccxtnfw1Fi0g==", "dev": true, "license": "MIT", "dependencies": { @@ -6127,36 +5905,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/foreground-child": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", - "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", - "dev": true, - "license": "ISC", - "dependencies": { - "cross-spawn": "^7.0.6", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/foreground-child/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/form-data": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.6.tgz", @@ -6281,6 +6029,7 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, "license": "ISC", "engines": { "node": "6.* || 8.* || >= 10.*" @@ -6791,38 +6540,12 @@ } } }, - "node_modules/iconv-corefoundation": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/iconv-corefoundation/-/iconv-corefoundation-1.1.7.tgz", - "integrity": "sha512-T10qvkw0zz4wnm560lOEg0PovVqUXuOFhhHAkixw8/sycy7TJt7v/RrkEKEQnAw2viPSJu6iAkErxnzR0g8PpQ==", - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "dependencies": { - "cli-truncate": "^2.1.0", - "node-addon-api": "^1.6.3" - }, - "engines": { - "node": "^8.11.2 || >=10" - } - }, - "node_modules/iconv-corefoundation/node_modules/node-addon-api": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-1.7.2.tgz", - "integrity": "sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==", - "dev": true, - "license": "MIT", - "optional": true - }, "node_modules/iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "devOptional": true, "license": "MIT", + "optional": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, @@ -7040,19 +6763,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-ci": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", - "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ci-info": "^3.2.0" - }, - "bin": { - "is-ci": "bin.js" - } - }, "node_modules/is-date-object": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", @@ -7083,6 +6793,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -7322,22 +7033,6 @@ "integrity": "sha512-VaFW53yt8QO61k2WJui0dHf4SlL8lxBofUuUmwBo0ljPk0Drz2TiuDW4jo3wDcv41qy/SxrJ+VAzJ/qYqsmzRw==", "license": "MIT" }, - "node_modules/jackspeak": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" - } - }, "node_modules/jake": { "version": "10.9.4", "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.4.tgz", @@ -7432,6 +7127,16 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jiti": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", + "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, "node_modules/jose": { "version": "6.2.3", "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.3.tgz", @@ -7500,191 +7205,62 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "license": "MIT", - "optional": true + "devOptional": true, + "license": "MIT" }, "node_modules/json-schema-typed": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-8.0.2.tgz", "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==", "license": "BSD-2-Clause", - "optional": true - }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", - "dev": true, - "license": "ISC", - "optional": true - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "license": "MIT", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", - "dev": true, - "license": "MIT", - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "license": "MIT", - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/lazy-val": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/lazy-val/-/lazy-val-1.0.5.tgz", - "integrity": "sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q==", - "license": "MIT" - }, - "node_modules/lazystream": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", - "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "readable-stream": "^2.0.5" - }, - "engines": { - "node": ">= 0.6.3" - } - }, - "node_modules/lazystream/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/lazystream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT", - "peer": true + "optional": true }, - "node_modules/lazystream/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "safe-buffer": "~5.1.0" - } + "license": "ISC", + "optional": true }, - "node_modules/localtunnel": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/localtunnel/-/localtunnel-2.0.2.tgz", - "integrity": "sha512-n418Cn5ynvJd7m/N1d9WVJISLJF/ellZnfsLnx8WBWGzxv/ntNcFkJ1o6se5quUhCplfLGBNL5tYHiq5WF3Nug==", + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, "license": "MIT", - "dependencies": { - "axios": "0.21.4", - "debug": "4.3.2", - "openurl": "1.1.1", - "yargs": "17.1.1" - }, "bin": { - "lt": "bin/lt.js" + "json5": "lib/cli.js" }, "engines": { - "node": ">=8.3.0" - } - }, - "node_modules/localtunnel/node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" + "node": ">=6" } }, - "node_modules/localtunnel/node_modules/debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, "license": "MIT", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "optionalDependencies": { + "graceful-fs": "^4.1.6" } }, - "node_modules/localtunnel/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "license": "MIT" - }, - "node_modules/localtunnel/node_modules/yargs": { - "version": "17.1.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.1.1.tgz", - "integrity": "sha512-c2k48R0PwKIqKhPMWjeiF6y2xY/gPMUlro0sgxqXpbOIohWiLNXWslsootttv7E1e73QPAMQSg5FeySbVcpsPQ==", + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, "license": "MIT", "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=12" + "json-buffer": "3.0.1" } }, - "node_modules/localtunnel/node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "license": "ISC", - "engines": { - "node": ">=10" - } + "node_modules/lazy-val": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/lazy-val/-/lazy-val-1.0.5.tgz", + "integrity": "sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q==", + "license": "MIT" }, "node_modules/lodash": { "version": "4.18.1", @@ -7693,36 +7269,12 @@ "dev": true, "license": "MIT" }, - "node_modules/lodash.defaults": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", - "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/lodash.difference": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", - "integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/lodash.escaperegexp": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz", "integrity": "sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==", "license": "MIT" }, - "node_modules/lodash.flatten": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", - "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/lodash.isequal": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", @@ -7730,22 +7282,6 @@ "deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead.", "license": "MIT" }, - "node_modules/lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/lodash.union": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", - "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -9127,6 +8663,13 @@ } } }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true, + "license": "MIT" + }, "node_modules/node-localstorage": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/node-localstorage/-/node-localstorage-2.2.1.tgz", @@ -9175,17 +8718,6 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/normalize-url": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", @@ -9303,12 +8835,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/openurl": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/openurl/-/openurl-1.1.1.tgz", - "integrity": "sha512-d/gTkTb1i1GKz5k3XE3XFV/PxQ1k45zDqGP2OA7YhgsaLoqm6qRvARAZOFer1fcXritWlGBRCu/UgeS4HAnXAA==", - "license": "MIT" - }, "node_modules/ora": { "version": "5.4.1", "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", @@ -9375,13 +8901,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/package-json-from-dist": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", - "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", - "dev": true, - "license": "BlueOak-1.0.0" - }, "node_modules/parse-entities": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", @@ -9443,40 +8962,6 @@ "node": ">=8" } }, - "node_modules/path-scurry": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" - }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/path-scurry/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/path-scurry/node_modules/minipass": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", - "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", - "dev": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, "node_modules/path-to-regexp": { "version": "8.4.2", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.2.tgz", @@ -9564,29 +9049,53 @@ "node": ">=16.20.0" } }, - "node_modules/plist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/plist/-/plist-3.1.1.tgz", - "integrity": "sha512-ZIfcLJC+7E7FBFnDxm9MPmt7D+DidyQ26lewieO75AdhA2ayMtsJSES0iWzqJQbcVRSrTufQoy0DR94xHue0oA==", + "node_modules/pkijs": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/pkijs/-/pkijs-3.4.3.tgz", + "integrity": "sha512-V9kOzaItwDgqlryhXysQsAXUEKi5O7kqWUaP3dXI7MLvkPqWWMb4wVb1QAtmEDCKI+XIAINsZoNKMFF7sZb1eg==", "dev": true, - "license": "MIT", + "license": "BSD-3-Clause", + "workspaces": [ + "website" + ], "dependencies": { - "@xmldom/xmldom": "^0.9.10", - "base64-js": "^1.5.1", - "xmlbuilder": "^15.1.1" + "@noble/hashes": "1.8.0", + "asn1js": "^3.0.6", + "bytestreamjs": "^2.0.1", + "pvtsutils": "^1.3.6", + "pvutils": "^1.1.3", + "tslib": "^2.8.1" }, "engines": { - "node": ">=10.4.0" + "node": ">=16.0.0" } }, - "node_modules/plist/node_modules/@xmldom/xmldom": { - "version": "0.9.12", - "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.9.12.tgz", - "integrity": "sha512-5AXjrcMClTryPe9LgZrygpB1lj7s0S9E0+W+AHaVKAVyHanafK86iPSvG5xHVSp/jC+VH1UXu0TAEmY279xH7A==", + "node_modules/pkijs/node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/plist": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/plist/-/plist-3.1.0.tgz", + "integrity": "sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==", "dev": true, "license": "MIT", + "dependencies": { + "@xmldom/xmldom": "^0.8.8", + "base64-js": "^1.5.1", + "xmlbuilder": "^15.1.1" + }, "engines": { - "node": ">=14.6" + "node": ">=10.4.0" } }, "node_modules/possible-typed-array-names": { @@ -9647,6 +9156,36 @@ } } }, + "node_modules/postject": { + "version": "1.0.0-alpha.6", + "resolved": "https://registry.npmjs.org/postject/-/postject-1.0.0-alpha.6.tgz", + "integrity": "sha512-b9Eb8h2eVqNE8edvKdwqkrY6O7kAwmI8kcnBv1NScolYJbo59XUF0noFq+lxbC1yN20bmC0WBEbDC5H/7ASb0A==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "commander": "^9.4.0" + }, + "bin": { + "postject": "dist/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/postject/node_modules/commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": "^12.20.0 || >=14" + } + }, "node_modules/prebuild-install": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz", @@ -9764,6 +9303,18 @@ "react-is": "^16.13.1" } }, + "node_modules/proper-lockfile": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz", + "integrity": "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "retry": "^0.12.0", + "signal-exit": "^3.0.2" + } + }, "node_modules/property-information": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.2.0.tgz", @@ -9807,14 +9358,24 @@ "once": "^1.3.1" } }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "node_modules/pvtsutils": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.6.tgz", + "integrity": "sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.8.1" + } + }, + "node_modules/pvutils": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.2.0.tgz", + "integrity": "sha512-BbubeCEyTuQjVMakvJQ/Sxbc93F2pwmbsxONT/ZRrwU7Ua38d8unYTwXpTVLAKJ4BDuH9IGztCjQcd/N/39Dvg==", "dev": true, "license": "MIT", "engines": { - "node": ">=6" + "node": ">=16.0.0" } }, "node_modules/qs": { @@ -10075,50 +9636,6 @@ "node": ">= 6" } }, - "node_modules/readdir-glob": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz", - "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "minimatch": "^5.1.0" - } - }, - "node_modules/readdir-glob/node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/readdir-glob/node_modules/brace-expansion": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.4.tgz", - "integrity": "sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/readdir-glob/node_modules/minimatch": { - "version": "5.1.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", - "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", - "dev": true, - "license": "ISC", - "peer": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/regexp.prototype.flags": { "version": "1.5.4", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", @@ -10209,6 +9726,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -10218,8 +9736,8 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "devOptional": true, "license": "MIT", - "optional": true, "engines": { "node": ">=0.10.0" } @@ -10478,8 +9996,8 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "devOptional": true, - "license": "MIT" + "license": "MIT", + "optional": true }, "node_modules/sanitize-filename": { "version": "1.6.4", @@ -10833,24 +10351,8 @@ "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/slice-ansi": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", - "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "license": "MIT", "engines": { "node": ">=8" } @@ -11043,21 +10545,6 @@ } }, "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width-cjs": { - "name": "string-width", "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", @@ -11087,19 +10574,6 @@ } }, "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi-cjs": { - "name": "strip-ansi", "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", @@ -11253,6 +10727,21 @@ "dev": true, "license": "ISC" }, + "node_modules/temp": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/temp/-/temp-0.9.4.tgz", + "integrity": "sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "mkdirp": "^0.5.1", + "rimraf": "~2.6.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/temp-file": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/temp-file/-/temp-file-3.4.0.tgz", @@ -11302,6 +10791,98 @@ "node": ">= 10.0.0" } }, + "node_modules/temp/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/temp/node_modules/brace-expansion": { + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz", + "integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/temp/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/temp/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/temp/node_modules/rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/tiny-async-pool": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/tiny-async-pool/-/tiny-async-pool-1.3.0.tgz", + "integrity": "sha512-01EAw5EDrcVrdgyCLgoSPvqznC0sVxDSVeiOz09FUpjh71G79VCqneOr+xvt7T1r76CF6ZZfPjHorN2+d+3mqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^5.5.0" + } + }, + "node_modules/tiny-async-pool/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, "node_modules/tiny-lru": { "version": "11.4.7", "resolved": "https://registry.npmjs.org/tiny-lru/-/tiny-lru-11.4.7.tgz", @@ -11401,6 +10982,13 @@ "utf8-byte-length": "^1.0.1" } }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, "node_modules/tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -11649,6 +11237,58 @@ "node": ">= 0.8" } }, + "node_modules/unzipper": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.12.5.tgz", + "integrity": "sha512-tXYOi9R57Uj/2Z25SOs5RRSzq886MBQj2gY8dPL+xl/kv6s6SvByoKfAtvfVeEuhntWDgjd2o9p2lb4TVPAz0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "bluebird": "~3.7.2", + "duplexer2": "~0.1.4", + "fs-extra": "11.3.1", + "graceful-fs": "^4.2.2", + "node-int64": "^0.4.0" + } + }, + "node_modules/unzipper/node_modules/fs-extra": { + "version": "11.3.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.1.tgz", + "integrity": "sha512-eXvGGwZ5CL17ZSwHWd3bbgk7UUpF6IFHtP57NYYakPvHOs8GDgDe5KJI36jIJzDkJ6eJjuzRA8eBQb6SkKue0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/unzipper/node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/unzipper/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/update-browserslist-db": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.2.tgz", @@ -11680,16 +11320,6 @@ "browserslist": ">= 4.21.0" } }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "punycode": "^2.1.0" - } - }, "node_modules/use-sync-external-store": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", @@ -11731,22 +11361,6 @@ "node": ">= 0.8" } }, - "node_modules/verror": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.1.tgz", - "integrity": "sha512-veufcmxri4e3XSrT0xwfUR7kguIkaxBeosDg00yDWhk49wdwkSUrvvsm7nc75e1PUyvIeZj6nS8VQRYz2/S4Xg==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - }, - "engines": { - "node": ">=0.6.0" - } - }, "node_modules/vfile": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", @@ -11851,6 +11465,20 @@ "defaults": "^1.0.3" } }, + "node_modules/webcrypto-core": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/webcrypto-core/-/webcrypto-core-1.9.2.tgz", + "integrity": "sha512-gsXecm82UQNlTBURJGuqOWy1Ww08S3kZUcr3aOJS02Pk0xLtkfeUAVC0u0xhgdonFme80edSJUIJyuvL/7250Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.7.0", + "@peculiar/json-schema": "^1.1.12", + "@peculiar/utils": "^2.0.2", + "asn1js": "^3.0.10", + "tslib": "^2.8.1" + } + }, "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", @@ -11942,24 +11570,6 @@ } }, "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", @@ -12038,6 +11648,7 @@ "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, "license": "ISC", "engines": { "node": ">=10" @@ -12103,102 +11714,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/zip-stream": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.1.tgz", - "integrity": "sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "archiver-utils": "^3.0.4", - "compress-commons": "^4.1.2", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/zip-stream/node_modules/archiver-utils": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-3.0.4.tgz", - "integrity": "sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "glob": "^7.2.3", - "graceful-fs": "^4.2.0", - "lazystream": "^1.0.0", - "lodash.defaults": "^4.2.0", - "lodash.difference": "^4.5.0", - "lodash.flatten": "^4.4.0", - "lodash.isplainobject": "^4.0.6", - "lodash.union": "^4.6.0", - "normalize-path": "^3.0.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/zip-stream/node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/zip-stream/node_modules/brace-expansion": { - "version": "1.1.18", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", - "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/zip-stream/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", - "dev": true, - "license": "ISC", - "peer": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/zip-stream/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "dev": true, - "license": "ISC", - "peer": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/zod": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", diff --git a/package.json b/package.json index 86c4de5723..14572ca055 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,6 @@ "commit-graph": "^2.4.0", "electron-updater": "^6.8.9", "i18next": "^26.3.6", - "localtunnel": "^2.0.2", "monaco-editor": "^0.52.2", "node-pty": "^1.0.0", "pixi.js": "^8.5.1", @@ -67,13 +66,12 @@ "@electron/notarize": "^2.5.0", "@electron/rebuild": "^3.7.0", "@types/better-sqlite3": "^7.6.13", - "@types/localtunnel": "^2.0.4", "@types/node": "^22.7.5", "@types/react": "^18.3.11", "@types/react-dom": "^18.3.0", "@vitejs/plugin-react": "^4.3.2", "electron": "32.3.3", - "electron-builder": "^25.1.8", + "electron-builder": "26.15.3", "electron-vite": "^2.3.0", "typescript": "^5.6.3", "vite": "^5.4.8" From 7661b3ea6c2c6b6140f666e2dc69eade44447884 Mon Sep 17 00:00:00 2001 From: T3sh Date: Thu, 22 Oct 2026 19:47:16 -0300 Subject: [PATCH 22/24] deps: vite 5.4.8->7.3.7 exact, electron-vite 2.3.0->4.0.1 (TSF-14 Onda-2) - vite pinned exact 7.3.7 (latest 7.3.x), electron-vite ^4.0.1 - no config changes needed; typecheck PASS (node+web); electron-vite build PASS - plugin-react kept at ^4.3.2 (4.7.0 peers vite ^7) - audit: 30 (2C/23H/5M) -> 27 (2C/22H/3M) - branch tsf9-wave2-vite7 from c531426 --- package-lock.json | 922 ++++++++++++++++++++++++++++++++++++++-------- package.json | 4 +- 2 files changed, 779 insertions(+), 147 deletions(-) diff --git a/package-lock.json b/package-lock.json index 28a4db9ec3..7a5c984c62 100644 --- a/package-lock.json +++ b/package-lock.json @@ -53,9 +53,9 @@ "@vitejs/plugin-react": "^4.3.2", "electron": "32.3.3", "electron-builder": "26.15.3", - "electron-vite": "^2.3.0", + "electron-vite": "^4.0.1", "typescript": "^5.6.3", - "vite": "^5.4.8" + "vite": "7.3.7" } }, "node_modules/@babel/code-frame": { @@ -1103,9 +1103,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", - "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", "cpu": [ "ppc64" ], @@ -1116,13 +1116,13 @@ "aix" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", - "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", "cpu": [ "arm" ], @@ -1133,13 +1133,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", - "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", "cpu": [ "arm64" ], @@ -1150,13 +1150,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", - "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", "cpu": [ "x64" ], @@ -1167,13 +1167,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", - "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", "cpu": [ "arm64" ], @@ -1184,13 +1184,13 @@ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", - "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", "cpu": [ "x64" ], @@ -1201,13 +1201,13 @@ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", - "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", "cpu": [ "arm64" ], @@ -1218,13 +1218,13 @@ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", - "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", "cpu": [ "x64" ], @@ -1235,13 +1235,13 @@ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", - "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", "cpu": [ "arm" ], @@ -1252,13 +1252,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", - "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", "cpu": [ "arm64" ], @@ -1269,13 +1269,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", - "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", "cpu": [ "ia32" ], @@ -1286,13 +1286,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", - "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", "cpu": [ "loong64" ], @@ -1303,13 +1303,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", - "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", "cpu": [ "mips64el" ], @@ -1320,13 +1320,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", - "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", "cpu": [ "ppc64" ], @@ -1337,13 +1337,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", - "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", "cpu": [ "riscv64" ], @@ -1354,13 +1354,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", - "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", "cpu": [ "s390x" ], @@ -1371,13 +1371,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", - "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", "cpu": [ "x64" ], @@ -1388,13 +1388,30 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.2.tgz", + "integrity": "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", - "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", "cpu": [ "x64" ], @@ -1405,13 +1422,30 @@ "netbsd" ], "engines": { - "node": ">=12" + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.2.tgz", + "integrity": "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", - "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", "cpu": [ "x64" ], @@ -1422,13 +1456,30 @@ "openbsd" ], "engines": { - "node": ">=12" + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.2.tgz", + "integrity": "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", - "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", "cpu": [ "x64" ], @@ -1439,13 +1490,13 @@ "sunos" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", - "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", "cpu": [ "arm64" ], @@ -1456,13 +1507,13 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", - "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", "cpu": [ "ia32" ], @@ -1473,13 +1524,13 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", - "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", "cpu": [ "x64" ], @@ -1490,7 +1541,7 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@floating-ui/core": { @@ -5236,28 +5287,28 @@ } }, "node_modules/electron-vite": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/electron-vite/-/electron-vite-2.3.0.tgz", - "integrity": "sha512-lsN2FymgJlp4k6MrcsphGqZQ9fKRdJKasoaiwIrAewN1tapYI/KINLdfEL7n10LuF0pPSNf/IqjzZbB5VINctg==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/electron-vite/-/electron-vite-4.0.1.tgz", + "integrity": "sha512-QqacJbA8f1pmwUTqki1qLL5vIBaOQmeq13CZZefZ3r3vKVaIoC7cpoTgE+KPKxJDFTax+iFZV0VYvLVWPiQ8Aw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/core": "^7.24.7", - "@babel/plugin-transform-arrow-functions": "^7.24.7", + "@babel/core": "^7.27.7", + "@babel/plugin-transform-arrow-functions": "^7.27.1", "cac": "^6.7.14", - "esbuild": "^0.21.5", - "magic-string": "^0.30.10", - "picocolors": "^1.0.1" + "esbuild": "^0.25.5", + "magic-string": "^0.30.17", + "picocolors": "^1.1.1" }, "bin": { "electron-vite": "bin/electron-vite.js" }, "engines": { - "node": "^18.0.0 || >=20.0.0" + "node": "^20.19.0 || >=22.12.0" }, "peerDependencies": { "@swc/core": "^1.0.0", - "vite": "^4.0.0 || ^5.0.0" + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0" }, "peerDependenciesMeta": { "@swc/core": { @@ -5446,9 +5497,9 @@ "optional": true }, "node_modules/esbuild": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", - "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -5456,32 +5507,86 @@ "esbuild": "bin/esbuild" }, "engines": { - "node": ">=12" + "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.21.5", - "@esbuild/android-arm": "0.21.5", - "@esbuild/android-arm64": "0.21.5", - "@esbuild/android-x64": "0.21.5", - "@esbuild/darwin-arm64": "0.21.5", - "@esbuild/darwin-x64": "0.21.5", - "@esbuild/freebsd-arm64": "0.21.5", - "@esbuild/freebsd-x64": "0.21.5", - "@esbuild/linux-arm": "0.21.5", - "@esbuild/linux-arm64": "0.21.5", - "@esbuild/linux-ia32": "0.21.5", - "@esbuild/linux-loong64": "0.21.5", - "@esbuild/linux-mips64el": "0.21.5", - "@esbuild/linux-ppc64": "0.21.5", - "@esbuild/linux-riscv64": "0.21.5", - "@esbuild/linux-s390x": "0.21.5", - "@esbuild/linux-x64": "0.21.5", - "@esbuild/netbsd-x64": "0.21.5", - "@esbuild/openbsd-x64": "0.21.5", - "@esbuild/sunos-x64": "0.21.5", - "@esbuild/win32-arm64": "0.21.5", - "@esbuild/win32-ia32": "0.21.5", - "@esbuild/win32-x64": "0.21.5" + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" } }, "node_modules/escalade": { @@ -10898,6 +11003,54 @@ "integrity": "sha512-qVtvMxeXbVej0cQWKqVSSAHmKZEHAvxdF8HEUBFWts8h+xEo5m/lEiPakuyZ3BnCBjOD8i24kzNOiOLLgsSxhA==", "license": "MIT" }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/tmp": { "version": "0.2.7", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.7.tgz", @@ -11390,21 +11543,24 @@ } }, "node_modules/vite": { - "version": "5.4.21", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", - "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.7.tgz", + "integrity": "sha512-AHEzTORMbi7/7aXp7w7KZ5+DCUdSeLsJz0grY8xHpc9DHdYb0vQu6DqJfm2tOw3gDExNgPgnJTXxM6syYFHaCA==", "dev": true, "license": "MIT", "dependencies": { - "esbuild": "^0.21.3", - "postcss": "^8.4.43", - "rollup": "^4.20.0" + "esbuild": "^0.27.0 || ^0.28.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" }, "bin": { "vite": "bin/vite.js" }, "engines": { - "node": "^18.0.0 || >=20.0.0" + "node": "^20.19.0 || >=22.12.0" }, "funding": { "url": "https://github.com/vitejs/vite?sponsor=1" @@ -11413,19 +11569,25 @@ "fsevents": "~2.3.3" }, "peerDependencies": { - "@types/node": "^18.0.0 || >=20.0.0", - "less": "*", + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", "lightningcss": "^1.21.0", - "sass": "*", - "sass-embedded": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.4.0" + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" }, "peerDependenciesMeta": { "@types/node": { "optional": true }, + "jiti": { + "optional": true + }, "less": { "optional": true }, @@ -11446,9 +11608,479 @@ }, "terser": { "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/@esbuild/aix-ppc64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.2.tgz", + "integrity": "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/android-arm": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.2.tgz", + "integrity": "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/android-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.2.tgz", + "integrity": "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/android-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.2.tgz", + "integrity": "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/darwin-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.2.tgz", + "integrity": "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/darwin-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.2.tgz", + "integrity": "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.2.tgz", + "integrity": "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/freebsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.2.tgz", + "integrity": "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-arm": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.2.tgz", + "integrity": "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.2.tgz", + "integrity": "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-ia32": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.2.tgz", + "integrity": "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-loong64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.2.tgz", + "integrity": "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-mips64el": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.2.tgz", + "integrity": "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-ppc64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.2.tgz", + "integrity": "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-riscv64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.2.tgz", + "integrity": "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-s390x": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.2.tgz", + "integrity": "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.2.tgz", + "integrity": "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/netbsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.2.tgz", + "integrity": "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/openbsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.2.tgz", + "integrity": "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/sunos-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.2.tgz", + "integrity": "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.2.tgz", + "integrity": "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-ia32": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.2.tgz", + "integrity": "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.2.tgz", + "integrity": "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/esbuild": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz", + "integrity": "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.28.2", + "@esbuild/android-arm": "0.28.2", + "@esbuild/android-arm64": "0.28.2", + "@esbuild/android-x64": "0.28.2", + "@esbuild/darwin-arm64": "0.28.2", + "@esbuild/darwin-x64": "0.28.2", + "@esbuild/freebsd-arm64": "0.28.2", + "@esbuild/freebsd-x64": "0.28.2", + "@esbuild/linux-arm": "0.28.2", + "@esbuild/linux-arm64": "0.28.2", + "@esbuild/linux-ia32": "0.28.2", + "@esbuild/linux-loong64": "0.28.2", + "@esbuild/linux-mips64el": "0.28.2", + "@esbuild/linux-ppc64": "0.28.2", + "@esbuild/linux-riscv64": "0.28.2", + "@esbuild/linux-s390x": "0.28.2", + "@esbuild/linux-x64": "0.28.2", + "@esbuild/netbsd-arm64": "0.28.2", + "@esbuild/netbsd-x64": "0.28.2", + "@esbuild/openbsd-arm64": "0.28.2", + "@esbuild/openbsd-x64": "0.28.2", + "@esbuild/openharmony-arm64": "0.28.2", + "@esbuild/sunos-x64": "0.28.2", + "@esbuild/win32-arm64": "0.28.2", + "@esbuild/win32-ia32": "0.28.2", + "@esbuild/win32-x64": "0.28.2" + } + }, + "node_modules/vite/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true } } }, + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/w3c-keyname": { "version": "2.2.8", "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz", diff --git a/package.json b/package.json index 14572ca055..117b3b1947 100644 --- a/package.json +++ b/package.json @@ -72,9 +72,9 @@ "@vitejs/plugin-react": "^4.3.2", "electron": "32.3.3", "electron-builder": "26.15.3", - "electron-vite": "^2.3.0", + "electron-vite": "^4.0.1", "typescript": "^5.6.3", - "vite": "^5.4.8" + "vite": "7.3.7" }, "overrides": { "app-builder-lib": { From f8139b801befede82a3886a1a7c7d52221b5c002 Mon Sep 17 00:00:00 2001 From: T3sh Date: Sat, 24 Oct 2026 12:52:48 -0300 Subject: [PATCH 23/24] feat(opencode): rotacao automatica de conta no limite do tier gratis Quando o motor opencode-cli imprime 'Free usage limit reached', o fork troca a conta ATIVA do CLI para a proxima credencial ja armazenada (opencode auth switch), poe a conta que falhou em cooldown de 4h e reinicia o terminal do agente afetado. O pool e automatico: qualquer conta logada no desktop entra sozinha. Sem cobranca, sem pedir login novo. - src/main/opencode-pool.ts: seletor puro (pickNextAccount/pooledCredentials/decodeJwtEmail) + rotateOpencodeCredential com cooldown em userData/opencode-rotation.json. Le o store via better-sqlite3 (lazy), troca pelo comando nativo do CLI (locks/migracoes ficam com ele) e verifica o flag active=1 no DB. No Windows, shims .cmd/bat passam por cmd.exe (execFile nao executa .cmd). - deteccao num unico ponto: terminalPool.watchQuota (cauda de 400 chars, throttle 60s) dispara 'hive:quota-hit' - useHive effect #8: ouve o evento, pede a troca ao main, escreve no feed do agente e respawna via o revive do auto-revive (effect #7 publica reviveRef). Um switch por vez: varios agentes no mesmo segundo descrevem a mesma conta. - test/opencode-pool.test.cjs: 9 testes do seletor (conta atual nunca repete, frescor por conta, cooldown/liberacao, store de 1 conta) --- src/main/index.ts | 15 + src/main/opencode-pool.ts | 294 ++++++++++++++++++++ src/preload/index.ts | 6 + src/renderer/src/components/terminalPool.ts | 33 +++ src/renderer/src/hooks/useHive.ts | 74 +++++ test/opencode-pool.test.cjs | 100 +++++++ 6 files changed, 522 insertions(+) create mode 100644 src/main/opencode-pool.ts create mode 100644 test/opencode-pool.test.cjs diff --git a/src/main/index.ts b/src/main/index.ts index a1ef2e87b9..095e759299 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -10,6 +10,7 @@ import { join, resolve, sep, basename, dirname, isAbsolute } from 'node:path'; import { homedir } from 'node:os'; import { request as httpsRequest } from 'node:https'; import { PtyManager, type SpawnOptions } from './pty'; +import { rotateOpencodeCredential } from './opencode-pool'; import { resolveCommand as resolveCliCommand, isSafeCommandName } from './shellEnv'; import { initAutoUpdater, abortPendingRestart } from './updater'; import { RealtimeFloorWatcher } from './realtimeFloorWatcher'; @@ -3117,6 +3118,20 @@ ipcMain.handle('pty:kill', (_evt, id: string) => { }); ipcMain.handle('pty:list', () => ptyManager.list()); +// ─── IPC: OpenCode account rotation ("pull de chaves") ─────────────────────── +/** After the free-tier limit error, the renderer asks us to move the desktop + * CLI's ACTIVE account to the next one in the store and reports the result. + * The renderer owns the respawn (it holds the terminal + agent state); main + * only performs the credential switch, because only main may run the CLI. */ +ipcMain.handle('opencode:rotate', async (_evt, exe: string) => { + try { + if (typeof exe !== 'string' || !exe.trim()) return { ok: false, reason: 'engine executable missing' }; + return await rotateOpencodeCredential({ exe: exe.trim(), stateDir: app.getPath('userData') }); + } catch (err) { + return { ok: false, reason: err instanceof Error ? err.message : String(err) }; + } +}); + // ─── IPC: analytics (the ONE renderer-facing seam) ────────────────────────── /** Count one human-sent message (TELEMETRY.md → `message_sent`). A COUNT, and * nothing else: this channel takes no text, no length and no id, so there is diff --git a/src/main/opencode-pool.ts b/src/main/opencode-pool.ts new file mode 100644 index 0000000000..7764c8db5b --- /dev/null +++ b/src/main/opencode-pool.ts @@ -0,0 +1,294 @@ +/** + * "Pull de chaves" — OpenCode free-tier account rotation. + * + * The OpenCode desktop CLI stores every account we've ever logged into in its + * credential store (`~/.local/share/opencode/opencode.db`, table `credential`, + * integration_id='opencode'). Exactly ONE row carries active=1 — the account + * every request is billed against. When that account's free tier runs out the + * CLI prints "Free usage limit reached" and refuses to continue; the fix users + * are pushed toward is paying. But the store usually already holds SEVERAL + * accounts (the user logged in more than once) — this module picks the next + * usable one, flips it active through the CLI's own `auth switch` command (not + * raw SQL — the CLI owns locking/migrations), and reports who we switched to. + * + * Deliberately dependency-light for testability: the picker is a pure function; + * better-sqlite3 is loaded lazily inside the rotate call so unit tests can + * import this file without the native binding. + */ +import { exec, execFile } from 'node:child_process'; +import { existsSync, readFileSync, writeFileSync } from 'node:fs'; +import { homedir } from 'node:os'; +import { join } from 'node:path'; +import type BetterSqlite3 from 'better-sqlite3'; + +/** How long an account stays benched after it reported the free-tier limit. + * The limit is a running window, not a monthly bucket, but 4h keeps us from + * ping-ponging between two exhausted accounts within one work session. */ +export const COOLDOWN_MS = 4 * 60 * 60 * 1000; + +export interface PooledCredential { + id: string; + /** Stable account identity — the JWT's email (or the row label as fallback). */ + account: string; + /** Epoch ms when the access token expires (higher = fresher login). */ + expires: number; + active: boolean; +} + +interface CredentialRow { + id: string; + label: string; + active: number; + value: string; +} + +/** Decode a JWT payload without verification — used ONLY to read the account's + * email and expiry out of a token this machine already owns. Never validates. */ +export function decodeJwtEmail(token: string): string | null { + try { + const payload = token.split('.')[1]; + if (!payload) return null; + const json = Buffer.from(payload.replace(/-/g, '+').replace(/_/g, '/'), 'base64').toString('utf8'); + const parsed = JSON.parse(json) as { email?: string }; + return typeof parsed.email === 'string' && parsed.email.includes('@') ? parsed.email : null; + } catch { + return null; + } +} + +/** Map raw `credential` rows to pooled credentials (one per ROW — several rows + * may share an account: repeated logins refresh the same account). */ +export function pooledCredentials(rows: CredentialRow[]): PooledCredential[] { + const out: PooledCredential[] = []; + for (const row of rows) { + let value: { access?: string; expires?: number; metadata?: { email?: string } } = {}; + try { + value = JSON.parse(row.value); + } catch { + continue; + } + const account = (typeof value.access === 'string' ? decodeJwtEmail(value.access) : null) + ?? (typeof value.metadata?.email === 'string' ? value.metadata.email : null) + ?? row.label; + const expires = typeof value.expires === 'number' ? value.expires : 0; + out.push({ id: row.id, account, expires, active: row.active === 1 }); + } + return out; +} + +export interface PickOptions { + /** Epoch ms "now" (injectable for tests). */ + now: number; + /** credId → cooldown-until (epoch ms). */ + cooldown: Record; +} + +export interface PickResult { + pick: PooledCredential | null; + current: PooledCredential | null; + /** Which of the pool's accounts are benched (for a "pool exhausted" message). */ + benchedAccounts: string[]; + /** When the next account leaves cooldown (epoch ms) — undefined if none. */ + nextAvailableAt?: number; +} + +/** + * Choose the next account to switch to. + * + * Rules, in order: + * 1. Never re-pick the account that just failed (the `active` one). + * 2. One row per ACCOUNT — prefer the freshest login of it (max expires). + * 3. Skip accounts currently benched; among candidates prefer the freshest. + * 4. If every other account is benched, pick nothing (return the earliest + * cooldown release so the caller can say "volta às HH:MM"). + */ +export function pickNextAccount(creds: PooledCredential[], opts: PickOptions): PickResult { + const current = creds.find((c) => c.active) ?? null; + const byAccount = new Map(); + for (const c of creds) { + const seen = byAccount.get(c.account); + if (!seen || c.expires > seen.expires) byAccount.set(c.account, c); + } + const benched: string[] = []; + const candidates: PooledCredential[] = []; + let nextAvailableAt: number | undefined; + for (const [account, freshest] of byAccount) { + if (current && account === current.account) continue; // rule 1 + const until = opts.cooldown[freshest.id] ?? 0; + if (until > opts.now) { + benched.push(account); + nextAvailableAt = nextAvailableAt === undefined ? until : Math.min(nextAvailableAt, until); + continue; + } + candidates.push(freshest); + } + candidates.sort((a, b) => b.expires - a.expires); // rule 3 (freshest first) + return { pick: candidates[0] ?? null, current, benchedAccounts: benched, nextAvailableAt }; +} + +export interface RotateResult { + ok: boolean; + /** Account email we switched TO (present when ok). */ + account?: string; + /** Account email we switched FROM. */ + previous?: string; + /** Human-readable reason when ok === false. */ + reason?: string; +} + +interface RotationState { + /** credId (of the account's freshest credential) → cooldown-until epoch ms. */ + cooldown: Record; +} + +function readState(file: string): RotationState { + try { + const parsed = JSON.parse(readFileSync(file, 'utf8')) as RotationState; + if (parsed && typeof parsed.cooldown === 'object' && parsed.cooldown) return parsed; + } catch { /* first run / corrupt — start clean */ } + return { cooldown: {} }; +} + +function writeState(file: string, state: RotationState): void { + try { + writeFileSync(file, JSON.stringify(state, null, 2), 'utf8'); + } catch { /* best-effort: state is a convenience, not correctness */ } +} + +/** Run the CLI's native account switch (owns DB locks + token refresh). + * + * On Windows the engine may be reached through an npm shim (`opencode.cmd`) or + * a bare PATH name (`opencode`) rather than a real `.exe`. `execFile` cannot + * execute those (ENOENT/EINVAL), so route them through cmd.exe — which also + * applies PATHEXT while resolving a bare name. */ +function runAuthSwitch(exe: string, credentialId: string): Promise { + // Defense in depth: an id may only look like `cred_…` before it reaches a shell. + if (!/^[A-Za-z0-9_-]+$/.test(credentialId)) { + return Promise.reject(new Error('credential id inválido')); + } + if (/["\r\n]/.test(exe)) { + return Promise.reject(new Error('caminho do executável inválido')); + } + const viaShell = process.platform === 'win32' && !/\.exe$/i.test(exe); + const options = { + timeout: 25_000, + windowsHide: true, + env: { ...process.env, NO_COLOR: '1' } + }; + return new Promise((resolve, reject) => { + const done = (err: Error | null): void => (err ? reject(err) : resolve()); + if (viaShell) { + // `exec` hands cmd.exe the raw command line, so OUR quotes survive (a + // quoted exe path with spaces works). `execFile` would backslash-escape + // the inner quotes, which cmd.exe does not understand. + exec(`"${exe}" auth switch opencode ${credentialId}`, options, done); + } else { + execFile(exe, ['auth', 'switch', 'opencode', credentialId], options, done); + } + }); +} + +export interface RotateOptions { + /** The engine executable to drive (`opencode-cli.exe`). */ + exe: string; + /** Where to keep our cooldown record (app userData dir). */ + stateDir: string; + /** Override the credential DB path (tests / odd installs). */ + dbPath?: string; + now?: number; + cooldownMs?: number; +} + +/** Default credential store the OpenCode CLI writes on this OS. */ +export function defaultCredentialDbPath(): string { + return join(homedir(), '.local', 'share', 'opencode', 'opencode.db'); +} + +/** + * Switch the ACTIVE OpenCode account to the next usable one. Never throws — + * callers get `{ ok:false, reason }` so the renderer can surface it in the feed. + */ +export async function rotateOpencodeCredential(opts: RotateOptions): Promise { + const now = opts.now ?? Date.now(); + const stateFile = join(opts.stateDir, 'opencode-rotation.json'); + const state = readState(stateFile); + // Forget cooldowns that already expired — keeps the file honest. + for (const [id, until] of Object.entries(state.cooldown)) { + if (until <= now) delete state.cooldown[id]; + } + + const dbPath = opts.dbPath ?? defaultCredentialDbPath(); + if (!existsSync(dbPath)) { + return { ok: false, reason: `store de credenciais não encontrado (${dbPath})` }; + } + + let rows: CredentialRow[]; + try { + // Lazy require: unit tests import this module without the native binding. + const Database = require('better-sqlite3') as typeof BetterSqlite3; + const db = new Database(dbPath, { readonly: true, fileMustExist: true }); + try { + rows = db.prepare( + "SELECT id, label, active, value FROM credential WHERE integration_id = 'opencode'" + ).all() as CredentialRow[]; + } finally { + db.close(); + } + } catch (err) { + return { ok: false, reason: `não consegui ler o store (${err instanceof Error ? err.message : String(err)})` }; + } + + const creds = pooledCredentials(rows); + if (creds.length === 0) return { ok: false, reason: 'nenhuma conta OpenCode armazenada' }; + + const { pick, current, benchedAccounts, nextAvailableAt } = pickNextAccount(creds, { + now, + cooldown: state.cooldown + }); + if (!pick) { + const when = nextAvailableAt ? ` — próxima conta libera ${new Date(nextAvailableAt).toLocaleTimeString()}` : ''; + return { + ok: false, + reason: benchedAccounts.length + ? `todas as contas no cooldown${when}` + : 'nenhuma outra conta além da atual' + }; + } + + try { + await runAuthSwitch(opts.exe, pick.id); + } catch (err) { + return { ok: false, reason: `auth switch falhou (${err instanceof Error ? err.message : String(err)})` }; + } + + // Verify the CLI actually flipped the flag (a stale service could no-op). + let activeId: string | null = null; + try { + const Database = require('better-sqlite3') as typeof BetterSqlite3; + const db = new Database(dbPath, { readonly: true, fileMustExist: true }); + try { + const row = db.prepare( + "SELECT id FROM credential WHERE integration_id = 'opencode' AND active = 1 LIMIT 1" + ).get() as { id: string } | undefined; + activeId = row?.id ?? null; + } finally { + db.close(); + } + } catch { /* fall through to the explicit failure below */ } + if (activeId !== pick.id) { + return { ok: false, reason: 'auth switch não persistiu (o CLI continua na conta anterior)' }; + } + + // Bench the account that just failed, so the next rotation doesn't come back + // to it within COOLDOWN_MS. Keyed by its freshest credential row. + const failed = current ?? null; + if (failed) { + const freshest = creds + .filter((c) => c.account === failed.account) + .sort((a, b) => b.expires - a.expires)[0]; + if (freshest) state.cooldown[freshest.id] = now + (opts.cooldownMs ?? COOLDOWN_MS); + } + writeState(stateFile, state); + + return { ok: true, account: pick.account, previous: current?.account }; +} diff --git a/src/preload/index.ts b/src/preload/index.ts index 23a3a4212c..939e53b3e4 100644 --- a/src/preload/index.ts +++ b/src/preload/index.ts @@ -589,6 +589,12 @@ const api = { ipcRenderer.invoke('pty:redraw', id), killPty: (id: string): Promise<{ ok: boolean; error?: string }> => ipcRenderer.invoke('pty:kill', id), + /** "Pull de chaves": after a free-tier limit error, switch the OpenCode CLI's + * ACTIVE account to the next stored one (main runs `auth switch`). The + * renderer respawns the affected agent afterwards so the new account takes + * effect in that session. */ + opencodeRotate: (exe: string): Promise<{ ok: boolean; account?: string; previous?: string; reason?: string }> => + ipcRenderer.invoke('opencode:rotate', exe), listPtys: (): Promise(); +const QUOTA_LAST_HIT = new Map(); +const QUOTA_RE = /Free usage limit reached/i; +const QUOTA_THROTTLE_MS = 60_000; + +function watchQuota(ptyId: string, chunk: string): void { + // The phrase may arrive split across chunk boundaries — keep a small tail. + const tail = ((QUOTA_TAIL.get(ptyId) ?? '') + chunk).slice(-400); + QUOTA_TAIL.set(ptyId, tail); + if (!QUOTA_RE.test(tail)) return; + const now = Date.now(); + if (now - (QUOTA_LAST_HIT.get(ptyId) ?? 0) < QUOTA_THROTTLE_MS) return; + QUOTA_LAST_HIT.set(ptyId, now); + QUOTA_TAIL.delete(ptyId); + try { + window.dispatchEvent(new CustomEvent('hive:quota-hit', { detail: { ptyId } })); + } catch { /* non-DOM context (tests) — nothing to announce */ } +} + export interface TerminalEntry { /** The pty this terminal mirrors — needed to poke `resizePty` on a reflow. */ ptyId: string; @@ -187,6 +219,7 @@ export function acquireTerminal(ptyId: string, theme?: ThemeMap, fontSize = 14): entry.unsub.push(window.cth.onPtyData(ptyId, (rawChunk) => { const chunk = normalizePtyChunk(rawChunk); if (!chunk) return; + watchQuota(ptyId, chunk); const active = term.buffer.active; const follow = shouldFollowTerminalOutput(active.viewportY, active.baseY); term.write(chunk, () => { diff --git a/src/renderer/src/hooks/useHive.ts b/src/renderer/src/hooks/useHive.ts index f75f1d3c82..1211e57a1b 100644 --- a/src/renderer/src/hooks/useHive.ts +++ b/src/renderer/src/hooks/useHive.ts @@ -330,6 +330,15 @@ export function useHive(config: HarnessConfig | null): void { // mid-revive) within REVIVE_DEBOUNCE_MS is skipped. Set BEFORE the async spawn // so a re-entrant event can't race a second respawn for the same id. const reviving = useRef>({}); + // The auto-revive respawn (effect #7) is the ONLY code path that knows how to + // restart an agent with its exact command/cwd/worktree/session. Effect #8 + // (free-tier rotation) needs that same respawn but lives in a different + // effect, so #7 publishes its `revive` here. + const reviveRef = useRef<((deadId: string) => Promise) | null>(null); + // One rotation at a time: several OpenCode agents can hit the limit within the + // same second, and they all describe the same exhausted account. Concurrent + // switches would fight over the DB flag (and could skip a fresh account). + const rotating = useRef(false); // Reactive so the assistant bootstrap (effect #1b) re-runs once Michael is ready. const godStatus = useStore((s) => s.godStatus); // Per-pty `lastOutputAt`, refreshed by the quiescence sweep (#2e) and read by @@ -1257,10 +1266,75 @@ export function useHive(config: HarnessConfig | null): void { } }; + // Publish the respawn so effect #8 (free-tier rotation) can restart the + // affected agent under the newly active account. + reviveRef.current = revive; + return window.cth.onPowerResume?.((e) => { const dead = Array.isArray(e?.dead) ? e.dead : []; if (!dead.length) return; // healthy wake — nothing wedged, no-op for (const id of dead) void revive(id); }); }, [config?.onboardingComplete]); + + // 8) Free-tier account rotation ("pull de chaves"). The OpenCode engine prints + // "Free usage limit reached" once the ACTIVE account's free quota is gone, + // then refuses every request in every agent on that account. `terminalPool` + // sees that line in the pty stream (the one tap every terminal shares) and + // dispatches `hive:quota-hit`. Here we ask main to switch the CLI's active + // account to the next stored one, then respawn THIS agent so its TUI stops + // showing the dead turn and picks up the new account. + // Other OpenCode agents need no respawn: the service resolves the active + // account per request, so their next message already uses the new one. + useEffect(() => { + if (!config?.onboardingComplete) return; + + const mask = (email?: string): string => + email && email.includes('@') ? email.replace(/^(.).*?(@.*)$/, '$1***$2') : (email ?? ''); + + const onQuotaHit = (evt: Event): void => { + const ptyId = (evt as CustomEvent<{ ptyId?: string }>).detail?.ptyId; + if (!ptyId) return; + if (rotating.current) return; // a switch is already in flight + const a = useStore.getState().agents.find((x) => x.ptyId === ptyId); + if (!a) return; + if (inferAgentProvider(a.command, a.provider) !== 'opencode') return; + const exe = tokenizeCommand((a.command ?? '').trim())[0]; + if (!exe) return; + + rotating.current = true; + const st = useStore.getState(); + st.updateAgent(a.id, { action: 'limite do grátis — trocando de conta' }); + st.pushFeed(a.id, '↻ Limite do tier grátis atingido — buscando outra conta…'); + + void (async () => { + try { + const res = await window.cth.opencodeRotate(exe); + const now = useStore.getState(); + if (!res?.ok) { + now.pushFeed(a.id, `✖ Sem outra conta disponível: ${res?.reason ?? 'motivo desconhecido'}`); + now.updateAgent(a.id, { action: 'limite do grátis (pool esgotado)' }); + return; + } + const who = mask(res.account); + now.pushFeed( + a.id, + `↻ Conta trocada para ${who}${res.previous ? ` (era ${mask(res.previous)})` : ''} — reiniciando o terminal…` + ); + await reviveRef.current?.(ptyId); + useStore.getState().updateAgent(a.id, { action: `conta ${who}` }); + } catch (err) { + useStore.getState().pushFeed( + a.id, + `✖ Falha ao trocar de conta: ${err instanceof Error ? err.message : String(err)}` + ); + } finally { + rotating.current = false; + } + })(); + }; + + window.addEventListener('hive:quota-hit', onQuotaHit); + return () => window.removeEventListener('hive:quota-hit', onQuotaHit); + }, [config?.onboardingComplete]); } diff --git a/test/opencode-pool.test.cjs b/test/opencode-pool.test.cjs new file mode 100644 index 0000000000..c0bd7ea038 --- /dev/null +++ b/test/opencode-pool.test.cjs @@ -0,0 +1,100 @@ +'use strict'; + +const test = require('node:test'); +const assert = require('node:assert/strict'); +const loadTs = require('./load-ts.cjs'); + +const { pickNextAccount, pooledCredentials, decodeJwtEmail, COOLDOWN_MS } = loadTs('src/main/opencode-pool.ts'); + +const HOUR = 60 * 60 * 1000; +const NOW = 1_800_000_000_000; + +/** Minimal fake credential row (the shape `credential` has in the store). */ +function row(id, email, expires, active = 0, label = 'Default') { + // Access token is a real JWT envelope so decodeJwtEmail is exercised too. + const payload = Buffer.from(JSON.stringify({ email, exp: Math.floor(expires / 1000) })).toString('base64url'); + const access = `header.${payload}.signature`; + return { id, label, active, value: JSON.stringify({ type: 'oauth', access, expires }) }; +} + +test('decodeJwtEmail reads the account out of an access token', () => { + const { access } = JSON.parse(row('c1', 'someone@example.com', NOW).value); + assert.equal(decodeJwtEmail(access), 'someone@example.com'); + assert.equal(decodeJwtEmail('not-a-jwt'), null); + assert.equal(decodeJwtEmail(''), null); +}); + +test('pooledCredentials keeps one entry per row and marks the active account', () => { + const creds = pooledCredentials([ + row('cred_a', 'a@x.com', NOW + 1 * HOUR, 0), + row('cred_b', 'b@x.com', NOW + 2 * HOUR, 1, 'Personal'), + row('cred_bad', 'ignored', NOW, 0) + ].map((r, i) => (i === 2 ? { ...r, value: '{not json' } : r))); + assert.equal(creds.length, 2); + assert.deepEqual(creds.map((c) => c.account), ['a@x.com', 'b@x.com']); + assert.equal(creds.find((c) => c.active).id, 'cred_b'); +}); + +test('never re-picks the account that just failed', () => { + const creds = pooledCredentials([ + row('cred_old', 'dead@x.com', NOW + 1 * HOUR, 1), + row('cred_new', 'live@x.com', NOW + 2 * HOUR, 0) + ]); + const { pick, current } = pickNextAccount(creds, { now: NOW, cooldown: {} }); + assert.equal(current.account, 'dead@x.com'); + assert.equal(pick.id, 'cred_new'); +}); + +test('one row per account, freshest login wins', () => { + const creds = pooledCredentials([ + row('cred_stale', 'same@x.com', NOW + 1 * HOUR, 0), + row('cred_fresh', 'same@x.com', NOW + 5 * HOUR, 0), + row('cred_other', 'other@x.com', NOW + 2 * HOUR, 1) + ]); + const { pick } = pickNextAccount(creds, { now: NOW, cooldown: {} }); + assert.equal(pick.id, 'cred_fresh', 'must not offer the stale row of the same account'); +}); + +test('prefers the freshest candidate when several accounts are free', () => { + const creds = pooledCredentials([ + row('cred_a', 'a@x.com', NOW + 1 * HOUR, 1), + row('cred_b', 'b@x.com', NOW + 3 * HOUR, 0), + row('cred_c', 'c@x.com', NOW + 2 * HOUR, 0) + ]); + const { pick } = pickNextAccount(creds, { now: NOW, cooldown: {} }); + assert.equal(pick.account, 'b@x.com'); +}); + +test('benched accounts are skipped and reported with the next release time', () => { + const creds = pooledCredentials([ + row('cred_a', 'a@x.com', NOW + 1 * HOUR, 1), + row('cred_b', 'b@x.com', NOW + 3 * HOUR, 0), + row('cred_c', 'c@x.com', NOW + 2 * HOUR, 0) + ]); + const cooldown = { cred_b: NOW + 2 * HOUR, cred_c: NOW + 1 * HOUR }; + const { pick, benchedAccounts, nextAvailableAt } = pickNextAccount(creds, { now: NOW, cooldown }); + assert.equal(pick, null); + assert.deepEqual(benchedAccounts.sort(), ['b@x.com', 'c@x.com']); + assert.equal(nextAvailableAt, NOW + 1 * HOUR); +}); + +test('an expired cooldown is usable again', () => { + const creds = pooledCredentials([ + row('cred_a', 'a@x.com', NOW + 1 * HOUR, 1), + row('cred_b', 'b@x.com', NOW + 3 * HOUR, 0) + ]); + const { pick } = pickNextAccount(creds, { now: NOW, cooldown: { cred_b: NOW - 1 } }); + assert.equal(pick.id, 'cred_b'); +}); + +test('a store with a single account yields no rotation', () => { + const creds = pooledCredentials([row('cred_only', 'only@x.com', NOW + HOUR, 1)]); + const { pick, benchedAccounts, nextAvailableAt } = pickNextAccount(creds, { now: NOW, cooldown: {} }); + assert.equal(pick, null); + assert.deepEqual(benchedAccounts, []); + assert.equal(nextAvailableAt, undefined); +}); + +test('cooldown is four hours', () => { + assert.equal(COOLDOWN_MS, 4 * HOUR); +}); From 97b788429f504d96fbef3438a03d2b0b134011f6 Mon Sep 17 00:00:00 2001 From: T3sh Date: Sat, 24 Oct 2026 13:00:53 -0300 Subject: [PATCH 24/24] fix(opencode): detectar o limite mesmo com cor/quebra de linha do TUI O TUI do opencode colore a frase e pode quebra-la na largura do terminal. A cauda do PTY agora e normalizada (ANSI fora, \\r\\n -> espaco) antes do match de 'Free usage limit reached', para a rotacao nao depender da pintura exata. --- src/renderer/src/components/terminalPool.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/renderer/src/components/terminalPool.ts b/src/renderer/src/components/terminalPool.ts index 074990ca88..d099560afe 100644 --- a/src/renderer/src/components/terminalPool.ts +++ b/src/renderer/src/components/terminalPool.ts @@ -57,14 +57,18 @@ import '@xterm/xterm/css/xterm.css'; */ const QUOTA_TAIL = new Map(); const QUOTA_LAST_HIT = new Map(); +// The TUI may paint the sentence in colour (escape codes between glyphs) and may +// hard-wrap it at the terminal width (a newline inside the phrase). Flatten both +// before matching — the phrase itself is the only stable signal. const QUOTA_RE = /Free usage limit reached/i; +const QUOTA_ANSI = /\u001b\[[0-9;?]*[ -/]*[@-~]|\u001b\][^\u0007\u001b]*(?:\u0007|\u001b\\)|\u001b[@-Z\\-_]/g; const QUOTA_THROTTLE_MS = 60_000; function watchQuota(ptyId: string, chunk: string): void { // The phrase may arrive split across chunk boundaries — keep a small tail. const tail = ((QUOTA_TAIL.get(ptyId) ?? '') + chunk).slice(-400); QUOTA_TAIL.set(ptyId, tail); - if (!QUOTA_RE.test(tail)) return; + if (!QUOTA_RE.test(tail.replace(QUOTA_ANSI, '').replace(/[\r\n]+/g, ' '))) return; const now = Date.now(); if (now - (QUOTA_LAST_HIT.get(ptyId) ?? 0) < QUOTA_THROTTLE_MS) return; QUOTA_LAST_HIT.set(ptyId, now);