Eklenti oluşturma
OpenChamber’a kendi panelinizi eklemek için @openchamber/sdk kullanın. Eklenti, OpenChamber’ın sağ şeritte gösterdiği küçük bir web sayfasıdır. Uygulamayla connectHost() üzerinden konuşur: geçerli projeyi ve oturumu okuyabilir, bildirim gösterebilir, sohbet kutusuna metin koyabilir, bir oturuma görev iliştirebilir ve kullanıcının onayıyla oturum başlatıp istem gönderebilir.
Eklentiler OpenChamber web ve masaüstünde çalışır. VS Code ve mobil henüz eklenti yüklemiyor.
Eklenti nedir
Üç dosyalı bir klasör:
openchamberbloğu (manifest) içerenpackage.jsonpanel/index.html, OpenChamber’ın gösterdiği sayfapanel/main.js, tek bir klasik dosya olarak derlenmiş betiğiniz (sayfa sandbox’lı bir iframe içinde yüklendiği için ES modülü değil, IIFE)
OpenChamber kodunuzu asla derlemez. Derlenmiş .js dosyasını yayınlayın. SDK bir paketleme komutu içerir; IIFE üreten herhangi bir paketleyici de olur.
npm install @openchamber/sdkbunx openchamber-guest-bundle panel/main.ts panel/main.jsPaketleme komutu Bun üzerinde çalışır. Bun yoksa esbuild’i ya da başka bir paketleyiciyi --format=iife --platform=browser ile kullanın.
Üç dosyanın tamamıyla çalışan eksiksiz bir eklenti Örnek sayfasında. Kopyalayın, API’yi ve listeyi değiştirin.
index.html içinde main.js dosyasına normal bir <script src="main.js"></script> ile bağlanın.
Çalışırken kurma
- OpenChamber’ı web veya masaüstünde çalıştırın.
- Ayarlar → Uzantılar sayfasını açın.
- Klasörünüzün mutlak yolunu yapıştırıp Ekle’ye tıklayın.
OpenChamber manifesti okur ve eklentinin ne istediğini listeleyen bir pencere gösterir (bkz. Yetenekler). Onaylayın, simgeniz şeritte belirir. Tıklayın, sayfanız yüklenir.
Yerel bir .zip dosyası ya da bir git deposuna veya zip dosyasına giden https bağlantısı da ekleyebilirsiniz. Yalnızca git kurulumu güncellenebilir: package.json içindeki version değerini yükseltip push edin; kullanıcı Ayarlar → Uzantılar sayfasını bir sonraki açışında OpenChamber güncellemeyi sunar. URL’deki #tag ya da #branch neyi izleyeceğini sabitler. Bunlar OpenChamber’ın veri klasörüne kopyalanır ve o kopyadan çalışır; bu yüzden node_modules veya TypeScript kaynaklarını değil, derlenmiş dosyaları yayınlayın. Eklentiyi kaldırmak kopyayı siler. Klasörden kurulum doğrudan sizin klasörünüzden çalışır; düzenleyip yeniden derleyip yeniden yükleyebilirsiniz.
Manifest
{ "name": "@acme/hello", "version": "1.0.0", "openchamber": { "apiVersion": 1, "engines": { "openchamber": ">=1.24.0" }, "contributes": { "panel": { "id": "acme-hello", "name": "Hello", "icon": "window", "entry": "panel/index.html" }, "attach": "dialog", "page": true, "capabilities": ["prompt", "sessions"], "integration": { "name": "Acme", "description": "Tasks from Acme", "token": { "apiOrigin": "https://api.acme.example", "account": { "path": "/me", "name": "login" }, "scheme": "bearer" }, "settings": [{ "id": "list-id", "label": "List ID" }] } } }}version zorunludur ve semver olmalıdır. Ayarlar → Uzantılar bunu kartta gösterir.
apiVersion değeri 1’dir. OpenChamber başka değerleri reddeder.
engines.openchamber isteğe bağlıdır. Eklentinizin çalıştığı en eski OpenChamber sürümünü 1.24.0 veya >=1.24.0 biçiminde yazın. Daha eski sürümler sonradan hata vermek yerine kurulumu reddeder.
contributes.panel şerit girişini tanımlar. id kebab-case olmalı ve kurulu eklentiler arasında benzersiz olmalıdır. icon bir Remixicon adı (RiWindowLine için window) ya da klasörünüzdeki bir SVG dosyasıdır, örneğin icon.svg. entry klasörünüzdeki HTML dosyasıdır; yalnızca tools tanımlayan bir eklentide bunu atlayın (bkz. Sohbetteki araçlarınız).
contributes.attach isteğe bağlıdır. Eklentinizi sohbet kutusunun yanındaki + menüsüne ekler; kullanıcı buradan bir görev seçip oturuma iliştirebilir.
"dialog"sayfanızı bir pencerede açartrueveya"panel"bunun yerine şerit panelini açar{ "mode": "dialog", "entry": "panel/attach.html" }pencerede size ait ayrı bir sayfa açar; böylece seçicinin şerit paneliyle kod paylaşması gerekmez- atlarsanız eklenti o menüde görünmez
ctx.surface, panel, dialog veya page olur. İliştirilmiş bir öğeye tıklanınca verileri ctx.item içinde gelir; diğer durumlarda değer null olur.
contributes.page: true, paneli oturum listesinin üstündeki Uzantı sayfaları menüsünden tam ekran açılabilir yapar. { "entry": "panel/page.html", "title": "Board" } ayrı HTML ve isteğe bağlı başlık kullanır. panel.entry zorunludur; yalıtım ve izinler aynıdır. Sayfayı yalnızca kullanıcı açar. Yenileme, duraklatma, kaldırma veya sunucu değiştirme sayfayı kapatır.
Panolar host.storage ile proje, worktree ve oturum listelerini ve canlı durumları kullanabilir. startSession, panoyu kapatmadan başka bir projeyi hedefleyebilir. Bkz. Host API.
contributes.integration isteğe bağlıdır. Ayarlar → Entegrasyonlar sayfasına kullanıcının hesap bağladığı bir kart ekler. Bkz. Hesaplar ve ağ.
contributes.service isteğe bağlıdır. OpenChamber’ın eklentinin yanında başlattığı yerel bir süreç tanımlar; bir web sayfasının ulaşamadığı şeyler için, örneğin bir Docker soketi. Bu süreç kullanıcının tam erişimiyle ve sandbox olmadan çalışır, bu yüzden onay iletişim kutusu bunu uyarır; sayfa işi yapamadığında bir tane tanımlayın. Paket dosyası GUEST_SERVICES.md dosyasına bakın. provides: ["browser"] içeren bir hizmet ajanın tarayıcısının yerine de geçebilir: browser.* eylemlerini sunucuda yanıtlar, böylece ajanlar açık bir masaüstü uygulaması olmadan gezinir; kullanıcı bunu Ayarlar → OpenChamber Araçları’ndan seçer. Böyle bir hizmetin panele ihtiyacı yoktur.
Yetenekler
Panel çizmek ve geçerli oturumu okumak izin gerektirmez. Kullanıcı adına bir şey yapan her şey gerektirir. Bunları contributes.capabilities içinde listeleyin:
| Yetenek | Neye izin verir |
|---|---|
prompt | kullanıcının oturumuna mesaj göndermek (prompt({ send: true }), text ile startSession) |
sessions | projeleri, worktree ve oturum durumlarını listelemek; kayıtlı projelerde oturum oluşturmak ve açmak |
files | açık projedeki dosyaları okuyup yazmak (göreli yol ile readFile, writeFile, listDir, stat) |
model | kullanıcının Small Model’iyle tek seferlik metin üretimi (generate), herhangi bir oturumun dışında |
Dört tanesi sizin için otomatik eklenir: bir integration tanımladığınızda network, bir service tanımladığınızda service, filesystem desenleri tanımladığınızda filesystem ve bir oturum eylemi mesajları istediğinde conversation (bkz. Eylemler, komutlar ve rozet).
Kullanıcı tam listeyi bir kez, eklentiyi kurarken görür ve ya onaylar ya da eklentiyi kaldırır. Yeni bir sürüm daha fazlasını isterse pencere yeniden görünür. Kullanıcının onaylamadığı bir yeteneği gerektiren çağrı NOT_GRANTED ile başarısız olur.
Metin üretme
model yeteneğiyle host.generate, kullanıcının Small Model’inden tek seferlik bir yanıt ister: bir özet, bir başlık, bir taslak. Hiçbir şey bir oturuma girmez, geçmiş tutulmaz ve eklenti asla bir sağlayıcı seçmez. OpenChamber, kendi arka plan işleri için kullandığı aynı modeli kullanır; bu model Ayarlar → Oturumlar → Small Model üzerinden seçilir veya kullanıcının oturum açtığı sağlayıcılardan otomatik olarak seçilir.
const { text } = await host.generate({ prompt: task.description, system: "Write a one-line summary. Return only the summary.", maxOutputTokens: 200,});Hiçbir model kullanılamadığında çağrı NO_MODEL ile başarısız olur; hata veren bir model MODEL_FAILED olur. İstemler 64.000 karakterle sınırlıdır ve çağrı en fazla 90 saniye bekler. Kullanıcı bu izni “Small Model’inizi kullanma” olarak görür ve bu ona jetona mal olur, bu yüzden istemleri kısa tutun ve her tuş vuruşunda değil, bir tıklamada çağırın.
Hesaplar ve ağ
Sayfanız bir sandbox içinde çalışır ve internete doğrudan erişemez. Bir integration tanımlayın; OpenChamber çağrıları host.request üzerinden, kullanıcının token’ı ekli olarak sizin yerinize yapar. Token sayfanıza asla ulaşmaz.
token: kullanıcı Ayarlar → Entegrasyonlar kartına bir API token’ı yapıştırır.apiOrigin,requestçağrısının erişebileceği tek kaynaktır.accountisteğe bağlıdır: bir GET yolu ve bir alan adı; kart böylece kimin bağlı olduğunu gösterebilir.scheme, token’ın nasıl gönderileceğini belirler; aşağıdaki tabloya bakın. Hangi başlığı beklediğini sağlayıcının API belgelerinden kontrol edin.oauth: kullanıcı bir client id yapıştırır, yetkilendirme akışını OpenChamber yürütür.authorizeUrl,tokenUrlveapiOrigingerekir.host: { "provider": "linear" }: OpenChamber’da zaten bağlı olan Linear hesabını yeniden kullanır. Client id gerekmez.
Her scheme ne gönderir:
scheme | OpenChamber’ın gönderdiği başlık | Ne zaman kullanılır |
|---|---|---|
| atlanmış | Authorization: <token> | API başlıkta çıplak bir token belgeliyorsa |
"bearer" | Authorization: Bearer <token> | API bearer veya personal access token belgeliyorsa |
"basic" | Authorization: Basic base64(username:token) | API kullanıcı adı (çoğunlukla e-posta) ve API token’ı ile HTTP Basic auth belgeliyorsa; kart ikisini de sorar ve usernameLabel ilk alanı adlandırır |
settings karta düz metin alanları ekler. Değerleri ctx.settings içinde gelir.
Dosyalar
Sayfanız diske kendisi dokunamaz. OpenChamber onun yerine, kullanıcının onayladığı sınırlar içinde okur ve yazar.
- Göreli bir yol (
README.md,src/index.ts,.) açık projeyi ifade eder.filesyeteneği gerektirir. Açık proje yoksaNO_DIRECTORYolur. /veya~/ile başlayan bir yol başka herhangi bir yeri ifade eder.contributes.filesystemiçinde tanımladığınız desenlerden biriyle eşleşmelidir ve kullanıcı onay penceresinde tam olarak bu desenleri görür:
"filesystem": ["~/.config/opencode/opencode.json", "~/notes/**"]Desenlerde * tek bir yol parçasını, ** herhangi bir derinliği karşılar. Bunların dışındaki her şey, onaydan sonra bile BAD_PATH olur. .. hiçbir zaman izinli değildir.
const config = await host.readFile("~/.config/opencode/opencode.json");await host.writeFile("~/.config/opencode/opencode.json", nextJson);const { entries } = await host.listDir(".");Yazmalar atomiktir: OpenChamber geçici bir dosya yazıp yeniden adlandırır, böylece okuyan taraf hiçbir zaman yarım yazılmış bir dosya görmez. Dosyalar UTF-8 metin olarak, en fazla 2 MB’a kadar okunur ve yazılır.
Eylemler, komutlar ve rozet
Şerit ve + menüsünün ötesinde, bir eklenti üç yerde daha görünebilir. Hepsi eklentiye, bir etiket tıklamasının yaptığı gibi bir item verir.
Mesajlar ve oturumlar üzerindeki eylemler. Menü girdileri tanımlayın, OpenChamber bunları yerleşik olanların yanında gösterir:
"actions": [ { "id": "create-task", "label": "Create task", "icon": "add-line", "where": "message", "roles": ["assistant"] }, { "id": "summarize", "label": "Summarize session", "where": "session", "payload": ["messages"] }]Bir mesaj eylemi, eklentinizi kind: "message" olan bir ctx.item ile açar: oturum id’si ve başlığı, proje dizini, mesaj id’si, rolü ve metni. Bir oturum eylemi ise kind: "session" ile, oturum id’si, başlığı ve dizini ile açar. "payload": ["messages"] ekleyin, öğe tüm konuşmayı da taşır, en eskisi önce olmak üzere, Markdown dışa aktarmanın ürettiği metnin aynısı. Bu, kullanıcının onay iletişim kutusunda ayrı bir satır olarak gördüğü conversation yeteneğini gerektirir. item.action hangi girdiye tıklandığını söyler.
İliştiren eğik çizgi komutları. Bir komut tanımlayın ve sayfada işleyin:
"commands": [{ "name": "task", "description": "Attach a task by id" }]host.onResolve(async ({ command, args }) => { const task = await findTask(args.trim()); return task ? { providerId: "acme-tasks", id: task.id, title: task.title, url: task.url } : null;});Kullanıcı sohbet kutusuna /task ABC-12 yazdığında OpenChamber eklentinizden bunu çözmesini ister ve döndürdüğünüzü, hiçbir şey açmadan, etiket olarak iliştirir. “Bir şey bulunamadı” için null döndürün. Paneliniz kapalıysa OpenChamber bu çağrı için onu arka planda yükler. OpenChamber’ın veya OpenCode’un zaten kullandığı bir ad yok sayılır.
Şerit simgesindeki rozet. host.setBadge(3) simgenizde bir sayı gösterir, örneğin açık görevler; host.setBadge(null) onu temizler. Paneli açmak da temizler.
Sohbetteki araçlarınız
OpenCode eklentiniz veya MCP sunucunuz bir araç eklediğinde sohbet, çağrılarını genel bir simge ve ham çıktıyla gösterir. Bunun yerine, kod yazmadan nasıl görünmeleri gerektiğini bildirin:
"tools": [ { "match": "mcp.jira.*", "name": "Jira", "icon": "task-line", "title": "{input.key}", "subtitle": "{output.status}", "output": "table", "columns": ["key", "summary", "status"] }]match, OpenCode’un bildirdiği haliyle aracın adıdır; sondaki * bir öneki eşleştirir. icon, panel.icon gibi bir Remixicon adı ya da paketinizdeki bir .svg dosyasıdır. title ve subtitle, çağrının input, output ve metadata değerleri üzerinde çalışan şablonlardır. output, gövdenin nasıl çizileceğini seçer: text, json (ağaç), markdown, language ile code, columns ile table (satırlar çıktı dizisinden veya output.items içinden gelir) ya da varsayılan için auto. Tam bir match joker karakteri yener; eşitlikte ilk yüklenen eklenti kazanır. İzin gerekmez: bu yalnızca sohbette zaten bulunan verilerin nasıl çizildiğini değiştirir.
Yalnızca araçları biçimlendiren bir eklentinin sayfaya hiç ihtiyacı yoktur: panel.entry öğesini atlayın, şeritte simgesi olmaz, sadece Ayarlar → Uzantılar içinde bir kart görünür. Sayfası olmadan yalnızca tools tanımlayabilir, başka bir şey tanımlamaz.
Paneldeki ilk satırlar
import { connectHost } from "@openchamber/sdk";
const host = connectHost();
host.onReady((ctx) => { document.body.dataset.theme = ctx.theme.mode; document.body.dataset.surface = ctx.surface;});connectHost yalnızca OpenChamber içinde çalışır. Sayfa düz bir dosya olarak açıldığında her çağrı HOST_UNAVAILABLE ile reddedilir.
Paneli önce @openchamber/sdk/ui yapı taşlarıyla kurun: düğmeler, alanlar, açılır listeler, sekmeler, listeler ve daha fazlası, uygulamanın renkleri ve yazı tipleriyle; böylece panel OpenChamber’ın bir parçası gibi hissedilir. Kendi HTML ve CSS’inizi yalnızca kitte olmayanlar için yazın. Bkz. UI kiti.