specrails-desktop 2.31.2 → 2.33.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/client/dist/assets/{ActivityFeedPage-Cdccp1kl.js → ActivityFeedPage-DaBTALGY.js} +1 -1
- package/client/dist/assets/{AgentBrowserCapture-DUwwfVOf.js → AgentBrowserCapture-SxwVNrUs.js} +1 -1
- package/client/dist/assets/{AgentModeCodePane-B1Fu0f_G.js → AgentModeCodePane-CmLgIoDw.js} +2 -2
- package/client/dist/assets/{AgentModeJobsPane-DA6wQKKt.js → AgentModeJobsPane-BvP_T32M.js} +1 -1
- package/client/dist/assets/{AgentsPage-CR72XsPj.js → AgentsPage-Bz7uDqvI.js} +1 -1
- package/client/dist/assets/{AnalyticsPage-CPnl0xkM.js → AnalyticsPage-DrNHMTed.js} +1 -1
- package/client/dist/assets/{CodePage-BYY7EF1b.js → CodePage-DZtAK2Ac.js} +1 -1
- package/client/dist/assets/{DesktopAnalyticsPage-9PUjsD8C.js → DesktopAnalyticsPage-DrvNiDb0.js} +1 -1
- package/client/dist/assets/{DocsDialog-zngqdI-4.js → DocsDialog-BEQpGC1o.js} +1 -1
- package/client/dist/assets/{DocsPage-CDJH_q9M.js → DocsPage-Btso3Viq.js} +1 -1
- package/client/dist/assets/{InteractiveJobComposer-drUo56r7.js → InteractiveJobComposer-Ca9-_4VF.js} +1 -1
- package/client/dist/assets/{JobDetailModal-CWmzaRXG.js → JobDetailModal-Brk7fL5A.js} +1 -1
- package/client/dist/assets/{JobDetailPage-xlzBYZEJ.js → JobDetailPage-DiQVcvW7.js} +1 -1
- package/client/dist/assets/{JobsPage-Dcnol1Y6.js → JobsPage-1SvirYQm.js} +1 -1
- package/client/dist/assets/{LoopBuilderPage-D3q7EoNM.js → LoopBuilderPage-X_YwJ-Ik.js} +1 -1
- package/client/dist/assets/{LoopPreviewModal-Q8osegkj.js → LoopPreviewModal-BeW-cr7A.js} +1 -1
- package/client/dist/assets/{LoopsPage-CATnNd1X.js → LoopsPage-Na9vDt4p.js} +1 -1
- package/client/dist/assets/{MinimizedChatsContext-DIsnQMVz.js → MinimizedChatsContext-BQQohTp2.js} +1 -1
- package/client/dist/assets/{PluginsPage-BOh6z0zK.js → PluginsPage-B-NLA93L.js} +1 -1
- package/client/dist/assets/{ProjectSettingsDialog-CNcANqEL.js → ProjectSettingsDialog-CQlq1Mf7.js} +1 -1
- package/client/dist/assets/{TemplatePreviewModal-4EpqyErX.js → TemplatePreviewModal-CPz1o3fP.js} +1 -1
- package/client/dist/assets/{TicketDetailModal-BfV4tnvr.js → TicketDetailModal-DEoAJOuD.js} +3 -3
- package/client/dist/assets/{Trans-cWtExGkC.js → Trans-CpUoGvNy.js} +1 -1
- package/client/dist/assets/agentstudio-BNUth0uj.js +1 -0
- package/client/dist/assets/agentstudio-BNdB5hkr.js +1 -0
- package/client/dist/assets/agentstudio-C7-bt8FO.js +1 -0
- package/client/dist/assets/agentstudio-C8uNchpV.js +1 -0
- package/client/dist/assets/agentstudio-CKabyMlg.js +1 -0
- package/client/dist/assets/agentstudio-CN2pokQu.js +1 -0
- package/client/dist/assets/agentstudio-DR7doNBV.js +1 -0
- package/client/dist/assets/agentstudio-y2dVDXeM.js +1 -0
- package/client/dist/assets/{dist-js-Cn09PP3z.js → dist-js-1QRck05T.js} +1 -1
- package/client/dist/assets/{dist-js-mq5XA-4f.js → dist-js-K9AsZWxz.js} +1 -1
- package/client/dist/assets/{formatDistanceToNow-DUyzS4rr.js → formatDistanceToNow-2bGOYubE.js} +1 -1
- package/client/dist/assets/{getTimezoneOffsetInMilliseconds-BCIwmmTj.js → getTimezoneOffsetInMilliseconds-B_N-0uSl.js} +1 -1
- package/client/dist/assets/{i18n-D21Pr8Sj.js → i18n-B2SaZsf2.js} +2 -2
- package/client/dist/assets/{index-CzNyrRn5.js → index-Bpzm94S9.js} +17 -17
- package/client/dist/assets/index-ChIuonbC.css +2 -0
- package/client/dist/assets/loops-B2_97D26.js +1 -0
- package/client/dist/assets/loops-BISOkuCu.js +1 -0
- package/client/dist/assets/loops-Bo6w_peZ.js +1 -0
- package/client/dist/assets/loops-BwxCndZk.js +1 -0
- package/client/dist/assets/loops-CD19kEzq.js +1 -0
- package/client/dist/assets/loops-CMMQOw2P.js +1 -0
- package/client/dist/assets/loops-CnxqL8IL.js +1 -0
- package/client/dist/assets/loops-aEb4RxN2.js +1 -0
- package/client/dist/assets/setup-CA9J5hck.js +1 -0
- package/client/dist/assets/setup-CK8IKkeD.js +1 -0
- package/client/dist/assets/setup-Cas_jrnl.js +1 -0
- package/client/dist/assets/setup-ClcYC8KP.js +1 -0
- package/client/dist/assets/setup-CtfFTXdf.js +1 -0
- package/client/dist/assets/setup-D73npsqO.js +1 -0
- package/client/dist/assets/setup-DXw1UgZB.js +1 -0
- package/client/dist/assets/setup-DsKIBie0.js +1 -0
- package/client/dist/assets/{spending-BCyUxoOI.js → spending-B20-uFLQ.js} +1 -1
- package/client/dist/assets/{useBrowserCaptureSession-CkVCDzer.js → useBrowserCaptureSession-DACautTD.js} +1 -1
- package/client/dist/assets/{useDesktop-DCP_MHp9.js → useDesktop-Cwyis9DX.js} +1 -1
- package/client/dist/index.html +14 -14
- package/package.json +1 -1
- package/server/dist/ai-invocations.js +35 -0
- package/server/dist/job-phase-breakdown.js +132 -0
- package/server/dist/loop-executors.js +10 -3
- package/server/dist/loop-factory.js +7 -5
- package/server/dist/loop-graph.js +4 -3
- package/server/dist/loop-run-manager.js +7 -3
- package/server/dist/loop-templates.js +4 -3
- package/server/dist/pr-body.js +13 -0
- package/server/dist/profiles-router.js +24 -1
- package/server/dist/project-router-jobs.js +16 -0
- package/server/dist/queue-manager.js +4 -0
- package/server/dist/rail-isolated-launch.js +15 -0
- package/server/dist/rail-pr-decision.js +10 -0
- package/server/dist/repo-map.js +293 -0
- package/server/dist/spawn-lifecycle.js +1 -1
- package/server/dist/worktree-node-modules.js +158 -0
- package/client/dist/assets/agentstudio-8TQqBenW.js +0 -1
- package/client/dist/assets/agentstudio-B8Z_mmEX.js +0 -1
- package/client/dist/assets/agentstudio-BZR9YmLs.js +0 -1
- package/client/dist/assets/agentstudio-Bge9pAWb.js +0 -1
- package/client/dist/assets/agentstudio-Bz169Vzt.js +0 -1
- package/client/dist/assets/agentstudio-D6L2jpNi.js +0 -1
- package/client/dist/assets/agentstudio-K2-Z7CL0.js +0 -1
- package/client/dist/assets/agentstudio-Zmgzthv8.js +0 -1
- package/client/dist/assets/index-Bz0TeGRs.css +0 -2
- package/client/dist/assets/loops-BzfXWEwO.js +0 -1
- package/client/dist/assets/loops-CPpgMapU.js +0 -1
- package/client/dist/assets/loops-CWWbKuVL.js +0 -1
- package/client/dist/assets/loops-Crc9It8o.js +0 -1
- package/client/dist/assets/loops-DH2hZcbK.js +0 -1
- package/client/dist/assets/loops-DS5TmvIU.js +0 -1
- package/client/dist/assets/loops-P2f0cN8-.js +0 -1
- package/client/dist/assets/loops-fJV-9hH7.js +0 -1
- package/client/dist/assets/setup-BBiHEO7h.js +0 -1
- package/client/dist/assets/setup-BlTWhNIQ.js +0 -1
- package/client/dist/assets/setup-Bp2L_oiP.js +0 -1
- package/client/dist/assets/setup-CInYXp1-.js +0 -1
- package/client/dist/assets/setup-CYH3bP6K.js +0 -1
- package/client/dist/assets/setup-DwcQ921P.js +0 -1
- package/client/dist/assets/setup-PBLjuDSs.js +0 -1
- package/client/dist/assets/setup-bx6FtoBp.js +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var e={configureAgents:`Configurer les agents {{provider}}`,configureSubtitle:`Passez en revue votre équipe d'agents et choisissez comment chacun s'exécute.`,tabs:{agents:`Agents`,models:`Modèles`},skipForNow:`Ignorer pour l'instant`,install:`Installer`,nextProvider:`Suivant : {{provider}}`,installingProvider:`Installation de {{provider}}…`,installingSpecrails:`Installation de specrails...`,installingFromTemplates:`Installation des agents à partir des templates`,waitingForOutput:`En attente de sortie...`,checkpoints:{baseInstall:`Installation de base`,agentSelection:`Configuration des agents`,agentGeneration:`Génération des agents`},steps:{configure:`Configurer`},summary:{agents:`Agents`,agentSkills:`Skills d'agent`,skills:`Skills`,openspecSkills:`Skills OpenSpec`,legacyRemoved_one:`{{count}} commande legacy <code>/specrails:*</code> supprimée`,legacyRemoved_other:`{{count}} commandes legacy <code>/specrails:*</code> supprimées`},complete:{welcome:`Bienvenue dans <spec>spec</spec><rails>rails</rails>`,configured:`<strong>{{projectName}}</strong> est maintenant configuré avec des workflows de développement pilotés par l'IA. Vos agents spécialisés et vos commandes sont prêts à l'emploi.`,installedForEngines_one:`Installé pour {{count}} moteur`,installedForEngines_other:`Installé pour {{count}} moteurs`,installed:`Installé`,installFailed:`Échec de l'installation`,learnMore:`Apprenez à tirer le meilleur de specrails :`,continueToProject:`Continuer vers le projet`,jira:{title:`Connecter un tableau Jira`,subtitle:`Facultatif — adossez les specs de ce projet à un tableau Jira. Vous pourrez aussi le faire plus tard dans les Paramètres.`,configure:`Configurer Jira`,optional:`facultatif`},mcpHint:`Connectez des outils d'IA externes à Specrails via un serveur MCP local sécurisé — activez-le dans les Paramètres.`,agentChatHint:`Pilotez Specrails en discutant — l'agent intégré pilote toute l'app pour vous. Ouvrez-le depuis la bulle ou avec ⌘⇧A.`},error:{title:`Échec de la configuration`,skipSetup:`Ignorer la configuration`,prereqMissing:`La configuration de SpecRails a besoin de Node.js, npm, npx et Git disponibles sur le PATH pour pouvoir installer ce projet.`,prereqRetryHint:`Installez les outils manquants, redémarrez Specrails, puis relancez la configuration.`}},t={title:`Ajouter un projet`,description:`Enregistrez un répertoire de projet pour le gérer depuis Specrails.`,noProviderDetected:`Aucune CLI d'IA détectée. Installez d'abord Claude Code, Codex CLI, Gemini CLI ou Kimi Code.`,pathLabel:`Chemin du projet`,pathPlaceholder:`/Users/moi/mon-projet`,pathHint:`Chemin absolu vers la racine du projet`,browseForFolder:`Parcourir les dossiers`,selectProjectFolder:`Sélectionner le dossier du projet`,nameLabel:`Nom d'affichage`,optional:`(facultatif)`,namePlaceholder:`Mon projet`,nameHint:`Par défaut, le nom du répertoire`,providersLabel:`Fournisseurs d'IA`,notFound:`introuvable`,coreUpdateRequired:`Mise à jour de Core requise`,multiProviderHint:`Les deux moteurs seront configurés. Le premier est le moteur par défaut du projet. Non modifiable après la création.`,singleProviderHint:`Non modifiable après la création du projet.`,adding:`Ajout...`,submit:`Ajouter le projet`,toolsRequired_one:`{{tools}} est requis pour ajouter un projet`,toolsRequired_other:`{{tools}} sont requis pour ajouter un projet`,errors:{pathRequired:`Le chemin du projet est requis`,selectProvider:`Sélectionnez au moins un fournisseur d'IA`,addFailed:`Échec de l'ajout du projet`},toasts:{registered:`Projet « {{name}} » enregistré`},chooser:{description:`Apportez un dépôt existant, ou construisez un tout nouveau projet à partir d'une idée.`,existingTitle:`Projet existant`,existingDescription:`Enregistrez un dépôt qui existe déjà sur le disque.`,newTitle:`Nouveau projet`,newDescription:`Décrivez une idée et obtenez un dépôt initialisé avec un backlog du Jalon 1.`}},n={corruptedBundle:`bundle corrompu — réinstallez l'application`,notInstalled:`non installé`,failedToExecute:`trouvé mais impossible à exécuter`,failedToExecuteAt:`trouvé à {{path}} mais impossible à exécuter`,failedToExecuteWithError:`trouvé mais impossible à exécuter ({{error}})`,failedToExecuteAtWithError:`trouvé à {{path}} mais impossible à exécuter ({{error}})`,needsMinimum:`{{version}} trouvé — nécessite {{minVersion}}+`,unknownVersion:`inconnue`,installedLabel:`installé`,verifyError:`Impossible de vérifier les outils de développement en local — l'installation s'en chargera.`,allDetected:`Tous les outils requis sont détectés`,bundleCorruptedTitle:`Bundle de l'application corrompu`,toolsRequired_one:`{{count}} outil de développement requis`,toolsRequired_other:`{{count}} outils de développement requis`,reinstallHint:`Réinstallez l'application Specrails pour restaurer les outils embarqués.`,installMissingHint:`Installez les outils manquants pour continuer.`,moreInfo:`Plus d'infos`,bundledBadge:`embarqué`,optional:`optionnel`,ghNoAuth:"Non connecté — exécutez `gh auth login`"},r={title:`Installer les outils de développement`,description:`SpecRails a besoin de Node.js, npm, npx et Git sur le PATH. Choisissez le snippet pour votre OS, exécutez-le, puis cliquez sur « Je l'ai installé, revérifier ».`,darwin:{intro:`Homebrew installe les deux outils en une seule ligne. Si vous n'avez pas brew, utilisez les téléchargements officiels.`,installNodeGit:`Installer Node.js et Git via Homebrew`},win32:{intro:`Winget est fourni avec Windows 11 et les versions récentes de Windows 10. Ouvrez PowerShell ou le Terminal et exécutez :`,installNode:`Installer Node.js LTS`,installGit:`Installer Git`,note:`Après l'installation, redémarrez Specrails pour que Windows actualise le PATH.`},linux:{intro:`Utilisez le gestionnaire de paquets de votre distribution :`,debian:`Debian / Ubuntu`,fedora:`Fedora / RHEL`},links:{nodeOfficial:`Node.js (officiel)`,gitOfficial:`Git (officiel)`,gitWindows:`Git pour Windows (officiel)`},showOtherPlatforms:`Afficher les autres plateformes`,hideOtherPlatforms:`Masquer les autres plateformes`,recheck:`Je l'ai installé, revérifier`,diagnostics:{copy:`Copier les diagnostics`,copied:`Diagnostics copiés`,failed:`Échec de la copie`},corrupted:{title:`Bundle de l'application corrompu`,description:`Un ou plusieurs outils embarqués (Node.js, Git) n'ont pas pu être vérifiés.`,body:`Cet outil est embarqué avec l'application Specrails et ne peut pas être installé séparément. Si vous voyez ce message, le bundle de l'application est peut-être corrompu. Veuillez réinstaller Specrails.`}},i={title:`Progression de la configuration`,progress:`{{done}} sur {{total}} terminés`,rawLog_one:`Log brut ({{count}} ligne)`,rawLog_other:`Log brut ({{count}} lignes)`},a={title:`Assistant de configuration`,subtitle:`Répondez aux invites pour configurer votre projet`,settingUp:`Configuration de votre projet...`,placeholder:`Saisissez une réponse...`,keyboardHint:`Entrée pour envoyer, Maj+Entrée pour une nouvelle ligne`},o={title:`Bienvenue dans <spec>spec</spec><rails>rails</rails>`,description:`Specrails gère plusieurs projets depuis une seule interface. Ajoutez votre premier projet pour commencer.`,addFirstProject:`Ajouter votre premier projet`,jiraHint:`Connectez chaque projet à son propre tableau Jira — les specs restent synchronisées dans les deux sens.`,mcpHint:`Connectez des outils d'IA externes à Specrails via un serveur MCP local sécurisé — activez-le dans les Paramètres.`,agentChatHint:`Pilotez Specrails en discutant — un agent intégré gère les specs, les rails et les analyses pour vous via le MCP local. Ouvrez-le depuis la bulle ou avec ⌘⇧A.`},s=JSON.parse(`{"productTour":"Visite guidée","stepCount":"Étape {{current}} sur {{total}}","goToStep":"Aller à l'étape {{step}} : {{label}}","stepLabel":"Étape {{step}}","dontShowAgain":"Ne plus afficher","skipTour":"Passer la visite","getStarted":"Commencer","flow":{"addSpec":"Ajouter une spec","dropInRail":"Déposer dans un rail","hitPlay":"Appuyer sur Play","ship":"Livrer","architect":"Architecte","developer":"Développeur","reviewer":"Relecteur"},"language":{"nav":"Langue","title":"Choisissez votre langue","subtitle":"Specrails parle votre langue","intro":"Choisissez la langue de l'interface. Elle s'applique instantanément — cette visite comprise.","note":"Vous pouvez en changer à tout moment dans Paramètres → Langue."},"theme":{"nav":"Thème","title":"Trouvez votre style","subtitle":"Des thèmes intégrés, appliqués instantanément","intro":"Choisissez l'apparence de Specrails — le thème s'applique dès que vous cliquez.","note":"Vous pouvez en changer à tout moment dans Paramètres → Apparence."},"welcome":{"nav":"Bienvenue","title":"Bienvenue dans Specrails","subtitle":"Votre cockpit local pour livrer du logiciel avec des agents IA","intro":"Specrails transforme une idée en code livré — et vous laisse <b>voir, piloter et vérifier</b> chaque étape. Rédigez une spec en discutant avec une IA, déposez-la sur un rail d'exécution et appuyez sur Play. Le pipeline gère l'architecture, l'implémentation, la revue et la pull request, en streamant son travail en direct du début à la fin.","coreLoopLabel":"La boucle de base","flowCaption":"Chaque spec passe automatiquement par <b>Architecte → Développeur → Relecteur → Livraison</b>.","localNote":"<b>100 % local · mono-utilisateur · sans compte.</b> Tout s'exécute sur votre machine. Votre code ne quitte jamais le laptop, sauf si <i>vous</i> lancez un agent dessus.","tourNote":"Cette visite rapide passe en revue tout ce que l'application sait faire — environ une minute."},"authorSpecs":{"nav":"Rédiger des specs","title":"Transformez vos idées en specs","subtitle":"Six façons de capturer exactement ce que vous voulez construire","intro":"Une <b>spec</b> est une description du travail à réaliser. Rédigez-la comme le moment s'y prête — de la simple phrase à la conversation complète avec l'IA.","exploreLabel":"Explore — conversez","exploreBody":"Décrivez ce que vous voulez dans un chat ; un brouillon vivant se reconstruit à chaque tour. Un curseur de presets règle la quantité de contexte projet que voit l'IA — de votre message seul jusqu'au codebase complet plus vos serveurs MCP.","quickLabel":"Quick — en un coup","quickBody":"Vous savez déjà ce que vous voulez ? Générez une spec complète en un seul tour. Enrichissez-la éventuellement d'un Contract Layer : noms exacts, formes de données, invariants et liste des fichiers touchés, pour que les agents ne réinventent rien.","websiteLabel":"Depuis un site web","websiteBody":"Ouvre un navigateur embarqué. Survolez un élément pour le sélectionner ou tracez un rectangle : la capture d'écran, le DOM et le CSS appliqué deviennent des pièces jointes. La version desktop embarque son propre Chromium, donc ça fonctionne hors ligne.","smashLabel":"SMASH pour les grosses epics","smashBody":"Éclatez une grande spec en une famille de sous-specs plus petites en un clic — chaque enfant porte un court résumé sur sa carte.","draftsLabel":"Brouillons & reprise d'édition","draftsBody":"Mettez une exploration en cours de côté comme ticket brouillon et reprenez-la plus tard ; rouvrez n'importe quelle spec dans Explore pour continuer à l'affiner.","compareLabel":"Comparer côte à côte","compareBody":"Glissez une spec vers le bord de l'écran et un sélecteur de vos autres specs apparaît — passez-en deux en revue ensemble, façon tablette."},"rails":{"nav":"Exécuter sur des rails","title":"Lancez le pipeline sur des rails","subtitle":"Organisez les specs en couloirs, puis lancez les agents","intro":"La partie droite du Dashboard, ce sont vos <b>Rails</b> — des couloirs d'exécution. Glissez une carte de spec sur un rail et appuyez sur <play>▶ Play</play> pour lancer un job d'implémentation.","jobLabel":"Ce que chaque job exécute","flowCaption":"Chaque phase streame ses logs en direct pendant qu'elle travaille.","modeLabel":"Choisissez un Loop à exécuter","modeBody":"Chaque rail exécute un <b>Loop</b>. Choisissez-en un intégré — <b>Implement</b> (le pipeline structuré complet), <b>Batch</b> (plusieurs specs à la fois) ou <b>Freestyle</b> (un fournisseur compatible travaille en autonomie, sans pipeline figé) — ou un que vous avez créé vous-même.","profilesLabel":"Profils d'agents","profilesBody":"Un catalogue déclaratif par projet qui décide quels agents s'exécutent et quel modèle chacun utilise — choisi par rail et snapshotté par job pour que les travaux concurrents restent isolés.","jobDetailLabel":"Détail de job en direct","jobDetailBody":"Chaque job affiche un en-tête d'identité de ticket, un chrono de durée en direct et des compteurs de tours/tokens, avec le coût définitif résolu à la fin.","isolationLabel":"Plusieurs projets, isolés","isolationBody":"Chaque projet a sa propre base de données et sa propre file de jobs. Exécutez plusieurs projets en même temps et passez de l'un à l'autre depuis la barre latérale gauche — votre position est mémorisée par projet.","loopsLabel":"Créez vos propres loops","loopsBody":"<b>Loops</b> est un éditeur visuel : enchaînez des étapes IA, des commandes shell et un <b>Loop Decider</b> qui répète jusqu'à ce qu'un objectif soit atteint — p. ex. vérifier → corriger → vérifier jusqu'à ce que tout soit au vert. Publiez un loop et choisissez-le sur n'importe quel rail."},"agent":{"nav":"Chat de l'agent","title":"Pilotez l'app en discutant","subtitle":"Un copilote qui pilote Specrails pour vous","intro":"Le <b>chat de l'agent</b> intégré vous permet de piloter Specrails en demandant — créer des specs, lancer des rails, consulter les analyses — au lieu de cliquer partout. Il fonctionne via les propres outils <b>MCP</b> de Specrails et, comme tout est en direct, vous voyez le tableau changer pendant qu'il travaille.","openLabel":"Toujours à portée de clic","openBody":"Ouvrez-le depuis la bulle flottante en bas, ou appuyez sur ⌘⇧A (Ctrl+Shift+A) depuis n'importe où. Le panneau se déplace, se redimensionne, s'agrandit et se souvient de l'endroit où vous l'avez laissé.","operateLabel":"Pilote toute l'app","operateBody":"Choisissez un projet (ou Accueil pour tout) et un fournisseur, puis demandez simplement : “lance les trois tickets les plus prioritaires”, “combien ai-je dépensé cette semaine ?”.","levelsLabel":"C'est vous qui tenez la laisse","levelsBody":"Un niveau en direct — <b>Observer → Modifier → Opérer → Autonome</b>, que l'on fait défiler avec Shift+Tab — décide jusqu'où il peut aller. Il n'agit jamais au-dessus du niveau que vous définissez.","watchLabel":"Regardez-le faire","watchBody":"Le panneau n'est pas modal : les rails et les specs apparaissent sur le tableau de bord en temps réel pendant que l'agent travaille. Une pastille d'état indique ce qu'il fait en ce moment.","mcpLabel":"Fonctionne sur le MCP local","mcpBody":"L'agent pilote l'app via le serveur MCP intégré de Specrails. S'il est désactivé, le panneau propose de l'activer en un clic — rien n'est installé."},"providers":{"nav":"Votre agent","title":"Apportez votre propre agent","subtitle":"Claude Code, Codex, Gemini et Kimi comme moteurs de premier ordre","intro":"L'app traite <b>Claude Code</b>, <b>Codex CLI</b>, <b>Gemini CLI</b> et <b>Kimi Code</b> comme des moteurs interchangeables derrière un même contrat. Un projet peut en installer un ou plusieurs — le choix se fait à l'installation.","table":{"capability":"Capacité","streamingResume":"Streaming & reprise de session","native":"Natif","costReporting":"Suivi des coûts","providerBilled":"Facturé par le fournisseur","estimated":"Estimé (~)","unavailable":"Indisponible","telemetry":"Télémétrie (OTEL)","synthesized":"Synthétisée","agentProfiles":"Profils d'agents"},"calloutLabel":"Quand plusieurs sont installés","calloutBody":"Choisissez le moteur <b>par spec, par rail ou par lancement de terminal</b>. Les coûts estimés sont marqués d'un <mono>~</mono> ; Kimi ne fournit ni tokens ni coût."},"cost":{"nav":"Suivre les coûts","title":"Suivez chaque centime","subtitle":"Chaque invocation facturable, enregistrée et visualisée","intro":"Chaque invocation d'IA enregistre son cycle de vie et son fournisseur. L'usage et le coût restent indisponibles lorsqu'un fournisseur, tel que Kimi, ne les fournit pas.","analyticsLabel":"Page Analytics","analyticsBody":"Un hero de burn-rate, une timeline quotidienne, le top des tickets, la répartition par modèle et un nuage coût vs tours. Filtrez par période (7 j / 30 j / 90 j / Tout) et par surface.","perTicketLabel":"Dépenses par ticket","perTicketBody":"Le détail de chaque spec montre ce qu'elle a coûté et combien de tours il a fallu, avec un lien direct vers Analytics filtré sur ce ticket.","honestLabel":"Des chiffres honnêtes","honestBody":"Le coût Claude est fourni par le fournisseur ; Codex et Gemini peuvent être estimés et marqués d'un <mono>~</mono>. Pour Kimi, les tokens et le coût USD sont indisponibles, pas nuls.","budgetsLabel":"Budgets & alertes","budgetsBody":"Définissez un budget quotidien et une alerte de coût par job ; l'application met automatiquement la file en pause quand vous franchissez la limite. Exportez tout en CSV ou JSON."},"workspace":{"nav":"Espace de travail","title":"Faites-en votre espace de travail","subtitle":"Tout ce qu'il vous faut sans quitter la fenêtre","terminalLabel":"Panneau de terminal","terminalBody":"Un vrai terminal façon VS Code en bas (<mod>{{mod}}</mod> <j>J</j>) — rendu WebGL, recherche, images inline, glisser-déposer de chemins et intégration shell. Jusqu'à 10 sessions par projet.","codeLabel":"Explorateur de code","codeBody":"Une arborescence de fichiers en lecture seule et un viewer Monaco avec des résumés IA en langage clair et des puces de provenance « touché par l'IA », pour que chacun puisse suivre ce qui a changé et pourquoi.","integrationsLabel":"Intégrations","integrationsBody":"Une marketplace d'intégrations MCP par projet — la navigation sémantique de code Serena est incluse. Les installations sont additives : en ajouter une ne perturbe jamais les autres.","themesLabel":"Thèmes","themesBody":"Six thèmes intégrés — specrails (par défaut), dracula, aurora-light, obsidian-dark, code-rain et galaxy — appliqués avant le rendu de l'UI, donc sans flash. Changez-les dans Paramètres → Apparence.","chatsLabel":"Chats minimisables","chatsBody":"Rangez une session Explore ou Édition IA dans une puce du dock et reprenez-la plus tard — jamais perdue, même après un rechargement ou un changement de projet.","desktopLabel":"Desktop ou navigateur","desktopBody":"Lancez Specrails dans votre navigateur, ou prenez l'application desktop signée (macOS & Windows) qui embarque son propre serveur et ses runtimes."},"companion":{"nav":"Compagnon mobile","title":"Emportez Specrails avec vous","subtitle":"Specrails Companion — vos pipelines, dans votre poche","intro":"<b>Specrails Companion</b> est une application web disponible sur specrails.dev/companion-app — ouvrez-la sur votre téléphone (ou ajoutez-la à votre écran d'accueil) pour parcourir le tableau des specs, lancer et arrêter des rails, suivre les logs des jobs en direct et jeter un œil aux analytics. Aucune installation, aucun app store.","localLabel":"100 % local, comme tout le reste","localBody":"Votre téléphone se connecte directement à cet ordinateur — en pair-à-pair et chiffré (WebRTC). Pas de relais cloud, pas de compte, et votre code ne quitte jamais vos appareils.","downloadLabel":"Ouvrez-la sur votre téléphone","downloadHint":"Scannez le code avec l'appareil photo de votre téléphone, ou ouvrez specrails.dev/companion-app dans son navigateur.","open":"Ouvrir Specrails Companion","pairLabel":"L'appairage prend dix secondes","pairBody":"Sur votre téléphone, ouvrez specrails.dev/companion-app, puis ici allez dans Paramètres → Compagnon mobile → Appairer le compagnon web et suivez les étapes à l'écran."},"moveFast":{"nav":"Aller vite","title":"Avancez à la vitesse de la pensée","subtitle":"Le clavier d'abord, partout","paletteLabel":"Palette de commandes","paletteShortcut":"<f>Appuyez sur</f> <mod>{{mod}}</mod> <m>+</m> <k>K</k> <m>n'importe où</m>","paletteBody":"Changez de projet, lancez des commandes de spec, sautez vers n'importe quelle page et retrouvez les jobs récents — le tout en recherche floue.","terminalLabel":"Panneau de terminal","terminalBody":"Basculez avec <mod>{{mod}}</mod> <j>J</j>.","shortcutsLabel":"Tous les raccourcis","shortcutsBody":"Appuyez sur <q>?</q> pour voir l'antisèche complète.","chatLabel":"Barre latérale de chat","chatBody":"Basculez la barre latérale droite avec <mod>{{mod}}</mod> <bkey>B</bkey>.","projectsLabel":"Barre latérale des projets","projectsBody":"Basculez la barre latérale Arc de gauche avec <alt>{{alt}}</alt> <mod>{{mod}}</mod> <bkey>B</bkey>.","outro":"<b>La visite est terminée.</b> Ajoutez un projet depuis la barre latérale gauche et livrez votre première spec. Vous pouvez rouvrir cette visite à tout moment depuis les Paramètres."},"jira":{"label":"Intégration Jira","body":"Adossez n'importe quel projet à un <b>tableau Jira</b> — chaque spec devient un ticket Jira, synchronisé dans les deux sens : le statut suit le rail et un commentaire est publié à la fin d'un job. Configurez-le par projet lors de l'ajout, ou à tout moment dans les Paramètres."}}`),c={wizard:e,addProject:t,prerequisites:n,instructions:r,checkpoints:i,setupChat:a,welcome:o,onboarding:s};export{t as addProject,i as checkpoints,c as default,r as instructions,s as onboarding,n as prerequisites,a as setupChat,o as welcome,e as wizard};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var e={configureAgents:`Configura gli agenti {{provider}}`,configureSubtitle:`Rivedi il tuo team di agenti e scegli come viene eseguito ciascuno.`,tabs:{agents:`Agenti`,models:`Modelli`},skipForNow:`Salta per ora`,install:`Installa`,nextProvider:`Avanti: {{provider}}`,installingProvider:`Installazione di {{provider}}…`,installingSpecrails:`Installazione di specrails...`,installingFromTemplates:`Installazione degli agenti dai template`,waitingForOutput:`In attesa dell'output...`,checkpoints:{baseInstall:`Installazione di base`,agentSelection:`Configurazione agenti`,agentGeneration:`Generazione degli agenti`},steps:{configure:`Configura`},summary:{agents:`Agenti`,agentSkills:`Skill degli agenti`,skills:`Skill`,openspecSkills:`Skill OpenSpec`,legacyRemoved_one:`Rimosso {{count}} comando legacy <code>/specrails:*</code>`,legacyRemoved_other:`Rimossi {{count}} comandi legacy <code>/specrails:*</code>`},complete:{welcome:`Benvenuto in <spec>spec</spec><rails>rails</rails>`,configured:`<strong>{{projectName}}</strong> è ora configurato con workflow di sviluppo basati sull'IA. I tuoi agenti specializzati e i comandi sono pronti all'uso.`,installedForEngines_one:`Installato per {{count}} engine`,installedForEngines_other:`Installato per {{count}} engine`,installed:`Installato`,installFailed:`Installazione non riuscita`,learnMore:`Scopri come ottenere il massimo da specrails:`,continueToProject:`Continua al progetto`,jira:{title:`Collega una board Jira`,subtitle:`Facoltativo — appoggia le spec di questo progetto a una board Jira. Puoi farlo anche più tardi nelle Impostazioni.`,configure:`Configura Jira`,optional:`facoltativo`},mcpHint:`Collega strumenti di IA esterni a Specrails tramite un server MCP locale sicuro — attivalo nelle Impostazioni.`,agentChatHint:`Gestisci Specrails chattando — l'agente integrato guida l'intera app per te. Aprilo dalla bolla o con ⌘⇧A.`},error:{title:`Setup non riuscito`,skipSetup:`Salta il setup`,prereqMissing:`Il setup di SpecRails richiede Node.js, npm, npx e Git disponibili sul PATH prima di poter installare questo progetto.`,prereqRetryHint:`Installa gli strumenti mancanti, riavvia Specrails e poi riprova il setup.`}},t={title:`Aggiungi progetto`,description:`Registra una directory di progetto per gestirla da Specrails.`,noProviderDetected:`Nessuna CLI IA rilevata. Installa prima Claude Code, Codex CLI, Gemini CLI o Kimi Code.`,pathLabel:`Percorso del progetto`,pathPlaceholder:`/Users/me/my-project`,pathHint:`Percorso assoluto alla root del progetto`,browseForFolder:`Sfoglia cartelle`,selectProjectFolder:`Seleziona la cartella del progetto`,nameLabel:`Nome visualizzato`,optional:`(facoltativo)`,namePlaceholder:`Il mio progetto`,nameHint:`Per impostazione predefinita usa il nome della directory`,providersLabel:`Provider IA`,notFound:`non trovato`,coreUpdateRequired:`Aggiornamento di Core richiesto`,multiProviderHint:`Verranno configurati entrambi gli engine. Il primo è il predefinito del progetto. Non modificabile dopo la creazione.`,singleProviderHint:`Non modificabile dopo la creazione del progetto.`,adding:`Aggiunta in corso...`,submit:`Aggiungi progetto`,toolsRequired_one:`{{tools}} è richiesto per aggiungere un progetto`,toolsRequired_other:`{{tools}} sono richiesti per aggiungere un progetto`,errors:{pathRequired:`Il percorso del progetto è obbligatorio`,selectProvider:`Seleziona almeno un provider IA`,addFailed:`Aggiunta del progetto non riuscita`},toasts:{registered:`Progetto "{{name}}" registrato`},chooser:{description:`Porta un repository esistente, oppure costruisci un progetto nuovo da un'idea.`,existingTitle:`Progetto esistente`,existingDescription:`Registra un repository già presente su disco.`,newTitle:`Nuovo progetto`,newDescription:`Descrivi un'idea e ottieni un repo inizializzato con un backlog della Milestone 1.`}},n={corruptedBundle:`bundle corrotto — reinstalla l'app`,notInstalled:`non installato`,failedToExecute:`trovato ma esecuzione non riuscita`,failedToExecuteAt:`trovato in {{path}} ma esecuzione non riuscita`,failedToExecuteWithError:`trovato ma esecuzione non riuscita ({{error}})`,failedToExecuteAtWithError:`trovato in {{path}} ma esecuzione non riuscita ({{error}})`,needsMinimum:`{{version}} trovata — serve {{minVersion}}+`,unknownVersion:`sconosciuta`,installedLabel:`installato`,verifyError:`Impossibile verificare localmente gli strumenti di sviluppo — l'installazione li convaliderà.`,allDetected:`Tutti gli strumenti richiesti rilevati`,bundleCorruptedTitle:`Bundle dell'app corrotto`,toolsRequired_one:`{{count}} strumento di sviluppo richiesto`,toolsRequired_other:`{{count}} strumenti di sviluppo richiesti`,reinstallHint:`Reinstalla l'app Specrails per ripristinare gli strumenti inclusi.`,installMissingHint:`Installa gli strumenti mancanti per continuare.`,moreInfo:`Maggiori informazioni`,bundledBadge:`incluso`,optional:`opzionale`,ghNoAuth:"Non connesso — esegui `gh auth login`"},r={title:`Installa gli strumenti di sviluppo`,description:`SpecRails richiede Node.js, npm, npx e Git sul PATH. Scegli lo snippet per il tuo sistema operativo, eseguilo e poi clicca "L'ho installato, ricontrolla".`,darwin:{intro:`Con Homebrew ottieni entrambi gli strumenti in una riga. Se non hai brew, usa i download ufficiali.`,installNodeGit:`Installa Node.js e Git con Homebrew`},win32:{intro:`Winget è incluso in Windows 11 e nelle versioni recenti di Windows 10. Apri PowerShell o il Terminale ed esegui:`,installNode:`Installa Node.js LTS`,installGit:`Installa Git`,note:`Dopo l'installazione, riavvia Specrails così Windows aggiorna il PATH.`},linux:{intro:`Usa il package manager della tua distro:`,debian:`Debian / Ubuntu`,fedora:`Fedora / RHEL`},links:{nodeOfficial:`Node.js (ufficiale)`,gitOfficial:`Git (ufficiale)`,gitWindows:`Git per Windows (ufficiale)`},showOtherPlatforms:`Mostra altre piattaforme`,hideOtherPlatforms:`Nascondi altre piattaforme`,recheck:`L'ho installato, ricontrolla`,diagnostics:{copy:`Copia diagnostica`,copied:`Diagnostica copiata`,failed:`Copia non riuscita`},corrupted:{title:`Bundle dell'app corrotto`,description:`Non è stato possibile verificare uno o più strumenti inclusi (Node.js, Git).`,body:`Questo strumento è incluso nell'app Specrails e non può essere installato separatamente. Se vedi questo messaggio, il bundle dell'app potrebbe essere corrotto. Reinstalla Specrails.`}},i={title:`Avanzamento del setup`,progress:`{{done}} di {{total}} completati`,rawLog_one:`Log grezzo ({{count}} riga)`,rawLog_other:`Log grezzo ({{count}} righe)`},a={title:`Assistente di setup`,subtitle:`Rispondi ai prompt per configurare il progetto`,settingUp:`Configurazione del progetto in corso...`,placeholder:`Scrivi una risposta...`,keyboardHint:`Invio per inviare, Shift+Invio per andare a capo`},o={title:`Benvenuto in <spec>spec</spec><rails>rails</rails>`,description:`Specrails gestisce più progetti da un'unica interfaccia. Aggiungi il tuo primo progetto per iniziare.`,addFirstProject:`Aggiungi il tuo primo progetto`,jiraHint:`Collega ogni progetto alla sua board Jira — le spec restano sincronizzate in entrambe le direzioni.`,mcpHint:`Collega strumenti di IA esterni a Specrails tramite un server MCP locale sicuro — attivalo nelle Impostazioni.`,agentChatHint:`Gestisci Specrails chattando — un agente integrato gestisce spec, rail e analisi per te tramite l'MCP locale. Aprilo dalla bolla o con ⌘⇧A.`},s=JSON.parse(`{"productTour":"Tour del prodotto","stepCount":"Passo {{current}} di {{total}}","goToStep":"Vai al passo {{step}}: {{label}}","stepLabel":"Passo {{step}}","dontShowAgain":"Non mostrare più","skipTour":"Salta il tour","getStarted":"Inizia","flow":{"addSpec":"Aggiungi Spec","dropInRail":"Trascina su un Rail","hitPlay":"Premi Play","ship":"Ship","architect":"Architetto","developer":"Developer","reviewer":"Reviewer"},"language":{"nav":"Lingua","title":"Scegli la tua lingua","subtitle":"Specrails parla la tua lingua","intro":"Seleziona la lingua in cui vuoi usare l'interfaccia. Si applica all'istante — questo tour incluso.","note":"Puoi cambiarla in qualsiasi momento da Impostazioni → Lingua."},"theme":{"nav":"Tema","title":"Scegli il tuo stile","subtitle":"Temi integrati, applicati all'istante","intro":"Scegli l'aspetto di Specrails — il tema si applica appena fai clic.","note":"Puoi cambiarlo in qualsiasi momento da Impostazioni → Aspetto."},"welcome":{"nav":"Benvenuto","title":"Benvenuto in Specrails","subtitle":"La tua cabina di pilotaggio locale per rilasciare software con agenti IA","intro":"Specrails trasforma un'idea in codice rilasciato — e ti permette di <b>vedere, guidare e verificare</b> ogni passo. Abbozza una spec parlando con un'IA, trascinala su un rail di esecuzione e premi Play. La pipeline gestisce architettura, implementazione, review e la pull request, trasmettendo il proprio lavoro in diretta per tutto il tempo.","coreLoopLabel":"Il ciclo fondamentale","flowCaption":"Ogni spec passa automaticamente per <b>Architect → Developer → Reviewer → Ship</b>.","localNote":"<b>100% locale · utente singolo · nessun account.</b> Tutto gira sulla tua macchina. Il tuo codice non lascia mai il laptop a meno che non sia <i>tu</i> a lanciarci sopra un agente.","tourNote":"Questo breve tour mostra tutto ciò che l'app sa fare — circa un minuto."},"authorSpecs":{"nav":"Scrivi le spec","title":"Trasforma le idee in spec","subtitle":"Sei modi per catturare esattamente cosa vuoi costruire","intro":"Una <b>spec</b> è una descrizione del lavoro che vuoi far svolgere. Scrivila come preferisci sul momento — da una riga veloce a una conversazione completa con l'IA.","exploreLabel":"Explore — conversa","exploreBody":"Descrivi cosa vuoi in una chat; una bozza live si ricostruisce a ogni turno. Uno slider di preset regola quanto contesto del progetto vede l'IA — dal solo tuo messaggio fino all'intero codebase più i tuoi server MCP.","quickLabel":"Quick — in un colpo solo","quickBody":"Sai già cosa vuoi? Genera una spec completa in un solo turno. Facoltativamente arricchiscila con un Contract Layer: nomi esatti, forme dei dati, invarianti e un elenco dei file da toccare, così gli agenti non reinventano nulla.","websiteLabel":"Da un sito web","websiteBody":"Apre un browser integrato. Seleziona un elemento al passaggio del mouse o trascina un rettangolo: screenshot, DOM e CSS applicato diventano allegati. La build desktop include il proprio Chromium, quindi funziona offline.","smashLabel":"SMASH su una grande epic","smashBody":"Esplodi una spec grande in una famiglia di sotto-spec più piccole con un clic — ogni figlia porta un breve riassunto sulla sua card.","draftsLabel":"Bozze e ripresa della modifica","draftsBody":"Parcheggia un'esplorazione in corso come ticket in bozza e riprendila più tardi; riapri qualsiasi spec in Explore per continuare a rifinirla.","compareLabel":"Confronta fianco a fianco","compareBody":"Trascina una spec verso il bordo dello schermo e scivola dentro un selettore delle altre spec — esaminane due insieme, in stile tablet."},"rails":{"nav":"Esegui sui rail","title":"Esegui la pipeline sui rail","subtitle":"Organizza le spec in corsie, poi lancia gli agenti","intro":"Il lato destro della Dashboard sono i tuoi <b>Rail</b> — corsie di esecuzione. Trascina una card spec su un rail e premi <play>▶ Play</play> per lanciare un job di implementazione.","jobLabel":"Cosa esegue ogni job","flowCaption":"Ogni fase trasmette i propri log in diretta mentre lavora.","modeLabel":"Scegli un Loop da eseguire","modeBody":"Ogni rail esegue un <b>Loop</b>. Scegline uno integrato — <b>Implement</b> (la pipeline strutturata completa), <b>Batch</b> (più spec contemporaneamente) o <b>Freestyle</b> (un provider compatibile lavora in autonomia, senza pipeline fissa) — oppure uno creato da te.","profilesLabel":"Profili agente","profilesBody":"Un catalogo dichiarativo per progetto che decide quali agenti girano e quale modello usa ciascuno — scelto per rail e congelato per job, così il lavoro concorrente resta isolato.","jobDetailLabel":"Dettaglio job in diretta","jobDetailBody":"Ogni job mostra un header con l'identità del ticket, un contatore di durata in tempo reale e conteggi correnti di turni e token, con il costo definitivo risolto alla chiusura.","isolationLabel":"Tanti progetti, isolati","isolationBody":"Ogni progetto ha il proprio database e la propria coda di job. Esegui progetti diversi contemporaneamente e passa dall'uno all'altro dalla sidebar sinistra — la tua posizione viene ricordata per progetto.","loopsLabel":"Crea i tuoi loop","loopsBody":"<b>Loops</b> è un costruttore visuale: concatena passaggi AI, comandi shell e un <b>Loop Decider</b> che ripete finché un obiettivo non è raggiunto — ad esempio verifica → correggi → verifica finché è tutto verde. Pubblica un loop e sceglilo su qualsiasi rail."},"agent":{"nav":"Chat dell'agente","title":"Gestisci l'app chattando","subtitle":"Un copilota che guida Specrails per te","intro":"La <b>chat dell'agente</b> integrata ti permette di usare Specrails chiedendo — creare spec, avviare rail, controllare le analisi — invece di cliccare qua e là. Funziona tramite gli strumenti <b>MCP</b> di Specrails e, poiché tutto è in tempo reale, vedi la board cambiare mentre lavora.","openLabel":"Sempre a portata di clic","openBody":"Aprila dalla bolla flottante in basso, oppure premi ⌘⇧A (Ctrl+Shift+A) da qualsiasi punto. Il pannello si sposta, si ridimensiona, si massimizza e ricorda dove l'hai lasciato.","operateLabel":"Guida l'intera app","operateBody":"Scegli un progetto (o Home per tutto) e un provider, poi chiedi semplicemente: “avvia i tre ticket a priorità più alta”, “quanto ho speso questa settimana?”.","levelsLabel":"Le redini sono tue","levelsBody":"Un livello in tempo reale — <b>Osserva → Modifica → Opera → Autonomo</b>, che scorri con Shift+Tab — decide fin dove può spingersi. Non agisce mai oltre il livello che imposti.","watchLabel":"Guardalo all'opera","watchBody":"Il pannello non è modale, quindi rail e spec compaiono sulla dashboard in tempo reale mentre l'agente lavora. Un chip di stato mostra cosa sta facendo in questo momento.","mcpLabel":"Funziona sull'MCP locale","mcpBody":"L'agente guida l'app tramite il server MCP integrato di Specrails. Se è spento, il pannello propone di attivarlo con un clic — non viene installato nulla."},"providers":{"nav":"Il tuo agente","title":"Porta il tuo agente","subtitle":"Claude Code, Codex, Gemini e Kimi come motori di prima classe","intro":"L'app tratta <b>Claude Code</b>, <b>Codex CLI</b>, <b>Gemini CLI</b> e <b>Kimi Code</b> come motori intercambiabili dietro un unico contratto. Un progetto può installarne uno o più — la scelta avviene all'installazione.","table":{"capability":"Capacità","streamingResume":"Streaming e ripresa della sessione","native":"Nativo","costReporting":"Report dei costi","providerBilled":"Fatturato dal provider","estimated":"Stimato (~)","unavailable":"Non disponibile","telemetry":"Telemetria (OTEL)","synthesized":"Sintetizzata","agentProfiles":"Profili agente"},"calloutLabel":"Quando ne sono installati diversi","calloutBody":"Scegli l'engine <b>per spec, per rail o per avvio del terminale</b>. I costi stimati sono marcati con <mono>~</mono>; Kimi non riporta token o costi."},"cost":{"nav":"Monitora i costi","title":"Traccia ogni centesimo","subtitle":"Ogni invocazione fatturabile, registrata e visualizzata","intro":"Ogni invocazione IA registra ciclo di vita e provider. Utilizzo e costo restano non disponibili quando un provider, come Kimi, non li riporta.","analyticsLabel":"Pagina Analytics","analyticsBody":"Un hero con il burn-rate, timeline giornaliera, ticket principali, ripartizione per modello e uno scatter costo-vs-turni. Filtra per periodo (7d / 30d / 90d / Tutto) e per superficie.","perTicketLabel":"Spesa per ticket","perTicketBody":"Il dettaglio di ogni spec mostra quanto è costata e quanti turni ha richiesto, con un link diretto ad Analytics filtrato su quel ticket.","honestLabel":"Numeri onesti","honestBody":"Il costo Claude è fornito dal provider; Codex e Gemini possono essere stimati e marcati con <mono>~</mono>. Per Kimi token e costo USD non sono disponibili, non sono zero.","budgetsLabel":"Budget e avvisi","budgetsBody":"Imposta un budget giornaliero e un avviso di costo per job; l'app mette in pausa automaticamente la coda quando superi la soglia. Esporta tutto in CSV o JSON."},"workspace":{"nav":"Workspace","title":"Rendilo il tuo workspace","subtitle":"Tutto ciò che ti serve senza lasciare la finestra","terminalLabel":"Pannello terminale","terminalBody":"Un vero terminale in stile VS Code in basso (<mod>{{mod}}</mod> <j>J</j>) — rendering WebGL, ricerca, immagini inline, trascinamento di percorsi e integrazione con la shell. Fino a 10 sessioni per progetto.","codeLabel":"Esploratore di codice","codeBody":"Un albero dei file in sola lettura e un visualizzatore Monaco con riassunti IA in linguaggio semplice e chip di provenienza “toccato dall'IA”, così chiunque può seguire cosa è cambiato e perché.","integrationsLabel":"Integrazioni","integrationsBody":"Un marketplace per progetto di integrazioni MCP — la navigazione semantica del codice di Serena è inclusa. Le installazioni sono additive: aggiungerne una non disturba mai le altre.","themesLabel":"Temi","themesBody":"Sei temi integrati — specrails (predefinito), dracula, aurora-light, obsidian-dark, code-rain e galaxy — applicati prima che la UI venga disegnata, quindi nessun flash. Cambiali in Impostazioni → Aspetto.","chatsLabel":"Chat minimizzabili","chatsBody":"Parcheggia una sessione Explore o AI Edit in una chip del dock e riprendila più tardi — mai persa tra refresh o cambi di progetto.","desktopLabel":"Desktop o browser","desktopBody":"Esegui Specrails nel browser, oppure scarica l'app desktop firmata (macOS e Windows) che include il proprio server e i runtime."},"companion":{"nav":"Companion mobile","title":"Porta Specrails con te","subtitle":"Specrails Companion — le tue pipeline, sul tuo telefono","intro":"<b>Specrails Companion</b> è una web app su specrails.dev/companion-app — aprila sul tuo telefono (o aggiungila alla schermata Home) per sfogliare la board delle spec, lanciare e fermare i rail, seguire i log dei job in diretta e dare un'occhiata alle Analytics. Nessuna installazione, nessuno app store.","localLabel":"100% locale, come tutto il resto","localBody":"Il tuo telefono si connette direttamente a questo computer — peer-to-peer e cifrato (WebRTC). Nessun relay cloud, nessun account, e il tuo codice non lascia mai i tuoi dispositivi.","downloadLabel":"Aprila sul tuo telefono","downloadHint":"Scansiona il codice con la fotocamera del telefono, oppure apri specrails.dev/companion-app nel suo browser.","open":"Apri Specrails Companion","pairLabel":"L'associazione richiede dieci secondi","pairBody":"Sul tuo telefono apri specrails.dev/companion-app, poi qui vai su Impostazioni → Companion mobile → Associa companion web e segui i passaggi a schermo."},"moveFast":{"nav":"Vai veloce","title":"Muoviti alla velocità del pensiero","subtitle":"Keyboard-first, ovunque","paletteLabel":"Palette dei comandi","paletteShortcut":"<f>Premi</f> <mod>{{mod}}</mod> <m>+</m> <k>K</k> <m>ovunque</m>","paletteBody":"Cambia progetto, esegui comandi spec, salta a qualsiasi pagina e trova i job recenti — tutto con ricerca fuzzy.","terminalLabel":"Pannello terminale","terminalBody":"Attiva/disattiva con <mod>{{mod}}</mod> <j>J</j>.","shortcutsLabel":"Tutte le scorciatoie","shortcutsBody":"Premi <q>?</q> per vedere il cheat-sheet completo.","chatLabel":"Sidebar della chat","chatBody":"Attiva/disattiva la sidebar destra con <mod>{{mod}}</mod> <bkey>B</bkey>.","projectsLabel":"Sidebar dei progetti","projectsBody":"Attiva/disattiva la sidebar Arc sinistra con <alt>{{alt}}</alt> <mod>{{mod}}</mod> <bkey>B</bkey>.","outro":"<b>Il tour finisce qui.</b> Aggiungi un progetto dalla sidebar sinistra e rilascia la tua prima spec. Puoi riaprire questa guida in qualsiasi momento dalle Impostazioni."},"jira":{"label":"Integrazione Jira","body":"Appoggia qualsiasi progetto a una <b>board Jira</b> — ogni spec diventa un ticket Jira, sincronizzato in entrambe le direzioni: lo stato segue il rail e viene pubblicato un commento al termine di un job. Configuralo per progetto quando lo aggiungi, o in qualsiasi momento nelle Impostazioni."}}`),c={wizard:e,addProject:t,prerequisites:n,instructions:r,checkpoints:i,setupChat:a,welcome:o,onboarding:s};export{t as addProject,i as checkpoints,c as default,r as instructions,s as onboarding,n as prerequisites,a as setupChat,o as welcome,e as wizard};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{r as e}from"./rolldown-runtime-CNC7AqOf.js";var t=e({addProject:()=>r,checkpoints:()=>o,default:()=>u,instructions:()=>a,onboarding:()=>l,prerequisites:()=>i,setupChat:()=>s,welcome:()=>c,wizard:()=>n}),n={configureAgents:`Configure {{provider}} agents`,configureSubtitle:`Review your agent team and choose how each agent runs.`,tabs:{agents:`Agents`,models:`Models`},skipForNow:`Skip for now`,install:`Install`,nextProvider:`Next: {{provider}}`,installingProvider:`Installing {{provider}}…`,installingSpecrails:`Installing specrails...`,installingFromTemplates:`Installing agents from templates`,waitingForOutput:`Waiting for output...`,checkpoints:{baseInstall:`Base installation`,agentSelection:`Agent configuration`,agentGeneration:`Agent generation`},steps:{configure:`Configure`},summary:{agents:`Agents`,agentSkills:`Agent skills`,skills:`Skills`,openspecSkills:`OpenSpec skills`,legacyRemoved_one:`Removed {{count}} legacy <code>/specrails:*</code> command`,legacyRemoved_other:`Removed {{count}} legacy <code>/specrails:*</code> commands`},complete:{welcome:`Welcome to <spec>spec</spec><rails>rails</rails>`,configured:`<strong>{{projectName}}</strong> is now configured with AI-powered development workflows. Your specialized agents and commands are ready to use.`,installedForEngines_one:`Installed for {{count}} engine`,installedForEngines_other:`Installed for {{count}} engines`,installed:`Installed`,installFailed:`Install failed`,learnMore:`Learn how to get the most out of specrails:`,continueToProject:`Continue to project`,jira:{title:`Connect a Jira board`,subtitle:`Optional — back this project's specs with a Jira board. You can also do it later in Settings.`,configure:`Configure Jira`,optional:`optional`},mcpHint:`Connect external AI tools to Specrails over a secure local MCP server — enable it in Settings.`,agentChatHint:`Operate Specrails by chatting — the built-in agent drives the whole app for you. Open it from the bubble or ⌘⇧A.`},error:{title:`Setup failed`,skipSetup:`Skip setup`,prereqMissing:`SpecRails setup needs Node.js, npm, npx and Git available on PATH before it can install this project.`,prereqRetryHint:`Install the missing tools, restart Specrails, then retry setup.`}},r={title:`Add Project`,description:`Register a project directory to manage it from Specrails.`,noProviderDetected:`No AI CLI detected. Install Claude Code, Codex CLI, Gemini CLI or Kimi Code first.`,pathLabel:`Project path`,pathPlaceholder:`/Users/me/my-project`,pathHint:`Absolute path to the project root`,browseForFolder:`Browse for folder`,selectProjectFolder:`Select project folder`,nameLabel:`Display name`,optional:`(optional)`,namePlaceholder:`My Project`,nameHint:`Defaults to the directory name`,providersLabel:`AI providers`,notFound:`not found`,coreUpdateRequired:`Core update required`,multiProviderHint:`Both engines will be set up. The first is the project default. Cannot be changed after creation.`,singleProviderHint:`Cannot be changed after the project is created.`,adding:`Adding...`,submit:`Add Project`,toolsRequired_one:`{{tools}} is required to add a project`,toolsRequired_other:`{{tools}} are required to add a project`,errors:{pathRequired:`Project path is required`,selectProvider:`Select at least one AI provider`,addFailed:`Failed to add project`},toasts:{registered:`Project "{{name}}" registered`},chooser:{description:`Bring an existing repository, or build a brand-new project from an idea.`,existingTitle:`Existing project`,existingDescription:`Register a repository that already exists on disk.`,newTitle:`New project`,newDescription:`Describe an idea and get a bootstrapped repo with a Milestone-1 backlog.`}},i={corruptedBundle:`bundle corrupted — reinstall app`,notInstalled:`not installed`,failedToExecute:`found but failed to execute`,failedToExecuteAt:`found at {{path}} but failed to execute`,failedToExecuteWithError:`found but failed to execute ({{error}})`,failedToExecuteAtWithError:`found at {{path}} but failed to execute ({{error}})`,needsMinimum:`{{version}} found — needs {{minVersion}}+`,unknownVersion:`unknown`,installedLabel:`installed`,verifyError:`Could not verify developer tools locally — install will validate.`,allDetected:`All required tools detected`,bundleCorruptedTitle:`App bundle corrupted`,toolsRequired_one:`{{count}} developer tool required`,toolsRequired_other:`{{count}} developer tools required`,reinstallHint:`Reinstall the Specrails app to restore bundled tools.`,installMissingHint:`Install the missing tools to continue.`,moreInfo:`More info`,bundledBadge:`bundled`,optional:`optional`,ghNoAuth:"Not signed in — run `gh auth login`"},a={title:`Install developer tools`,description:`SpecRails needs Node.js, npm, npx, and Git on PATH. Pick the snippet for your OS, run it, then click "I installed it, recheck".`,darwin:{intro:`Homebrew gets you both tools in one line. If you do not have brew, use the official downloads.`,installNodeGit:`Install Node.js and Git via Homebrew`},win32:{intro:`Winget ships with Windows 11 and recent Windows 10. Open PowerShell or Terminal and run:`,installNode:`Install Node.js LTS`,installGit:`Install Git`,note:`After install, restart Specrails so Windows refreshes PATH.`},linux:{intro:`Use your distro package manager:`,debian:`Debian / Ubuntu`,fedora:`Fedora / RHEL`},links:{nodeOfficial:`Node.js (official)`,gitOfficial:`Git (official)`,gitWindows:`Git for Windows (official)`},showOtherPlatforms:`Show other platforms`,hideOtherPlatforms:`Hide other platforms`,recheck:`I installed it, recheck`,diagnostics:{copy:`Copy diagnostics`,copied:`Diagnostics copied`,failed:`Copy failed`},corrupted:{title:`App bundle corrupted`,description:`One or more bundled tools (Node.js, Git) could not be verified.`,body:`This tool is bundled with the Specrails app and cannot be installed separately. If you see this message, the app bundle may be corrupted. Please reinstall Specrails.`}},o={title:`Setup progress`,progress:`{{done}} of {{total}} complete`,rawLog_one:`Raw log ({{count}} line)`,rawLog_other:`Raw log ({{count}} lines)`},s={title:`Setup assistant`,subtitle:`Respond to prompts to configure your project`,settingUp:`Setting up your project...`,placeholder:`Type a response...`,keyboardHint:`Enter to send, Shift+Enter for new line`},c={title:`Welcome to <spec>spec</spec><rails>rails</rails>`,description:`Specrails manages multiple projects from a single interface. Add your first project to get started.`,addFirstProject:`Add your first project`,jiraHint:`Connect each project to its own Jira board — specs stay in sync, both ways.`,mcpHint:`Connect external AI tools to Specrails over a secure local MCP server — enable it in Settings.`,agentChatHint:`Operate Specrails by chatting — a built-in agent drives specs, rails and analytics for you through the local MCP. Open it from the bubble or ⌘⇧A.`},l=JSON.parse(`{"productTour":"Product tour","stepCount":"Step {{current}} of {{total}}","goToStep":"Go to step {{step}}: {{label}}","stepLabel":"Step {{step}}","dontShowAgain":"Don't show this again","skipTour":"Skip tour","getStarted":"Get Started","flow":{"addSpec":"Add Spec","dropInRail":"Drop in a Rail","hitPlay":"Hit Play","ship":"Ship","architect":"Architect","developer":"Developer","reviewer":"Reviewer"},"language":{"nav":"Language","title":"Choose your language","subtitle":"Specrails speaks your language","intro":"Pick the language you want the interface in. It applies instantly — this tour included.","note":"You can change it any time in Settings → Language."},"theme":{"nav":"Theme","title":"Pick your look","subtitle":"Built-in themes, applied instantly","intro":"Choose how Specrails should look — the theme applies the moment you click.","note":"You can change it any time in Settings → Appearance."},"welcome":{"nav":"Welcome","title":"Welcome to Specrails","subtitle":"Your local cockpit for shipping software with AI agents","intro":"Specrails turns an idea into shipped code — and lets you <b>see, steer, and trust</b> every step. Draft a spec by talking to an AI, drop it on an execution rail, and hit Play. The pipeline handles architecture, implementation, review and the pull request, streaming its work live the whole way.","coreLoopLabel":"The core loop","flowCaption":"Each spec flows through <b>Architect → Developer → Reviewer → Ship</b> automatically.","localNote":"<b>100% local · single user · no accounts.</b> Everything runs on your machine. Your code never leaves the laptop unless <i>you</i> spawn an agent against it.","tourNote":"This quick tour walks through everything the app can do — about a minute."},"authorSpecs":{"nav":"Author specs","title":"Turn ideas into specs","subtitle":"Six ways to capture exactly what you want built","intro":"A <b>spec</b> is a description of work you want done. Author one however suits the moment — from a quick one-liner to a full conversation with the AI.","exploreLabel":"Explore — converse","exploreBody":"Describe what you want in a chat; a live draft rebuilds itself every turn. A preset slider tunes how much project context the AI sees — from your message only, up to the full codebase plus your MCP servers.","quickLabel":"Quick — one shot","quickBody":"Already know what you want? Generate a complete spec in a single turn. Optionally enrich it with a Contract Layer: exact names, data shapes, invariants and a file-touch list so the agents don't reinvent anything.","websiteLabel":"From a website","websiteBody":"Opens an embedded browser. Hover-select an element or drag a rectangle, and the screenshot, DOM and applied CSS become attachments. The desktop build ships its own Chromium, so it works offline.","smashLabel":"SMASH a big epic","smashBody":"Explode a large spec into a family of smaller sub-specs in one click — each child carries a short summary on its card.","draftsLabel":"Drafts & Continue Editing","draftsBody":"Park an in-progress exploration as a draft ticket and resume it later; reopen any spec back in Explore to keep refining it.","compareLabel":"Compare side by side","compareBody":"Drag a spec to the screen edge and a picker of your other specs slides in — review two of them together, tablet-style."},"rails":{"nav":"Run on rails","title":"Run the pipeline on rails","subtitle":"Organize specs into lanes, then launch the agents","intro":"The right side of the Dashboard is your <b>Rails</b> — execution lanes. Drag a spec card onto a rail and press <play>▶ Play</play> to launch an implementation job.","jobLabel":"What each job runs","flowCaption":"Every phase streams its logs live as it works.","modeLabel":"Pick a Loop to run","modeBody":"Each rail runs a <b>Loop</b>. Pick a built-in one — <b>Implement</b> (the full structured pipeline), <b>Batch</b> (several specs at once) or <b>Freestyle</b> (a capable provider works autonomously, no fixed pipeline) — or one you built yourself.","profilesLabel":"Agent profiles","profilesBody":"A per-project, declarative catalog that decides which agents run and which model each one uses — picked per rail and snapshotted per job so concurrent work stays isolated.","jobDetailLabel":"Live job detail","jobDetailBody":"Every job shows a ticket-identity header, a live duration ticker and running turn/token counts, with the authoritative cost resolved on exit.","isolationLabel":"Many projects, isolated","isolationBody":"Each project has its own database and job queue. Run different projects at the same time and switch between them from the left sidebar — your place is remembered per project.","loopsLabel":"Build your own loops","loopsBody":"<b>Loops</b> is a visual builder: chain AI steps, shell commands and a <b>Loop Decider</b> that repeats until a goal is met — e.g. verify → fix → verify until everything is green. Publish a loop and pick it on any rail."},"agent":{"nav":"Agent chat","title":"Operate the app by chatting","subtitle":"A copilot that drives Specrails for you","intro":"The built-in <b>agent chat</b> lets you run Specrails by asking — create specs, launch rails, check analytics — instead of clicking around. It works through Specrails' own <b>MCP</b> tools, and because everything is live you watch the board change as it works.","openLabel":"Always a click away","openBody":"Open it from the floating bubble at the bottom, or press ⌘⇧A (Ctrl+Shift+A) from anywhere. The panel moves, resizes, maximizes and remembers where you left it.","operateLabel":"Drives the whole app","operateBody":"Pick a project (or Home for everything) and a provider, then just ask: “launch the three highest-priority tickets”, “how much did I spend this week?”.","levelsLabel":"You hold the leash","levelsBody":"A live level — <b>Observe → Edit → Operate → Autonomous</b>, cycled with Shift+Tab — decides how far it can go. It never acts above the level you set.","watchLabel":"Watch it happen","watchBody":"The panel is non-modal, so rails and specs appear on the dashboard in real time while the agent works. A status chip shows what it's doing right now.","mcpLabel":"Runs on the local MCP","mcpBody":"The agent drives the app through the embedded Specrails MCP server. If it's off, the panel offers a one-click enable — nothing is installed."},"providers":{"nav":"Your agent","title":"Bring your own agent","subtitle":"Claude Code, Codex, Gemini and Kimi as first-class engines","intro":"The app treats <b>Claude Code</b>, <b>Codex CLI</b>, <b>Gemini CLI</b> and <b>Kimi Code</b> as interchangeable engines behind one contract. A project can install one or more — the choice is made at install time.","table":{"capability":"Capability","streamingResume":"Streaming & session resume","native":"Native","costReporting":"Cost reporting","providerBilled":"Provider-billed","estimated":"Estimated (~)","unavailable":"Unavailable","telemetry":"Telemetry (OTEL)","synthesized":"Synthesized","agentProfiles":"Agent profiles"},"calloutLabel":"When several are installed","calloutBody":"Pick the engine <b>per spec, per rail, or per terminal launch</b>. The app remembers your last choice per project. Estimated costs are marked with <mono>~</mono>; Kimi does not report token or cost data."},"cost":{"nav":"Track cost","title":"Track every cent","subtitle":"Every billable invocation, recorded and visualized","intro":"Every AI invocation — across rails, Quick, Explore, AI edits, SMASH and file summaries — records its lifecycle and provider. Usage and cost fields remain unavailable when a provider, such as Kimi, does not report them.","analyticsLabel":"Analytics page","analyticsBody":"A burn-rate hero, daily timeline, top tickets, model breakdown and a cost-vs-turns scatter. Filter by period (7d / 30d / 90d / All) and by surface.","perTicketLabel":"Per-ticket spending","perTicketBody":"Each spec's detail shows what it cost and how many turns it took, deep-linking into Analytics filtered to that ticket.","honestLabel":"Honest numbers","honestBody":"Claude cost is provider-billed; Codex and Gemini may be estimated and marked with <mono>~</mono>. Kimi reports neither tokens nor native USD cost, so those fields show as unavailable rather than zero.","budgetsLabel":"Budgets & alerts","budgetsBody":"Set a daily budget and a per-job cost alert; the app auto-pauses the queue when you cross the line. Export anything to CSV or JSON."},"workspace":{"nav":"Workspace","title":"Make it your workspace","subtitle":"Everything you need without leaving the window","terminalLabel":"Terminal panel","terminalBody":"A real VS-Code-style terminal at the bottom (<mod>{{mod}}</mod> <j>J</j>) — WebGL rendering, search, inline images, drag-drop paths and shell integration. Up to 10 sessions per project.","codeLabel":"Code explorer","codeBody":"A read-only file tree and Monaco viewer with plain-language AI summaries and “touched by AI” provenance chips, so anyone can follow what changed and why.","integrationsLabel":"Integrations","integrationsBody":"A per-project marketplace of MCP integrations — Serena semantic code-navigation is bundled. Installs are additive: adding one never disturbs another.","themesLabel":"Themes","themesBody":"Six built-in themes — specrails (default), dracula, aurora-light, obsidian-dark, code-rain and galaxy — applied before the UI paints, so there's no flash. Change them in Settings → Appearance.","chatsLabel":"Minimizable chats","chatsBody":"Park an Explore or AI-Edit session into a dock chip and pick it back up later — never lost across refreshes or project switches.","desktopLabel":"Desktop or browser","desktopBody":"Run Specrails in your browser, or grab the signed desktop app (macOS & Windows) that bundles its own server and runtimes."},"companion":{"nav":"Mobile companion","title":"Take Specrails with you","subtitle":"Specrails Companion — your pipelines, on your phone","intro":"<b>Specrails Companion</b> is a web app at specrails.dev/companion-app — open it on your phone (or add it to your Home Screen) to browse the specs board, launch and stop rails, follow live job logs and glance at analytics. No install, no app store.","localLabel":"100% local, like everything else","localBody":"Your phone connects straight to this computer — peer-to-peer and encrypted (WebRTC). No cloud relay, no account, and your code never leaves your devices.","downloadLabel":"Open it on your phone","downloadHint":"Scan the code with your phone's camera, or open specrails.dev/companion-app in its browser.","open":"Open Specrails Companion","pairLabel":"Pairing takes ten seconds","pairBody":"On your phone open specrails.dev/companion-app, then here go to Settings → Mobile companion → Pair web companion and follow the on-screen steps."},"moveFast":{"nav":"Move fast","title":"Move at the speed of thought","subtitle":"Keyboard-first, everywhere","paletteLabel":"Command palette","paletteShortcut":"<f>Press</f> <mod>{{mod}}</mod> <m>+</m> <k>K</k> <m>anywhere</m>","paletteBody":"Switch projects, run spec commands, jump to any page and find recent jobs — all with fuzzy search.","terminalLabel":"Terminal panel","terminalBody":"Toggle with <mod>{{mod}}</mod> <j>J</j>.","shortcutsLabel":"All shortcuts","shortcutsBody":"Press <q>?</q> to see the full cheat-sheet.","chatLabel":"Chat sidebar","chatBody":"Toggle the right sidebar with <mod>{{mod}}</mod> <bkey>B</bkey>.","projectsLabel":"Projects sidebar","projectsBody":"Toggle the left Arc sidebar with <alt>{{alt}}</alt> <mod>{{mod}}</mod> <bkey>B</bkey>.","outro":"<b>That's the tour.</b> Add a project from the left sidebar and ship your first spec. You can reopen this walkthrough anytime from Settings."},"jira":{"label":"Jira integration","body":"Back any project with a <b>Jira board</b> — each spec becomes a Jira issue, kept in sync both ways: status follows the rail, and a comment is posted when a job finishes. Configure it per project when you add it, or anytime in Settings."}}`),u={wizard:n,addProject:r,prerequisites:i,instructions:a,checkpoints:o,setupChat:s,welcome:c,onboarding:l};export{t};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var e={configureAgents:`Configurar agentes de {{provider}}`,configureSubtitle:`Revisa tu equipo de agentes y elige cómo se ejecuta cada uno.`,tabs:{agents:`Agentes`,models:`Modelos`},skipForNow:`Omitir por ahora`,install:`Instalar`,nextProvider:`Siguiente: {{provider}}`,installingProvider:`Instalando {{provider}}…`,installingSpecrails:`Instalando specrails...`,installingFromTemplates:`Instalando agentes desde plantillas`,waitingForOutput:`Esperando salida...`,checkpoints:{baseInstall:`Instalación base`,agentSelection:`Configuración de agentes`,agentGeneration:`Generación de agentes`},steps:{configure:`Configurar`},summary:{agents:`Agentes`,agentSkills:`Skills de agente`,skills:`Skills`,openspecSkills:`Skills de OpenSpec`,legacyRemoved_one:`Eliminado {{count}} comando legacy <code>/specrails:*</code>`,legacyRemoved_other:`Eliminados {{count}} comandos legacy <code>/specrails:*</code>`},complete:{welcome:`Bienvenido a <spec>spec</spec><rails>rails</rails>`,configured:`<strong>{{projectName}}</strong> ya está configurado con flujos de desarrollo impulsados por IA. Tus agentes y comandos especializados están listos para usar.`,installedForEngines_one:`Instalado para {{count}} motor`,installedForEngines_other:`Instalado para {{count}} motores`,installed:`Instalado`,installFailed:`Error en la instalación`,learnMore:`Aprende a sacar el máximo partido a specrails:`,continueToProject:`Continuar al proyecto`,jira:{title:`Conecta un tablero de Jira`,subtitle:`Opcional — respalda las specs de este proyecto con un tablero de Jira. También puedes hacerlo más tarde en Ajustes.`,configure:`Configurar Jira`,optional:`opcional`},mcpHint:`Conecta herramientas de IA externas a Specrails mediante un servidor MCP local seguro — actívalo en Ajustes.`,agentChatHint:`Opera Specrails conversando — el agente integrado maneja toda la app por ti. Ábrelo desde la burbuja o con ⌘⇧A.`},error:{title:`La configuración ha fallado`,skipSetup:`Omitir configuración`,prereqMissing:`La configuración de SpecRails necesita Node.js, npm, npx y Git disponibles en el PATH antes de poder instalar este proyecto.`,prereqRetryHint:`Instala las herramientas que faltan, reinicia Specrails y reintenta la configuración.`}},t={title:`Añadir proyecto`,description:`Registra un directorio de proyecto para gestionarlo desde Specrails.`,noProviderDetected:`No se ha detectado ningún CLI de IA. Instala primero Claude Code, Codex CLI, Gemini CLI o Kimi Code.`,pathLabel:`Ruta del proyecto`,pathPlaceholder:`/Users/yo/mi-proyecto`,pathHint:`Ruta absoluta a la raíz del proyecto`,browseForFolder:`Buscar carpeta`,selectProjectFolder:`Seleccionar carpeta del proyecto`,nameLabel:`Nombre para mostrar`,optional:`(opcional)`,namePlaceholder:`Mi proyecto`,nameHint:`Por defecto, el nombre del directorio`,providersLabel:`Proveedores de IA`,notFound:`no encontrado`,coreUpdateRequired:`Actualiza Specrails Core`,multiProviderHint:`Se configurarán ambos motores. El primero es el predeterminado del proyecto. No se puede cambiar después de la creación.`,singleProviderHint:`No se puede cambiar una vez creado el proyecto.`,adding:`Añadiendo...`,submit:`Añadir proyecto`,toolsRequired_one:`Se necesita {{tools}} para añadir un proyecto`,toolsRequired_other:`Se necesitan {{tools}} para añadir un proyecto`,errors:{pathRequired:`La ruta del proyecto es obligatoria`,selectProvider:`Selecciona al menos un proveedor de IA`,addFailed:`No se pudo añadir el proyecto`},toasts:{registered:`Proyecto "{{name}}" registrado`},chooser:{description:`Trae un repositorio existente o construye un proyecto nuevo desde una idea.`,existingTitle:`Proyecto existente`,existingDescription:`Registra un repositorio que ya existe en disco.`,newTitle:`Proyecto nuevo`,newDescription:`Describe una idea y recibe un repo inicializado con un backlog del Hito 1.`}},n={corruptedBundle:`bundle dañado — reinstala la app`,notInstalled:`no instalado`,failedToExecute:`encontrado pero no se pudo ejecutar`,failedToExecuteAt:`encontrado en {{path}} pero no se pudo ejecutar`,failedToExecuteWithError:`encontrado pero no se pudo ejecutar ({{error}})`,failedToExecuteAtWithError:`encontrado en {{path}} pero no se pudo ejecutar ({{error}})`,needsMinimum:`{{version}} encontrada — se necesita {{minVersion}}+`,unknownVersion:`desconocida`,installedLabel:`instalado`,verifyError:`No se pudieron verificar las herramientas de desarrollo en local — la instalación lo validará.`,allDetected:`Todas las herramientas necesarias detectadas`,bundleCorruptedTitle:`Bundle de la app dañado`,toolsRequired_one:`{{count}} herramienta de desarrollo necesaria`,toolsRequired_other:`{{count}} herramientas de desarrollo necesarias`,reinstallHint:`Reinstala la app Specrails para restaurar las herramientas incluidas.`,installMissingHint:`Instala las herramientas que faltan para continuar.`,moreInfo:`Más información`,bundledBadge:`incluida`,optional:`opcional`,ghNoAuth:"Sin sesión — ejecuta `gh auth login`"},r={title:`Instalar herramientas de desarrollo`,description:`SpecRails necesita Node.js, npm, npx y Git en el PATH. Elige el snippet de tu SO, ejecútalo y pulsa "Ya lo he instalado, volver a comprobar".`,darwin:{intro:`Homebrew te da ambas herramientas en una línea. Si no tienes brew, usa las descargas oficiales.`,installNodeGit:`Instalar Node.js y Git con Homebrew`},win32:{intro:`Winget viene incluido en Windows 11 y en las versiones recientes de Windows 10. Abre PowerShell o Terminal y ejecuta:`,installNode:`Instalar Node.js LTS`,installGit:`Instalar Git`,note:`Tras la instalación, reinicia Specrails para que Windows actualice el PATH.`},linux:{intro:`Usa el gestor de paquetes de tu distro:`,debian:`Debian / Ubuntu`,fedora:`Fedora / RHEL`},links:{nodeOfficial:`Node.js (oficial)`,gitOfficial:`Git (oficial)`,gitWindows:`Git para Windows (oficial)`},showOtherPlatforms:`Mostrar otras plataformas`,hideOtherPlatforms:`Ocultar otras plataformas`,recheck:`Ya lo he instalado, volver a comprobar`,diagnostics:{copy:`Copiar diagnóstico`,copied:`Diagnóstico copiado`,failed:`Error al copiar`},corrupted:{title:`Bundle de la app dañado`,description:`No se pudieron verificar una o más herramientas incluidas (Node.js, Git).`,body:`Esta herramienta viene incluida con la app Specrails y no puede instalarse por separado. Si ves este mensaje, el bundle de la app puede estar dañado. Reinstala Specrails.`}},i={title:`Progreso de la configuración`,progress:`{{done}} de {{total}} completados`,rawLog_one:`Log sin procesar ({{count}} línea)`,rawLog_other:`Log sin procesar ({{count}} líneas)`},a={title:`Asistente de configuración`,subtitle:`Responde a las preguntas para configurar tu proyecto`,settingUp:`Configurando tu proyecto...`,placeholder:`Escribe una respuesta...`,keyboardHint:`Enter para enviar, Shift+Enter para nueva línea`},o={title:`Bienvenido a <spec>spec</spec><rails>rails</rails>`,description:`Specrails gestiona varios proyectos desde una única interfaz. Añade tu primer proyecto para empezar.`,addFirstProject:`Añade tu primer proyecto`,jiraHint:`Conecta cada proyecto a su propio tablero de Jira — las specs se sincronizan en ambos sentidos.`,mcpHint:`Conecta herramientas de IA externas a Specrails mediante un servidor MCP local seguro — actívalo en Ajustes.`,agentChatHint:`Opera Specrails conversando — un agente integrado gestiona specs, rails y analíticas por ti a través del MCP local. Ábrelo desde la burbuja o con ⌘⇧A.`},s=JSON.parse(`{"productTour":"Tour del producto","stepCount":"Paso {{current}} de {{total}}","goToStep":"Ir al paso {{step}}: {{label}}","stepLabel":"Paso {{step}}","dontShowAgain":"No volver a mostrar","skipTour":"Saltar el tour","getStarted":"Empezar","flow":{"addSpec":"Añade una spec","dropInRail":"Suéltala en un rail","hitPlay":"Dale a Play","ship":"Ship","architect":"Arquitecto","developer":"Desarrollador","reviewer":"Revisor"},"language":{"nav":"Idioma","title":"Elige tu idioma","subtitle":"Specrails habla tu idioma","intro":"Selecciona el idioma en el que quieres la interfaz. Se aplica al instante — este tour incluido.","note":"Puedes cambiarlo cuando quieras en Ajustes → Idioma."},"theme":{"nav":"Tema","title":"Elige tu estilo","subtitle":"Temas integrados, aplicados al instante","intro":"Decide qué aspecto tendrá Specrails — el tema se aplica en cuanto haces clic.","note":"Puedes cambiarlo cuando quieras en Ajustes → Apariencia."},"welcome":{"nav":"Bienvenida","title":"Bienvenido a Specrails","subtitle":"Tu centro de mando local para publicar software con agentes de IA","intro":"Specrails convierte una idea en código publicado — y te permite <b>ver, dirigir y confiar en</b> cada paso. Redacta una spec hablando con una IA, suéltala en un rail de ejecución y dale a Play. El pipeline se encarga de la arquitectura, la implementación, la revisión y la pull request, retransmitiendo su trabajo en directo en todo momento.","coreLoopLabel":"El bucle principal","flowCaption":"Cada spec pasa automáticamente por <b>Arquitecto → Desarrollador → Revisor → Ship</b>.","localNote":"<b>100 % local · un solo usuario · sin cuentas.</b> Todo se ejecuta en tu máquina. Tu código nunca sale del portátil a menos que <i>tú</i> lances un agente sobre él.","tourNote":"Este tour rápido repasa todo lo que puede hacer la aplicación — alrededor de un minuto."},"authorSpecs":{"nav":"Crea specs","title":"Convierte ideas en specs","subtitle":"Seis formas de capturar exactamente lo que quieres construir","intro":"Una <b>spec</b> es una descripción del trabajo que quieres que se haga. Redáctala como mejor encaje en cada momento — desde una línea rápida hasta una conversación completa con la IA.","exploreLabel":"Explore — conversa","exploreBody":"Describe lo que quieres en un chat; un borrador en vivo se reconstruye en cada turno. Un slider de presets ajusta cuánto contexto del proyecto ve la IA — desde solo tu mensaje hasta el codebase completo más tus servidores MCP.","quickLabel":"Quick — de una sola vez","quickBody":"¿Ya sabes lo que quieres? Genera una spec completa en un solo turno. Opcionalmente, enriquécela con una Contract Layer: nombres exactos, formas de datos, invariantes y una lista de archivos a tocar para que los agentes no reinventen nada.","websiteLabel":"Desde una web","websiteBody":"Abre un navegador embebido. Selecciona un elemento al pasar el ratón o arrastra un rectángulo, y la captura, el DOM y el CSS aplicado se convierten en adjuntos. La versión de escritorio incluye su propio Chromium, así que funciona sin conexión.","smashLabel":"SMASH para una épica grande","smashBody":"Divide una spec grande en una familia de sub-specs más pequeñas con un clic — cada hija lleva un breve resumen en su tarjeta.","draftsLabel":"Borradores y seguir editando","draftsBody":"Aparca una exploración en curso como ticket en borrador y retómala más tarde; reabre cualquier spec en Explore para seguir refinándola.","compareLabel":"Compara lado a lado","compareBody":"Arrastra una spec al borde de la pantalla y se desliza un selector con tus otras specs — revisa dos a la vez, al estilo tablet."},"rails":{"nav":"Ejecuta en rails","title":"Ejecuta el pipeline sobre rails","subtitle":"Organiza las specs en carriles y lanza los agentes","intro":"El lado derecho del Dashboard son tus <b>Rails</b> — carriles de ejecución. Arrastra una tarjeta de spec a un rail y pulsa <play>▶ Play</play> para lanzar un job de implementación.","jobLabel":"Qué ejecuta cada job","flowCaption":"Cada fase retransmite sus logs en directo mientras trabaja.","modeLabel":"Elige un Loop para ejecutar","modeBody":"Cada rail ejecuta un <b>Loop</b>. Elige uno de serie — <b>Implement</b> (el pipeline estructurado completo), <b>Batch</b> (varias specs a la vez) o <b>Freestyle</b> (un proveedor compatible trabaja de forma autónoma, sin pipeline fijo) — o uno que hayas creado tú.","profilesLabel":"Perfiles de agentes","profilesBody":"Un catálogo declarativo por proyecto que decide qué agentes se ejecutan y qué modelo usa cada uno — se elige por rail y se congela por job para que el trabajo concurrente quede aislado.","jobDetailLabel":"Detalle del job en directo","jobDetailBody":"Cada job muestra una cabecera con la identidad del ticket, un contador de duración en directo y los turnos y tokens acumulados, con el coste definitivo resuelto al terminar.","isolationLabel":"Muchos proyectos, aislados","isolationBody":"Cada proyecto tiene su propia base de datos y su propia cola de jobs. Ejecuta proyectos distintos a la vez y cambia entre ellos desde la barra lateral izquierda — tu posición se recuerda por proyecto.","loopsLabel":"Crea tus propios loops","loopsBody":"<b>Loops</b> es un editor visual: encadena pasos de IA, comandos de shell y un <b>Loop Decider</b> que se repite hasta cumplir un objetivo — p. ej. verificar → corregir → verificar hasta que todo esté en verde. Publica un loop y elígelo en cualquier rail."},"agent":{"nav":"Chat con el agente","title":"Opera la app conversando","subtitle":"Un copiloto que maneja Specrails por ti","intro":"El <b>chat con el agente</b> integrado te permite manejar Specrails preguntando — crea specs, lanza rails, consulta analíticas — en lugar de ir haciendo clic. Funciona a través de las propias herramientas <b>MCP</b> de Specrails y, como todo es en vivo, ves cómo cambia el tablero mientras trabaja.","openLabel":"Siempre a un clic","openBody":"Ábrelo desde la burbuja flotante de abajo, o pulsa ⌘⇧A (Ctrl+Shift+A) desde cualquier sitio. El panel se mueve, se redimensiona, se maximiza y recuerda dónde lo dejaste.","operateLabel":"Maneja toda la app","operateBody":"Elige un proyecto (o Inicio para todo) y un proveedor, y simplemente pide: “lanza los tres tickets de mayor prioridad”, “¿cuánto he gastado esta semana?”.","levelsLabel":"Tú llevas las riendas","levelsBody":"Un nivel en vivo — <b>Observa → Edita → Opera → Autónomo</b>, que se alterna con Shift+Tab — decide hasta dónde puede llegar. Nunca actúa por encima del nivel que fijes.","watchLabel":"Míralo suceder","watchBody":"El panel no es modal, así que los rails y las specs aparecen en el dashboard en tiempo real mientras el agente trabaja. Un chip de estado muestra qué está haciendo ahora mismo.","mcpLabel":"Funciona sobre el MCP local","mcpBody":"El agente maneja la app a través del servidor MCP integrado de Specrails. Si está apagado, el panel ofrece activarlo con un clic — no se instala nada."},"providers":{"nav":"Tu agente","title":"Trae tu propio agente","subtitle":"Claude Code, Codex, Gemini y Kimi como motores de primera clase","intro":"La app trata <b>Claude Code</b>, <b>Codex CLI</b>, <b>Gemini CLI</b> y <b>Kimi Code</b> como motores intercambiables tras un mismo contrato. Un proyecto puede instalar uno o varios — la elección se hace al instalar.","table":{"capability":"Capacidad","streamingResume":"Streaming y reanudación de sesión","native":"Nativo","costReporting":"Informe de costes","providerBilled":"Facturado por el proveedor","estimated":"Estimado (~)","unavailable":"No disponible","telemetry":"Telemetría (OTEL)","synthesized":"Sintetizada","agentProfiles":"Perfiles de agentes"},"calloutLabel":"Cuando hay varios instalados","calloutBody":"Elige el motor <b>por spec, por rail o por lanzamiento de terminal</b>. La aplicación recuerda tu última elección por proyecto. Los costes estimados se marcan con <mono>~</mono>; Kimi no informa de tokens ni coste."},"cost":{"nav":"Controla el coste","title":"Controla cada céntimo","subtitle":"Cada invocación facturable, registrada y visualizada","intro":"Cada invocación de IA — en rails, Quick, Explore, ediciones con IA, SMASH y resúmenes de archivos — registra su ciclo de vida y proveedor. El uso y el coste quedan no disponibles cuando el proveedor, como Kimi, no los informa.","analyticsLabel":"Página de analítica","analyticsBody":"Un hero de burn-rate, línea temporal diaria, top de tickets, desglose por modelo y un scatter de coste frente a turnos. Filtra por periodo (7d / 30d / 90d / Todo) y por superficie.","perTicketLabel":"Gasto por ticket","perTicketBody":"El detalle de cada spec muestra cuánto costó y cuántos turnos llevó, con enlace directo a la analítica filtrada por ese ticket.","honestLabel":"Números honestos","honestBody":"El coste de Claude es el facturado por el proveedor; Codex y Gemini pueden estimarse y se marcan con <mono>~</mono>. Kimi no informa de tokens ni coste USD nativo, así que esos campos aparecen como no disponibles, no como cero.","budgetsLabel":"Presupuestos y alertas","budgetsBody":"Define un presupuesto diario y una alerta de coste por job; la aplicación pausa la cola automáticamente cuando cruzas la línea. Exporta lo que quieras a CSV o JSON."},"workspace":{"nav":"Espacio de trabajo","title":"Hazlo tu espacio de trabajo","subtitle":"Todo lo que necesitas sin salir de la ventana","terminalLabel":"Panel de terminal","terminalBody":"Un terminal real al estilo VS Code en la parte inferior (<mod>{{mod}}</mod> <j>J</j>) — renderizado WebGL, búsqueda, imágenes inline, arrastrar y soltar rutas e integración con el shell. Hasta 10 sesiones por proyecto.","codeLabel":"Explorador de código","codeBody":"Un árbol de archivos de solo lectura y un visor Monaco con resúmenes de IA en lenguaje llano y chips de procedencia «tocado por IA», para que cualquiera pueda seguir qué cambió y por qué.","integrationsLabel":"Integraciones","integrationsBody":"Un marketplace por proyecto de integraciones MCP — la navegación semántica de código de Serena viene incluida. Las instalaciones son aditivas: añadir una nunca altera otra.","themesLabel":"Temas","themesBody":"Seis temas integrados — specrails (por defecto), dracula, aurora-light, obsidian-dark, code-rain y galaxy — aplicados antes de que la UI pinte, así no hay parpadeo. Cámbialos en Ajustes → Apariencia.","chatsLabel":"Chats minimizables","chatsBody":"Aparca una sesión de Explore o AI Edit en un chip del dock y retómala más tarde — nunca se pierde entre recargas o cambios de proyecto.","desktopLabel":"Escritorio o navegador","desktopBody":"Ejecuta Specrails en tu navegador o descarga la app de escritorio firmada (macOS y Windows), que incluye su propio servidor y runtimes."},"companion":{"nav":"Compañera móvil","title":"Llévate Specrails contigo","subtitle":"Specrails Companion — tus pipelines, en tu teléfono","intro":"<b>Specrails Companion</b> es una app web en specrails.dev/companion-app — ábrela en tu teléfono (o añádela a tu pantalla de inicio) para navegar por el tablero de specs, lanzar y detener rails, seguir los logs de los jobs en directo y echar un vistazo a la analítica. Sin instalación, sin tienda de apps.","localLabel":"100 % local, como todo lo demás","localBody":"Tu teléfono se conecta directamente a este ordenador — peer-to-peer y cifrado (WebRTC). Sin servidores intermedios en la nube, sin cuentas, y tu código nunca sale de tus dispositivos.","downloadLabel":"Ábrela en tu teléfono","downloadHint":"Escanea el código con la cámara de tu teléfono o abre specrails.dev/companion-app en su navegador.","open":"Abrir Specrails Companion","pairLabel":"Emparejar lleva diez segundos","pairBody":"En tu teléfono abre specrails.dev/companion-app y luego, aquí, ve a Ajustes → Compañera móvil → Emparejar compañera web y sigue los pasos en pantalla."},"moveFast":{"nav":"Ve rápido","title":"Muévete a la velocidad del pensamiento","subtitle":"Teclado primero, en todas partes","paletteLabel":"Paleta de comandos","paletteShortcut":"<f>Pulsa</f> <mod>{{mod}}</mod> <m>+</m> <k>K</k> <m>en cualquier parte</m>","paletteBody":"Cambia de proyecto, ejecuta comandos de spec, salta a cualquier página y encuentra jobs recientes — todo con búsqueda difusa.","terminalLabel":"Panel de terminal","terminalBody":"Alterna con <mod>{{mod}}</mod> <j>J</j>.","shortcutsLabel":"Todos los atajos","shortcutsBody":"Pulsa <q>?</q> para ver la chuleta completa.","chatLabel":"Barra lateral de chat","chatBody":"Alterna la barra lateral derecha con <mod>{{mod}}</mod> <bkey>B</bkey>.","projectsLabel":"Barra lateral de proyectos","projectsBody":"Alterna la barra lateral Arc izquierda con <alt>{{alt}}</alt> <mod>{{mod}}</mod> <bkey>B</bkey>.","outro":"<b>Fin del tour.</b> Añade un proyecto desde la barra lateral izquierda y publica tu primera spec. Puedes reabrir este recorrido cuando quieras desde Ajustes."},"jira":{"label":"Integración con Jira","body":"Respalda cualquier proyecto con un <b>tablero de Jira</b> — cada spec es un issue de Jira, sincronizado en ambos sentidos: el estado sigue al rail y se publica un comentario al terminar un job. Configúralo por proyecto al añadirlo, o cuando quieras en Ajustes."}}`),c={wizard:e,addProject:t,prerequisites:n,instructions:r,checkpoints:i,setupChat:a,welcome:o,onboarding:s};export{t as addProject,i as checkpoints,c as default,r as instructions,s as onboarding,n as prerequisites,a as setupChat,o as welcome,e as wizard};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var e={configureAgents:`{{provider}}-Agenten konfigurieren`,configureSubtitle:`Überprüfe dein Agenten-Team und lege fest, wie jeder Agent ausgeführt wird.`,tabs:{agents:`Agenten`,models:`Modelle`},skipForNow:`Vorerst überspringen`,install:`Installieren`,nextProvider:`Weiter: {{provider}}`,installingProvider:`{{provider}} wird installiert…`,installingSpecrails:`specrails wird installiert…`,installingFromTemplates:`Agenten werden aus Vorlagen installiert`,waitingForOutput:`Warten auf Ausgabe…`,checkpoints:{baseInstall:`Basisinstallation`,agentSelection:`Agenten-Konfiguration`,agentGeneration:`Agentengenerierung`},steps:{configure:`Konfigurieren`},summary:{agents:`Agenten`,agentSkills:`Agenten-Skills`,skills:`Skills`,openspecSkills:`OpenSpec-Skills`,legacyRemoved_one:`{{count}} Legacy-Befehl <code>/specrails:*</code> entfernt`,legacyRemoved_other:`{{count}} Legacy-Befehle <code>/specrails:*</code> entfernt`},complete:{welcome:`Willkommen bei <spec>spec</spec><rails>rails</rails>`,configured:`<strong>{{projectName}}</strong> ist jetzt mit KI-gestützten Entwicklungs-Workflows konfiguriert. Ihre spezialisierten Agenten und Befehle sind einsatzbereit.`,installedForEngines_one:`Für {{count}} Engine installiert`,installedForEngines_other:`Für {{count}} Engines installiert`,installed:`Installiert`,installFailed:`Installation fehlgeschlagen`,learnMore:`Erfahren Sie, wie Sie das Beste aus specrails herausholen:`,continueToProject:`Weiter zum Projekt`,jira:{title:`Ein Jira-Board verbinden`,subtitle:`Optional — hinterlege die Specs dieses Projekts mit einem Jira-Board. Du kannst das auch später in den Einstellungen tun.`,configure:`Jira einrichten`,optional:`optional`},mcpHint:`Verbinde externe KI-Tools über einen sicheren lokalen MCP-Server mit Specrails — aktiviere ihn in den Einstellungen.`,agentChatHint:`Steuere Specrails per Chat — der integrierte Agent bedient die gesamte App für dich. Öffne ihn über die Blase oder mit ⌘⇧A.`},error:{title:`Setup fehlgeschlagen`,skipSetup:`Setup überspringen`,prereqMissing:`Das SpecRails-Setup benötigt Node.js, npm, npx und Git im PATH, bevor dieses Projekt installiert werden kann.`,prereqRetryHint:`Installieren Sie die fehlenden Tools, starten Sie Specrails neu und versuchen Sie das Setup erneut.`}},t={title:`Projekt hinzufügen`,description:`Registrieren Sie ein Projektverzeichnis, um es über Specrails zu verwalten.`,noProviderDetected:`Keine KI-CLI gefunden. Installieren Sie zuerst Claude Code, Codex CLI, Gemini CLI oder Kimi Code.`,pathLabel:`Projektpfad`,pathPlaceholder:`/Users/ich/mein-projekt`,pathHint:`Absoluter Pfad zum Projekt-Root`,browseForFolder:`Ordner auswählen`,selectProjectFolder:`Projektordner auswählen`,nameLabel:`Anzeigename`,optional:`(optional)`,namePlaceholder:`Mein Projekt`,nameHint:`Standard ist der Verzeichnisname`,providersLabel:`KI-Anbieter`,notFound:`nicht gefunden`,coreUpdateRequired:`Core-Update erforderlich`,multiProviderHint:`Beide Engines werden eingerichtet. Die erste ist der Projektstandard. Kann nach dem Erstellen nicht geändert werden.`,singleProviderHint:`Kann nach dem Erstellen des Projekts nicht geändert werden.`,adding:`Wird hinzugefügt…`,submit:`Projekt hinzufügen`,toolsRequired_one:`{{tools}} wird benötigt, um ein Projekt hinzuzufügen`,toolsRequired_other:`{{tools}} werden benötigt, um ein Projekt hinzuzufügen`,errors:{pathRequired:`Projektpfad ist erforderlich`,selectProvider:`Wählen Sie mindestens einen KI-Anbieter aus`,addFailed:`Projekt konnte nicht hinzugefügt werden`},toasts:{registered:`Projekt „{{name}}“ registriert`},chooser:{description:`Bring ein bestehendes Repository mit oder baue ein ganz neues Projekt aus einer Idee.`,existingTitle:`Bestehendes Projekt`,existingDescription:`Registriere ein Repository, das bereits auf der Festplatte existiert.`,newTitle:`Neues Projekt`,newDescription:`Beschreibe eine Idee und erhalte ein aufgesetztes Repo mit einem Meilenstein-1-Backlog.`}},n={corruptedBundle:`Bundle beschädigt – App neu installieren`,notInstalled:`nicht installiert`,failedToExecute:`gefunden, aber Ausführung fehlgeschlagen`,failedToExecuteAt:`unter {{path}} gefunden, aber Ausführung fehlgeschlagen`,failedToExecuteWithError:`gefunden, aber Ausführung fehlgeschlagen ({{error}})`,failedToExecuteAtWithError:`unter {{path}} gefunden, aber Ausführung fehlgeschlagen ({{error}})`,needsMinimum:`{{version}} gefunden – benötigt {{minVersion}}+`,unknownVersion:`unbekannt`,installedLabel:`installiert`,verifyError:`Entwickler-Tools konnten lokal nicht überprüft werden – die Installation validiert sie.`,allDetected:`Alle erforderlichen Tools erkannt`,bundleCorruptedTitle:`App-Bundle beschädigt`,toolsRequired_one:`{{count}} Entwickler-Tool erforderlich`,toolsRequired_other:`{{count}} Entwickler-Tools erforderlich`,reinstallHint:`Installieren Sie die Specrails-App neu, um die mitgelieferten Tools wiederherzustellen.`,installMissingHint:`Installieren Sie die fehlenden Tools, um fortzufahren.`,moreInfo:`Mehr Infos`,bundledBadge:`mitgeliefert`,optional:`optional`,ghNoAuth:"Nicht angemeldet — führe `gh auth login` aus"},r={title:`Entwickler-Tools installieren`,description:`SpecRails benötigt Node.js, npm, npx und Git im PATH. Wählen Sie das Snippet für Ihr Betriebssystem, führen Sie es aus und klicken Sie dann auf „Installiert, erneut prüfen“.`,darwin:{intro:`Mit Homebrew bekommen Sie beide Tools in einer Zeile. Ohne brew nutzen Sie die offiziellen Downloads.`,installNodeGit:`Node.js und Git über Homebrew installieren`},win32:{intro:`Winget ist in Windows 11 und aktuellen Windows-10-Versionen enthalten. Öffnen Sie PowerShell oder Terminal und führen Sie aus:`,installNode:`Node.js LTS installieren`,installGit:`Git installieren`,note:`Starten Sie Specrails nach der Installation neu, damit Windows den PATH aktualisiert.`},linux:{intro:`Verwenden Sie den Paketmanager Ihrer Distribution:`,debian:`Debian / Ubuntu`,fedora:`Fedora / RHEL`},links:{nodeOfficial:`Node.js (offiziell)`,gitOfficial:`Git (offiziell)`,gitWindows:`Git für Windows (offiziell)`},showOtherPlatforms:`Andere Plattformen anzeigen`,hideOtherPlatforms:`Andere Plattformen ausblenden`,recheck:`Installiert, erneut prüfen`,diagnostics:{copy:`Diagnose kopieren`,copied:`Diagnose kopiert`,failed:`Kopieren fehlgeschlagen`},corrupted:{title:`App-Bundle beschädigt`,description:`Mindestens ein mitgeliefertes Tool (Node.js, Git) konnte nicht verifiziert werden.`,body:`Dieses Tool ist in der Specrails-App enthalten und kann nicht separat installiert werden. Wenn Sie diese Meldung sehen, ist das App-Bundle möglicherweise beschädigt. Bitte installieren Sie Specrails neu.`}},i={title:`Setup-Fortschritt`,progress:`{{done}} von {{total}} abgeschlossen`,rawLog_one:`Roh-Log ({{count}} Zeile)`,rawLog_other:`Roh-Log ({{count}} Zeilen)`},a={title:`Setup-Assistent`,subtitle:`Beantworten Sie die Prompts, um Ihr Projekt zu konfigurieren`,settingUp:`Ihr Projekt wird eingerichtet…`,placeholder:`Antwort eingeben…`,keyboardHint:`Enter zum Senden, Shift+Enter für neue Zeile`},o={title:`Willkommen bei <spec>spec</spec><rails>rails</rails>`,description:`Specrails verwaltet mehrere Projekte über eine einzige Oberfläche. Fügen Sie Ihr erstes Projekt hinzu, um loszulegen.`,addFirstProject:`Erstes Projekt hinzufügen`,jiraHint:`Verbinde jedes Projekt mit seinem eigenen Jira-Board — Specs bleiben in beide Richtungen synchron.`,mcpHint:`Verbinde externe KI-Tools über einen sicheren lokalen MCP-Server mit Specrails — aktiviere ihn in den Einstellungen.`,agentChatHint:`Steuere Specrails per Chat — ein integrierter Agent verwaltet Specs, Rails und Analysen für dich über den lokalen MCP. Öffne ihn über die Blase oder mit ⌘⇧A.`},s=JSON.parse(`{"productTour":"Produkttour","stepCount":"Schritt {{current}} von {{total}}","goToStep":"Zu Schritt {{step}}: {{label}}","stepLabel":"Schritt {{step}}","dontShowAgain":"Nicht mehr anzeigen","skipTour":"Tour überspringen","getStarted":"Loslegen","flow":{"addSpec":"Spec hinzufügen","dropInRail":"Auf eine Rail ziehen","hitPlay":"Play drücken","ship":"Ship","architect":"Architekt","developer":"Entwickler","reviewer":"Reviewer"},"language":{"nav":"Sprache","title":"Wählen Sie Ihre Sprache","subtitle":"Specrails spricht Ihre Sprache","intro":"Wählen Sie die Sprache für die Oberfläche. Sie gilt sofort – diese Tour eingeschlossen.","note":"Sie können sie jederzeit unter Einstellungen → Sprache ändern."},"theme":{"nav":"Theme","title":"Wählen Sie Ihren Look","subtitle":"Integrierte Themes, sofort angewendet","intro":"Wählen Sie, wie Specrails aussehen soll — das Theme wird sofort beim Klick angewendet.","note":"Sie können es jederzeit unter Einstellungen → Erscheinungsbild ändern."},"welcome":{"nav":"Willkommen","title":"Willkommen bei Specrails","subtitle":"Ihr lokales Cockpit, um Software mit KI-Agenten auszuliefern","intro":"Specrails verwandelt eine Idee in ausgelieferten Code – und lässt Sie jeden Schritt <b>sehen, steuern und nachvollziehen</b>. Entwerfen Sie eine Spec im Gespräch mit einer KI, ziehen Sie sie auf eine Ausführungs-Rail und drücken Sie Play. Die Pipeline übernimmt Architektur, Implementierung, Review und den Pull Request – und streamt ihre Arbeit dabei live.","coreLoopLabel":"Der Kern-Loop","flowCaption":"Jede Spec durchläuft automatisch <b>Architekt → Entwickler → Reviewer → Ship</b>.","localNote":"<b>100 % lokal · Single-User · keine Konten.</b> Alles läuft auf Ihrem Rechner. Ihr Code verlässt den Laptop nur, wenn <i>Sie</i> einen Agent darauf ansetzen.","tourNote":"Diese kurze Tour zeigt alles, was die App kann – dauert etwa eine Minute."},"authorSpecs":{"nav":"Specs verfassen","title":"Aus Ideen werden Specs","subtitle":"Sechs Wege, genau festzuhalten, was gebaut werden soll","intro":"Eine <b>Spec</b> beschreibt Arbeit, die erledigt werden soll. Verfassen Sie sie, wie es gerade passt – vom schnellen Einzeiler bis zum ausführlichen Gespräch mit der KI.","exploreLabel":"Explore – im Dialog","exploreBody":"Beschreiben Sie im Chat, was Sie wollen; ein Live-Entwurf baut sich mit jedem Zug neu auf. Ein Preset-Regler steuert, wie viel Projektkontext die KI sieht – von nur Ihrer Nachricht bis zur kompletten Codebasis samt Ihren MCP-Servern.","quickLabel":"Quick – in einem Schritt","quickBody":"Sie wissen schon, was Sie wollen? Generieren Sie eine vollständige Spec in einem einzigen Zug. Optional mit Contract Layer anreichern: exakte Namen, Datenformen, Invarianten und eine Liste der berührten Dateien, damit die Agenten nichts neu erfinden.","websiteLabel":"Von einer Website","websiteBody":"Öffnet einen eingebetteten Browser. Wählen Sie per Hover ein Element oder ziehen Sie ein Rechteck – Screenshot, DOM und angewendetes CSS werden zu Anhängen. Die Desktop-Version bringt ein eigenes Chromium mit und funktioniert daher offline.","smashLabel":"Ein großes Epic SMASHen","smashBody":"Zerlegen Sie eine große Spec mit einem Klick in eine Familie kleinerer Sub-Specs – jedes Kind trägt eine Kurzzusammenfassung auf seiner Karte.","draftsLabel":"Entwürfe & Weiterbearbeiten","draftsBody":"Parken Sie eine laufende Exploration als Entwurfs-Ticket und nehmen Sie sie später wieder auf; öffnen Sie jede Spec erneut in Explore, um weiter zu verfeinern.","compareLabel":"Seite an Seite vergleichen","compareBody":"Ziehen Sie eine Spec an den Bildschirmrand, und eine Auswahl Ihrer anderen Specs gleitet herein – prüfen Sie zwei davon gemeinsam, wie auf einem Tablet."},"rails":{"nav":"Auf Rails ausführen","title":"Die Pipeline auf Rails laufen lassen","subtitle":"Specs in Bahnen organisieren, dann die Agenten starten","intro":"Die rechte Seite des Dashboards sind Ihre <b>Rails</b> – Ausführungsbahnen. Ziehen Sie eine Spec-Karte auf eine Rail und drücken Sie <play>▶ Play</play>, um einen Implementierungsjob zu starten.","jobLabel":"Was jeder Job ausführt","flowCaption":"Jede Phase streamt ihre Logs live, während sie arbeitet.","modeLabel":"Wähle einen Loop zum Ausführen","modeBody":"Jeder rail führt einen <b>Loop</b> aus. Wähle einen integrierten Loop — <b>Implement</b> (die vollständige strukturierte Pipeline), <b>Batch</b> (mehrere Specs auf einmal) oder <b>Freestyle</b> (ein geeigneter Anbieter arbeitet autonom, ohne feste Pipeline) — oder einen, den du selbst erstellt hast.","profilesLabel":"Agentenprofile","profilesBody":"Ein deklarativer Katalog pro Projekt, der bestimmt, welche Agenten laufen und welches Modell jeder nutzt – pro Rail gewählt und pro Job eingefroren, damit parallele Arbeit isoliert bleibt.","jobDetailLabel":"Live-Jobdetails","jobDetailBody":"Jeder Job zeigt einen Ticket-Identitäts-Header, eine live tickende Laufzeit und laufende Turn-/Token-Zähler; die verbindlichen Kosten werden beim Beenden ermittelt.","isolationLabel":"Viele Projekte, isoliert","isolationBody":"Jedes Projekt hat seine eigene Datenbank und Job-Queue. Lassen Sie verschiedene Projekte gleichzeitig laufen und wechseln Sie über die linke Seitenleiste – Ihre Position wird pro Projekt gemerkt.","loopsLabel":"Erstelle deine eigenen Loops","loopsBody":"<b>Loops</b> ist ein visueller Builder: Verkette KI-Schritte, Shell-Befehle und einen <b>Loop Decider</b>, der so lange wiederholt, bis ein Ziel erreicht ist — z. B. prüfen → beheben → prüfen, bis alles grün ist. Veröffentliche einen Loop und wähle ihn auf jedem rail aus."},"agent":{"nav":"Agent-Chat","title":"Bediene die App per Chat","subtitle":"Ein Copilot, der Specrails für dich steuert","intro":"Der integrierte <b>Agent-Chat</b> lässt dich Specrails per Frage bedienen — Specs erstellen, Rails starten, Analysen prüfen — statt herumzuklicken. Er arbeitet über die eigenen <b>MCP</b>-Tools von Specrails, und da alles live ist, siehst du das Board sich verändern, während er arbeitet.","openLabel":"Immer nur einen Klick entfernt","openBody":"Öffne ihn über die schwebende Blase unten oder drücke ⌘⇧A (Ctrl+Shift+A) von überall. Das Panel lässt sich verschieben, in der Größe ändern, maximieren und merkt sich, wo du es zuletzt hattest.","operateLabel":"Bedient die gesamte App","operateBody":"Wähle ein Projekt (oder Start für alles) und einen Anbieter und frag einfach: “starte die drei Tickets mit der höchsten Priorität”, “wie viel habe ich diese Woche ausgegeben?”.","levelsLabel":"Du hältst die Leine","levelsBody":"Eine Live-Stufe — <b>Beobachten → Bearbeiten → Ausführen → Autonom</b>, mit Shift+Tab durchgeschaltet — bestimmt, wie weit er gehen darf. Er handelt nie über der von dir gesetzten Stufe.","watchLabel":"Sieh ihm zu","watchBody":"Das Panel ist nicht modal, daher erscheinen Rails und Specs in Echtzeit auf dem Dashboard, während der Agent arbeitet. Ein Status-Chip zeigt, was er gerade tut.","mcpLabel":"Läuft über den lokalen MCP","mcpBody":"Der Agent steuert die App über den eingebetteten Specrails-MCP-Server. Ist er aus, bietet das Panel eine Aktivierung mit einem Klick — es wird nichts installiert."},"providers":{"nav":"Ihr Agent","title":"Bringen Sie Ihren eigenen Agent mit","subtitle":"Claude Code, Codex, Gemini und Kimi als erstklassige Engines","intro":"Die App behandelt <b>Claude Code</b>, <b>Codex CLI</b>, <b>Gemini CLI</b> und <b>Kimi Code</b> als austauschbare Engines hinter einem Vertrag. Ein Projekt kann eine oder mehrere installieren — die Wahl fällt bei der Installation.","table":{"capability":"Fähigkeit","streamingResume":"Streaming & Sitzungsfortsetzung","native":"Nativ","costReporting":"Kostenberichte","providerBilled":"Anbieterseitig abgerechnet","estimated":"Geschätzt (~)","unavailable":"Nicht verfügbar","telemetry":"Telemetrie (OTEL)","synthesized":"Synthetisiert","agentProfiles":"Agentenprofile"},"calloutLabel":"Wenn mehrere installiert sind","calloutBody":"Wählen Sie die Engine <b>pro Spec, pro Rail oder pro Terminal-Start</b>. Geschätzte Kosten sind mit <mono>~</mono> markiert; Kimi meldet keine Token- oder Kostendaten."},"cost":{"nav":"Kosten verfolgen","title":"Jeden Cent im Blick","subtitle":"Jeder kostenpflichtige Aufruf, erfasst und visualisiert","intro":"Jeder KI-Aufruf erfasst Lebenszyklus und Anbieter. Nutzungs- und Kostendaten bleiben nicht verfügbar, wenn ein Anbieter wie Kimi sie nicht meldet.","analyticsLabel":"Analytics-Seite","analyticsBody":"Ein Burn-Rate-Hero, Tages-Timeline, Top-Tickets, Modellaufschlüsselung und ein Kosten-vs.-Turns-Scatter. Filtern nach Zeitraum (7d / 30d / 90d / Alle) und nach Bereich.","perTicketLabel":"Ausgaben pro Ticket","perTicketBody":"Die Detailansicht jeder Spec zeigt, was sie gekostet hat und wie viele Turns sie brauchte – mit Deep-Link in die auf dieses Ticket gefilterte Analytics-Ansicht.","honestLabel":"Ehrliche Zahlen","honestBody":"Claude-Kosten werden vom Anbieter gemeldet; Codex und Gemini können geschätzt und mit <mono>~</mono> markiert werden. Bei Kimi sind Tokens und USD-Kosten nicht verfügbar, nicht null.","budgetsLabel":"Budgets & Alarme","budgetsBody":"Legen Sie ein Tagesbudget und einen Kostenalarm pro Job fest; die App pausiert die Queue automatisch, wenn die Grenze überschritten wird. Exportieren Sie alles als CSV oder JSON."},"workspace":{"nav":"Arbeitsbereich","title":"Machen Sie es zu Ihrem Arbeitsbereich","subtitle":"Alles Nötige, ohne das Fenster zu verlassen","terminalLabel":"Terminal-Panel","terminalBody":"Ein echtes Terminal im VS-Code-Stil am unteren Rand (<mod>{{mod}}</mod> <j>J</j>) – WebGL-Rendering, Suche, Inline-Bilder, Drag-and-drop-Pfade und Shell-Integration. Bis zu 10 Sessions pro Projekt.","codeLabel":"Code-Explorer","codeBody":"Ein schreibgeschützter Dateibaum und Monaco-Viewer mit verständlichen KI-Zusammenfassungen und „Von KI berührt“-Herkunfts-Chips – so kann jeder nachvollziehen, was sich warum geändert hat.","integrationsLabel":"Integrationen","integrationsBody":"Ein Marketplace für MCP-Integrationen pro Projekt – Serena (semantische Code-Navigation) ist bereits enthalten. Installationen sind additiv: Eine neue stört nie eine bestehende.","themesLabel":"Themes","themesBody":"Sechs integrierte Themes – specrails (Standard), dracula, aurora-light, obsidian-dark, code-rain und galaxy – werden angewendet, bevor die UI zeichnet, also ohne Aufblitzen. Ändern Sie sie unter Einstellungen → Erscheinungsbild.","chatsLabel":"Minimierbare Chats","chatsBody":"Parken Sie eine Explore- oder AI-Edit-Sitzung als Dock-Chip und nehmen Sie sie später wieder auf – sie geht weder beim Neuladen noch beim Projektwechsel verloren.","desktopLabel":"Desktop oder Browser","desktopBody":"Nutzen Sie Specrails im Browser oder holen Sie sich die signierte Desktop-App (macOS & Windows) mit eigenem Server und eigenen Runtimes."},"companion":{"nav":"Mobiler Companion","title":"Nehmen Sie Specrails überallhin mit","subtitle":"Specrails Companion – Ihre Pipelines auf Ihrem Smartphone","intro":"<b>Specrails Companion</b> ist eine Web-App unter specrails.dev/companion-app – öffnen Sie sie auf Ihrem Smartphone (oder fügen Sie sie zu Ihrem Home-Bildschirm hinzu), um das Specs-Board zu durchstöbern, Rails zu starten und zu stoppen, Live-Job-Logs zu verfolgen und einen Blick auf die Analytics zu werfen. Keine Installation, kein App-Store.","localLabel":"100 % lokal, wie alles andere","localBody":"Ihr Smartphone verbindet sich direkt mit diesem Rechner – Peer-to-Peer und verschlüsselt (WebRTC). Kein Cloud-Relay, kein Konto, und Ihr Code verlässt nie Ihre Geräte.","downloadLabel":"Auf Ihrem Smartphone öffnen","downloadHint":"Scannen Sie den Code mit der Kamera Ihres Smartphones oder öffnen Sie specrails.dev/companion-app im Browser.","open":"Specrails Companion öffnen","pairLabel":"Die Kopplung dauert zehn Sekunden","pairBody":"Öffnen Sie auf Ihrem Smartphone specrails.dev/companion-app und gehen Sie dann hier zu Einstellungen → Mobiler Companion → Web-Companion koppeln und folgen Sie den Schritten am Bildschirm."},"moveFast":{"nav":"Schnell arbeiten","title":"In Gedankengeschwindigkeit arbeiten","subtitle":"Keyboard-first, überall","paletteLabel":"Befehlspalette","paletteShortcut":"<f>Drücken Sie</f> <mod>{{mod}}</mod> <m>+</m> <k>K</k> <m>überall</m>","paletteBody":"Projekte wechseln, Spec-Befehle ausführen, zu jeder Seite springen und letzte Jobs finden – alles mit Fuzzy-Suche.","terminalLabel":"Terminal-Panel","terminalBody":"Umschalten mit <mod>{{mod}}</mod> <j>J</j>.","shortcutsLabel":"Alle Shortcuts","shortcutsBody":"Drücken Sie <q>?</q> für die vollständige Übersicht.","chatLabel":"Chat-Seitenleiste","chatBody":"Rechte Seitenleiste umschalten mit <mod>{{mod}}</mod> <bkey>B</bkey>.","projectsLabel":"Projekt-Seitenleiste","projectsBody":"Linke Arc-Seitenleiste umschalten mit <alt>{{alt}}</alt> <mod>{{mod}}</mod> <bkey>B</bkey>.","outro":"<b>Das war die Tour.</b> Fügen Sie über die linke Seitenleiste ein Projekt hinzu und liefern Sie Ihre erste Spec aus. Diese Tour lässt sich jederzeit über die Einstellungen erneut öffnen."},"jira":{"label":"Jira-Integration","body":"Hinterlege jedes Projekt mit einem <b>Jira-Board</b> — jede Spec wird zu einem Jira-Vorgang, in beide Richtungen synchronisiert: Der Status folgt dem Rail und am Ende eines Jobs wird ein Kommentar gepostet. Richte es pro Projekt beim Hinzufügen ein oder jederzeit in den Einstellungen."}}`),c={wizard:e,addProject:t,prerequisites:n,instructions:r,checkpoints:i,setupChat:a,welcome:o,onboarding:s};export{t as addProject,i as checkpoints,c as default,r as instructions,s as onboarding,n as prerequisites,a as setupChat,o as welcome,e as wizard};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{o as e}from"./i18n-
|
|
1
|
+
import{o as e}from"./i18n-B2SaZsf2.js";var t={job:`analytics:surfaces.job`,"quick-spec":`analytics:surfaces.quickSpec`,"explore-spec":`analytics:surfaces.exploreSpec`,"ai-edit":`analytics:surfaces.aiEdit`,smash:`analytics:surfaces.smash`,"file-summary":`analytics:surfaces.fileSummary`,loop:`analytics:surfaces.loop`,"chat-sidebar":`analytics:surfaces.chatSidebar`,"spec-launcher":`analytics:surfaces.specLauncher`,proposal:`analytics:surfaces.proposal`,"agent-studio":`analytics:surfaces.agentStudio`,setup:`analytics:surfaces.setup`},n={bg:`bg-muted/40`,text:`text-muted-foreground`,ring:`ring-border/40`,dot:`bg-muted-foreground`},r={job:{bg:`bg-accent-info/15`,text:`text-accent-info`,ring:`ring-accent-info/40`,dot:`bg-accent-info`},"quick-spec":{bg:`bg-accent-secondary/15`,text:`text-accent-secondary`,ring:`ring-accent-secondary/40`,dot:`bg-accent-secondary`},"explore-spec":{bg:`bg-accent-highlight/15`,text:`text-accent-highlight`,ring:`ring-accent-highlight/40`,dot:`bg-accent-highlight`},"ai-edit":{bg:`bg-accent-success/15`,text:`text-accent-success`,ring:`ring-accent-success/40`,dot:`bg-accent-success`},smash:{bg:`bg-accent-highlight/15`,text:`text-accent-highlight`,ring:`ring-accent-highlight/40`,dot:`bg-accent-highlight`},"file-summary":{bg:`bg-accent-warning/15`,text:`text-accent-warning`,ring:`ring-accent-warning/40`,dot:`bg-accent-warning`},loop:{bg:`bg-accent-primary/15`,text:`text-accent-primary`,ring:`ring-accent-primary/40`,dot:`bg-accent-primary`},"chat-sidebar":{bg:`bg-accent-info/15`,text:`text-accent-info`,ring:`ring-accent-info/40`,dot:`bg-accent-info`},"spec-launcher":{bg:`bg-accent-secondary/15`,text:`text-accent-secondary`,ring:`ring-accent-secondary/40`,dot:`bg-accent-secondary`},proposal:{bg:`bg-accent-highlight/15`,text:`text-accent-highlight`,ring:`ring-accent-highlight/40`,dot:`bg-accent-highlight`},"agent-studio":{bg:`bg-accent-success/15`,text:`text-accent-success`,ring:`ring-accent-success/40`,dot:`bg-accent-success`},setup:{bg:`bg-accent-primary/15`,text:`text-accent-primary`,ring:`ring-accent-primary/40`,dot:`bg-accent-primary`}};function i(e,t){return new Proxy(e,{get(e,n,r){return typeof n==`string`&&!(n in e)?t(n):Reflect.get(e,n,r)}})}var a=i(Object.defineProperties({},Object.fromEntries(Object.keys(t).map(n=>[n,{get:()=>e.t(t[n]),enumerable:!0}]))),e=>e),o=i(r,()=>n);export{a as n,o as t};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as e}from"./rolldown-runtime-CNC7AqOf.js";import{n as t}from"./jsx-runtime-zu2_FqZY.js";import{o as n}from"./i18n-D21Pr8Sj.js";import{t as r}from"./createLucideIcon-Bjbbp_KS.js";import{a as i,n as a}from"./auth-D_5bQv5W.js";import{t as o}from"./api-B2M7CtDw.js";var s=r(`arrow-right`,[[`path`,{d:`M5 12h14`,key:`1ays0h`}],[`path`,{d:`m12 5 7 7-7 7`,key:`xquz4c`}]]),c=r(`globe`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`path`,{d:`M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20`,key:`13o1zl`}],[`path`,{d:`M2 12h20`,key:`9i4pu4`}]]),l=r(`rotate-cw`,[[`path`,{d:`M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8`,key:`1p45f6`}],[`path`,{d:`M21 3v5h-5`,key:`1q7to0`}]]),u=e(t(),1);function d(){return typeof window<`u`&&`__TAURI_INTERNALS__`in window||typeof window<`u`&&window.location.protocol!==`http:`&&window.location.protocol!==`https:`?`ws://localhost:4200`:`${window.location.protocol===`https:`?`wss:`:`ws:`}//${window.location.host}`}var f=d();function p(){let e={BASE_URL:`/`,DEV:!1,MODE:`production`,PROD:!0,SSR:!1}.VITE_FEATURE_BROWSER_CAPTURE;return typeof e!=`string`||e!==`false`}var m={desktop:{width:1280,height:800},tablet:{width:768,height:1024},mobile:{width:375,height:667}},h=class extends Error{},g=class extends Error{};function _(e){if(!e)throw Error(`A project owner is required for browser sessions`);return`${i}/api/projects/${encodeURIComponent(e)}`}async function v(e,t){let n=await fetch(`${_(e)}/browser/sessions`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({initialUrl:t})});if(n.status===409)throw new h(`Too many open browser sessions`);if(n.status===502)throw new g(`The browser failed to launch`);if(!n.ok)throw Error(`Failed to open browser (${n.status})`);return(await n.json()).session}async function y(e,t,n,r){let i=await fetch(`${_(e)}/browser/sessions/${t}/navigate`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:n,url:r})});if(!i.ok)throw Error(`Navigation failed (${i.status})`);return await i.json()}async function b(e,t,n,r,i){let a=await fetch(`${_(e)}/browser/sessions/${t}/capture`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({rect:n,pendingSpecId:r,captureNetwork:i?.captureNetwork??!0})});if(!a.ok)throw Error(await x(a));return await a.json()}async function x(e){let t=await e.json().then(e=>e.error).catch(()=>void 0);return t?`Capture failed (${e.status}): ${t}`:`Capture failed (${e.status})`}async function S(e,t,n,r,i,a=m){let o=await fetch(`${_(e)}/browser/sessions/${t}/capture-breakpoints`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({rect:n,anchorPoint:r,pendingSpecId:i,breakpoints:a})});if(!o.ok)throw Error(await x(o));return await o.json()}async function C(e,t,n){let r=new FormData;r.append(`file`,t,n);let i=await fetch(`${o()}/tickets/${e}/attachments`,{method:`POST`,body:r});if(!i.ok)throw Error(`Upload failed (${i.status})`);return(await i.json()).attachment}async function w(e,t,n,r){let i=await fetch(`${_(e)}/browser/sessions/${t}/clipboard`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:n,text:r})});if(!i.ok)throw Error(`Clipboard failed (${i.status})`);return await i.json()}async function T(e,t,n,r){let i=await fetch(`${_(e)}/browser/sessions/${t}/element`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({selector:n,direction:r})});if(!i.ok)throw Error(`Element navigate failed (${i.status})`);return(await i.json()).probe}async function E(e,t,n){try{await fetch(`${_(e)}/browser/sessions/${t}/popup-view`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({target:n})})}catch{}}function D(e){if(!e||e===`about:blank`)return`…`;try{return new URL(e).hostname||`…`}catch{return`…`}}async function O(e,t){try{await fetch(`${_(e)}/browser/sessions/${t}`,{method:`DELETE`})}catch{}}function k(e,t){return`${f||(typeof window<`u`?`${window.location.protocol===`https:`?`wss:`:`ws:`}//${window.location.host}`:`ws://localhost:4200`)}/ws/browser/${e}?projectId=${encodeURIComponent(t)}`}function A(e,t){let n=k(e,t),r=a(),i=r?new WebSocket(n,[`specrails-desktop`,r]):new WebSocket(n);return i.binaryType=`arraybuffer`,i}function j(e,t=e=>requestAnimationFrame(e),n=e=>cancelAnimationFrame(e)){let r=null,i=null,a=null,o=!1,s=()=>{a!=null&&(n(a),a=null);let t=r,o=i;r=null,i=null,t&&(!o||t.x!==o.x||t.y!==o.y)&&e({type:`mouse`,action:`move`,x:t.x,y:t.y}),o&&e({type:`wheel`,x:o.x,y:o.y,deltaX:o.deltaX,deltaY:o.deltaY})},c=()=>{a==null&&!o&&(a=t(()=>{a=null,s()}))};return{move(e,t){o||(r={x:e,y:t},c())},wheel(e,t,n,r){o||(i?(i.x=e,i.y=t,i.deltaX+=n,i.deltaY+=r):i={x:e,y:t,deltaX:n,deltaY:r},c())},flush(){o||s()},dispose(){o||(o=!0,a!=null&&(n(a),a=null),r=null,i=null)}}}function M(e,t,n){let r=t.width>0?(e.x-t.left)/t.width:0,i=t.height>0?(e.y-t.top)/t.height:0,a=Math.min(Math.max(r,0),1)*n.width,o=Math.min(Math.max(i,0),1)*n.height;return{x:Math.round(a),y:Math.round(o)}}function N(e,t,n){let r=n.width>0?t.width/n.width:0,i=n.height>0?t.height/n.height:0;return{left:t.left+e.x*r,top:t.top+e.y*i,width:e.width*r,height:e.height*i}}function P(e,t){return{x:Math.min(e.x,t.x),y:Math.min(e.y,t.y),width:Math.abs(e.x-t.x),height:Math.abs(e.y-t.y)}}function F(e,t=8){return e.width>=t&&e.height>=t}function I(e,t){let n=Math.max(1,t.width),r=Math.max(1,t.height),i=Math.max(0,Math.min(e.x,n-1)),a=Math.max(0,Math.min(e.y,r-1)),o=Math.min(n,Math.max(i+1,e.x+e.width)),s=Math.min(r,Math.max(a+1,e.y+e.height));return{x:Math.round(i),y:Math.round(a),width:Math.round(o-i),height:Math.round(s-a)}}function L(e){return{nodeCount:e.nodes.length,htmlBytes:e.html.length,truncated:e.htmlTruncated,networkCount:e.networkRequests?.length??0}}function R(e){let t=e.schedule??(e=>requestAnimationFrame(e)),n=e.cancel??(e=>cancelAnimationFrame(e)),r=e.now??(()=>typeof performance<`u`?performance.now():Date.now()),i=e.release??(()=>{}),a={received:0,decoded:0,drawn:0,droppedStale:0,droppedUndrawn:0,decodeMsTotal:0,drawMsTotal:0},o=!1,s=!1,c=null,l=null,u=null,d=()=>{u=null;let t=l;if(l=null,t==null||o){t!=null&&f(t);return}let n=r();try{e.draw(t),a.drawn++,a.drawMsTotal+=r()-n}catch{}finally{f(t)}},f=e=>{try{i(e)}catch{}},p=()=>{u==null&&!o&&(u=t(d))},m=t=>{s=!0;let n=r();e.decode(t).then(e=>{if(o){f(e);return}a.decoded++,a.decodeMsTotal+=r()-n,l!=null&&(a.droppedUndrawn++,f(l)),l=e,p(),h()},()=>{h()})},h=()=>{if(o){s=!1;return}let e=c;c=null,e==null?s=!1:m(e)};return{push(e){if(!o){if(a.received++,s){c!=null&&a.droppedStale++,c=e;return}m(e)}},stats(){return{...a}},dispose(){if(!o){if(o=!0,c=null,u!=null){try{n(u)}catch{}u=null}l!=null&&(f(l),l=null)}}}}var z=`specrails-desktop:browser-capture-debug`;function B(){try{return typeof localStorage<`u`&&localStorage.getItem(z)===`1`}catch{return!1}}function V(e,t,n){let r=Math.max(1,n),i=t.decoded-e.decoded,a=t.drawn-e.drawn,o=e=>Math.round(e*10)/10;return{fpsReceived:o((t.received-e.received)*1e3/r),fpsDrawn:o(a*1e3/r),droppedStale:t.droppedStale-e.droppedStale,droppedUndrawn:t.droppedUndrawn-e.droppedUndrawn,avgDecodeMs:i>0?o((t.decodeMsTotal-e.decodeMsTotal)/i):0,avgDrawMs:a>0?o((t.drawMsTotal-e.drawMsTotal)/a):0}}function H(e,t=e=>console.table([e]),n=2e3,r=()=>Date.now()){let i=e(),a=r(),o=setInterval(()=>{let n=e(),o=r();t(V(i,n,o-a)),i=n,a=o},n);return()=>clearInterval(o)}function U(e){let{projectId:t,open:r,initialUrl:i}=e,a=(0,u.useRef)(null),o=(0,u.useRef)(null),s=(0,u.useRef)(null),c=(0,u.useRef)(0),l=(0,u.useRef)(new Map),d=(0,u.useCallback)(()=>{if(c.current!==0||l.current.size===0)return;let e=[...l.current.values()];l.current.clear();for(let t of e)O(t.projectId,t.sessionId)},[]),[f,p]=(0,u.useState)({status:`connecting`,errorMsg:null,url:null,title:null,viewport:{width:1280,height:800},hoverRect:null,hoverSelector:null,hoverPath:null,popup:null});(0,u.useEffect)(()=>{if(!r||!t)return;let e=!1,u=null;p(e=>({...e,status:`connecting`,errorMsg:null,popup:null}));let d=R({decode:e=>createImageBitmap(new Blob([e],{type:`image/jpeg`})),draw:e=>{let t=a.current;t&&(t.width!==e.width&&(t.width=e.width),t.height!==e.height&&(t.height=e.height),t.getContext(`2d`)?.drawImage(e,0,0))},release:e=>e.close()}),f=B()?H(()=>d.stats()):null;return(async()=>{try{let r=await v(t,i);if(e){O(t,r.id);return}u=r.id,s.current={id:r.id,projectId:t},p(e=>({...e,url:r.url,title:r.title,viewport:{width:r.viewportWidth,height:r.viewportHeight}}));let a=A(r.id,t);o.current=a,a.onmessage=e=>{if(typeof e.data==`string`){try{let t=JSON.parse(e.data);if(t.type===`ready`)p(e=>({...e,status:`ready`,url:t.url??e.url,title:t.title??e.title,viewport:t.viewport??e.viewport}));else if(t.type===`nav`)p(e=>({...e,url:t.url??e.url,title:t.title??e.title}));else if(t.type===`hover`)p(e=>({...e,hoverRect:t.rect??null,hoverSelector:t.selector??null,hoverPath:t.path??null}));else if(t.type===`popup`){let e=typeof t.count==`number`?t.count:0;p(n=>({...n,popup:e>0?{count:e,active:t.active===!0,url:t.url??null}:null}))}}catch{}return}d.push(e.data)},a.onopen=()=>{e||p(e=>({...e,status:`ready`}))},a.onerror=()=>{e||p(e=>({...e,status:`error`,errorMsg:n.t(`browser:session.connectionError`)}))},a.onclose=()=>{e||p(e=>e.status===`ready`?{...e,status:`error`,errorMsg:n.t(`browser:session.lostConnection`)}:e)}}catch(t){if(e)return;let r=t instanceof h?n.t(`browser:session.tooManySessions`):t instanceof g?n.t(`browser:session.launchFailed`):n.t(`browser:session.openFailed`);p(e=>({...e,status:`error`,errorMsg:r}))}})(),()=>{e=!0,f?.(),d.dispose();let n=o.current;if(n){n.onmessage=null,n.onopen=null,n.onerror=null,n.onclose=null;try{n.close()}catch{}}o.current=null;let r=u;r&&s.current?.id===r&&s.current.projectId===t&&(s.current=null),r&&(c.current>0?l.current.set(`${t}\0${r}`,{sessionId:r,projectId:t}):O(t,r))}},[r,t,i,d]);let m=(0,u.useCallback)(e=>{let t=o.current;if(t&&t.readyState===WebSocket.OPEN)try{t.send(JSON.stringify({type:`input`,event:e}))}catch{}},[]),_=(0,u.useCallback)(async(e,t)=>{let n=s.current;if(n)try{let r=await y(n.projectId,n.id,e,t);if(s.current?.id!==n.id||s.current.projectId!==n.projectId)return;p(e=>({...e,url:r.url,title:r.title}))}catch{}},[]),x=(0,u.useCallback)(async(e,t,n)=>{let r=s.current;if(!r)throw Error(`No active browser session`);c.current+=1;try{return await b(r.projectId,r.id,e,t,n)}finally{c.current=Math.max(0,c.current-1),d()}},[d]),C=(0,u.useCallback)(async(e,t,n,r)=>{let i=s.current;if(!i)throw Error(`No active browser session`);c.current+=1;try{return await S(i.projectId,i.id,e,t,n,r)}finally{c.current=Math.max(0,c.current-1),d()}},[d]),D=(0,u.useCallback)(async(e,t)=>{let n=s.current;return n?w(n.projectId,n.id,e,t):{text:``}},[]),k=(0,u.useCallback)((e,t)=>{let n=Math.max(1,Math.round(e)),r=Math.max(1,Math.round(t));p(e=>({...e,viewport:{width:n,height:r}})),m({type:`resize`,width:n,height:r})},[m]),j=(0,u.useCallback)(e=>{let t=o.current;if(t&&t.readyState===WebSocket.OPEN)try{t.send(JSON.stringify({type:`probe`,x:e.x,y:e.y}))}catch{}},[]),M=(0,u.useCallback)(()=>{p(e=>e.hoverRect||e.hoverPath?{...e,hoverRect:null,hoverSelector:null,hoverPath:null}:e)},[]),N=(0,u.useCallback)(async(e,t)=>{let n=s.current;return n?T(n.projectId,n.id,e,t):null},[]),P=(0,u.useCallback)(e=>{let t=s.current;t&&(p(t=>t.popup?{...t,popup:{...t.popup,active:e===`popup`}}:t),E(t.projectId,t.id,e))},[]);return{...f,canvasRef:a,forwardInput:m,navigate:_,capture:x,captureBreakpoints:C,clipboard:D,navigateElement:N,setViewport:k,probe:j,clearHover:M,setPopupView:P}}export{L as a,M as c,P as d,C as f,s as g,c as h,j as i,N as l,l as m,m as n,p as o,f as p,I as r,F as s,U as t,D as u};
|
|
1
|
+
import{a as e}from"./rolldown-runtime-CNC7AqOf.js";import{n as t}from"./jsx-runtime-zu2_FqZY.js";import{o as n}from"./i18n-B2SaZsf2.js";import{t as r}from"./createLucideIcon-Bjbbp_KS.js";import{a as i,n as a}from"./auth-D_5bQv5W.js";import{t as o}from"./api-B2M7CtDw.js";var s=r(`arrow-right`,[[`path`,{d:`M5 12h14`,key:`1ays0h`}],[`path`,{d:`m12 5 7 7-7 7`,key:`xquz4c`}]]),c=r(`globe`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`path`,{d:`M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20`,key:`13o1zl`}],[`path`,{d:`M2 12h20`,key:`9i4pu4`}]]),l=r(`rotate-cw`,[[`path`,{d:`M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8`,key:`1p45f6`}],[`path`,{d:`M21 3v5h-5`,key:`1q7to0`}]]),u=e(t(),1);function d(){return typeof window<`u`&&`__TAURI_INTERNALS__`in window||typeof window<`u`&&window.location.protocol!==`http:`&&window.location.protocol!==`https:`?`ws://localhost:4200`:`${window.location.protocol===`https:`?`wss:`:`ws:`}//${window.location.host}`}var f=d();function p(){let e={BASE_URL:`/`,DEV:!1,MODE:`production`,PROD:!0,SSR:!1}.VITE_FEATURE_BROWSER_CAPTURE;return typeof e!=`string`||e!==`false`}var m={desktop:{width:1280,height:800},tablet:{width:768,height:1024},mobile:{width:375,height:667}},h=class extends Error{},g=class extends Error{};function _(e){if(!e)throw Error(`A project owner is required for browser sessions`);return`${i}/api/projects/${encodeURIComponent(e)}`}async function v(e,t){let n=await fetch(`${_(e)}/browser/sessions`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({initialUrl:t})});if(n.status===409)throw new h(`Too many open browser sessions`);if(n.status===502)throw new g(`The browser failed to launch`);if(!n.ok)throw Error(`Failed to open browser (${n.status})`);return(await n.json()).session}async function y(e,t,n,r){let i=await fetch(`${_(e)}/browser/sessions/${t}/navigate`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:n,url:r})});if(!i.ok)throw Error(`Navigation failed (${i.status})`);return await i.json()}async function b(e,t,n,r,i){let a=await fetch(`${_(e)}/browser/sessions/${t}/capture`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({rect:n,pendingSpecId:r,captureNetwork:i?.captureNetwork??!0})});if(!a.ok)throw Error(await x(a));return await a.json()}async function x(e){let t=await e.json().then(e=>e.error).catch(()=>void 0);return t?`Capture failed (${e.status}): ${t}`:`Capture failed (${e.status})`}async function S(e,t,n,r,i,a=m){let o=await fetch(`${_(e)}/browser/sessions/${t}/capture-breakpoints`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({rect:n,anchorPoint:r,pendingSpecId:i,breakpoints:a})});if(!o.ok)throw Error(await x(o));return await o.json()}async function C(e,t,n){let r=new FormData;r.append(`file`,t,n);let i=await fetch(`${o()}/tickets/${e}/attachments`,{method:`POST`,body:r});if(!i.ok)throw Error(`Upload failed (${i.status})`);return(await i.json()).attachment}async function w(e,t,n,r){let i=await fetch(`${_(e)}/browser/sessions/${t}/clipboard`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:n,text:r})});if(!i.ok)throw Error(`Clipboard failed (${i.status})`);return await i.json()}async function T(e,t,n,r){let i=await fetch(`${_(e)}/browser/sessions/${t}/element`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({selector:n,direction:r})});if(!i.ok)throw Error(`Element navigate failed (${i.status})`);return(await i.json()).probe}async function E(e,t,n){try{await fetch(`${_(e)}/browser/sessions/${t}/popup-view`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({target:n})})}catch{}}function D(e){if(!e||e===`about:blank`)return`…`;try{return new URL(e).hostname||`…`}catch{return`…`}}async function O(e,t){try{await fetch(`${_(e)}/browser/sessions/${t}`,{method:`DELETE`})}catch{}}function k(e,t){return`${f||(typeof window<`u`?`${window.location.protocol===`https:`?`wss:`:`ws:`}//${window.location.host}`:`ws://localhost:4200`)}/ws/browser/${e}?projectId=${encodeURIComponent(t)}`}function A(e,t){let n=k(e,t),r=a(),i=r?new WebSocket(n,[`specrails-desktop`,r]):new WebSocket(n);return i.binaryType=`arraybuffer`,i}function j(e,t=e=>requestAnimationFrame(e),n=e=>cancelAnimationFrame(e)){let r=null,i=null,a=null,o=!1,s=()=>{a!=null&&(n(a),a=null);let t=r,o=i;r=null,i=null,t&&(!o||t.x!==o.x||t.y!==o.y)&&e({type:`mouse`,action:`move`,x:t.x,y:t.y}),o&&e({type:`wheel`,x:o.x,y:o.y,deltaX:o.deltaX,deltaY:o.deltaY})},c=()=>{a==null&&!o&&(a=t(()=>{a=null,s()}))};return{move(e,t){o||(r={x:e,y:t},c())},wheel(e,t,n,r){o||(i?(i.x=e,i.y=t,i.deltaX+=n,i.deltaY+=r):i={x:e,y:t,deltaX:n,deltaY:r},c())},flush(){o||s()},dispose(){o||(o=!0,a!=null&&(n(a),a=null),r=null,i=null)}}}function M(e,t,n){let r=t.width>0?(e.x-t.left)/t.width:0,i=t.height>0?(e.y-t.top)/t.height:0,a=Math.min(Math.max(r,0),1)*n.width,o=Math.min(Math.max(i,0),1)*n.height;return{x:Math.round(a),y:Math.round(o)}}function N(e,t,n){let r=n.width>0?t.width/n.width:0,i=n.height>0?t.height/n.height:0;return{left:t.left+e.x*r,top:t.top+e.y*i,width:e.width*r,height:e.height*i}}function P(e,t){return{x:Math.min(e.x,t.x),y:Math.min(e.y,t.y),width:Math.abs(e.x-t.x),height:Math.abs(e.y-t.y)}}function F(e,t=8){return e.width>=t&&e.height>=t}function I(e,t){let n=Math.max(1,t.width),r=Math.max(1,t.height),i=Math.max(0,Math.min(e.x,n-1)),a=Math.max(0,Math.min(e.y,r-1)),o=Math.min(n,Math.max(i+1,e.x+e.width)),s=Math.min(r,Math.max(a+1,e.y+e.height));return{x:Math.round(i),y:Math.round(a),width:Math.round(o-i),height:Math.round(s-a)}}function L(e){return{nodeCount:e.nodes.length,htmlBytes:e.html.length,truncated:e.htmlTruncated,networkCount:e.networkRequests?.length??0}}function R(e){let t=e.schedule??(e=>requestAnimationFrame(e)),n=e.cancel??(e=>cancelAnimationFrame(e)),r=e.now??(()=>typeof performance<`u`?performance.now():Date.now()),i=e.release??(()=>{}),a={received:0,decoded:0,drawn:0,droppedStale:0,droppedUndrawn:0,decodeMsTotal:0,drawMsTotal:0},o=!1,s=!1,c=null,l=null,u=null,d=()=>{u=null;let t=l;if(l=null,t==null||o){t!=null&&f(t);return}let n=r();try{e.draw(t),a.drawn++,a.drawMsTotal+=r()-n}catch{}finally{f(t)}},f=e=>{try{i(e)}catch{}},p=()=>{u==null&&!o&&(u=t(d))},m=t=>{s=!0;let n=r();e.decode(t).then(e=>{if(o){f(e);return}a.decoded++,a.decodeMsTotal+=r()-n,l!=null&&(a.droppedUndrawn++,f(l)),l=e,p(),h()},()=>{h()})},h=()=>{if(o){s=!1;return}let e=c;c=null,e==null?s=!1:m(e)};return{push(e){if(!o){if(a.received++,s){c!=null&&a.droppedStale++,c=e;return}m(e)}},stats(){return{...a}},dispose(){if(!o){if(o=!0,c=null,u!=null){try{n(u)}catch{}u=null}l!=null&&(f(l),l=null)}}}}var z=`specrails-desktop:browser-capture-debug`;function B(){try{return typeof localStorage<`u`&&localStorage.getItem(z)===`1`}catch{return!1}}function V(e,t,n){let r=Math.max(1,n),i=t.decoded-e.decoded,a=t.drawn-e.drawn,o=e=>Math.round(e*10)/10;return{fpsReceived:o((t.received-e.received)*1e3/r),fpsDrawn:o(a*1e3/r),droppedStale:t.droppedStale-e.droppedStale,droppedUndrawn:t.droppedUndrawn-e.droppedUndrawn,avgDecodeMs:i>0?o((t.decodeMsTotal-e.decodeMsTotal)/i):0,avgDrawMs:a>0?o((t.drawMsTotal-e.drawMsTotal)/a):0}}function H(e,t=e=>console.table([e]),n=2e3,r=()=>Date.now()){let i=e(),a=r(),o=setInterval(()=>{let n=e(),o=r();t(V(i,n,o-a)),i=n,a=o},n);return()=>clearInterval(o)}function U(e){let{projectId:t,open:r,initialUrl:i}=e,a=(0,u.useRef)(null),o=(0,u.useRef)(null),s=(0,u.useRef)(null),c=(0,u.useRef)(0),l=(0,u.useRef)(new Map),d=(0,u.useCallback)(()=>{if(c.current!==0||l.current.size===0)return;let e=[...l.current.values()];l.current.clear();for(let t of e)O(t.projectId,t.sessionId)},[]),[f,p]=(0,u.useState)({status:`connecting`,errorMsg:null,url:null,title:null,viewport:{width:1280,height:800},hoverRect:null,hoverSelector:null,hoverPath:null,popup:null});(0,u.useEffect)(()=>{if(!r||!t)return;let e=!1,u=null;p(e=>({...e,status:`connecting`,errorMsg:null,popup:null}));let d=R({decode:e=>createImageBitmap(new Blob([e],{type:`image/jpeg`})),draw:e=>{let t=a.current;t&&(t.width!==e.width&&(t.width=e.width),t.height!==e.height&&(t.height=e.height),t.getContext(`2d`)?.drawImage(e,0,0))},release:e=>e.close()}),f=B()?H(()=>d.stats()):null;return(async()=>{try{let r=await v(t,i);if(e){O(t,r.id);return}u=r.id,s.current={id:r.id,projectId:t},p(e=>({...e,url:r.url,title:r.title,viewport:{width:r.viewportWidth,height:r.viewportHeight}}));let a=A(r.id,t);o.current=a,a.onmessage=e=>{if(typeof e.data==`string`){try{let t=JSON.parse(e.data);if(t.type===`ready`)p(e=>({...e,status:`ready`,url:t.url??e.url,title:t.title??e.title,viewport:t.viewport??e.viewport}));else if(t.type===`nav`)p(e=>({...e,url:t.url??e.url,title:t.title??e.title}));else if(t.type===`hover`)p(e=>({...e,hoverRect:t.rect??null,hoverSelector:t.selector??null,hoverPath:t.path??null}));else if(t.type===`popup`){let e=typeof t.count==`number`?t.count:0;p(n=>({...n,popup:e>0?{count:e,active:t.active===!0,url:t.url??null}:null}))}}catch{}return}d.push(e.data)},a.onopen=()=>{e||p(e=>({...e,status:`ready`}))},a.onerror=()=>{e||p(e=>({...e,status:`error`,errorMsg:n.t(`browser:session.connectionError`)}))},a.onclose=()=>{e||p(e=>e.status===`ready`?{...e,status:`error`,errorMsg:n.t(`browser:session.lostConnection`)}:e)}}catch(t){if(e)return;let r=t instanceof h?n.t(`browser:session.tooManySessions`):t instanceof g?n.t(`browser:session.launchFailed`):n.t(`browser:session.openFailed`);p(e=>({...e,status:`error`,errorMsg:r}))}})(),()=>{e=!0,f?.(),d.dispose();let n=o.current;if(n){n.onmessage=null,n.onopen=null,n.onerror=null,n.onclose=null;try{n.close()}catch{}}o.current=null;let r=u;r&&s.current?.id===r&&s.current.projectId===t&&(s.current=null),r&&(c.current>0?l.current.set(`${t}\0${r}`,{sessionId:r,projectId:t}):O(t,r))}},[r,t,i,d]);let m=(0,u.useCallback)(e=>{let t=o.current;if(t&&t.readyState===WebSocket.OPEN)try{t.send(JSON.stringify({type:`input`,event:e}))}catch{}},[]),_=(0,u.useCallback)(async(e,t)=>{let n=s.current;if(n)try{let r=await y(n.projectId,n.id,e,t);if(s.current?.id!==n.id||s.current.projectId!==n.projectId)return;p(e=>({...e,url:r.url,title:r.title}))}catch{}},[]),x=(0,u.useCallback)(async(e,t,n)=>{let r=s.current;if(!r)throw Error(`No active browser session`);c.current+=1;try{return await b(r.projectId,r.id,e,t,n)}finally{c.current=Math.max(0,c.current-1),d()}},[d]),C=(0,u.useCallback)(async(e,t,n,r)=>{let i=s.current;if(!i)throw Error(`No active browser session`);c.current+=1;try{return await S(i.projectId,i.id,e,t,n,r)}finally{c.current=Math.max(0,c.current-1),d()}},[d]),D=(0,u.useCallback)(async(e,t)=>{let n=s.current;return n?w(n.projectId,n.id,e,t):{text:``}},[]),k=(0,u.useCallback)((e,t)=>{let n=Math.max(1,Math.round(e)),r=Math.max(1,Math.round(t));p(e=>({...e,viewport:{width:n,height:r}})),m({type:`resize`,width:n,height:r})},[m]),j=(0,u.useCallback)(e=>{let t=o.current;if(t&&t.readyState===WebSocket.OPEN)try{t.send(JSON.stringify({type:`probe`,x:e.x,y:e.y}))}catch{}},[]),M=(0,u.useCallback)(()=>{p(e=>e.hoverRect||e.hoverPath?{...e,hoverRect:null,hoverSelector:null,hoverPath:null}:e)},[]),N=(0,u.useCallback)(async(e,t)=>{let n=s.current;return n?T(n.projectId,n.id,e,t):null},[]),P=(0,u.useCallback)(e=>{let t=s.current;t&&(p(t=>t.popup?{...t,popup:{...t.popup,active:e===`popup`}}:t),E(t.projectId,t.id,e))},[]);return{...f,canvasRef:a,forwardInput:m,navigate:_,capture:x,captureBreakpoints:C,clipboard:D,navigateElement:N,setViewport:k,probe:j,clearHover:M,setPopupView:P}}export{L as a,M as c,P as d,C as f,s as g,c as h,j as i,N as l,l as m,m as n,p as o,f as p,I as r,F as s,U as t,D as u};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as e}from"./rolldown-runtime-CNC7AqOf.js";import{n as t,t as n}from"./jsx-runtime-zu2_FqZY.js";import{o as r}from"./i18n-
|
|
1
|
+
import{a as e}from"./rolldown-runtime-CNC7AqOf.js";import{n as t,t as n}from"./jsx-runtime-zu2_FqZY.js";import{o as r}from"./i18n-B2SaZsf2.js";import{n as i}from"./dist-bVqfYmby.js";import{a}from"./auth-D_5bQv5W.js";import{n as o}from"./useSharedWebSocket-DaPh7QBL.js";import{n as s}from"./api-B2M7CtDw.js";var c=e(t(),1),l=new Map;function u(e,t){return`${e}:${t}`}function d(e){return(e instanceof Error?e.message:e==null?``:String(e)).trim()||`Request failed`}function f(e){if(!e)return;let t=`${e}:`;for(let e of l.keys())e.startsWith(t)&&l.delete(e)}function p({namespace:e,projectId:t,initialValue:n,fetcher:r,pollInterval:i=0}){let a=t?u(t,e):null,[o,s]=(0,c.useState)(()=>a&&l.has(a)?l.get(a):n),[f,p]=(0,c.useState)(()=>!a||!l.has(a)),[m,h]=(0,c.useState)(f),[g,_]=(0,c.useState)(null),v=(0,c.useRef)(r);v.current=r;let y=(0,c.useRef)(n);y.current=n;let b=(0,c.useRef)(a);b.current=a;let x=(0,c.useRef)(0),S=(0,c.useRef)(null),C=(0,c.useCallback)(async(e,t,n)=>{let r=++x.current;S.current?.abort();let i=new AbortController;S.current=i,n&&b.current===e&&(h(!0),_(null));try{let n=await v.current({projectId:t,signal:i.signal});if(i.signal.aborted||r!==x.current)return;l.set(e,n),b.current===e&&(s(n),_(null))}catch(t){if(i.signal.aborted||r!==x.current)return;b.current===e&&_(d(t))}finally{r===x.current&&(S.current===i&&(S.current=null),b.current===e&&(h(!1),p(!1)))}},[]);return(0,c.useEffect)(()=>{if(x.current+=1,S.current?.abort(),S.current=null,_(null),!a||!t){s(y.current),p(!0),h(!1);return}let e=l.has(a);e?(s(l.get(a)),p(!1),h(!1)):(s(y.current),p(!0),h(!0)),C(a,t,!e);let n;return i>0&&(n=setInterval(()=>{C(a,t,!1)},i)),()=>{x.current+=1,S.current?.abort(),S.current=null,n&&clearInterval(n)}},[a,t,i,C]),{data:o,isLoading:m,isFirstLoad:f,error:g,refresh:(0,c.useCallback)(async()=>{!a||!t||await C(a,t,!0)},[a,t,C])}}var m=n();function h(e){return e.providers&&e.providers.length>0?e.providers:[e.provider]}var g=(0,c.createContext)(null),_=`specrails-desktop:activeProjectId`;function v(e){try{e?localStorage.setItem(_,e):localStorage.removeItem(_)}catch{}}function y(){try{return localStorage.getItem(_)}catch{return null}}function b({children:e}){let[t,n]=(0,c.useState)([]),[l,u]=(0,c.useState)(null),[d,p]=(0,c.useState)(!0),[h,_]=(0,c.useState)(!1),[b,x]=(0,c.useState)(new Set),S=(0,c.useRef)(null),C=(0,c.useRef)(new Set),w=(0,c.useCallback)(e=>{v(e),s(e),u(t=>(t!==null&&t!==e&&(S.current&&clearTimeout(S.current),_(!0),S.current=setTimeout(()=>_(!1),400)),e))},[]),{registerHandler:T,unregisterHandler:E}=o();(0,c.useEffect)(()=>{async function e(){try{let e=await fetch(`${a}/api/projects`);if(!e.ok)return;let t=await e.json();n(t.projects),t.setupProjectIds&&t.setupProjectIds.length>0&&x(new Set(t.setupProjectIds))}catch{}finally{p(!1)}}e()},[]);let D=(0,c.useCallback)(e=>{let t=e;if(typeof t.type==`string`){if(t.type===`desktop.projects`){if(!Array.isArray(t.projects))return;let e=t.projects;n(e),u(t=>{let n;if(t&&e.find(e=>e.id===t))n=t;else{let t=y();n=t&&e.find(e=>e.id===t)?t:e.length>0?e[0].id:null}return v(n),s(n),n}),p(!1)}else if(t.type===`desktop.project_added`){let e=t.project;n(t=>t.find(t=>t.id===e.id)?t:[...t,e]),C.current.has(e.id)?C.current.delete(e.id):(i.success(r.t(`nav:projects.added`,{name:e.name})),w(e.id))}else if(t.type===`desktop.project_removed`){let e=t.projectId;i.success(r.t(`nav:projects.removed`)),f(e),n(t=>t.filter(t=>t.id!==e)),u(t=>t===e?(v(null),s(null),null):t)}}},[]);(0,c.useLayoutEffect)(()=>(T(`desktop`,D),()=>E(`desktop`)),[D,T,E]);let O=(0,c.useCallback)(async(e,t,r=[`claude`])=>{try{let i={path:e,providers:r.length>0?r:[`claude`]};t&&(i.name=t);let a=await fetch(`/api/projects`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify(i)});if(!a.ok){let e=await a.json();throw Error(e.error??`HTTP ${a.status}`)}let o=await a.json();return C.current.add(o.project.id),n(e=>e.find(e=>e.id===o.project.id)?e:[...e,o.project]),w(o.project.id),o}catch(e){throw console.error(`[useDesktop] addProject error:`,e),e}},[w]),k=(0,c.useCallback)(async e=>{try{let t=await fetch(`${a}/api/projects/${e}`,{method:`DELETE`});if(!t.ok){let e=await t.json();throw Error(e.error??`HTTP ${t.status}`)}f(e),n(t=>t.filter(t=>t.id!==e)),x(t=>{if(!t.has(e))return t;let n=new Set(t);return n.delete(e),n}),u(t=>t===e?(v(null),s(null),null):t)}catch(e){throw console.error(`[useDesktop] removeProject error:`,e),e}},[]),A=(0,c.useCallback)(e=>{x(t=>new Set([...t,e]))},[]),j=(0,c.useCallback)(e=>{x(t=>{let n=new Set(t);return n.delete(e),n})},[]),M=(0,c.useMemo)(()=>({projects:t,activeProjectId:l,setActiveProjectId:w,addProject:O,removeProject:k,isLoading:d,isSwitchingProject:h,setupProjectIds:b,startSetupWizard:A,completeSetupWizard:j}),[t,l,w,O,k,d,h,b,A,j]);return(0,m.jsx)(g.Provider,{value:M,children:e})}var x={projects:[],activeProjectId:null,setActiveProjectId:()=>{},addProject:async()=>null,removeProject:async()=>{},isLoading:!1,isSwitchingProject:!1,setupProjectIds:new Set,startSetupWizard:()=>{},completeSetupWizard:()=>{}};function S(){return(0,c.useContext)(g)??x}export{p as i,h as n,S as r,b as t};
|
package/client/dist/index.html
CHANGED
|
@@ -204,7 +204,7 @@
|
|
|
204
204
|
.specrails-splash__mark .pill { opacity: 1; }
|
|
205
205
|
}
|
|
206
206
|
</style>
|
|
207
|
-
<script type="module" crossorigin src="/assets/index-
|
|
207
|
+
<script type="module" crossorigin src="/assets/index-Bpzm94S9.js"></script>
|
|
208
208
|
<link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-CNC7AqOf.js">
|
|
209
209
|
<link rel="modulepreload" crossorigin href="/assets/jsx-runtime-zu2_FqZY.js">
|
|
210
210
|
<link rel="modulepreload" crossorigin href="/assets/react-dom-DiWzBDP9.js">
|
|
@@ -215,7 +215,7 @@
|
|
|
215
215
|
<link rel="modulepreload" crossorigin href="/assets/addspec-x3mizDxc.js">
|
|
216
216
|
<link rel="modulepreload" crossorigin href="/assets/agent-Bs9NilfI.js">
|
|
217
217
|
<link rel="modulepreload" crossorigin href="/assets/agents-ms7TwG16.js">
|
|
218
|
-
<link rel="modulepreload" crossorigin href="/assets/agentstudio-
|
|
218
|
+
<link rel="modulepreload" crossorigin href="/assets/agentstudio-CN2pokQu.js">
|
|
219
219
|
<link rel="modulepreload" crossorigin href="/assets/aiedit-iIjz2_Qk.js">
|
|
220
220
|
<link rel="modulepreload" crossorigin href="/assets/analytics-BHqUazhP.js">
|
|
221
221
|
<link rel="modulepreload" crossorigin href="/assets/attachments-B53PG733.js">
|
|
@@ -230,27 +230,27 @@
|
|
|
230
230
|
<link rel="modulepreload" crossorigin href="/assets/integrations-mB-7zoyT.js">
|
|
231
231
|
<link rel="modulepreload" crossorigin href="/assets/jira-CmKWERE0.js">
|
|
232
232
|
<link rel="modulepreload" crossorigin href="/assets/jobs-B_TeSQxb.js">
|
|
233
|
-
<link rel="modulepreload" crossorigin href="/assets/loops-
|
|
233
|
+
<link rel="modulepreload" crossorigin href="/assets/loops-CnxqL8IL.js">
|
|
234
234
|
<link rel="modulepreload" crossorigin href="/assets/mcp-uDkXYu4L.js">
|
|
235
235
|
<link rel="modulepreload" crossorigin href="/assets/nav-VaB-C4k5.js">
|
|
236
236
|
<link rel="modulepreload" crossorigin href="/assets/settings-CuVwOpe0.js">
|
|
237
|
-
<link rel="modulepreload" crossorigin href="/assets/setup-
|
|
237
|
+
<link rel="modulepreload" crossorigin href="/assets/setup-D73npsqO.js">
|
|
238
238
|
<link rel="modulepreload" crossorigin href="/assets/specs-DII0C8gw.js">
|
|
239
239
|
<link rel="modulepreload" crossorigin href="/assets/terminal-BFRZnMPP.js">
|
|
240
240
|
<link rel="modulepreload" crossorigin href="/assets/tickets-CqqOHbli.js">
|
|
241
|
-
<link rel="modulepreload" crossorigin href="/assets/i18n-
|
|
242
|
-
<link rel="modulepreload" crossorigin href="/assets/Trans-
|
|
241
|
+
<link rel="modulepreload" crossorigin href="/assets/i18n-B2SaZsf2.js">
|
|
242
|
+
<link rel="modulepreload" crossorigin href="/assets/Trans-CpUoGvNy.js">
|
|
243
243
|
<link rel="modulepreload" crossorigin href="/assets/dist-bVqfYmby.js">
|
|
244
244
|
<link rel="modulepreload" crossorigin href="/assets/arrow-left-CpIR4j7G.js">
|
|
245
245
|
<link rel="modulepreload" crossorigin href="/assets/auth-D_5bQv5W.js">
|
|
246
246
|
<link rel="modulepreload" crossorigin href="/assets/api-B2M7CtDw.js">
|
|
247
|
-
<link rel="modulepreload" crossorigin href="/assets/useBrowserCaptureSession-
|
|
247
|
+
<link rel="modulepreload" crossorigin href="/assets/useBrowserCaptureSession-DACautTD.js">
|
|
248
248
|
<link rel="modulepreload" crossorigin href="/assets/arrow-up-right-9DoMn7fD.js">
|
|
249
249
|
<link rel="modulepreload" crossorigin href="/assets/sparkles-DrY8hb0X.js">
|
|
250
250
|
<link rel="modulepreload" crossorigin href="/assets/x-CBMI9ejn.js">
|
|
251
251
|
<link rel="modulepreload" crossorigin href="/assets/useSharedWebSocket-DaPh7QBL.js">
|
|
252
|
-
<link rel="modulepreload" crossorigin href="/assets/useDesktop-
|
|
253
|
-
<link rel="modulepreload" crossorigin href="/assets/MinimizedChatsContext-
|
|
252
|
+
<link rel="modulepreload" crossorigin href="/assets/useDesktop-Cwyis9DX.js">
|
|
253
|
+
<link rel="modulepreload" crossorigin href="/assets/MinimizedChatsContext-BQQohTp2.js">
|
|
254
254
|
<link rel="modulepreload" crossorigin href="/assets/external-link-BcU5EWZp.js">
|
|
255
255
|
<link rel="modulepreload" crossorigin href="/assets/chevron-right-CViMxucY.js">
|
|
256
256
|
<link rel="modulepreload" crossorigin href="/assets/circle-x-CMYsN4ZH.js">
|
|
@@ -274,11 +274,11 @@
|
|
|
274
274
|
<link rel="modulepreload" crossorigin href="/assets/jira-api-BgFIr8eD.js">
|
|
275
275
|
<link rel="modulepreload" crossorigin href="/assets/provider-capabilities-BvoExILy.js">
|
|
276
276
|
<link rel="modulepreload" crossorigin href="/assets/lib-CGdyxIWg.js">
|
|
277
|
-
<link rel="modulepreload" crossorigin href="/assets/getTimezoneOffsetInMilliseconds-
|
|
278
|
-
<link rel="modulepreload" crossorigin href="/assets/formatDistanceToNow-
|
|
279
|
-
<link rel="modulepreload" crossorigin href="/assets/spending-
|
|
280
|
-
<link rel="modulepreload" crossorigin href="/assets/TicketDetailModal-
|
|
281
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
277
|
+
<link rel="modulepreload" crossorigin href="/assets/getTimezoneOffsetInMilliseconds-B_N-0uSl.js">
|
|
278
|
+
<link rel="modulepreload" crossorigin href="/assets/formatDistanceToNow-2bGOYubE.js">
|
|
279
|
+
<link rel="modulepreload" crossorigin href="/assets/spending-B20-uFLQ.js">
|
|
280
|
+
<link rel="modulepreload" crossorigin href="/assets/TicketDetailModal-DEoAJOuD.js">
|
|
281
|
+
<link rel="stylesheet" crossorigin href="/assets/index-ChIuonbC.css">
|
|
282
282
|
</head>
|
|
283
283
|
<body>
|
|
284
284
|
<div id="specrails-splash" aria-hidden="false" role="status" aria-label="Loading Specrails">
|
package/package.json
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.InvalidSurfaceError = void 0;
|
|
4
4
|
exports.recordInvocation = recordInvocation;
|
|
5
|
+
exports.sumInvocationCostForRuns = sumInvocationCostForRuns;
|
|
5
6
|
exports.updateTicketIdForConversation = updateTicketIdForConversation;
|
|
6
7
|
exports.listInvocationsForConversation = listInvocationsForConversation;
|
|
7
8
|
exports.getTicketSpendingSummary = getTicketSpendingSummary;
|
|
@@ -45,6 +46,40 @@ function recordInvocation(db, input) {
|
|
|
45
46
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
46
47
|
`).run(input.id, input.project_id, input.provider, input.surface, input.surface_ref_id ?? null, input.ticket_id ?? null, input.conversation_id ?? null, input.model ?? null, input.status, input.started_at, input.finished_at ?? null, input.duration_ms ?? null, input.duration_api_ms ?? null, input.tokens_in ?? null, input.tokens_out ?? null, input.tokens_cache_read ?? null, input.tokens_cache_create ?? null, input.total_cost_usd ?? null, input.total_cost_usd_estimated ? 1 : 0, input.num_turns ?? null, input.session_id ?? null, input.loop_run_id ?? null);
|
|
47
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* Total AI spend attributable to a set of implementation runs, for the PR-body
|
|
51
|
+
* cost footer. A "run" id is either a loop_runs row id (loop AI-step/decider
|
|
52
|
+
* invocations link via `loop_run_id`) or a QueueManager job id (rows with
|
|
53
|
+
* surface='job' and `surface_ref_id` = the id, plus the merge-orchestrator's
|
|
54
|
+
* `<jobId>:merge:<step>` sub-rows). Failed/aborted rows count — they billed
|
|
55
|
+
* real tokens. Returns null when no priced rows match, so callers can omit
|
|
56
|
+
* the footer instead of printing $0.00 for legacy runs.
|
|
57
|
+
*/
|
|
58
|
+
function sumInvocationCostForRuns(db, runIds) {
|
|
59
|
+
const ids = [...new Set(runIds.filter((id) => typeof id === 'string' && id.length > 0))];
|
|
60
|
+
if (ids.length === 0)
|
|
61
|
+
return null;
|
|
62
|
+
const placeholders = ids.map(() => '?').join(', ');
|
|
63
|
+
const mergePrefixes = ids.map(() => `surface_ref_id LIKE ? ESCAPE '\\'`).join(' OR ');
|
|
64
|
+
const rows = db.prepare(`SELECT total_cost_usd, total_cost_usd_estimated FROM ai_invocations
|
|
65
|
+
WHERE total_cost_usd IS NOT NULL
|
|
66
|
+
AND (loop_run_id IN (${placeholders})
|
|
67
|
+
OR surface_ref_id IN (${placeholders})
|
|
68
|
+
OR ${mergePrefixes})`).all(...ids, ...ids, ...ids.map((id) => `${escapeLikePattern(id)}:merge:%`));
|
|
69
|
+
if (rows.length === 0)
|
|
70
|
+
return null;
|
|
71
|
+
let totalUsd = 0;
|
|
72
|
+
let estimated = false;
|
|
73
|
+
for (const row of rows) {
|
|
74
|
+
totalUsd += row.total_cost_usd;
|
|
75
|
+
if (row.total_cost_usd_estimated === 1)
|
|
76
|
+
estimated = true;
|
|
77
|
+
}
|
|
78
|
+
return { totalUsd, estimated };
|
|
79
|
+
}
|
|
80
|
+
function escapeLikePattern(value) {
|
|
81
|
+
return value.replace(/[\\%_]/g, (ch) => `\\${ch}`);
|
|
82
|
+
}
|
|
48
83
|
function updateTicketIdForConversation(db, conversationId, ticketId) {
|
|
49
84
|
const result = db.prepare(`UPDATE ai_invocations SET ticket_id = ? WHERE conversation_id = ? AND ticket_id IS NULL`).run(ticketId, conversationId);
|
|
50
85
|
return result.changes;
|