diff --git a/.agents/skills/communication-style/SKILL.md b/.agents/skills/communication-style/SKILL.md new file mode 100644 index 00000000..d1760fb8 --- /dev/null +++ b/.agents/skills/communication-style/SKILL.md @@ -0,0 +1,81 @@ +--- +name: communication-style +description: Use it always. +author: poteto (pstack) +--- + +# Communication style + +Edit text to remove AI patterns and add human voice. + +## Process + +1. Scan for the patterns below. +2. Rewrite. Preserve meaning, match intended tone. +3. Add soul (see next section). +4. Self-audit: "What makes this obviously AI generated?" Fix remaining tells. + +## Adding soul + +Removing patterns is half the job. Sterile, voiceless writing is just as obvious. + +- **Have opinions.** React to facts instead of neutrally listing pros and cons. +- **Vary rhythm.** Short sentences. Then longer ones that take their time. Mix it up. +- **Acknowledge complexity.** "Impressive but also kind of unsettling" beats "impressive." +- **Use "I" when it fits.** First person isn't unprofessional. +- **Let some mess in.** Perfect structure looks machine-made. +- **Be specific.** Not "this is concerning" but "there's something unsettling about agents churning away at 3am." + +## Patterns to detect and fix + +### Content + +1. **Puffery.** "pivotal moment", "testament to", "evolving landscape", "setting the stage for", "indelible mark", "deeply rooted". Cut puffery, state what happened. +2. **Name-dropping.** Listing media outlets without context. Pick one, say what was said. +3. **Superficial -ing phrases.** "highlighting...", "ensuring...", "reflecting...", "showcasing...", "fostering...". Delete or expand with real sources. +4. **Promotional language.** "nestled", "vibrant", "breathtaking", "groundbreaking", "renowned", "stunning", "must-visit". Use neutral descriptions. +5. **Vague attributions.** "Experts believe", "Industry reports suggest", "Some critics argue". Name the source or delete. +6. **Formulaic challenges.** "Despite challenges... continues to thrive." Replace with specific facts. + +### Language + +7. **AI vocabulary.** Additionally, crucial, delve, enduring, enhance, fostering, garner, interplay, intricate, landscape (abstract), pivotal, showcase, tapestry (abstract), testament, underscore, vibrant. Replace with plain words. +8. **Fancy ways to say "is".** "serves as", "stands as", "boasts", "features". Just say "is" or "has". +9. **"Not just X, but Y."** State the point directly instead. +10. **Rule of three.** Forcing ideas into groups of three. Use the natural number. +11. **Synonym cycling.** Protagonist, main character, central figure, hero all in one paragraph. Pick one, repeat it. +12. **False ranges.** "from X to Y" where X and Y aren't on a meaningful scale. List topics directly. + +### Style + +13. **Em dash overuse.** Avoid em dashes entirely. Use periods or commas only (no parentheses, no en dashes, no hyphen-as-dash substitutes). Em dashes are an AI tell, and reaching for parentheses instead just trades one tell for another. If a thought needs separation, end the sentence or use a comma. +14. **Colon overuse.** Colons are fine before a list or example. Not as mid-sentence connectors. "If you're coming from traditional automation: instead of registering event handlers, you describe conditions" adds nothing with the colon. Rewrite to let the point stand on its own without comparison framing. "Describing when the scheduler should fire works best as plain English." Same meaning, no crutch punctuation. +15. **Boldface overuse.** Don't bold every proper noun or acronym. +16. **Inline-header lists.** The tell is a bold label and colon that restates the line: "**Performance:** Performance improved...". Convert to prose. A bold lead-in that ends in a period, names the item, and is followed by genuinely new detail ("**Schema in TypeScript.** Tables live in one file.") is fine. +17. **Title case headings.** Use sentence case. +18. **Decorative emojis.** Remove from headings and bullets. +19. **Curly quotes.** Replace with straight quotes. + +### Communication artifacts + +20. **Chatbot phrases.** "I hope this helps!", "Let me know if...", "Of course!", "Certainly!", "Found the smoking gun!" Remove. +21. **Cutoff disclaimers.** "While specific details are limited..." Find sources or remove. +22. **Sycophantic tone.** "Great question! You're absolutely right!" Respond directly. + +### Filler + +23. **Filler phrases.** "In order to" becomes "To". "Due to the fact that" becomes "Because". "It is important to note that" gets deleted. +24. **Excessive hedging.** "could potentially possibly be argued that it might" becomes "may". +25. **Generic conclusions.** "The future looks bright." State specific plans or facts. + +### Jargon + +26. **Abstract metaphor nouns.** Substrate, wedge, vector, locus, vantage, nexus, primitive (as noun), harness (as metaphor), surface (as in "API surface"), bedrock, scaffolding (as metaphor), modality, paradigm, gold-plating, ratchet (as metaphor), evacuate (for moving code), endgame, north star, flywheel. These read as technical but usually have a plainer concrete word. "Substrate" becomes "base". "Wedge in" becomes "add". "Vector" becomes "way" or "method". "Gold-plating" becomes "more than the job needs". "Ratchet" becomes the mechanism's real name or "a limit that only tightens". "Evacuate" becomes "move out". "Endgame" becomes "the last phase". Pick the concrete word. + +### Plain speech + +27. **Say what it does, not how it feels.** "the database stays close at hand", "SQL you can read", "types that follow your schema" name a feeling. The fix names the mechanism or a number: "`.toSQL()` returns the exact string sent to the database", "a column rename fails the build". Ask what the sentence tells the reader to do or know, then write it. If you can't restate it as a concrete instruction, fact, or number, cut it. One more check: if the sentence could appear unchanged in another project's docs, it says nothing about this one. Cut it. +28. **Shorten or split dense sentences.** If the reader has to backtrack to parse a sentence, break it in two or drop clauses. One idea per sentence. +29. **Active voice.** Prefer it. Catch "is/are/was/were + past participle" and name the actor: "queries are validated" becomes "the compiler validates queries", "the file is parsed by the loader" becomes "the loader parses the file". Passive is fine only when the actor is unknown or genuinely doesn't matter. +30. **Cut adverbs, or use a stronger verb.** "runs quickly" becomes "is fast" or the number. "significantly improves" becomes the measured delta. An adverb propping up a weak verb means the verb is wrong. +31. **Prefer the plain word.** "utilize" becomes "use", "leverage" becomes "use", "facilitate" becomes "help", "numerous" becomes "many", "in the event that" becomes "if". The fancier synonym is rarely clearer. diff --git a/.github/workflows/pr-review.yml b/.github/workflows/pr-review.yml index 04fbeb9c..e82bbba0 100644 --- a/.github/workflows/pr-review.yml +++ b/.github/workflows/pr-review.yml @@ -1,12 +1,7 @@ name: pr-review on: - pull_request_target: - types: [opened, synchronize, reopened, ready_for_review, converted_to_draft] - issue_comment: - types: [created] - pull_request_review_comment: - types: [created] + workflow_dispatch: concurrency: # PR conversation comments arrive as `issue_comment` events, so their PR number diff --git a/.opencode/agent/reproduce-issue.md b/.opencode/agent/reproduce-issue.md index de21e373..640ee322 100644 --- a/.opencode/agent/reproduce-issue.md +++ b/.opencode/agent/reproduce-issue.md @@ -1,7 +1,7 @@ --- mode: primary hidden: true -model: opencode-go/deepseek-v4-flash +model: opencode-go/mimo-v2.5 color: "#c0392b" permission: edit: allow diff --git a/.opencode/agent/summarize.md b/.opencode/agent/summarize.md index 99db887e..c3cd2b21 100644 --- a/.opencode/agent/summarize.md +++ b/.opencode/agent/summarize.md @@ -1,7 +1,7 @@ --- mode: primary hidden: true -model: opencode-go/deepseek-v4-flash +model: opencode-go/mimo-v2.5 color: "#4f8f8f" permission: edit: deny diff --git a/.opencode/agent/triage.md b/.opencode/agent/triage.md index 4df9199a..314f874d 100644 --- a/.opencode/agent/triage.md +++ b/.opencode/agent/triage.md @@ -1,7 +1,7 @@ --- mode: primary hidden: true -model: opencode-go/deepseek-v4-flash +model: opencode-go/mimo-v2.5 color: "#c4920a" permission: edit: deny diff --git a/AGENTS.md b/AGENTS.md index 0ea1ebb6..9d2a437d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -79,6 +79,10 @@ task-required reference named by those skills. Skills are canonical for their detailed workflows and checklists. Treating this table as optional advice is a process violation. +**Always load `.agents/skills/communication-style/SKILL.md` at the start of +every task, before any analysis, tool call, or response. Apply its guidance to +all messages and written output, not only to user-facing copy or documentation.** + | Trigger | Required skill | |---|---| | Source/dependency changes, exports or package contracts, build/generated assets, or module ownership | `openchamber-change-discipline` | diff --git a/CHANGELOG.md b/CHANGELOG.md index 349fb84d..65659752 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,20 +4,32 @@ All notable changes to this project will be documented in this file. ## [Unreleased] -- **Project knowledge:** the Project notes panel is now Project knowledge, with notes, todos, plans and their search in a resizable sidebar. Notes are cards you expand by clicking anywhere on them, plans open and edit in the panel itself instead of a separate tab, and notes and plans you pin travel with every message you send in that project until you unpin them. -- **Work status:** the Context sources section now names each pinned note and plan riding along with your messages, and its pin button unpins them from there. -- **Settings:** OpenChamber no longer replaces a full OpenCode config with an empty `$schema`-only stub when the file uses JSON5-style unquoted keys; Settings changes now fail instead of wiping plugins, MCP servers, and providers (thanks to @makeittech). +- Chat: if OpenCode restarts while a response is still running, the chat now stops with an interrupted state and a notification to continue instead of hanging silently (thanks to @sum117). + +## [1.19.0] - 2026-08-19 + - **Settings/Integrations:** a new Integrations settings page lists Claude Code, Command Code, and Cursor plugins with install, update, setup, and remove actions, plus Discord and Telegram Coming soon placeholders. -- **Chat:** an open conversation no longer keeps re-coloring the same code blocks in the background, so browsing files with a chat open stops pinning a CPU core and spinning up the fans (thanks to @makeittech). -- **Stability/Proxy:** the local server now reuses its connection to OpenCode instead of opening a new one for every API request. Under sustained traffic the old behavior could use up every outgoing network port on the machine, at which point nothing on the computer could open a new connection until the traffic stopped and the ports were released (thanks to @alohaninja). +- **Project knowledge:** the Project notes panel is now Project knowledge, with notes, todos, plans and their search in a resizable sidebar. Notes are cards you expand by clicking anywhere on them, plans open and edit in the panel itself instead of a separate tab, and notes and plans can be pinned as context. +- **Files:** drag files onto the Files sidebar to upload them into the project or a specific folder; existing files require confirmation before replacement, and open previews refresh after an upload (thanks to @makeittech, @alanzchen). +- Settings: OpenChamber no longer replaces a full OpenCode config with an empty `$schema`-only stub when the file uses JSON5-style unquoted keys; Settings changes now fail instead of wiping plugins, MCP servers, and providers (thanks to @makeittech). +- Chat: an open conversation no longer keeps re-coloring the same code blocks in the background, so browsing files with a chat open stops pinning a CPU core and spinning up the fans (thanks to @makeittech). +- Stability/Proxy: the local server now reuses its connection to OpenCode instead of opening a new one for every API request. Under sustained traffic the old behavior could use up every outgoing network port on the machine, at which point nothing on the computer could open a new connection until the traffic stopped and the ports were released (thanks to @alohaninja). - Usage/Claude: Claude plan limits now work when you are signed in through Claude Code, without also signing into Anthropic in OpenCode; the account is read from Claude Code's own login on macOS, Linux, and WSL. The page shows your session and weekly limits again, adds per-model weekly limits and extra usage spending, and names your plan. Limits are kept on screen instead of disappearing when Anthropic temporarily blocks refreshes. +- Usage/Command Code: Command Code plan limits now appear in the Usage page and work status panel. - Git: the pull request panel now follows the branch's current open PR, and an open PR always wins over an older merged or closed one. After a PR is merged or closed the panel keeps showing it as the branch's last PR and offers creating the next one right below it (thanks to @makeittech). +- Git/Worktrees: creating a worktree from a pull request now falls back to GitHub's pull-request reference when the source fork was deleted or cannot be reached, instead of failing before creating the worktree (thanks to @makeittech). - Chat: new chats no longer start against a deleted last worktree directory; they fall back to the active project instead of saving the first message and never starting. +- Chat: typing with Chinese, Japanese, or Korean input methods no longer interrupts composition or jumps the cursor to the end of the composer (thanks to @makeittech). - Chat: opening a busy subagent in the context panel now shows its history instead of only the working-status line (thanks to @makeittech). - Chat: saved chats in the context panel open again instead of staying blank. - Chat: the context meter no longer climbs over 100% (330% readouts) after turns with many tool calls and no longer jumps when reopening an older session; it now shows what the window actually holds, everywhere the value appears — header, context sidebar, work status panel, mini chat, and mobile (thanks to @pocharlies). +- Chat/Attachments: extracted Office and OpenDocument content is now capped and presented more compactly, preventing large documents and their images from overwhelming the message context. - Projects: project names now match the folder name exactly, so `.ssh` and `opencode-claude` are no longer shown as `.Ssh` and `Opencode Claude` in the sidebar, window title, settings and notifications; names you renamed yourself are kept. +- Files: files reached through a symlink inside the workspace now open correctly instead of being rejected as outside the workspace. - Settings: the session retention action you pick is now saved instead of being dropped (thanks to @Gautam0507). +- Mobile: connecting through an ngrok address now bypasses ngrok's browser warning page instead of failing the server check. +- Mobile/iOS: text selection in the chat composer now uses native CodeMirror selection handles. +- Desktop: browser pages served from a self-signed loopback HTTPS address now load instead of being blocked by the certificate warning. - Browser: typing a comment on a page no longer triggers app shortcuts. - Skills Catalog: the source is now named ClawHub instead of "ClawdHub" (thanks to @makeittech). diff --git a/bun.lock b/bun.lock index dc2f7923..753e10c4 100644 --- a/bun.lock +++ b/bun.lock @@ -97,7 +97,7 @@ }, "packages/electron": { "name": "@openchamber/electron", - "version": "1.18.4", + "version": "1.19.0", "dependencies": { "@openchamber/web": "workspace:*", "electron-context-menu": "^4.1.2", @@ -134,7 +134,7 @@ }, "packages/ui": { "name": "@openchamber/ui", - "version": "1.18.4", + "version": "1.19.0", "dependencies": { "@aparajita/capacitor-secure-storage": "^8.0.0", "@base-ui/react": "^1.4.0", @@ -238,7 +238,7 @@ }, "packages/vscode": { "name": "openchamber", - "version": "1.18.4", + "version": "1.19.0", "dependencies": { "@openchamber/ui": "workspace:*", "@opencode-ai/sdk": "1.18.18", @@ -261,7 +261,7 @@ }, "packages/web": { "name": "@openchamber/web", - "version": "1.18.4", + "version": "1.19.0", "bin": { "openchamber": "./bin/cli.js", }, @@ -270,7 +270,6 @@ "@octokit/rest": "^22.0.1", "@opencode-ai/sdk": "1.18.18", "@simplewebauthn/server": "13.3.1", - "adm-zip": "^0.6.0", "bun-pty": "^0.4.5", "compression": "^1.8.1", "cron-parser": "^4.9.0", @@ -306,7 +305,6 @@ "@remixicon/react": "^4.7.0", "@simplewebauthn/browser": "13.3.0", "@tailwindcss/postcss": "^4.0.0", - "@types/adm-zip": "^0.5.7", "@types/node": "^24.3.1", "@types/react": "^19.1.10", "@types/react-dom": "^19.1.7", diff --git a/package.json b/package.json index 4a7751e4..d8a591f0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "openchamber-monorepo", - "version": "1.18.4", + "version": "1.19.0", "description": "OpenChamber monorepo workspace for web, ui, and desktop runtimes", "private": true, "type": "module", diff --git a/packages/docs/content/docs/de/integrations.mdx b/packages/docs/content/docs/de/integrations.mdx new file mode 100644 index 00000000..42f5972b --- /dev/null +++ b/packages/docs/content/docs/de/integrations.mdx @@ -0,0 +1,62 @@ +--- +title: Integrationen +description: Nutze dein Claude-, Command-Code- oder Cursor-Abo als Provider. +--- + +# Integrationen + +Eine Integration ist ein kleines Plugin, das OpenChamber einen Provider hinzufügt — auf Basis eines Abos, das du bereits hast. Verwalten kannst du sie unter **Settings → Integrations**. + +Verfügbare Integrationen: + +- **Claude Code** — dein Claude Pro- oder Max-Plan, ohne API-Keys +- **Command Code** — dein Command-Code-Plan +- **Cursor** — die Modell-Limits deines Cursor-Plans + +## Integration installieren + +1. Öffne **Settings → Integrations**. +2. Suche die Integration und wähle **Install**. +3. Starte OpenCode neu, wenn darum gebeten wird — der Provider erscheint nach dem Neustart. +4. Wähle **Set up** und melde dich an. Die Modelle erscheinen danach in der Modellauswahl im Chat. + +Integrationen werden für deinen Benutzer installiert und funktionieren damit in jedem Projekt. Aktualisieren oder entfernen kannst du sie jederzeit über dieselbe Karte. + +## Claude Code + +Claude Code nutzt deinen Claude Pro- oder Max-Plan — ohne API-Keys und ohne separate Claude-App. + +1. Installiere die Integration (siehe oben). +2. Wähle **Set up** und melde dich an. Wenn du die Claude Code CLI noch nicht hast, bietet die Einrichtung an, sie zuerst zu installieren, und meldet dich danach an. + +Claude Code ist die einzige Integration hier, die ihre Provider-CLI installiert und angemeldet benötigt. Command Code und Cursor brauchen ihre CLIs nicht. + +**Wie dein Claude-Konto geschützt bleibt:** Diese Integration nutzt das offizielle Claude Agent SDK von Anthropic und deine installierte Claude Code CLI. Sie kapert kein OAuth, extrahiert oder wiederholt keine Browser-Tokens, gibt sich nicht als nicht unterstützter Client aus und umgeht nicht Anthropics Authentifizierung. Sie bleibt auf dem von Anthropic unterstützten Zugriffsweg und trägt daher nicht das mit Token-Hijacking oder unautorisierten Authentifizierungsumgehungen verbundene Sperrrisiko. + +## Command Code + +Command Code nutzt deinen Command-Code-Plan. + +1. Installiere die Integration (siehe oben). +2. Wähle **Set up** — es öffnet sich eine Browserseite. Genehmige den Zugriff und kehre zu OpenChamber zurück. + +Auf einem Headless-Server oder in CI setze stattdessen die Umgebungsvariable `COMMAND_CODE_API_KEY`, anstatt dich im Browser anzumelden. + +## Cursor + +Cursor macht die Modelle deines Cursor-Plans in OpenChamber nutzbar. + +1. Installiere die Integration (siehe oben). +2. Wähle **Set up**, öffne den Link und genehmige den Zugriff im Browser. Kein API-Key nötig. Die Modellliste lädt nach der Anmeldung automatisch. + +## Aktualisieren oder entfernen + +- **Update** installiert die neueste veröffentlichte Version des Plugins. +- **Remove** löscht das Plugin aus deiner OpenCode-Konfiguration. Der Provider wird beim nächsten Neuladen von OpenCode nicht mehr geladen. + +Wenn eine Karte meldet, dass Einträge manuell verwaltet werden müssen, wähle **Manage plugins** und bereinige die Duplikate dort. + +## Verwandtes + +- [Anbieter, Modelle und Agenten](/de/providers/) — weitere Provider verbinden und Modelle wählen +- [Nutzung und Kontingente](/de/usage/) — verfolge, wie viel du genutzt hast diff --git a/packages/docs/content/docs/de/providers.mdx b/packages/docs/content/docs/de/providers.mdx index 4d5738f5..f559dab2 100644 --- a/packages/docs/content/docs/de/providers.mdx +++ b/packages/docs/content/docs/de/providers.mdx @@ -45,5 +45,6 @@ Provider-Anmeldungen werden von OpenCode gespeichert, nicht von OpenChamber, dah ## Weiterführend +- [Integrationen](/integrations/) — nutze ein Claude-, Command-Code- oder Cursor-Abo als Provider - [MCP-Server](/mcp/) — füge Agents zusätzliche Werkzeuge hinzu - [Nutzung & Kontingente](/usage/) — verfolge, wie viel du verbraucht hast diff --git a/packages/docs/content/docs/de/skills-catalog.mdx b/packages/docs/content/docs/de/skills-catalog.mdx index afb5f31e..7026837b 100644 --- a/packages/docs/content/docs/de/skills-catalog.mdx +++ b/packages/docs/content/docs/de/skills-catalog.mdx @@ -12,7 +12,7 @@ Zum Schreiben eigener Skills siehe [Skills](/skills/). ## Einen Skill installieren 1. Öffne den Katalog. -2. Durchsuche die eingebauten Quellen — das Anthropic-Skills-Repo und die ClawHub-Community-Registry — oder nutze die Suche. +2. Durchsuche die eingebauten Quellen — wie das Anthropic-Skills-Repo — oder nutze die Suche. 3. Wähle einen Skill aus und installiere ihn. 4. Entscheide, wo er installiert werden soll: für alles, was du tust, oder nur für das aktuelle Projekt. diff --git a/packages/docs/content/docs/es/integrations.mdx b/packages/docs/content/docs/es/integrations.mdx new file mode 100644 index 00000000..206e40d8 --- /dev/null +++ b/packages/docs/content/docs/es/integrations.mdx @@ -0,0 +1,62 @@ +--- +title: Integraciones +description: Usa tu suscripción de Claude, Command Code o Cursor como proveedor. +--- + +# Integraciones + +Una integración es un pequeño plugin que añade un proveedor a OpenChamber usando una suscripción que ya tienes. Las gestionas en **Settings → Integrations**. + +Integraciones disponibles: + +- **Claude Code** — tu plan Claude Pro o Max, sin claves de API +- **Command Code** — tu plan de Command Code +- **Cursor** — los límites de modelos de tu plan de Cursor + +## Instalar una integración + +1. Abre **Settings → Integrations**. +2. Busca la integración y elige **Install**. +3. Reinicia OpenCode cuando se te pida — el proveedor aparece tras el reinicio. +4. Elige **Set up** e inicia sesión. Los modelos aparecerán luego en el selector de modelos del chat. + +Las integraciones se instalan para tu usuario, así que funcionan en todos los proyectos. Puedes actualizarlas o eliminarlas desde la misma tarjeta en cualquier momento. + +## Claude Code + +Claude Code usa tu plan Claude Pro o Max — sin claves de API y sin una app de Claude aparte. + +1. Instala la integración (arriba). +2. Elige **Set up** e inicia sesión. Si aún no tienes la CLI de Claude Code, la configuración ofrece instalarla primero y luego iniciar sesión. + +Claude Code es la única integración de esta página que requiere tener la CLI de su proveedor instalada y con sesión iniciada. Command Code y Cursor no requieren sus CLIs. + +**Cómo se protege tu cuenta de Claude:** esta integración usa el Claude Agent SDK oficial de Anthropic y tu CLI de Claude Code instalada. No secuestra OAuth, no extrae ni reutiliza tokens del navegador, no se hace pasar por un cliente no admitido ni omite la autenticación de Anthropic. Se mantiene en la vía de acceso admitida por Anthropic, por lo que no conlleva el riesgo de baneo asociado al secuestro de tokens o a rodeos de autenticación no autorizados. + +## Command Code + +Command Code usa tu plan de Command Code. + +1. Instala la integración (arriba). +2. Elige **Set up** — se abre una página en el navegador. Autoriza el acceso y vuelve a OpenChamber. + +En una máquina sin interfaz gráfica o en CI, define la variable de entorno `COMMAND_CODE_API_KEY` en lugar de iniciar sesión en el navegador. + +## Cursor + +Cursor hace disponibles en OpenChamber los modelos incluidos en tu plan de Cursor. + +1. Instala la integración (arriba). +2. Elige **Set up**, abre el enlace y autoriza el acceso en tu navegador. No necesitas clave de API. La lista de modelos se carga automáticamente tras iniciar sesión. + +## Actualizar o eliminar + +- **Update** instala la última versión publicada del plugin. +- **Remove** elimina el plugin de tu configuración de OpenCode. El proveedor deja de cargarse cuando OpenCode se recarga. + +Si una tarjeta indica que las entradas requieren gestión manual, elige **Manage plugins** y limpia ahí los duplicados. + +## Relacionado + +- [Proveedores, modelos y agentes](/es/providers/) — conecta otros proveedores y elige modelos +- [Uso y cuotas](/es/usage/) — sigue cuánto has usado diff --git a/packages/docs/content/docs/es/providers.mdx b/packages/docs/content/docs/es/providers.mdx index e6df93d2..24e5b94f 100644 --- a/packages/docs/content/docs/es/providers.mdx +++ b/packages/docs/content/docs/es/providers.mdx @@ -45,5 +45,6 @@ Los inicios de sesión de los proveedores los guarda OpenCode, no OpenChamber, a ## Relacionado +- [Integraciones](/es/integrations/) — usa una suscripción de Claude, Command Code o Cursor como proveedor - [Servidores MCP](/es/mcp/) — añade herramientas extra para los agentes - [Uso y cuotas](/es/usage/) — controla cuánto has consumido diff --git a/packages/docs/content/docs/es/skills-catalog.mdx b/packages/docs/content/docs/es/skills-catalog.mdx index eadec080..c29ffb71 100644 --- a/packages/docs/content/docs/es/skills-catalog.mdx +++ b/packages/docs/content/docs/es/skills-catalog.mdx @@ -12,7 +12,7 @@ Para escribir tus propias skills, consulta [Skills](/es/skills/). ## Instala una skill 1. Abre el catálogo. -2. Explora las fuentes integradas —el repositorio de skills de Anthropic y el registro comunitario de ClawHub— o busca. +2. Explora las fuentes integradas —como el repositorio de skills de Anthropic— o busca. 3. Elige una skill e instálala. 4. Elige dónde instalarla: para todo lo que hagas, o solo en el proyecto actual. diff --git a/packages/docs/content/docs/fr/integrations.mdx b/packages/docs/content/docs/fr/integrations.mdx new file mode 100644 index 00000000..df347a34 --- /dev/null +++ b/packages/docs/content/docs/fr/integrations.mdx @@ -0,0 +1,62 @@ +--- +title: Intégrations +description: Utilise ton abonnement Claude, Command Code ou Cursor comme fournisseur. +--- + +# Intégrations + +Une intégration est un petit plugin qui ajoute un fournisseur à OpenChamber à partir d'un abonnement que tu possèdes déjà. Tu les gères dans **Settings → Integrations**. + +Intégrations disponibles : + +- **Claude Code** — ton plan Claude Pro ou Max, sans clés API +- **Command Code** — ton plan Command Code +- **Cursor** — les limites de modèles de ton plan Cursor + +## Installer une intégration + +1. Ouvre **Settings → Integrations**. +2. Trouve l'intégration et choisis **Install**. +3. Redémarre OpenCode quand c'est demandé — le fournisseur apparaît après le redémarrage. +4. Choisis **Set up** et connecte-toi. Les modèles apparaissent ensuite dans le sélecteur de modèles du chat. + +Les intégrations s'installent pour ton utilisateur et fonctionnent donc dans tous les projets. Tu peux les mettre à jour ou les retirer à tout moment depuis la même carte. + +## Claude Code + +Claude Code utilise ton plan Claude Pro ou Max — sans clés API et sans application Claude séparée. + +1. Installe l'intégration (ci-dessus). +2. Choisis **Set up** et connecte-toi. Si tu n'as pas encore la CLI Claude Code, la configuration propose de l'installer d'abord, puis de te connecter. + +Claude Code est la seule intégration ici qui exige que la CLI de son fournisseur soit installée et connectée. Command Code et Cursor n'exigent pas leurs CLIs. + +**Comment ton compte Claude reste protégé :** cette intégration utilise le Claude Agent SDK officiel d'Anthropic et ta CLI Claude Code installée. Elle ne détourne pas l'OAuth, n'extrait ni rejoue de tokens de navigateur, ne se fait pas passer pour un client non pris en charge et ne contourne pas l'authentification d'Anthropic. Elle reste sur la voie d'accès prise en charge par Anthropic et ne porte donc pas le risque de bannissement associé au détournement de tokens ou aux contournements d'authentification non autorisés. + +## Command Code + +Command Code utilise ton plan Command Code. + +1. Installe l'intégration (ci-dessus). +2. Choisis **Set up** — une page s'ouvre dans le navigateur. Autorise l'accès, puis reviens dans OpenChamber. + +Sur une machine sans interface graphique ou en CI, définis la variable d'environnement `COMMAND_CODE_API_KEY` au lieu de te connecter via le navigateur. + +## Cursor + +Cursor rend disponibles dans OpenChamber les modèles inclus dans ton plan Cursor. + +1. Installe l'intégration (ci-dessus). +2. Choisis **Set up**, ouvre le lien et autorise l'accès dans ton navigateur. Aucune clé API n'est nécessaire. La liste des modèles se charge automatiquement après la connexion. + +## Mettre à jour ou retirer + +- **Update** installe la dernière version publiée du plugin. +- **Remove** supprime le plugin de ta configuration OpenCode. Le fournisseur cesse d'être chargé au prochain rechargement d'OpenCode. + +Si une carte indique que les entrées nécessitent une gestion manuelle, choisis **Manage plugins** et nettoie les doublons à cet endroit. + +## À voir aussi + +- [Fournisseurs, modèles et agents](/fr/providers/) — connecter d'autres fournisseurs et choisir des modèles +- [Utilisation et quotas](/fr/usage/) — suis ta consommation diff --git a/packages/docs/content/docs/fr/providers.mdx b/packages/docs/content/docs/fr/providers.mdx index dde4838e..d79633d8 100644 --- a/packages/docs/content/docs/fr/providers.mdx +++ b/packages/docs/content/docs/fr/providers.mdx @@ -45,5 +45,6 @@ Les connexions aux fournisseurs sont stockées par OpenCode, pas OpenChamber ; e ## Pages liées +- [Intégrations](/integrations/) — utiliser un abonnement Claude, Command Code ou Cursor comme fournisseur - [Serveurs MCP](/mcp/) — ajouter des outils supplémentaires aux agents - [Utilisation et quotas](/usage/) — suivre votre consommation diff --git a/packages/docs/content/docs/fr/skills-catalog.mdx b/packages/docs/content/docs/fr/skills-catalog.mdx index 72123162..e6eb2323 100644 --- a/packages/docs/content/docs/fr/skills-catalog.mdx +++ b/packages/docs/content/docs/fr/skills-catalog.mdx @@ -12,7 +12,7 @@ Pour écrire vos propres skills, voir [Skills](/skills/). ## Installer un skill 1. Ouvrez le catalogue. -2. Parcourez les sources intégrées — le dépôt de skills Anthropic et le registre communautaire ClawHub — ou lancez une recherche. +2. Parcourez les sources intégrées — comme le dépôt de skills Anthropic — ou lancez une recherche. 3. Choisissez un skill et installez-le. 4. Choisissez où l’installer : pour tout ce que vous faites, ou seulement pour le projet actuel. diff --git a/packages/docs/content/docs/integrations.mdx b/packages/docs/content/docs/integrations.mdx new file mode 100644 index 00000000..14aee1f1 --- /dev/null +++ b/packages/docs/content/docs/integrations.mdx @@ -0,0 +1,62 @@ +--- +title: Integrations +description: Use your Claude, Command Code, or Cursor subscription as a provider. +--- + +# Integrations + +An integration is a small plugin that adds a provider to OpenChamber using a subscription you already have. You manage them at **Settings → Integrations**. + +Available integrations: + +- **Claude Code** — your Claude Pro or Max plan, no API keys +- **Command Code** — your Command Code plan +- **Cursor** — the model limits of your Cursor plan + +## Install an integration + +1. Open **Settings → Integrations**. +2. Find the integration and choose **Install**. +3. Restart OpenCode when asked — the provider appears after the restart. +4. Choose **Set up** and sign in. The models then appear in the chat model picker. + +Integrations install for your user, so they work in every project. You can update or remove them from the same card at any time. + +## Claude Code + +Claude Code uses your Claude Pro or Max plan — no API keys and no separate Claude app. + +1. Install the integration (above). +2. Choose **Set up** and sign in. If you don't have the Claude Code CLI yet, setup offers to install it first and then sign you in. + +Claude Code is the only integration here that requires its provider CLI to be installed and signed in. Command Code and Cursor do not require their CLIs. + +**How your Claude account stays safe:** this integration uses Anthropic's official Claude Agent SDK and your installed Claude Code CLI. It does not hijack OAuth, extract or replay browser tokens, impersonate an unsupported client, or bypass Anthropic's authentication flow. It stays on Anthropic's supported access path, so it does not carry the account-ban risk of token hijacking or unauthorized authentication workarounds. + +## Command Code + +Command Code uses your Command Code plan. + +1. Install the integration (above). +2. Choose **Set up** — a browser page opens. Approve access, then return to OpenChamber. + +On a headless machine or in CI, set the `COMMAND_CODE_API_KEY` environment variable instead of signing in in the browser. + +## Cursor + +Cursor makes the models included in your Cursor plan available in OpenChamber. + +1. Install the integration (above). +2. Choose **Set up**, open the link, and approve access in your browser. No API key is required. The model list loads automatically after you sign in. + +## Update or remove + +- **Update** installs the latest published version of the plugin. +- **Remove** deletes the plugin from your OpenCode config. The provider stops loading after OpenCode refreshes. + +If a card says the entries need manual management, choose **Manage plugins** and clean up the duplicates there. + +## Related + +- [Providers, Models & Agents](/providers/) — connect other providers and pick models +- [Usage & Quotas](/usage/) — track how much you've used diff --git a/packages/docs/content/docs/ja/integrations.mdx b/packages/docs/content/docs/ja/integrations.mdx new file mode 100644 index 00000000..02fa8e36 --- /dev/null +++ b/packages/docs/content/docs/ja/integrations.mdx @@ -0,0 +1,62 @@ +--- +title: 統合機能 +description: Claude、Command Code、Cursor のサブスクリプションをプロバイダーとして使う。 +--- + +# 統合機能 + +統合機能(インテグレーション)は、すでに持っているサブスクリプションを使って OpenChamber にプロバイダーを追加する小さなプラグインです。**Settings → Integrations** で管理します。 + +利用できる統合機能: + +- **Claude Code** — Claude Pro または Max プラン、API キー不要 +- **Command Code** — Command Code のプラン +- **Cursor** — Cursor プランのモデル利用枠 + +## 統合機能をインストールする + +1. **Settings → Integrations** を開きます。 +2. 統合機能を見つけて **Install** を選びます。 +3. 求められたら OpenCode を再起動します — 再起動後にプロバイダーが現れます。 +4. **Set up** を選んでサインインします。するとチャットのモデル選択にモデルが表示されます。 + +統合機能はユーザー単位でインストールされるため、すべてのプロジェクトで使えます。同じカードからいつでも更新や削除ができます。 + +## Claude Code + +Claude Code は Claude Pro または Max プランを使います — API キーも Claude アプリも不要です。 + +1. 統合機能をインストールします(上記)。 +2. **Set up** を選んでサインインします。Claude Code CLI がまだない場合は、セットアップがまずインストールを提案し、その後サインインします。 + +Claude Code は、ここで唯一プロバイダーの CLI のインストールとサインインを必要とする統合機能です。Command Code と Cursor は CLI を必要としません。 + +**Claude アカウントが守られる仕組み:** この統合機能は Anthropic の公式 Claude Agent SDK と、インストール済みの Claude Code CLI を使用します。OAuth の乗っ取り、ブラウザートークンの抽出や再生、未対応クライアントへの偽装、Anthropic の認証フローの回避は一切行いません。Anthropic がサポートする正規のアクセス経路を使うため、トークン乗っ取りや不正な認証の回避につきもののアカウント停止リスクはありません。 + +## Command Code + +Command Code は Command Code のプランを使います。 + +1. 統合機能をインストールします(上記)。 +2. **Set up** を選ぶとブラウザーでページが開きます。アクセスを許可して OpenChamber に戻ります。 + +画面のないサーバーや CI では、ブラウザーでサインインする代わりに環境変数 `COMMAND_CODE_API_KEY` を設定してください。 + +## Cursor + +Cursor は Cursor プランに含まれるモデルを OpenChamber で使えるようにします。 + +1. 統合機能をインストールします(上記)。 +2. **Set up** を選び、リンクを開いてブラウザーでアクセスを許可します。API キーは不要です。サインイン後、モデル一覧は自動的に読み込まれます。 + +## 更新と削除 + +- **Update** はプラグインの最新の公開バージョンをインストールします。 +- **Remove** は OpenCode の設定からプラグインを削除します。OpenCode が再読み込みされるとプロバイダーは読み込まれなくなります。 + +カードに手動での管理が必要だと表示された場合は、**Manage plugins** を選んで重複を整理してください。 + +## 関連情報 + +- [プロバイダー、モデル、エージェント](/ja/providers/) — 他のプロバイダーの接続とモデルの選択 +- [使用量とクォータ](/ja/usage/) — 利用量を追跡 diff --git a/packages/docs/content/docs/ja/providers.mdx b/packages/docs/content/docs/ja/providers.mdx index 56b1616b..62f1c663 100644 --- a/packages/docs/content/docs/ja/providers.mdx +++ b/packages/docs/content/docs/ja/providers.mdx @@ -45,5 +45,6 @@ OpenChamber が何かを行うには、少なくとも 1 つの AI プロバイ ## 関連 +- [統合機能](/integrations/) — Claude、Command Code、Cursor のサブスクリプションをプロバイダーとして使う - [MCP サーバー](/mcp/) — エージェントに追加ツールを加える - [使用量とクォータ](/usage/) — 使った量を追跡する diff --git a/packages/docs/content/docs/ja/skills-catalog.mdx b/packages/docs/content/docs/ja/skills-catalog.mdx index 8991f05f..029a0882 100644 --- a/packages/docs/content/docs/ja/skills-catalog.mdx +++ b/packages/docs/content/docs/ja/skills-catalog.mdx @@ -12,7 +12,7 @@ Skills Catalog では、自分で書く代わりに、他の人が公開した ## スキルをインストールする 1. カタログを開きます。 -2. 組み込みソース(Anthropic skills repo と ClawHub community registry)を閲覧するか、検索します。 +2. 組み込みソース(Anthropic skills repo など)を閲覧するか、検索します。 3. スキルを選び、インストールします。 4. インストール先を選びます。すべての作業で使うか、現在のプロジェクトだけで使うかです。 diff --git a/packages/docs/content/docs/ko/integrations.mdx b/packages/docs/content/docs/ko/integrations.mdx new file mode 100644 index 00000000..f2589d50 --- /dev/null +++ b/packages/docs/content/docs/ko/integrations.mdx @@ -0,0 +1,62 @@ +--- +title: 통합 기능 +description: Claude, Command Code 또는 Cursor 구독을 공급자로 사용하세요. +--- + +# 통합 기능 + +통합 기능(인테그레이션)은 이미 가지고 있는 구독을 사용해 OpenChamber에 공급자를 추가하는 작은 플러그인입니다. **Settings → Integrations**에서 관리합니다. + +사용 가능한 통합 기능: + +- **Claude Code** — Claude Pro 또는 Max 플랜, API 키 불필요 +- **Command Code** — Command Code 플랜 +- **Cursor** — Cursor 플랜의 모델 한도 + +## 통합 기능 설치 + +1. **Settings → Integrations**를 엽니다. +2. 통합 기능을 찾아 **Install**을 선택합니다. +3. 요청되면 OpenCode를 다시 시작합니다 — 재시작 후 공급자가 나타납니다. +4. **Set up**를 선택하고 로그인합니다. 그러면 채팅의 모델 선택기에 모델이 나타납니다. + +통합 기능은 사용자 단위로 설치되므로 모든 프로젝트에서 작동합니다. 같은 카드에서 언제든 업데이트하거나 제거할 수 있습니다. + +## Claude Code + +Claude Code는 Claude Pro 또는 Max 플랜을 사용합니다 — API 키도 별도의 Claude 앱도 필요 없습니다. + +1. 통합 기능을 설치합니다(위 참고). +2. **Set up**를 선택하고 로그인합니다. Claude Code CLI가 아직 없으면 설정에서 먼저 설치를 제안한 뒤 로그인을 진행합니다. + +Claude Code는 여기에서 유일하게 공급자 CLI 설치와 로그인을 필요로 하는 통합 기능입니다. Command Code와 Cursor는 CLI가 필요 없습니다. + +**Claude 계정이 안전하게 유지되는 방식:** 이 통합 기능은 Anthropic의 공식 Claude Agent SDK와 설치된 Claude Code CLI를 사용합니다. OAuth 탈취, 브라우저 토큰 추출·재사용, 지원되지 않는 클라이언트로의 위장, Anthropic 인증 우회를 하지 않습니다. Anthropic이 지원하는 정상 경로를 사용하므로 토큰 탈취나 비인가 인증 우회에 따른 계정 정지 위험이 없습니다. + +## Command Code + +Command Code는 Command Code 플랜을 사용합니다. + +1. 통합 기능을 설치합니다(위 참고). +2. **Set up**를 선택하면 브라우저에서 페이지가 열립니다. 접근을 승인한 뒤 OpenChamber로 돌아옵니다. + +화면이 없는 서버나 CI 환경에서는 브라우저 로그인 대신 `COMMAND_CODE_API_KEY` 환경 변수를 설정하세요. + +## Cursor + +Cursor는 Cursor 플랜에 포함된 모델을 OpenChamber에서 사용할 수 있게 합니다. + +1. 통합 기능을 설치합니다(위 참고). +2. **Set up**를 선택하고 링크를 열어 브라우저에서 접근을 승인합니다. API 키는 필요 없습니다. 로그인 후 모델 목록이 자동으로 로드됩니다. + +## 업데이트 및 제거 + +- **Update**는 플러그인의 최신 공개 버전을 설치합니다. +- **Remove**는 OpenCode 설정에서 플러그인을 삭제합니다. OpenCode가 다시 로드되면 공급자는 더 이상 로드되지 않습니다. + +카드에 항목을 수동으로 관리해야 한다고 표시되면 **Manage plugins**를 선택해 중복 항목을 정리하세요. + +## 관련 문서 + +- [공급자, 모델, 에이전트](/ko/providers/) — 다른 공급자 연결과 모델 선택 +- [사용량 및 할당량](/ko/usage/) — 사용량 추적 diff --git a/packages/docs/content/docs/ko/providers.mdx b/packages/docs/content/docs/ko/providers.mdx index 16869b26..11d9007f 100644 --- a/packages/docs/content/docs/ko/providers.mdx +++ b/packages/docs/content/docs/ko/providers.mdx @@ -45,5 +45,6 @@ OpenChamber가 무언가를 하려면 먼저 최소한 하나의 AI 공급자가 ## 관련 항목 +- [통합 기능](/ko/integrations/) — Claude, Command Code, Cursor 구독을 공급자로 사용 - [MCP Servers](/ko/mcp/) — 에이전트에 추가 도구를 제공합니다 - [Usage & Quotas](/ko/usage/) — 사용량을 추적합니다 diff --git a/packages/docs/content/docs/ko/skills-catalog.mdx b/packages/docs/content/docs/ko/skills-catalog.mdx index ba16461a..d2cbb407 100644 --- a/packages/docs/content/docs/ko/skills-catalog.mdx +++ b/packages/docs/content/docs/ko/skills-catalog.mdx @@ -12,7 +12,7 @@ Skills Catalog를 사용하면 직접 작성하는 대신 다른 사람이 게 ## 스킬 설치하기 1. 카탈로그를 엽니다. -2. 내장된 소스(Anthropic 스킬 저장소와 ClawHub 커뮤니티 레지스트리)를 둘러보거나 검색합니다. +2. 내장된 소스(예: Anthropic 스킬 저장소)를 둘러보거나 검색합니다. 3. 스킬을 선택하고 설치합니다. 4. 설치 위치를 선택합니다. 모든 작업에 적용할지, 현재 프로젝트에만 적용할지 선택합니다. diff --git a/packages/docs/content/docs/pl/integrations.mdx b/packages/docs/content/docs/pl/integrations.mdx new file mode 100644 index 00000000..aca4b269 --- /dev/null +++ b/packages/docs/content/docs/pl/integrations.mdx @@ -0,0 +1,62 @@ +--- +title: Integracje +description: Używaj subskrypcji Claude, Command Code lub Cursor jako dostawcy. +--- + +# Integracje + +Integracja to mała wtyczka, która dodaje dostawcę do OpenChamber na podstawie subskrypcji, którą już masz. Zarządzasz nimi w **Settings → Integrations**. + +Dostępne integracje: + +- **Claude Code** — Twój plan Claude Pro lub Max, bez kluczy API +- **Command Code** — Twój plan Command Code +- **Cursor** — limity modeli z Twojego planu Cursor + +## Instalacja integracji + +1. Otwórz **Settings → Integrations**. +2. Znajdź integrację i wybierz **Install**. +3. Uruchom OpenCode ponownie, gdy o to poproszą — dostawca pojawi się po restarcie. +4. Wybierz **Set up** i zaloguj się. Modele pojawią się potem w selektorze modeli na czacie. + +Integracje instalują się dla Twojego użytkownika, więc działają w każdym projekcie. W każdej chwili możesz je zaktualizować lub usunąć z tej samej karty. + +## Claude Code + +Claude Code korzysta z Twojego planu Claude Pro lub Max — bez kluczy API i bez osobnej aplikacji Claude. + +1. Zainstaluj integrację (patrz wyżej). +2. Wybierz **Set up** i zaloguj się. Jeśli nie masz jeszcze Claude Code CLI, konfiguracja zaoferuje najpierw jego instalację, a potem logowanie. + +Claude Code jest jedyną integracją tutaj, która wymaga zainstalowanego i zalogowanego CLI swojego dostawcy. Command Code i Cursor nie wymagają swoich CLI. + +**Jak chronione jest Twoje konto Claude:** ta integracja używa oficjalnego Claude Agent SDK od Anthropic i Twojego zainstalowanego Claude Code CLI. Nie przechwytuje OAuth, nie wyodrębnia ani nie odtwarza tokenów przeglądarki, nie podszywa się pod nieobsługiwany klient i nie omija uwierzytelniania Anthropic. Działa na obsługiwanej przez Anthropic ścieżce dostępu, więc nie niesie ryzyka zablokowania konta związanego z przechwytywaniem tokenów lub nieautoryzowanymi obejściami uwierzytelniania. + +## Command Code + +Command Code korzysta z Twojego planu Command Code. + +1. Zainstaluj integrację (patrz wyżej). +2. Wybierz **Set up** — w przeglądarce otworzy się strona. Zatwierdź dostęp i wróć do OpenChamber. + +Na maszynie bez interfejsu graficznego lub w CI ustaw zmienną środowiskową `COMMAND_CODE_API_KEY` zamiast logowania w przeglądarce. + +## Cursor + +Cursor udostępnia w OpenChamber modele zawarte w Twoim planie Cursor. + +1. Zainstaluj integrację (patrz wyżej). +2. Wybierz **Set up**, otwórz link i zatwierdź dostęp w przeglądarce. Klucz API nie jest potrzebny. Lista modeli wczyta się automatycznie po zalogowaniu. + +## Aktualizacja i usuwanie + +- **Update** instaluje najnowszą opublikowaną wersję wtyczki. +- **Remove** usuwa wtyczkę z konfiguracji OpenCode. Dostawca przestanie się ładować po odświeżeniu OpenCode. + +Jeśli karta wskazuje, że wpisy wymagają ręcznego zarządzania, wybierz **Manage plugins** i wyczyść tam duplikaty. + +## Powiązane + +- [Dostawcy, modele i agenci](/pl/providers/) — podłączanie innych dostawców i wybór modeli +- [Zużycie i limity](/pl/usage/) — śledź, ile wykorzystałeś diff --git a/packages/docs/content/docs/pl/providers.mdx b/packages/docs/content/docs/pl/providers.mdx index 8675b91a..79d1ad41 100644 --- a/packages/docs/content/docs/pl/providers.mdx +++ b/packages/docs/content/docs/pl/providers.mdx @@ -45,5 +45,6 @@ Logowania dostawców są przechowywane przez OpenCode, a nie OpenChamber, więc ## Powiązane +- [Integracje](/pl/integrations/) — używaj subskrypcji Claude, Command Code lub Cursor jako dostawcy - [Serwery MCP](/pl/mcp/) — dodaj agentom dodatkowe narzędzia - [Zużycie i limity](/pl/usage/) — śledź, ile już wykorzystałeś diff --git a/packages/docs/content/docs/pl/skills-catalog.mdx b/packages/docs/content/docs/pl/skills-catalog.mdx index d3544fa1..d38a842f 100644 --- a/packages/docs/content/docs/pl/skills-catalog.mdx +++ b/packages/docs/content/docs/pl/skills-catalog.mdx @@ -12,7 +12,7 @@ Aby pisać własne skille, zobacz [Skille](/pl/skills/). ## Zainstaluj skill 1. Otwórz katalog. -2. Przeglądaj wbudowane źródła — repozytorium skilli Anthropic oraz rejestr społeczności ClawHub — albo wyszukaj. +2. Przeglądaj wbudowane źródła — na przykład repozytorium skilli Anthropic — albo wyszukaj. 3. Wybierz skill i zainstaluj go. 4. Wybierz, gdzie go zainstalować: dla wszystkiego, co robisz, albo tylko dla bieżącego projektu. diff --git a/packages/docs/content/docs/providers.mdx b/packages/docs/content/docs/providers.mdx index 6b8a8e83..df7a7d1e 100644 --- a/packages/docs/content/docs/providers.mdx +++ b/packages/docs/content/docs/providers.mdx @@ -57,5 +57,6 @@ Provider sign-ins are stored by OpenCode, not OpenChamber, so they're shared wit ## Related +- [Integrations](/integrations/) — use a Claude, Command Code, or Cursor subscription as a provider - [MCP Servers](/mcp/) — add extra tools for agents - [Usage & Quotas](/usage/) — track how much you've used diff --git a/packages/docs/content/docs/pt-br/integrations.mdx b/packages/docs/content/docs/pt-br/integrations.mdx new file mode 100644 index 00000000..1d66cbda --- /dev/null +++ b/packages/docs/content/docs/pt-br/integrations.mdx @@ -0,0 +1,62 @@ +--- +title: Integrações +description: Use sua assinatura Claude, Command Code ou Cursor como provedor. +--- + +# Integrações + +Uma integração é um pequeno plugin que adiciona um provedor ao OpenChamber usando uma assinatura que você já tem. Você as gerencia em **Settings → Integrations**. + +Integrações disponíveis: + +- **Claude Code** — seu plano Claude Pro ou Max, sem chaves de API +- **Command Code** — seu plano Command Code +- **Cursor** — os limites de modelos do seu plano Cursor + +## Instalar uma integração + +1. Abra **Settings → Integrations**. +2. Encontre a integração e escolha **Install**. +3. Reinicie o OpenCode quando solicitado — o provedor aparece após a reinicialização. +4. Escolha **Set up** e faça login. Os modelos aparecem então no seletor de modelos do chat. + +As integrações são instaladas para o seu usuário, então funcionam em todos os projetos. Você pode atualizá-las ou removê-las do mesmo cartão a qualquer momento. + +## Claude Code + +O Claude Code usa seu plano Claude Pro ou Max — sem chaves de API e sem um app Claude separado. + +1. Instale a integração (acima). +2. Escolha **Set up** e faça login. Se você ainda não tem a CLI do Claude Code, a configuração oferece instalá-la primeiro e depois fazer login. + +O Claude Code é a única integração aqui que exige que a CLI do provedor esteja instalada e autenticada. Command Code e Cursor não exigem suas CLIs. + +**Como sua conta Claude fica protegida:** esta integração usa o Claude Agent SDK oficial da Anthropic e a CLI do Claude Code instalada em sua máquina. Ela não sequestra OAuth, não extrai nem reproduz tokens do navegador, não se passa por um cliente não suportado e não contorna a autenticação da Anthropic. Ela permanece no caminho de acesso suportado pela Anthropic, portanto não traz o risco de banimento de conta associado a sequestro de tokens ou a contornos de autenticação não autorizados. + +## Command Code + +O Command Code usa seu plano Command Code. + +1. Instale a integração (acima). +2. Escolha **Set up** — uma página abre no navegador. Autorize o acesso e volte ao OpenChamber. + +Em uma máquina sem interface gráfica ou em CI, defina a variável de ambiente `COMMAND_CODE_API_KEY` em vez de fazer login pelo navegador. + +## Cursor + +O Cursor torna disponíveis no OpenChamber os modelos incluídos no seu plano Cursor. + +1. Instale a integração (acima). +2. Escolha **Set up**, abra o link e autorize o acesso no navegador. Nenhuma chave de API é necessária. A lista de modelos carrega automaticamente após o login. + +## Atualizar ou remover + +- **Update** instala a versão publicada mais recente do plugin. +- **Remove** exclui o plugin da sua configuração do OpenCode. O provedor deixa de ser carregado quando o OpenCode é recarregado. + +Se um cartão indicar que as entradas precisam de gerenciamento manual, escolha **Manage plugins** e limpe as duplicatas lá. + +## Relacionado + +- [Provedores, modelos e agentes](/pt-br/providers/) — conecte outros provedores e escolha modelos +- [Uso e cotas](/pt-br/usage/) — acompanhe quanto você usou diff --git a/packages/docs/content/docs/pt-br/providers.mdx b/packages/docs/content/docs/pt-br/providers.mdx index 035002bc..b05dc222 100644 --- a/packages/docs/content/docs/pt-br/providers.mdx +++ b/packages/docs/content/docs/pt-br/providers.mdx @@ -45,5 +45,6 @@ Os logins de provedores são armazenados pelo OpenCode, não pelo OpenChamber, e ## Relacionado +- [Integrações](/pt-br/integrations/) — use uma assinatura Claude, Command Code ou Cursor como provedor - [Servidores MCP](/pt-br/mcp/) — adicione ferramentas extras para os agentes - [Uso e Cotas](/pt-br/usage/) — acompanhe quanto você já usou diff --git a/packages/docs/content/docs/pt-br/skills-catalog.mdx b/packages/docs/content/docs/pt-br/skills-catalog.mdx index eea841f4..b28c44f3 100644 --- a/packages/docs/content/docs/pt-br/skills-catalog.mdx +++ b/packages/docs/content/docs/pt-br/skills-catalog.mdx @@ -12,7 +12,7 @@ Para escrever suas próprias skills, veja [Skills](/pt-br/skills/). ## Instalar uma skill 1. Abra o catálogo. -2. Navegue pelas fontes integradas — o repositório de skills da Anthropic e o registro comunitário ClawHub — ou pesquise. +2. Navegue pelas fontes integradas — como o repositório de skills da Anthropic — ou pesquise. 3. Escolha uma skill e instale-a. 4. Escolha onde instalá-la: para tudo o que você faz, ou apenas no projeto atual. diff --git a/packages/docs/content/docs/skills-catalog.mdx b/packages/docs/content/docs/skills-catalog.mdx index 9ddcb131..e223a459 100644 --- a/packages/docs/content/docs/skills-catalog.mdx +++ b/packages/docs/content/docs/skills-catalog.mdx @@ -12,7 +12,7 @@ For writing your own skills, see [Skills](/skills/). ## Install a skill 1. Open the catalog. -2. Browse the built-in sources — the Anthropic skills repo and the ClawHub community registry — or search. +2. Browse the built-in sources — like the Anthropic skills repo — or search. 3. Pick a skill and install it. 4. Choose where to install it: for everything you do, or just the current project. diff --git a/packages/docs/content/docs/uk/integrations.mdx b/packages/docs/content/docs/uk/integrations.mdx new file mode 100644 index 00000000..b68da46c --- /dev/null +++ b/packages/docs/content/docs/uk/integrations.mdx @@ -0,0 +1,62 @@ +--- +title: Інтеграції +description: Використовуйте підписки Claude, Command Code або Cursor як провайдерів. +--- + +# Інтеграції + +Інтеграція — це невеликий плагін, що додає провайдера до OpenChamber на основі підписки, яка в вас уже є. Керувати ними можна в **Settings → Integrations**. + +Доступні інтеграції: + +- **Claude Code** — ваша підписка Claude Pro або Max, без API-ключів +- **Command Code** — ваша підписка Command Code +- **Cursor** — ліміти моделей вашої підписки Cursor + +## Встановлення інтеграції + +1. Відкрийте **Settings → Integrations**. +2. Знайдіть інтеграцію та натисніть **Install**. +3. Перезапустіть OpenCode, коли про це попросять, — провайдер з'явиться після перезапуску. +4. Натисніть **Set up** і увійдіть. Після цього моделі з'являться в перемикачі моделей у чаті. + +Інтеграції встановлюються для вашого користувача, тож працюють у всіх проєктах. Оновити або видалити їх можна в будь-який момент з тієї ж карточки. + +## Claude Code + +Claude Code використовує вашу підписку Claude Pro або Max — без API-ключів і без окремого застосунку Claude. + +1. Встановіть інтеграцію (вище). +2. Натисніть **Set up** і увійдіть. Якщо у вас ще немає Claude Code CLI, програма встановлення спершу запропонує його встановити, а потім виконає вхід. + +Claude Code — єдина інтеграція тут, яка вимагає встановленого та залогіненого CLI свого провайдера. Для Command Code і Cursor їхні CLI не потрібні. + +**Як захищається ваш обліковий запис Claude:** ця інтеграція використовує офіційний Claude Agent SDK від Anthropic і ваш встановлений Claude Code CLI. Вона не перехоплює OAuth, не витягує й не відтворює браузерні токени, не видає себе за непідтримуваний клієнт і не обходить процес автентифікації Anthropic. Усе працює через підтримуваний Anthropic шлях доступу, тож інтеграція не несе ризику блокування облікового запису, пов'язаного з перехопленням токенів або несанкціонованими способами автентифікації. + +## Command Code + +Command Code використовує вашу підписку Command Code. + +1. Встановіть інтеграцію (вище). +2. Натисніть **Set up** — відкриється сторінка в браузері. Підтвердьте доступ і поверніться до OpenChamber. + +На сервері без графічного інтерфейсу або в CI замість входу через браузер задайте змінну середовища `COMMAND_CODE_API_KEY`. + +## Cursor + +Cursor робить доступними в OpenChamber моделі, що входять у вашу підписку Cursor. + +1. Встановіть інтеграцію (вище). +2. Натисніть **Set up**, відкрийте посилання та підтвердьте доступ у браузері. API-ключ не потрібен. Список моделей завантажиться автоматично після входу. + +## Оновлення та видалення + +- **Update** встановлює найновішу опубліковану версію плагіна. +- **Remove** видаляє плагін із конфігурації OpenCode. Провайдер перестане завантажуватися після оновлення OpenCode. + +Якщо карточка повідомляє, що записи потребують ручного керування, натисніть **Manage plugins** і приберіть дублікати там. + +## Пов'язане + +- [Провайдери, моделі та агенти](/uk/providers/) — підключення інших провайдерів і вибір моделей +- [Використання та квоти](/uk/usage/) — відстежуйте, скільки ви витратили diff --git a/packages/docs/content/docs/uk/providers.mdx b/packages/docs/content/docs/uk/providers.mdx index 693e15a7..4fb61d65 100644 --- a/packages/docs/content/docs/uk/providers.mdx +++ b/packages/docs/content/docs/uk/providers.mdx @@ -45,5 +45,6 @@ description: Підключайте AI-провайдерів, обирайте ## Пов'язане +- [Інтеграції](/uk/integrations/) — використовуйте підписки Claude, Command Code або Cursor як провайдерів - [MCP Servers](/uk/mcp/) — додайте агентам додаткові інструменти - [Використання та квоти](/uk/usage/) — відстежуйте, скільки ви витратили diff --git a/packages/docs/content/docs/uk/skills-catalog.mdx b/packages/docs/content/docs/uk/skills-catalog.mdx index 78c0c1d6..585ad77a 100644 --- a/packages/docs/content/docs/uk/skills-catalog.mdx +++ b/packages/docs/content/docs/uk/skills-catalog.mdx @@ -12,7 +12,7 @@ description: Переглядайте та встановлюйте готові ## Встановлення навички 1. Відкрийте каталог. -2. Перегляньте вбудовані джерела — репозиторій навичок Anthropic та спільнотний реєстр ClawHub — або скористайтеся пошуком. +2. Перегляньте вбудовані джерела — наприклад репозиторій навичок Anthropic — або скористайтеся пошуком. 3. Оберіть навичку й установіть її. 4. Виберіть, куди встановити: для всього, що ви робите, чи лише для поточного проєкту. diff --git a/packages/docs/content/docs/zh-cn/integrations.mdx b/packages/docs/content/docs/zh-cn/integrations.mdx new file mode 100644 index 00000000..94daf884 --- /dev/null +++ b/packages/docs/content/docs/zh-cn/integrations.mdx @@ -0,0 +1,62 @@ +--- +title: 集成 +description: 将你的 Claude、Command Code 或 Cursor 订阅用作提供商。 +--- + +# 集成 + +集成是一个小型插件,它使用你已有的订阅为 OpenChamber 添加一个提供商。你可以在 **Settings → Integrations** 中管理它们。 + +可用的集成: + +- **Claude Code** — 你的 Claude Pro 或 Max 套餐,无需 API 密钥 +- **Command Code** — 你的 Command Code 套餐 +- **Cursor** — 你的 Cursor 套餐的模型额度 + +## 安装集成 + +1. 打开 **Settings → Integrations**。 +2. 找到所需的集成并选择 **Install**。 +3. 在提示时重启 OpenCode — 重启后提供商就会出现。 +4. 选择 **Set up** 并登录。之后模型会出现在聊天室的模型选择器中。 + +集成按用户安装,因此在所有项目中都可用。你可以随时在同一张卡片上更新或移除它们。 + +## Claude Code + +Claude Code 使用你的 Claude Pro 或 Max 套餐 — 无需 API 密钥,也无需单独的 Claude 应用。 + +1. 安装集成(见上文)。 +2. 选择 **Set up** 并登录。如果你还没有 Claude Code CLI,安装向导会先提供安装,然后再登录。 + +Claude Code 是这里唯一要求安装并登录其提供商 CLI 的集成。Command Code 和 Cursor 不需要它们的 CLI。 + +**你的 Claude 账户如何受到保护:** 此集成使用 Anthropic 官方的 Claude Agent SDK 和你已安装的 Claude Code CLI。它不会劫持 OAuth,不会提取或重放浏览器令牌,不会冒充不受支持的客户端,也不会绕过 Anthropic 的身份验证。它始终运行在 Anthropic 支持的访问路径上,因此不会带来与令牌劫持或未授权身份验证变通手段相关的封号风险。 + +## Command Code + +Command Code 使用你的 Command Code 套餐。 + +1. 安装集成(见上文)。 +2. 选择 **Set up** — 浏览器中会打开一个页面。授权访问,然后返回 OpenChamber。 + +在没有图形界面的服务器或 CI 环境中,请设置环境变量 `COMMAND_CODE_API_KEY` 来代替浏览器登录。 + +## Cursor + +Cursor 让你的 Cursor 套餐中包含的模型可以在 OpenChamber 中使用。 + +1. 安装集成(见上文)。 +2. 选择 **Set up**,打开链接并在浏览器中授权访问。无需 API 密钥。登录后模型列表会自动加载。 + +## 更新或移除 + +- **Update** 安装插件的最新发布版本。 +- **Remove** 从你的 OpenCode 配置中删除该插件。OpenCode 重新加载后,该提供商将不再加载。 + +如果卡片提示条目需要手动管理,请选择 **Manage plugins** 并在那里清理重复项。 + +## 相关内容 + +- [提供商、模型与智能体](/zh-cn/providers/) — 连接其他提供商并选择模型 +- [用量与配额](/zh-cn/usage/) — 跟踪你的使用量 diff --git a/packages/docs/content/docs/zh-cn/providers.mdx b/packages/docs/content/docs/zh-cn/providers.mdx index 8e92afd0..62cf4019 100644 --- a/packages/docs/content/docs/zh-cn/providers.mdx +++ b/packages/docs/content/docs/zh-cn/providers.mdx @@ -45,5 +45,6 @@ description: 连接 AI 提供商、选择模型并设置智能体。 ## 相关内容 +- [集成](/zh-cn/integrations/) — 将 Claude、Command Code 或 Cursor 订阅用作提供商 - [MCP Servers](/zh-cn/mcp/) — 为智能体添加额外工具 - [用量与配额](/zh-cn/usage/) — 跟踪你已使用的量 diff --git a/packages/docs/content/docs/zh-cn/skills-catalog.mdx b/packages/docs/content/docs/zh-cn/skills-catalog.mdx index f393944e..a3d982b1 100644 --- a/packages/docs/content/docs/zh-cn/skills-catalog.mdx +++ b/packages/docs/content/docs/zh-cn/skills-catalog.mdx @@ -12,7 +12,7 @@ Skills 目录让你能够安装其他人发布的 skill,而不必自己编写 ## 安装 skill 1. 打开目录。 -2. 浏览内置来源 — Anthropic skills 仓库和 ClawHub 社区注册表 — 或进行搜索。 +2. 浏览内置来源 — 例如 Anthropic skills 仓库 — 或进行搜索。 3. 选择一个 skill 并安装它。 4. 选择安装位置:用于你的所有工作,或仅用于当前项目。 diff --git a/packages/docs/sidebar.config.json b/packages/docs/sidebar.config.json index d40c927d..e0ca0aad 100644 --- a/packages/docs/sidebar.config.json +++ b/packages/docs/sidebar.config.json @@ -364,6 +364,21 @@ "de": "Anbieter, Modelle und Agenten" } }, + { + "label": "Integrations", + "link": "/integrations/", + "translations": { + "uk": "Інтеграції", + "zh-CN": "集成", + "es": "Integraciones", + "pt-BR": "Integrações", + "ko": "통합 기능", + "pl": "Integracje", + "fr": "Intégrations", + "ja": "統合機能", + "de": "Integrationen" + } + }, { "label": "MCP Servers", "link": "/mcp/", diff --git a/packages/electron/README.md b/packages/electron/README.md index abda712a..a7763d48 100644 --- a/packages/electron/README.md +++ b/packages/electron/README.md @@ -159,7 +159,9 @@ Use an explicit override when testing a different OpenCode CLI build or when a u grants permission requests by default when no handler is set, and the panel loads whatever address the user types. Tab favicons are fetched in this session too, so icons behind the page's own login resolve and the app's origin - never requests anything from a third-party host. + never requests anything from a third-party host. Self-signed loopback HTTPS + pages may use an untrusted certificate authority; certificate failures for + external hosts and all other certificate errors remain blocked. ## IPC Pattern diff --git a/packages/electron/browser-panel-security.mjs b/packages/electron/browser-panel-security.mjs new file mode 100644 index 00000000..532148d2 --- /dev/null +++ b/packages/electron/browser-panel-security.mjs @@ -0,0 +1,12 @@ +const LOOPBACK_HOSTNAMES = new Set(['localhost', '127.0.0.1', '[::1]']); + +export const shouldAllowBrowserPanelCertificateError = ({ url, error }) => { + if (error !== 'net::ERR_CERT_AUTHORITY_INVALID') return false; + + try { + const parsed = new URL(url); + return parsed.protocol === 'https:' && LOOPBACK_HOSTNAMES.has(parsed.hostname.toLowerCase()); + } catch { + return false; + } +}; diff --git a/packages/electron/browser-panel-security.test.mjs b/packages/electron/browser-panel-security.test.mjs new file mode 100644 index 00000000..a81a9e87 --- /dev/null +++ b/packages/electron/browser-panel-security.test.mjs @@ -0,0 +1,41 @@ +import assert from 'node:assert/strict'; +import test from 'node:test'; + +import { shouldAllowBrowserPanelCertificateError } from './browser-panel-security.mjs'; + +test('allows untrusted certificate authorities for loopback HTTPS pages', () => { + for (const url of [ + 'https://localhost:58580/', + 'https://127.0.0.1:58580/', + 'https://[::1]:58580/', + ]) { + assert.equal(shouldAllowBrowserPanelCertificateError({ + url, + error: 'net::ERR_CERT_AUTHORITY_INVALID', + }), true); + } +}); + +test('keeps certificate validation for non-loopback pages', () => { + for (const url of [ + 'https://example.com/', + 'https://localhost.example.com/', + 'https://0.0.0.0:58580/', + ]) { + assert.equal(shouldAllowBrowserPanelCertificateError({ + url, + error: 'net::ERR_CERT_AUTHORITY_INVALID', + }), false); + } +}); + +test('does not bypass other certificate failures or malformed URLs', () => { + assert.equal(shouldAllowBrowserPanelCertificateError({ + url: 'https://localhost:58580/', + error: 'net::ERR_CERT_DATE_INVALID', + }), false); + assert.equal(shouldAllowBrowserPanelCertificateError({ + url: 'not a url', + error: 'net::ERR_CERT_AUTHORITY_INVALID', + }), false); +}); diff --git a/packages/electron/main.mjs b/packages/electron/main.mjs index 0bcc1de9..c6fe8edb 100644 --- a/packages/electron/main.mjs +++ b/packages/electron/main.mjs @@ -31,6 +31,7 @@ import { setLinuxAutostartEnabled, } from './linux-autostart.mjs'; import { unsupportedAppSpecificOpenError, validateLocalPath } from './path-open-utils.mjs'; +import { shouldAllowBrowserPanelCertificateError } from './browser-panel-security.mjs'; import { mintOutsideFileGrant } from '@openchamber/web/server/lib/fs/routes.js'; const execFileAsync = promisify(execFile); @@ -1186,6 +1187,15 @@ const resolveBrowserPanelContents = (rawId) => { const hardenBrowserPanelSession = () => { const panelSession = session.fromPartition(BROWSER_PANEL_PARTITION); + app.on('certificate-error', (event, contents, url, error, _certificate, callback) => { + if (contents.session === panelSession && shouldAllowBrowserPanelCertificateError({ url, error })) { + event.preventDefault(); + callback(true); + return; + } + callback(false); + }); + panelSession.setPermissionRequestHandler((_contents, permission, callback, details) => { log.info('[electron] browser panel denied a permission request', { permission, diff --git a/packages/electron/package.json b/packages/electron/package.json index 5473fc3b..8432487f 100644 --- a/packages/electron/package.json +++ b/packages/electron/package.json @@ -1,6 +1,6 @@ { "name": "@openchamber/electron", - "version": "1.18.4", + "version": "1.19.0", "private": true, "description": "Electron desktop runtime for OpenChamber", "author": "OpenChamber", diff --git a/packages/ui/package.json b/packages/ui/package.json index 751a2956..2b224dcb 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@openchamber/ui", - "version": "1.18.4", + "version": "1.19.0", "private": true, "type": "module", "main": "src/main.tsx", diff --git a/packages/ui/src/components/chat/FileAttachment.tsx b/packages/ui/src/components/chat/FileAttachment.tsx index 158a78f8..e0d140fd 100644 --- a/packages/ui/src/components/chat/FileAttachment.tsx +++ b/packages/ui/src/components/chat/FileAttachment.tsx @@ -555,19 +555,56 @@ interface FilePart { source?: Record; } -const GITHUB_ISSUE_LINK_MIME = 'application/vnd.github.issue-link'; -const GITHUB_PR_LINK_MIME = 'application/vnd.github.pull-request-link'; +const FORGE_LINK_MIMES = new Set([ + 'application/vnd.github.issue-link', + 'application/vnd.github.pull-request-link', + 'application/vnd.gitlab.issue-link', + 'application/vnd.gitlab.merge-request-link', + 'application/vnd.gitea.issue-link', + 'application/vnd.gitea.pull-request-link', +]); -const getGitHubLinkKind = (file: FilePart): 'issue' | 'pr' | null => { - if (file.mime === GITHUB_ISSUE_LINK_MIME) { - return 'issue'; +const ISSUE_LINK_MIMES = new Set([ + 'application/vnd.github.issue-link', + 'application/vnd.gitlab.issue-link', + 'application/vnd.gitea.issue-link', +]); + +const PR_LINK_MIMES = new Set([ + 'application/vnd.github.pull-request-link', + 'application/vnd.gitlab.merge-request-link', + 'application/vnd.gitea.pull-request-link', +]); + +type ForgeLinkInfo = { kind: 'issue' | 'pr'; provider: 'github' | 'gitlab' | 'gitea' } | null; + +const getForgeLinkInfo = (file: FilePart): ForgeLinkInfo => { + const mime = file.mime; + if (!mime || !FORGE_LINK_MIMES.has(mime)) return null; + + if (ISSUE_LINK_MIMES.has(mime)) { + if (mime.includes('gitlab')) return { kind: 'issue', provider: 'gitlab' }; + if (mime.includes('gitea')) return { kind: 'issue', provider: 'gitea' }; + return { kind: 'issue', provider: 'github' }; } - if (file.mime === GITHUB_PR_LINK_MIME) { - return 'pr'; + + if (PR_LINK_MIMES.has(mime)) { + if (mime.includes('gitlab')) return { kind: 'pr', provider: 'gitlab' }; + if (mime.includes('gitea')) return { kind: 'pr', provider: 'gitea' }; + return { kind: 'pr', provider: 'github' }; } + return null; }; +const forgeLinkIconName = (info: ForgeLinkInfo): 'github' | 'gitlab' | 'git-branch' | 'git-pull-request' => { + if (!info) return 'github'; + if (info.kind === 'pr') return 'git-pull-request'; + if (info.provider === 'gitlab') return 'gitlab'; + if (info.provider === 'gitea') return 'git-branch'; + return 'github'; +}; + interface MessageFilesDisplayProps { files: FilePart[]; onShowPopup?: (content: ToolPopupContent) => void; @@ -590,8 +627,8 @@ export const MessageFilesDisplay = memo(({ files, onShowPopup, compact = false } }; const resolveDisplayName = React.useCallback((file: FilePart): string => { - const isGitHubLink = getGitHubLinkKind(file) !== null; - if (isGitHubLink && typeof file.filename === 'string' && file.filename.trim().length > 0) { + const isForgeLink = getForgeLinkInfo(file) !== null; + if (isForgeLink && typeof file.filename === 'string' && file.filename.trim().length > 0) { return file.filename.trim(); } return extractFilename(file.filename || file.url); @@ -664,11 +701,11 @@ export const MessageFilesDisplay = memo(({ files, onShowPopup, compact = false } const fileName = resolveDisplayName(file); const ext = fileName.split('.').pop() || ''; const sizeText = formatFileSize(file.size); - const githubLinkKind = getGitHubLinkKind(file); + const forgeLink = getForgeLinkInfo(file); return ( - {githubLinkKind && file.url ? ( + {forgeLink && file.url ? ( + ); +}; + export const SkillsCatalogPage: React.FC = ({ mode, onModeChange, showModeTabs = true }) => { const { t } = useI18n(); const { @@ -80,12 +194,9 @@ export const SkillsCatalogPage: React.FC = ({ mode, onMo setSelectedSource, loadCatalog, loadSource, - loadMoreClawdHub, isLoadingCatalog, isLoadingSource, - isLoadingMore, loadedSourceIds, - clawdhubHasMoreBySource, lastCatalogError, } = useSkillsCatalogStore(useShallow((s) => ({ sources: s.sources, @@ -94,12 +205,9 @@ export const SkillsCatalogPage: React.FC = ({ mode, onMo setSelectedSource: s.setSelectedSource, loadCatalog: s.loadCatalog, loadSource: s.loadSource, - loadMoreClawdHub: s.loadMoreClawdHub, isLoadingCatalog: s.isLoadingCatalog, isLoadingSource: s.isLoadingSource, - isLoadingMore: s.isLoadingMore, loadedSourceIds: s.loadedSourceIds, - clawdhubHasMoreBySource: s.clawdhubHasMoreBySource, lastCatalogError: s.lastCatalogError, }))); @@ -109,43 +217,72 @@ export const SkillsCatalogPage: React.FC = ({ mode, onMo const [installItem, setInstallItem] = React.useState(null); const [isRemovingCatalog, setIsRemovingCatalog] = React.useState(false); const [isRemoveCatalogDialogOpen, setIsRemoveCatalogDialogOpen] = React.useState(false); + const searchInputRef = React.useRef(null); React.useEffect(() => { void loadCatalog(); }, [loadCatalog]); + // Load every source in the background so global search covers all of them. React.useEffect(() => { - if (!selectedSourceId) { + const unloaded = sources.filter((src) => !loadedSourceIds[src.id]); + if (unloaded.length === 0) { return; } - if (!loadedSourceIds[selectedSourceId]) { - void loadSource(selectedSourceId); + let cancelled = false; + const loadRest = async () => { + for (const src of unloaded) { + if (cancelled) { + return; + } + await loadSource(src.id); + } + }; + void loadRest(); + return () => { + cancelled = true; + }; + }, [sources, loadedSourceIds, loadSource]); + + React.useEffect(() => { + if (!selectedSourceId || loadedSourceIds[selectedSourceId]) { + return; } + void loadSource(selectedSourceId); }, [selectedSourceId, loadedSourceIds, loadSource]); - const items = React.useMemo(() => { - if (!selectedSourceId) return []; - return itemsBySource[selectedSourceId] || []; - }, [itemsBySource, selectedSourceId]); + React.useEffect(() => { + const onKeyDown = (e: KeyboardEvent) => { + if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === 'k') { + e.preventDefault(); + searchInputRef.current?.focus(); + } + }; + window.addEventListener('keydown', onKeyDown); + return () => window.removeEventListener('keydown', onKeyDown); + }, []); + + const isSearching = search.trim().length > 0; const filtered = React.useMemo(() => { const q = search.trim().toLowerCase(); - if (!q) return items; - return items.filter((item) => { - const name = item.skillName.toLowerCase(); - const desc = (item.description || '').toLowerCase(); - const fm = (item.frontmatterName || '').toLowerCase(); - return name.includes(q) || desc.includes(q) || fm.includes(q); - }); - }, [items, search]); + const matches = (item: SkillsCatalogItem) => + item.skillName.toLowerCase().includes(q) + || (item.description || '').toLowerCase().includes(q) + || (item.frontmatterName || '').toLowerCase().includes(q); + + if (isSearching) { + return sources.flatMap((src) => (itemsBySource[src.id] || []).filter(matches)); + } + if (!selectedSourceId) { + return []; + } + return itemsBySource[selectedSourceId] || []; + }, [sources, itemsBySource, selectedSourceId, search, isSearching]); const selectedSource = React.useMemo(() => sources.find((s) => s.id === selectedSourceId) || null, [sources, selectedSourceId]); const isCustomSource = Boolean(selectedSourceId && selectedSourceId.startsWith('custom:')); - const isClawdHubSource = selectedSource?.source === 'clawdhub:registry' || selectedSource?.sourceType === 'clawdhub'; - const hasMoreClawdHub = Boolean( - selectedSourceId && (clawdhubHasMoreBySource[selectedSourceId] ?? true) - ); const removeSelectedCatalog = async () => { if (!selectedSourceId || !isCustomSource) { @@ -165,6 +302,17 @@ export const SkillsCatalogPage: React.FC = ({ mode, onMo } }; + const listTitle = isSearching + ? t('settings.skills.catalog.page.list.searchTitle') + : (selectedSource?.label ?? ''); + + // The selected source has no items yet and a load is in flight — show the + // loading state instead of a stale list from the previously selected source. + const isSelectedSourceLoading = !isSearching + && selectedSourceId !== null + && !loadedSourceIds[selectedSourceId] + && (isLoadingSource || isLoadingCatalog); + return ( <> = ({ mode, onMo )} +

+ {t('settings.skills.catalog.page.subtitle')} +

- +
+
+ + setSearch(e.target.value)} + placeholder={t('settings.skills.catalog.page.searchAllPlaceholder')} + className={cn('h-8 pl-8 w-full', search && 'pr-8')} + /> + {search && ( + + )} +
+
-
- +
+ {sources.map((src) => ( + setSelectedSource(src.id)} + t={t} + /> + ))} - - - {isCustomSource && ( - - )} - - -
- -
-
- - setSearch(e.target.value)} - placeholder={t('settings.skills.catalog.shared.field.searchSkillsPlaceholder')} - className="h-7 pl-8 w-full sm:w-64" - /> -
- - {isLoadingCatalog - ? t('settings.skills.catalog.page.loading.catalog') - : t('settings.skills.catalog.page.foundCount', { count: filtered.length })} +
+ + + {t('settings.skills.catalog.page.source.addOwnTitle')} + + + {t('settings.skills.catalog.page.source.addOwnDescription')} + + + +
{lastCatalogError && ( @@ -286,21 +418,63 @@ export const SkillsCatalogPage: React.FC = ({ mode, onMo )} - {filtered.length === 0 && !isLoadingSource ? ( -
-

{t('settings.skills.catalog.page.empty.noSkillsTitle')}

-

{t('settings.skills.catalog.page.empty.noSkillsDescription')}

-
- ) : isLoadingSource ? ( +
+
+ + {listTitle} + + + {t('settings.skills.catalog.page.foundCount', { count: filtered.length })} + +
+
+ + {isCustomSource && !isSearching && ( + + )} +
+
+ + {isSelectedSourceLoading || (isLoadingSource && filtered.length === 0) ? (

{t('settings.skills.catalog.page.loading.skills')}

+ ) : filtered.length === 0 ? ( +
+

{t('settings.skills.catalog.page.empty.noSkillsTitle')}

+

{t('settings.skills.catalog.page.empty.noSkillsDescription')}

+
) : (
{filtered.map((item) => { const installed = item.installed?.isInstalled; const installedScope = item.installed?.scope; + const skillUrl = getSkillUrl(item); return (
@@ -326,24 +500,28 @@ export const SkillsCatalogPage: React.FC = ({ mode, onMo
{t('settings.skills.catalog.shared.noDescription')}
)} - {item.clawdhub && ( -
- {item.clawdhub.owner && ( - {t('settings.skills.catalog.page.byOwnerPrefix')} {item.clawdhub.owner} - )} - - - {item.clawdhub.downloads?.toLocaleString() ?? 0} - - {(item.clawdhub.stars ?? 0) > 0 && ( - - - {item.clawdhub.stars} - - )} - v{item.clawdhub.version} -
- )} +
+ {skillUrl ? ( + + + {item.repoSource} + + ) : ( + {item.repoSource} + )} + {item.skillDir && ( + <> + · + {item.skillDir} + + )} +
{item.warnings?.length ? (
@@ -352,37 +530,43 @@ export const SkillsCatalogPage: React.FC = ({ mode, onMo ) : null}
- +
+ {skillUrl && ( + + )} + {installed ? ( + + + + ) : ( + + )} +
); })} )} - {isClawdHubSource && hasMoreClawdHub && !isLoadingSource && filtered.length > 0 && ( -
- -
- )}
diff --git a/packages/ui/src/components/session/ArchiveAllDropdown.tsx b/packages/ui/src/components/session/ArchiveAllDropdown.tsx index 4e3bb808..6a76c3af 100644 --- a/packages/ui/src/components/session/ArchiveAllDropdown.tsx +++ b/packages/ui/src/components/session/ArchiveAllDropdown.tsx @@ -17,7 +17,7 @@ const ArchiveAllDropdown: React.FC = ({ onArchiveAll }) const { t } = useI18n(); return ( - +