Зробити розширення
Використовуйте @openchamber/sdk, щоб додати власну панель в OpenChamber. Розширення - це невелика вебсторінка, яку OpenChamber показує на правій рейці. Із застосунком вона спілкується через connectHost(): може читати поточний проєкт і сесію, показувати тости, вставляти текст у поле чату, прикріплювати задачу до сесії, а зі згоди користувача ще й створювати сесії та надсилати повідомлення.
Розширення працюють в OpenChamber у вебі та на десктопі. VS Code і мобільний застосунок їх поки не завантажують.
Що таке розширення
Тека з трьома файлами:
package.jsonз блокомopenchamber(маніфест)panel/index.html, сторінка, яку показує OpenChamberpanel/main.js, ваш скрипт, зібраний в один класичний файл (IIFE, не ES-модуль, бо сторінка завантажується в ізольованому iframe)
OpenChamber ніколи не компілює ваш код. Віддавайте вже зібраний .js. У SDK є команда збірки; підійде й будь-який інший бандлер, який видає IIFE.
npm install @openchamber/sdkbunx openchamber-guest-bundle panel/main.ts panel/main.jsКоманда збірки працює на Bun. Без Bun беріть esbuild або будь-який інший бандлер з --format=iife --platform=browser.
Повне робоче розширення, усі три файли, є на сторінці Приклад. Скопіюйте його і замініть API та список.
Підключіть main.js в index.html звичайним <script src="main.js"></script>.
Встановити під час роботи
- Запустіть OpenChamber у вебі або на десктопі.
- Відкрийте Налаштування → Розширення.
- Вставте абсолютний шлях до своєї теки і натисніть Додати.
OpenChamber читає маніфест і показує діалог зі списком того, що просить розширення (див. Дозволи). Підтвердьте, і ваша іконка з’явиться на рейці. Натисніть її, і сторінка завантажиться.
Можна також додати локальний .zip або https-посилання на git-репозиторій чи zip-файл. Оновлюватися вміє лише встановлення з git: підніміть version у package.json і запуште, і OpenChamber перевірить це невдовзі після відкриття та кожні кілька годин, один раз повідомить користувача й запропонує оновлення в Налаштування → Розширення. Посилання на openchamber://extensions/install?url=<encoded repository URL> на будь-якій сторінці відкриває десктопний застосунок із цим репозиторієм у діалозі додавання, тож можна запропонувати кнопку встановлення. #tag чи #branch в URL закріплює, за чим саме воно стежить. Їх OpenChamber копіює у свою теку даних і запускає з тієї копії, тому віддавайте зібрані файли, а не node_modules чи TypeScript-джерела. Видалення розширення видаляє копію. Розширення з теки працює прямо з вашої теки, тож можна редагувати, перезбирати й перезавантажувати.
Маніфест
{ "name": "@acme/hello", "version": "1.0.0", "openchamber": { "apiVersion": 1, "engines": { "openchamber": ">=1.24.0" }, "id": "acme-hello", "name": "Hello", "icon": "window", "contributes": { "panel": { "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 обов’язкова і має бути semver. Налаштування → Розширення показує її на картці.
apiVersion дорівнює 1. Будь-яке інше значення OpenChamber відхиляє.
engines.openchamber необов’язкове. Вкажіть найстарішу версію OpenChamber, з якою працює ваше розширення, як 1.24.0 або >=1.24.0. Старіші збірки відмовляться його встановлювати замість того, щоб ламатися пізніше.
id, name і icon називають розширення. id пишеться в kebab-case і має бути унікальним серед встановлених розширень. icon - це назва іконки Remixicon (RiWindowLine стає window) або SVG-файл у вашій теці, наприклад icon.svg. contributes.panel - це панель розширення на рейці: її entry - HTML-файл у вашій теці. Розширення без панелі на рейці пропускає panel. Старіші пакети тримають id, name і icon всередині panel, і це далі працює.
contributes.attach необов’язкове. Воно додає ваше розширення в меню + біля поля чату, щоб користувач міг вибрати задачу і прикріпити її до сесії.
"dialog"відкриває вашу сторінку у вікніtrueабо"panel"замість цього відкриває панель на рейці{ "mode": "dialog", "entry": "panel/attach.html" }відкриває у вікні окрему вашу сторінку, тож вибір не мусить ділити код із панеллю на рейці- без цього поля розширення в тому меню не з’являється
ctx.surface має значення panel, dialog, page, status або block. Натискання прикріпленого елемента передає його дані в ctx.item; в інших випадках це null.
contributes.page: true додає повноекранну версію панелі в меню Сторінки розширень над списком сесій. { "entry": "panel/page.html", "title": "Board" } задає окремий HTML і необов’язковий заголовок. panel.entry залишається обов’язковим, ізоляція та дозволи спільні з панеллю. Сторінку відкриває лише користувач. Перезавантаження, пауза, видалення чи зміна сервера закривають її.
Для дошки є host.storage та списки проєктів, worktree і сесій із живими станами. startSession може працювати в іншому проєкті, не закриваючи дошку. Деталі в Host API.
contributes.integration необов’язкове. Воно додає картку в Налаштування → Інтеграції, де користувач підключає обліковий запис. Див. Облікові записи і мережа.
contributes.service необов’язкове. Воно оголошує локальний сервіс (процес, який OpenChamber запускає поруч із розширенням) для речей, до яких вебсторінка не дотягнеться, наприклад сокета Docker. Цей процес працює з повним доступом користувача і без пісочниці, тому діалог підтвердження попереджає про нього; оголошуйте його лише тоді, коли сторінка не може впоратися із завданням. Див. файл пакета GUEST_SERVICES.md. Сервіс із provides: ["browser"] може також замінити браузер агента: він відповідає на дії browser.* на сервері, тож агенти працюють з вебом без відкритого десктопного застосунку, а користувач обирає його в Налаштування → Інструменти OpenChamber. Такому сервісу панель не потрібна. Сервіс також може дізнаватися, що відбувається в сесіях користувача: оголосіть поруч із ним contributes.sessionEvents, і OpenChamber надсилатиме сервісу кожен хід, який завершився або зазнав збою, і кожен дозвіл чи питання, яке ставить агент, з усіх проєктів і без відкритого вікна. Див. Події сесій. А сервіс із provides: ["notifications"] доставляє сповіщення користувача поруч із десктопом і телефоном: у Slack, Matrix або на власний сервер; користувач підключає обліковий запис у Налаштування → Інтеграції, а токен лишається в OpenChamber. Див. Канали сповіщень. Сервіс із provides: ["tracker"] — трекер робочих елементів поруч із Linear, з карткою облікового запису в розділі Облікові записи розширень; див. Трекери. А сервіс із provides: ["quota"] звітує про використання поруч із вбудованими провайдерами, читаючи облікові дані, які OpenCode зберігає для провайдерів, перелічених у маніфесті; див. Провайдери використання.
Дозволи
Щоб намалювати панель і прочитати поточну сесію, дозвіл не потрібен. Він потрібен для всього, що діє від імені користувача. Перелічіть такі речі в contributes.capabilities:
| Дозвіл | Що дозволяє |
|---|---|
prompt | надсилати повідомлення в сесію користувача (prompt({ send: true }), startSession з text) |
sessions | переглядати проєкти, worktree та стани сесій; створювати й відкривати сесії в доданих проєктах |
files | читати й писати файли всередині відкритого проєкту (readFile, writeFile, listDir, stat з відносним шляхом) |
model | одноразова генерація тексту через Small Model користувача (generate), поза будь-якою сесією |
Ще одинадцять додаються автоматично: network, коли ви оголошуєте integration, service, коли оголошуєте service, filesystem, коли оголошуєте шаблони filesystem, origins, коли оголошуєте origins, conversation, коли дія сесії просить повідомлення (див. Дії, команди та бейдж), transcript, коли sessionEvents або sessionControl просить content (див. Події сесій), sessionControl, коли ваш сервіс діє над сесіями (див. Виклик OpenChamber), sessionAnswers, коли він відповідає за користувача на запити дозволів і форми агента (sessionControl: { answers: true }), instructions, коли він доповнює те, що читають агенти, і skills, коли ви оголошуєте contributes.skills, теку пакета зі скілами, які доходять до кожного агента, поки розширення увімкнене, і opencodePlugin, коли ви оголошуєте contributes.opencodePlugin (див. нижче).
Користувач бачить повний список один раз, під час встановлення розширення, і або підтверджує його, або видаляє розширення. Якщо нова версія просить більше, діалог з’являється знову. Виклик, якому потрібен непідтверджений дозвіл, завершується помилкою NOT_GRANTED.
Плагін OpenCode у вашому пакеті
Розширення може постачати плагін OpenCode, щоб люди встановлювали одну річ замість двох. Оголосіть "opencodePlugin": "plugin", теку всередині пакета з index.js або server.js у корені. OpenCode не читає main, тож для файлу входу в іншому місці додайте name і exports у package.json цієї теки. Файл входу експортує за замовчуванням { id, setup }, форму, яку завантажує OpenCode; він нічого не імпортує, бо OpenCode завантажує його простим import() з вашої теки, де нічого не встановлено. input інструмента є звичайною JSON Schema, а його execute відповідає { content }.
{ "contributes": { "panel": { "id": "teapot-tools", "name": "Teapot Tools", "icon": "cup" }, "opencodePlugin": "plugin" }}Діалог схвалення отримує ще один рядок, Додати плагін до OpenCode, який прямо каже, що код плагіна виконується всередині OpenCode з усіма правами користувача. Після дозволу OpenChamber вписує вашу теку в конфігурацію OpenCode, якою він керує, той самий файл, що несе contributes.skills; OpenCode, який він запускає, стежить за цим файлом і завантажує плагін за кілька секунд. Вимкнення або видалення розширення прибирає його тим самим шляхом. У власний opencode.json користувача нічого не пишеться: цей файл належить користувачу, а плагін у ньому пережив би ваше розширення і працював би в кожному OpenCode на машині.
Там, де цей файл не доходить до OpenCode, екран розширення каже про це і пропонує Додати до глобальної конфігурації, що записує вашу теку в глобальну конфігурацію OpenCode користувача як запис, який відтоді належить йому. Так буває, коли OpenChamber не запускав OpenCode, з яким спілкується, або коли середовище сервера задає власний OPENCODE_CONFIG (тоді плагін завантажиться під час наступного запуску OpenCode). OpenCode на іншій машині не може завантажити теку з цієї; екран каже про це й нічого не пропонує. Про плагін, який не завантажується, OpenCode повідомляє в Налаштуваннях → Плагіни, коли там є запис; ваше розширення працює далі в будь-якому разі. Встановлення відхиляє пакет, у якого немає теки плагіна або чий package.json не вказує файл входу.
VS Code і мобільні застосунки не завантажують розширень, тож плагін до них не доходить. Сесія в ізольованому просторі запускає власний OpenCode, який ніколи не читає конфігурацію хоста. Корпоративний режим трактує плагін як локальний сервіс: він встановлюється лише з репозиторію, який вказав адміністратор. У SDK є робочий приклад, examples/opencode-plugin.
Генерація тексту
З дозволом model host.generate просить Small Model користувача дати одноразову відповідь: резюме, заголовок, чернетку. Нічого не потрапляє в сесію, історія не зберігається, і розширення ніколи не обирає провайдера. OpenChamber використовує ту саму модель, яку використовує для власної фонової роботи, обрану в Налаштування → Сесії → Small Model, або малу модель провайдера, з яким працює користувач, або модель за замовчуванням з його конфігурації OpenCode.
const { text } = await host.generate({ prompt: task.description, system: "Write a one-line summary. Return only the summary.", maxOutputTokens: 200,});Коли жодна модель недоступна, виклик завершується помилкою NO_MODEL; модель, що повернула помилку, — MODEL_FAILED. Промпти обмежені 64 000 символів, а виклик чекає до 90 секунд. Користувач бачить цей дозвіл як «Використовувати ваш Small Model», і це коштує йому токенів, тож тримайте промпти короткими й викликайте це по кліку, а не на кожне натискання клавіші.
Облікові записи і мережа
Ваша сторінка працює в пісочниці і не може сама виходити в мережу: скрипти, стилі, зображення, шрифти й медіа завантажуються лише з вашого пакета, а fetch дістає лише файли вашого пакета. Кладіть шрифти й зображення в пакет, а не завантажуйте їх із CDN.
Щоб звертатися до зовнішнього сервісу, оголосіть integration, і OpenChamber робитиме запити за вас через host.request, додаючи токен користувача. Токен ніколи не потрапляє на вашу сторінку.
Для всього іншого, що вашій сторінці потрібно напряму, наприклад шрифтів чи зображень із CDN або публічного API, перелічіть до 8 https-джерел:
"origins": ["https://fonts.example.com"]Користувач бачить їх у діалозі підтвердження як адреси, на які ваше розширення може надсилати дані й з яких може їх отримувати, і підтверджує їх знову, якщо оновлення додає нове. Підтверджені джерела відкриті для fetch, зображень, шрифтів, стилів і медіа, але ніколи для скриптів: код має постачатися у вашому пакеті. Джерело сторінки — null, тож щоб прочитати відповідь fetch, сервер має дозволити CORS для цього джерела.
У корпоративному режимі розширення з origins, integration або service встановлюється лише з Git-репозиторію, який адміністратор додав до списку. Якщо ваше розширення може працювати без них, такі команди й далі зможуть його встановити. Щоб розробляти розширення на такій машині, попросіть адміністратора про allowLocalExtensions: тоді ви зможете встановити його прямо з папки.
token: користувач вставляє API-токен на картці в Налаштування → Інтеграції.apiOrigin- єдине джерело, яке може викликатиrequest.accountнеобов’язкове: GET-шлях і назва поля, щоб картка могла показати, хто підключений.schemeкаже, як надсилати токен; див. таблицю нижче. Перевірте в документації API провайдера, який заголовок він очікує.oauth: користувач вставляє client id, а OpenChamber проводить авторизацію. ПотрібніauthorizeUrl,tokenUrlіapiOrigin.host: { "provider": "linear" }: використати обліковий запис Linear, який уже підключено в OpenChamber. Client id не потрібен.
Що надсилає кожен scheme:
scheme | Заголовок, який надсилає OpenChamber | Коли використовувати |
|---|---|---|
| не вказано | Authorization: <token> | API документує голий токен у заголовку |
"bearer" | Authorization: Bearer <token> | API документує bearer або personal access token |
"basic" | Authorization: Basic base64(username:token) | API документує HTTP Basic auth з іменем користувача (часто це email) і API-токеном; картка запитує обидва, а usernameLabel задає підпис першого поля |
settings додає на картку прості текстові поля. Їхні значення приходять у ctx.settings. Поле з "secret": true замасковане на картці й ніколи не потрапляє на сторінку; ваш сервіс читає його через readSettings().
Файли
Ваша сторінка не може торкатися диска сама. OpenChamber читає і пише за неї, у межах, які підтвердив користувач.
- Відносний шлях (
README.md,src/index.ts,.) означає відкритий проєкт. Потрібен дозвілfiles. Немає відкритого проєкту -NO_DIRECTORY. - Шлях, що починається з
/або~/, означає будь-яке інше місце. Він має збігатися з одним із шаблонів, які ви оголошуєте вcontributes.filesystem, і користувач бачить саме ці шаблони в діалозі підтвердження:
"filesystem": ["~/.config/opencode/opencode.json", "~/notes/**"]У шаблонах * означає один сегмент шляху, а ** - будь-яку глибину. Усе поза ними - BAD_PATH, навіть після підтвердження. .. не дозволяється ніколи.
const config = await host.readFile("~/.config/opencode/opencode.json");await host.writeFile("~/.config/opencode/opencode.json", nextJson);const { entries } = await host.listDir(".");Запис атомарний: OpenChamber пише тимчасовий файл і перейменовує його, тож читач ніколи не побачить напівзаписаний файл. Файли читаються і пишуться як текст UTF-8, до 2 МБ.
Секція в Work Status
contributes.statusSection додає вашу власну секцію в панель Work Status поруч із чатом. Користувачі вмикають і вимикають її та пересувають у списку секцій цієї панелі, як і вбудовані.
"statusSection": { "entry": "status/index.html", "title": "Recent commits", "height": 160 }trueбереpanel.entry.entryє окремою HTML-сторінкою у вашій теці. З неюpanel.entryне потрібен, тож розширення може складатися лише з цієї секції, без іконки на рейці.titleзамінює назву панелі в заголовку секції, до 60 символів.heightзадає початкову висоту в пікселях, від 24 до 320 (за замовчуванням 120). Викликайтеhost.setHeight(), коли розмір вмісту змінюється.
Ваша сторінка бачить ctx.surface як status. OpenChamber завантажує її, лише поки панель Work Status видно, а ваша секція розгорнута, і вивантажує, коли користувач згортає секцію, тож не тримайте там нічого, що не зможете відновити. Розширення лише із секцією може використовувати дозволи, сервіс, інтеграцію та файли, але не page, attach, actions чи commands. Лише веб і десктоп. Приклад git-graph-status є готовою секцією.
Редактор для вашого типу файлів
contributes.fileEditors відкриває файли у вашій сторінці замість текстового редактора. Коли користувач відкриває відповідний файл у Files, OpenChamber показує там ваш редактор із тим самим перемикачем вихідного коду, кнопкою повноекранного режиму та кнопкою збереження, що й у вбудованих переглядачів.
"fileEditors": [ { "id": "canvas", "title": "Excalidraw", "match": ["*.excalidraw", "*.excalidraw.md"], "entry": "editor/index.html" }]matchпорівнює лише імена файлів, без урахування регістру.*відповідає будь-якій послідовності символів, а?одному символу. Шаблон не може містити/і не може складатися лише із символів підстановки.entryє HTML-сторінкою у вашій теці.panel.entryне потрібен, тож розширення може складатися лише з редактора, без іконки на рейці.contentмає значення"text"(типово) або"binary", див. нижче.- До 8 редакторів на розширення, до 16 шаблонів у кожному.
Файлом керує OpenChamber. Ваша сторінка ніколи не читає і не записує його та не потребує для цього жодного дозволу. OpenChamber передає вам текст, просить змінений текст під час збереження і сам обробляє Cmd/Ctrl+S, автозбереження, запит про незбережені зміни, закінчення рядків і зміни на диску:
import { connectHost, createFileSaveTracker } from "@openchamber/sdk";
const host = connectHost();let tracker = createFileSaveTracker(null);
host.onFileOpen((file) => { if (file.encoding !== "text") return; // текстовий редактор завжди отримує текст load(file.content); // а також file.path, file.name, file.readOnly tracker = createFileSaveTracker(versionOf(currentText()));});
// Викликайте це після кожної зміни. `edited` притримує автозбереження, доки користувач не зупиниться.const changed = () => host.reportFileChange(tracker.observe(versionOf(currentText())));
host.onFileSnapshot(() => ({ content: currentText(), version: versionOf(currentText()) }));
// Зміни, зроблені, поки OpenChamber записував файл, залишають його незбереженим.host.onFileSaved((version) => host.reportFileChange({ dirty: tracker.markSaved(version), edited: false }));version є будь-яким коротким рядком, що змінюється разом із документом, наприклад хешем. Якщо ваш редактор не вміє відкрити файл, викличте host.reportFileUnsupported(), і OpenChamber покаже його вихідний код із повідомленням. Файли понад 20 MB залишаються в перегляді вихідного коду.
Бінарні файли
Вкажіть "content": "binary", щоб відкривати файли, які не є текстом, наприклад таблиці, документи чи зображення. Ваш редактор отримує байти файлу і повертає байти; усе інше працює так само.
host.onFileOpen((file) => { if (file.encoding !== "binary") return; open(file.bytes); // Uint8Array, точно такий, як на диску});
host.onFileSnapshot(() => ({ bytes: currentBytes(), version: versionOf(currentBytes()) }));Бінарний редактор може взяти будь-який файл, що відповідає його шаблонам, зокрема ті, які OpenChamber сам показує в перегляді, як-от зображення та PDF. Перегляду вихідного коду він не має, а коли користувач переводить його в повноекранний режим чи виводить із нього з незбереженими змінами, OpenChamber спершу зберігає їх. Читати й записувати формат має ваш редактор: OpenChamber записує рівно ті байти, які ви повертаєте.
Ваша сторінка бачить ctx.surface як file. OpenChamber перезавантажує її і знову передає файл, коли файл змінюється на диску, користувач скасовує зміни або редактор переходить у повноекранний режим чи виходить із нього. Перемагає перше увімкнене розширення, чий шаблон збігся, і воно має пріоритет над власними переглядачами OpenChamber. Розширення лише з редактором може використовувати дозволи, сервіс, інтеграцію та файли, але не page, attach, actions чи commands. Лише веб і десктоп. Приклад checklist-editor є готовим редактором.
Дії, команди та бейдж
Крім рейки і меню +, розширення може з’являтися ще в трьох місцях. Усі вони передають розширенню item так само, як клік по чипу.
Дії на повідомленнях і сесіях. Оголосіть пункти меню, і OpenChamber покаже їх поруч із вбудованими:
"actions": [ { "id": "create-task", "label": "Create task", "icon": "add-line", "where": "message", "roles": ["assistant"] }, { "id": "summarize", "label": "Summarize session", "where": "session", "payload": ["messages"] }]where також приймає selection (виділений текст у повідомленні), file (рядок у Files) і diff (виділені рядки файлу чи diff). Їхні елементи мають kind з такою самою назвою: selection містить текст, file шлях, diff шлях і діапазон рядків. На виділенні display визначає, як показується дія: label (типово), icon з підписом у підказці або both.
Дія на повідомленні відкриває ваше розширення з ctx.item виду kind: "message": id і назва сесії, тека проєкту, id повідомлення, його роль і текст. Дія на сесії відкриває його з kind: "session" та id, назвою і текою сесії. Додайте "payload": ["messages"], і елемент також несе всю розмову, від найстарішого повідомлення, той самий текст, який дає експорт у Markdown. Для цього потрібен дозвіл conversation, який користувач бачить окремим рядком у діалозі схвалення. item.action каже, який пункт натиснули.
Слеш-команди, які прикріплюють. Оголосіть команду і обробіть її на сторінці:
"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;});Коли користувач вводить /task ABC-12 у полі чату, OpenChamber просить ваше розширення розв’язати її і прикріплює те, що ви повернули, як чип, нічого не відкриваючи. Поверніть null, якщо нічого не знайдено. Якщо ваша панель закрита, OpenChamber завантажує її у фоні для цього виклику. Ім’я, яке вже використовує OpenChamber або OpenCode, ігнорується.
Бейдж на іконці в рейці. host.setBadge(3) ставить крапку на вашій іконці, а число показує в її підказці, наприклад кількість відкритих задач; host.setBadge(null) прибирає його. Відкриття панелі теж його прибирає.
Ваші інструменти в чаті
Коли ваш плагін OpenCode або MCP-сервер додає інструмент, чат показує його виклики з типовою іконкою і сирим виводом. Натомість опишіть, як вони мають виглядати, без жодного коду:
"tools": [ { "match": "mcp.jira.*", "name": "Jira", "icon": "task-line", "title": "{input.key}", "subtitle": "{output.status}", "output": "table", "columns": ["key", "summary", "status"] }]match це ім’я інструмента так, як його повідомляє OpenCode; * наприкінці збігається з префіксом. icon - це назва іконки Remixicon або .svg-файл у вашому пакеті, як і panel.icon. title і subtitle це шаблони над input, output і metadata виклику. output визначає, як малюється тіло: text, json (дерево), markdown, code з language, table з columns (рядки беруться з масиву виводу або з output.items) або auto для типового вигляду. Точний match перемагає шаблон із зірочкою, а за нічиєї виграє перше встановлене розширення. Дозвіл не потрібен: це змінює лише те, як малюються дані, що вже є в чаті.
Розширенню, яке лише оформлює інструменти, сторінка взагалі не потрібна: пропустіть panel.entry, і воно не матиме іконки на рейці, лише картку в Налаштування → Розширення. Без сторінки воно може оголошувати tools і більше нічого. Інший виняток становить секція Work Status або редактор файлів із власним entry, див. вище.
Перші рядки в панелі
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 працює лише всередині OpenChamber. Якщо відкрити сторінку як звичайний файл, кожен виклик відхиляється з HOST_UNAVAILABLE.
Спершу збирайте панель з готових елементів @openchamber/sdk/ui: кнопки, поля, випадні списки, вкладки, списки тощо, оформлені кольорами і шрифтами застосунку, щоб панель відчувалася частиною OpenChamber. Власний HTML і CSS пишіть лише для того, чого в наборі немає. Див. UI-набір.
Дивіться також
- Розширення про встановлення через SSH і вибір Git identity сервера
- Host API: кожен метод
connectHost, його обмеження і коди помилок - UI-набір: готові елементи
- Приклад: повне розширення з трьох файлів, яке можна скопіювати