openclacky 1.5.13 → 1.5.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +51 -0
- data/lib/clacky/agent/chunk_index.rb +83 -0
- data/lib/clacky/agent/history_navigation.rb +239 -0
- data/lib/clacky/agent/session_serializer.rb +38 -97
- data/lib/clacky/agent.rb +281 -276
- data/lib/clacky/agent_config.rb +1 -1
- data/lib/clacky/billing/billing_store.rb +2 -2
- data/lib/clacky/billing/platform_billing.rb +6 -0
- data/lib/clacky/brand_config.rb +13 -2
- data/lib/clacky/cli.rb +27 -0
- data/lib/clacky/client.rb +2 -2
- data/lib/clacky/default_extensions/ext-studio/agents/ext-developer/system_prompt.md +70 -134
- data/lib/clacky/default_extensions/ext-studio/panels/studio/view.js +91 -5
- data/lib/clacky/default_extensions/ext-studio/skills/ext-develop/SKILL.md +179 -577
- data/lib/clacky/default_extensions/git/panels/git/view.js +34 -14
- data/lib/clacky/default_extensions/preview/ext.yml +20 -0
- data/lib/clacky/default_extensions/preview/panels/preview/view.js +475 -0
- data/lib/clacky/default_extensions/time_machine/panels/time_machine/view.js +1 -10
- data/lib/clacky/extension/api_extension.rb +1 -1
- data/lib/clacky/extension/verifier.rb +1 -1
- data/lib/clacky/media/openai_compat.rb +70 -30
- data/lib/clacky/message_format/bedrock.rb +6 -1
- data/lib/clacky/prompts/base.md +1 -1
- data/lib/clacky/providers.rb +38 -3
- data/lib/clacky/rich_ui/rich_ui_controller.rb +1 -1
- data/lib/clacky/search_config.rb +3 -3
- data/lib/clacky/server/channel/channel_manager.rb +8 -5
- data/lib/clacky/server/git_panel.rb +10 -2
- data/lib/clacky/server/http_server.rb +161 -14
- data/lib/clacky/server/preview.rb +351 -0
- data/lib/clacky/server/web_ui_controller.rb +1 -1
- data/lib/clacky/skill.rb +48 -0
- data/lib/clacky/tools/browser.rb +176 -19
- data/lib/clacky/tools/web_search.rb +79 -8
- data/lib/clacky/ui2/components/command_suggestions.rb +2 -1
- data/lib/clacky/ui2/components/input_area.rb +22 -2
- data/lib/clacky/ui2/components/modal_component.rb +35 -6
- data/lib/clacky/ui2/ui_controller.rb +44 -7
- data/lib/clacky/utils/file_processor.rb +19 -7
- data/lib/clacky/utils/mac_app_detector.rb +186 -0
- data/lib/clacky/utils/model_pricing.rb +114 -66
- data/lib/clacky/utils/windows_app_detector.rb +334 -0
- data/lib/clacky/version.rb +1 -1
- data/lib/clacky/web/app.css +596 -130
- data/lib/clacky/web/components/chat-navigator.js +489 -202
- data/lib/clacky/web/components/code-editor.js +191 -5
- data/lib/clacky/web/components/model-picker.js +2 -1
- data/lib/clacky/web/components/quote-select.js +235 -0
- data/lib/clacky/web/core/aside.js +157 -8
- data/lib/clacky/web/core/ext.js +16 -0
- data/lib/clacky/web/features/billing/view.js +75 -21
- data/lib/clacky/web/features/skills/store.js +18 -1
- data/lib/clacky/web/features/skills/view.js +128 -7
- data/lib/clacky/web/features/workspace/store.js +80 -7
- data/lib/clacky/web/features/workspace/view.js +392 -40
- data/lib/clacky/web/i18n.js +90 -5
- data/lib/clacky/web/index.html +15 -6
- data/lib/clacky/web/sessions.js +193 -38
- data/lib/clacky/web/utils.js +34 -0
- data/lib/clacky/web/vendor/codemirror/codemirror.min.js +24 -19
- data/lib/clacky/web/vendor/codemirror/entry.js +130 -0
- data/lib/clacky/web/vendor/codemirror/package.json +29 -0
- data/lib/clacky/web/ws-dispatcher.js +20 -0
- data/lib/clacky.rb +2 -0
- metadata +11 -1
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
+
# Maintenance note: Do not relax the installed-gem source restriction.
|
|
3
|
+
# After context compression, previously inspected host files may be
|
|
4
|
+
# mistaken for extension edit targets.
|
|
2
5
|
name: ext-develop
|
|
3
6
|
description: Build, debug, or publish an OpenClacky extension — scaffold a new one from an idea, fix a broken/invisible panel/api/skill/agent, or ship it to the marketplace. Trigger on create/start extension, plugin, panel, ext verify error, "won't load", "not showing up", publish/ship/unpublish an extension.
|
|
4
7
|
agent: ext-developer
|
|
@@ -6,586 +9,185 @@ agent: ext-developer
|
|
|
6
9
|
|
|
7
10
|
# Extension Development
|
|
8
11
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
**Reference: the contracts** is not a path — it's the field/slot/event/API ground truth
|
|
65
|
-
you consult from whichever path you're on.
|
|
66
|
-
|
|
67
|
-
---
|
|
68
|
-
|
|
69
|
-
## Reference: the contracts
|
|
70
|
-
|
|
71
|
-
Read the relevant reference doc with `web_fetch` before writing code — don't guess field
|
|
72
|
-
names, hook events, adapter methods, or the `Clacky.ext` WebUI contract. These docs are
|
|
73
|
-
long (well over the default cap); pass `max_length: 20000` so you get the whole page in one
|
|
74
|
-
fetch instead of a truncated head full of nav chrome.
|
|
75
|
-
|
|
76
|
-
### Authoritative documentation
|
|
77
|
-
|
|
78
|
-
- Extension system overview → https://www.openclacky.com/docs/extension-system
|
|
79
|
-
- **ext.yml manifest — every field (names, avatar, title_zh, order, …)** → https://www.openclacky.com/docs/ext-manifest
|
|
80
|
-
- Panels (WebUI) → https://www.openclacky.com/docs/extend-webui
|
|
81
|
-
- API backends → https://www.openclacky.com/docs/extend-api
|
|
82
|
-
- **Calling the host's native APIs from a panel (sessions, trash/file-recovery, skills, memories, cron, billing, media)** → https://www.openclacky.com/docs/extend-host-api
|
|
83
|
-
- Agents (prompt, avatar, panels/skills wiring) → https://www.openclacky.com/docs/agent-config
|
|
84
|
-
- Channel adapters → https://www.openclacky.com/docs/extend-channel-adapter
|
|
85
|
-
- Patches → https://www.openclacky.com/docs/extend-patches
|
|
86
|
-
- Shell hooks → https://www.openclacky.com/docs/extend-shell-hooks
|
|
87
|
-
|
|
88
|
-
### WebUI panels: the `Clacky.ext` contract
|
|
89
|
-
|
|
90
|
-
A panel is a plain `view.js` (no build step, no React, no iframe). It reaches the host
|
|
91
|
-
**only** through `window.Clacky` — everything else on the page is off-limits. There are
|
|
92
|
-
exactly three capabilities:
|
|
93
|
-
|
|
94
|
-
```js
|
|
95
|
-
Clacky.ext.ui.mount(slot, spec, opts) // inject UI into a named slot
|
|
96
|
-
Clacky.ext.subscribe(event, handler) // observe store events + live session events (read-only)
|
|
97
|
-
Clacky.ext.api.register(name, fn) // expose a named data source; api.resolve(name)
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
**`subscribe(event, handler)`** - two event families: (1) host **store** events (`skills:changed`, `tasks:changed`, `profile:changed`, …) and (2) **live session events** mirrored from the WebSocket stream — conversation (`session:assistant-message`, `session:tool-call`, `session:tool-result`), status/errors (`session:error`, `session:warning`, `session:update`), lifecycle (`session:renamed`, `session:deleted`, …). Payload is `{ sessionId, ...wsFields }`. Full list in the "Core Events" section of the extend-webui docs. Handlers are read-only.
|
|
101
|
-
|
|
102
|
-
**`ui.mount(slot, spec, opts)`** — `spec` is either `(container, ctx, runtime) => …` or
|
|
103
|
-
`{ create?, render }`. The render function:
|
|
104
|
-
- gets a host-owned `container` DOM element — append into it, **or** return a Node / HTML
|
|
105
|
-
string and the host appends for you;
|
|
106
|
-
- returning a **function** registers it as a teardown callback;
|
|
107
|
-
- returning **`null`/`undefined` renders nothing** (safe) — a red "crashed" placeholder
|
|
108
|
-
means the render **threw**; the #1 cause is a wrong signature shifting every argument
|
|
109
|
-
(e.g. `(ctx) => …` instead of `(container, ctx) => …`). Match the signature exactly.
|
|
110
|
-
|
|
111
|
-
`ctx` carries `{ sessionId, agentProfile }`. `opts`: `order` (lower renders first,
|
|
112
|
-
default 100), `tab: { id, label, badge? }` (**required** for tabbed slots — `session.aside`
|
|
113
|
-
is tabbed), `agents: [profile]` (override auto scope), `workspace: id` (for nav items).
|
|
114
|
-
|
|
115
|
-
**Valid slot names** (mounting into any other name silently renders nothing, warned once):
|
|
116
|
-
|
|
117
|
-
```
|
|
118
|
-
header.left header.right
|
|
119
|
-
sidebar.nav.top sidebar.nav sidebar.nav.bottom sidebar.footer
|
|
120
|
-
main.workspace
|
|
121
|
-
session.banner session.composer session.aside (session.aside is tabbed)
|
|
122
|
-
settings.tabs settings.body
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
Agent scope is automatic: mounts into `session.*` / `settings.*` slots only show for the
|
|
126
|
-
panel's owning agent(s); all other slots (`sidebar.*`, `header.*`, `main.workspace`) are
|
|
127
|
-
global chrome. You rarely set `agents:` by hand.
|
|
128
|
-
|
|
129
|
-
**Per-session state** — for `session.aside/banner/composer`, pass `{ create(ctx), render }`:
|
|
130
|
-
`create` runs once per session and returns a runtime (put timers/recorders/subscriptions
|
|
131
|
-
there), `render(container, ctx, runtime)` runs on each show, and `runtime.dispose()` runs
|
|
132
|
-
when the session leaves. State survives tab switches; use this instead of module globals.
|
|
133
|
-
|
|
134
|
-
**Full-page workspace** - `Clacky.ext.ui.registerWorkspace(id, { title, render })` takes
|
|
135
|
-
over the main area with its own `#ext/<id>` URL; open it with `Clacky.ext.ui.openWorkspace(id)`,
|
|
136
|
-
typically from a `sidebar.nav` item mounted with `opts.workspace: id`.
|
|
137
|
-
|
|
138
|
-
**Sidebar nav items** - render the host nav-item structure (`div.task-item.task-item-summary >
|
|
139
|
-
div.task-row > svg.task-icon + div.task-info > span.task-name` - copy `navRow()` from the
|
|
140
|
-
`full` scaffold template) with `opts.workspace: id` so the item inherits theme styling
|
|
141
|
-
and the Router's active highlight.
|
|
142
|
-
|
|
143
|
-
**Safe mode** - `?pure=true` makes the whole registry a no-op; never rely on side effects
|
|
144
|
-
outside these calls.
|
|
145
|
-
|
|
146
|
-
### Other host services under `Clacky.*`
|
|
147
|
-
|
|
148
|
-
Beyond `Clacky.ext`, the host exposes stores as properties on `window.Clacky`. Use them
|
|
149
|
-
instead of bare globals:
|
|
150
|
-
|
|
151
|
-
```js
|
|
152
|
-
Clacky.Sessions.on("switched", handler); // active session store
|
|
153
|
-
Clacky.Router.go("session"); // top-level view routing
|
|
154
|
-
Clacky.Router.navigate("session", { id }); // navigate with params
|
|
155
|
-
Clacky.I18n.t("some.key"); // translations
|
|
156
|
-
Clacky.Modal.confirm("Delete?"); // dialogs
|
|
157
|
-
Clacky.Modal.toast("Saved", "success"); // toasts (not window.alert)
|
|
158
|
-
Clacky.Auth.passed; // auth state
|
|
159
|
-
Clacky.Workspace.list(dir); // working-directory files
|
|
160
|
-
Clacky.Skills.list(); // skill catalog
|
|
161
|
-
Clacky.WS.send({ type: "..." }); // send a WebSocket message to the agent
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
- Prefer `Clacky.Xxx.method(...)` — the recommended, forward-stable form. Never test with
|
|
165
|
-
`window.Sessions` / `"Sessions" in window` (see Hard rules).
|
|
166
|
-
|
|
167
|
-
A panel can also `fetch("/api/...")` the host's own REST endpoints directly (same origin,
|
|
168
|
-
auth is automatic) — sessions, trash/**file-recovery**, skills, memories, cron, billing,
|
|
169
|
-
media, and more each have a ready-made endpoint. Before telling a user a feature "can't be
|
|
170
|
-
done" (e.g. "delete a file but keep it recoverable"), check whether the host already
|
|
171
|
-
exposes it — `web_fetch` https://www.openclacky.com/docs/extend-host-api for the callable
|
|
172
|
-
list. Don't rebuild what the host already provides.
|
|
173
|
-
|
|
174
|
-
### API backend: the `Clacky::ApiExtension` contract
|
|
175
|
-
|
|
176
|
-
`api/handler.rb` subclasses `Clacky::ApiExtension`. Routes mount under
|
|
177
|
-
`/api/ext/<ext_id>/`. This base class already wires up auth, JSON envelopes, timeouts, and
|
|
178
|
-
path params — you only write business logic. Full surface:
|
|
179
|
-
|
|
180
|
-
```ruby
|
|
181
|
-
class MyExt < Clacky::ApiExtension
|
|
182
|
-
timeout 30 # class-wide default (max 600s)
|
|
183
|
-
|
|
184
|
-
get "/summary" do
|
|
185
|
-
json(count: session_manager.list.size) # json(key: val) → 200 JSON
|
|
186
|
-
end
|
|
187
|
-
|
|
188
|
-
post "/items/:id" do # :id → params["id"]
|
|
189
|
-
body = json_body # parsed request JSON (Hash)
|
|
190
|
-
q = query["page"] # query string params
|
|
191
|
-
File.write(data_path("items", "#{params['id']}.json"), body.to_json) # persistence
|
|
192
|
-
json({ ok: true }, status: 201)
|
|
193
|
-
end
|
|
194
|
-
|
|
195
|
-
get "/export", timeout: 60 do
|
|
196
|
-
send_data(bytes, content_type: "text/csv", filename: "out.csv")
|
|
197
|
-
end
|
|
198
|
-
end
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
Response helpers: `json` / `text(str)` / `send_data(bytes, content_type:, filename:)` /
|
|
202
|
-
`error!(msg, status:)`. Request: `params` (path), `query`, `json_body`, `req`.
|
|
203
|
-
|
|
204
|
-
- **`data_path(*parts)`** is the **official way to persist user data** — it returns a path
|
|
205
|
-
under `~/.clacky/ext-data/<id>/`, **outside** the package tree, so it survives reloads,
|
|
206
|
-
`gem update`, and even uninstall/reinstall (uninstall keeps it by default; the user opts
|
|
207
|
-
in to deleting it via a checkbox). **Never** write user data into the extension's code
|
|
208
|
-
dir (`ext_dir` / `File.join(ext_dir, ...)`) — uninstall deletes the whole package, so
|
|
209
|
-
anything there is lost. Package-internal writes are only for disposable caches.
|
|
210
|
-
- Host context (white-listed): `session_manager`, `registry`, `agent_config`, `config`
|
|
211
|
-
(from ext.yml), `logger`, `ext_id`, `ext_dir`, `project_manager`.
|
|
212
|
-
- Drive sessions from the backend: `create_session(prompt:, profile:, …)`,
|
|
213
|
-
`submit_task(session_id, prompt)`, `dispatch_to_session(session_id, prompt)` (runs a
|
|
214
|
-
side task on a fork and returns its reply without touching the conversation).
|
|
215
|
-
- **Projects**: `project_manager.all` lists projects, `find(id)` returns one (or
|
|
216
|
-
`nil`), `create(name:, working_dir:, …)` / `update(id, …)` / `delete(id)` mutate.
|
|
217
|
-
Pass `project_id:` to `create_session` to bind a session to a project - its
|
|
218
|
-
`working_dir` is inherited (unless overridden) and `agent.project_id` is persisted.
|
|
219
|
-
A panel can also `fetch("/api/projects")` directly (same-origin, no-auth; see
|
|
220
|
-
[Host API](/docs/extend-host-api)).
|
|
221
|
-
- **Session source grouping** (⚠️ opt-in only): `create_session` accepts `source: "manual"`
|
|
222
|
-
(default) or `source: "ext"`; anything else is rejected with 400. Use `"ext"` **only**
|
|
223
|
-
when the extension creates sessions the user did not individually ask for (bookkeeping,
|
|
224
|
-
background workers, one per webhook) and would otherwise flood the list — they collapse
|
|
225
|
-
under a single "Extensions" sidebar entry with their own 200-session cleanup pool.
|
|
226
|
-
**Default to `"manual"`**: a session the user asked for is one they should be able to
|
|
227
|
-
find, and folded sessions are easy to overlook while the separate pool silently consumes
|
|
228
|
-
storage until evicted. Sessions bound to a project always show in that project's area
|
|
229
|
-
regardless of `source`, and count toward the regular pool rather than the ext one.
|
|
230
|
-
- Public (no-auth) endpoints: call `public_endpoint("/path")` in the class **and** set
|
|
231
|
-
`public: true` at ext.yml top level — both are required.
|
|
232
|
-
|
|
233
|
-
### Patches & hooks (advanced — only when asked)
|
|
234
|
-
|
|
235
|
-
- **Patch** (`contributes.patches: [{ target, file, fingerprint?, on_mismatch }]`):
|
|
236
|
-
overrides a method via `Module#prepend` without editing gem source. `target` is
|
|
237
|
-
`"Clacky::Tools::WebSearch#execute"` (`#` = instance, `.` = class). `fingerprint` is a
|
|
238
|
-
SHA of the original method source; on drift the patch is disabled (`on_mismatch: disable`,
|
|
239
|
-
default) or warned (`warn`).
|
|
240
|
-
- **Hook** (`contributes.hooks: [{ event, file }]`): registers a lifecycle callback. Valid
|
|
241
|
-
`event` values (exactly these): `before_tool_use after_tool_use on_tool_error on_start
|
|
242
|
-
on_complete on_iteration session_rollback`. A `before_tool_use` hook returning
|
|
243
|
-
`{ action: :deny, reason: "…" }` **blocks** the tool call — this is how you audit or
|
|
244
|
-
gate dangerous commands. Every event passes the **agent as its last block arg**
|
|
245
|
-
(`|call, result, agent|` for `after_tool_use`); call `agent.emit_event("ext.<id>.<event>",
|
|
246
|
-
persist: true, **data)` to push structured events to the frontend. `persist: false`
|
|
247
|
-
(default) vanishes on refresh — emit a `persist: true` terminal event at the end.
|
|
248
|
-
|
|
249
|
-
### Custom tools
|
|
250
|
-
|
|
251
|
-
**Tool** (`contributes.tools: [{ id, file }]`): adds a brand-new tool to an agent's
|
|
252
|
-
schema. The tool is injected **only into agents that declare it** via `tools: [<id>]`
|
|
253
|
-
in the same container's agent spec — an agent can only reference tools from its own
|
|
254
|
-
container. `file` points at a Ruby file in the container (`tools/<id>.rb`) defining
|
|
255
|
-
`Clacky::Tools::<Camelized id>` — the file name IS the class-name mapping
|
|
256
|
-
(`tools/hello.rb` → `Clacky::Tools::Hello`). The class contract is identical to a
|
|
257
|
-
built-in tool:
|
|
258
|
-
|
|
259
|
-
```ruby
|
|
260
|
-
module Clacky
|
|
261
|
-
module Tools
|
|
262
|
-
class Weather < Base
|
|
263
|
-
self.tool_name = "weather" # the name the model calls
|
|
264
|
-
self.tool_description = "Get current weather for a city."
|
|
265
|
-
self.tool_category = "general"
|
|
266
|
-
self.tool_parameters = {
|
|
267
|
-
type: "object",
|
|
268
|
-
properties: { city: { type: "string", description: "City name" } },
|
|
269
|
-
required: %w[city]
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
def execute(city:, **)
|
|
273
|
-
{ temperature: 22, city: city }
|
|
274
|
-
end
|
|
275
|
-
end
|
|
276
|
-
end
|
|
277
|
-
end
|
|
278
|
-
```
|
|
279
|
-
|
|
280
|
-
Rules:
|
|
281
|
-
- **Instance methods only** — `execute(**args)` takes keyword args; `working_dir: nil`
|
|
282
|
-
is passed when the agent runs inside a project directory.
|
|
283
|
-
- A broken tool file is logged and skipped at startup — it never blocks the agent.
|
|
284
|
-
- Name collisions with built-ins: the extension tool **wins** (registered last, same as
|
|
285
|
-
the `local > installed > builtin` layer precedence).
|
|
286
|
-
- Prefer a `skill` when the capability can be composed from existing tools — a tool is
|
|
287
|
-
only needed for something no built-in tool can do (new API integration, new
|
|
288
|
-
system-level operation).
|
|
289
|
-
|
|
290
|
-
## Scaffold
|
|
291
|
-
|
|
292
|
-
Turn a plain-language idea into a working skeleton.
|
|
293
|
-
|
|
294
|
-
### 1 — Understand the idea
|
|
295
|
-
|
|
296
|
-
Figure out what it should DO and which contributes types it needs. Ask one clarifying
|
|
297
|
-
question only if genuinely ambiguous. Common mappings:
|
|
298
|
-
|
|
299
|
-
| User wants to… | contributes: field |
|
|
12
|
+
Use this skill to guide the workflow, not as a second API manual. The online
|
|
13
|
+
references below own the detailed contracts, examples, and reload behavior. The local
|
|
14
|
+
engineering checks below remain mandatory even when those references cannot be fetched.
|
|
15
|
+
|
|
16
|
+
## Before designing or editing
|
|
17
|
+
|
|
18
|
+
1. Identify what the user wants and the smallest capability set that can provide it.
|
|
19
|
+
Check existing host services and shared panels before building a replacement.
|
|
20
|
+
2. For behavior-only discussion, apply **Engineering checks** without enumerating APIs.
|
|
21
|
+
Before specifying or implementing an interface, choose its one matching capability
|
|
22
|
+
reference below; read the overview when container/scaffold/reload behavior is relevant.
|
|
23
|
+
Reuse verified text still in context. For a named interface, obey the system prompt's
|
|
24
|
+
strict lookup budget and stop as unverified when it is exhausted. Use the article's
|
|
25
|
+
contract/examples, not the documentation site's navigation, styles, or scripts. If the
|
|
26
|
+
user declined a fallback, request only the missing source and never ask again.
|
|
27
|
+
3. Confirm the proposed behavior, affected files, and visible result with the user
|
|
28
|
+
before scaffolding or editing. Do not publish, restart, or add privileged behavior
|
|
29
|
+
merely because implementation was approved.
|
|
30
|
+
|
|
31
|
+
### Documentation fallback
|
|
32
|
+
|
|
33
|
+
1. Fetch the relevant official URL directly; a web search is not required. For truncated
|
|
34
|
+
output, read the returned `temp_file` for the needed section. For HTML pages, `web_fetch`
|
|
35
|
+
saves extracted text with whitespace collapsed, not original HTML: line-based reading
|
|
36
|
+
may still return one long line. One targeted text extraction is enough to check a
|
|
37
|
+
detail. Do not write helper scripts or try to reconstruct code formatting from that
|
|
38
|
+
text; lost newlines can change the meaning of code comments and examples.
|
|
39
|
+
A no-file-change task includes temporary files such as `/tmp/*.py`: only read the
|
|
40
|
+
tool-returned cache, do not create a script or reformatted copy elsewhere.
|
|
41
|
+
2. If the needed contract is still missing, truncated, or ambiguous, stop this lookup.
|
|
42
|
+
Report it as unverified; no match on a page does not prove the method or its namespace
|
|
43
|
+
absent, private, or unsupported. Do not inventory other APIs to infer an answer.
|
|
44
|
+
Do not retry extraction or probe other extensions/the running host to fill the gap.
|
|
45
|
+
Ask permission to open the official documentation in a new browser tab. If already
|
|
46
|
+
authorized for this task's documentation lookup, do not ask again for each page.
|
|
47
|
+
3. After consent, use the available `browser` tool to read only the relevant official
|
|
48
|
+
documentation. Do not navigate, inspect, or close unrelated tabs. Read beyond truncated
|
|
49
|
+
snapshots as needed; opening a page alone does not verify its contents. If browser setup
|
|
50
|
+
is required, ask whether the user wants to use `browser-setup`; never enable it silently
|
|
51
|
+
or bypass a disabled browser. If the tool is unavailable, do not invent another browser
|
|
52
|
+
control mechanism or install one without approval.
|
|
53
|
+
4. If the user declines or the browser cannot retrieve the reference, ask the user to
|
|
54
|
+
supply the documentation or designate a separate source checkout matching the running
|
|
55
|
+
version and permit read-only inspection. Do not search installed OpenClacky gem source.
|
|
56
|
+
Reading a checkout does not authorize modifying it to make an extension work.
|
|
57
|
+
5. If still blocked, end with only **Unverified detail**, **Reference checked**, and
|
|
58
|
+
**Evidence or permission needed next**. For example: "I could not verify this method
|
|
59
|
+
from this page; please provide its source." Do not turn that into "the object does
|
|
60
|
+
not exist" followed by a disclaimer. Clarifying the user's goal may continue, but
|
|
61
|
+
implementation against that contract must wait. Resolve version differences before
|
|
62
|
+
relying on a contract; version metadata is allowed, installed implementation source is not.
|
|
63
|
+
|
|
64
|
+
## Capability → reference
|
|
65
|
+
|
|
66
|
+
| Need | Read |
|
|
300
67
|
|---|---|
|
|
301
|
-
|
|
|
302
|
-
|
|
|
303
|
-
|
|
|
304
|
-
|
|
|
305
|
-
|
|
|
306
|
-
|
|
|
307
|
-
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
68
|
+
| Container model, source layers, scaffold, reload, verification, publishing | [Extension System Overview](https://www.openclacky.com/docs/extension-system) |
|
|
69
|
+
| Manifest metadata, panels, agents, tools, skill restrictions, field validation | [ext.yml Manifest](https://www.openclacky.com/docs/ext-manifest) |
|
|
70
|
+
| Slots, agent scope, tab lifecycle/badges, subscriptions, replay, Composer, Aside, Modal, Workspace | [Web UI Extensions](https://www.openclacky.com/docs/extend-webui) |
|
|
71
|
+
| Extension-owned backend, route parameters, persistent data, session/project helpers, public endpoints | [HTTP API Extensions](https://www.openclacky.com/docs/extend-api) |
|
|
72
|
+
| Host sessions/history, files, recovery, billing, media, development UI helpers | [Calling Host APIs](https://www.openclacky.com/docs/extend-host-api) |
|
|
73
|
+
| Agent persona and configuration | [Agent Configuration](https://www.openclacky.com/docs/agent-config) |
|
|
74
|
+
| Skill authoring and invocation | [Skills](https://www.openclacky.com/docs/how-to-use-a-skill) |
|
|
75
|
+
| IM adapters, optional file delivery and buffered output | [Channel Adapters](https://www.openclacky.com/docs/extend-channel-adapter) |
|
|
76
|
+
| Tool-call/lifecycle hooks and persistent custom events | [Hooks](https://www.openclacky.com/docs/extend-shell-hooks) |
|
|
77
|
+
| Explicitly requested runtime patches | [Runtime Patches](https://www.openclacky.com/docs/extend-patches) |
|
|
78
|
+
|
|
79
|
+
Read the pages needed for this task, not every reference indiscriminately. This index
|
|
80
|
+
routes lookups; field lists, signatures, and code examples belong in those pages.
|
|
81
|
+
|
|
82
|
+
## Working boundaries
|
|
83
|
+
|
|
84
|
+
- Develop in `~/.clacky/ext/local/<id>/`. Never edit installed/builtin packages or
|
|
85
|
+
gem source to customize a user's extension. Do not search or read installed OpenClacky
|
|
86
|
+
gem implementation source, even to resolve missing documentation; version metadata is
|
|
87
|
+
allowed. Confirm intentional id overrides.
|
|
88
|
+
- Do not add hooks or patches without an explicit request; they execute arbitrary Ruby.
|
|
89
|
+
- Reuse the documented host APIs and theme conventions. Do not guess methods from
|
|
90
|
+
similarly named libraries or manipulate host internals.
|
|
91
|
+
- Keep data outside the extension package using the documented persistence facility.
|
|
92
|
+
Validate input and get consent for destructive or paid operations.
|
|
93
|
+
- Choose the reload procedure from the overview's contribution-specific table.
|
|
94
|
+
Do not claim that every change hot-reloads, or restart the server without consent.
|
|
95
|
+
- Verification is evidence, not a prediction: distinguish manifest checks, tests,
|
|
96
|
+
actual UI/API behavior, and anything still awaiting user verification.
|
|
97
|
+
- Local development does not imply marketplace publication.
|
|
98
|
+
|
|
99
|
+
## Engineering checks
|
|
100
|
+
|
|
101
|
+
Apply these when proposing the design and again against the actual code before handoff.
|
|
102
|
+
Do not count a promise to follow a rule as evidence that the implementation follows it.
|
|
103
|
+
|
|
104
|
+
1. **Access and side effects:** identify files, sessions, credentials, and external
|
|
105
|
+
destinations involved. Refuse unauthorized access or disclosure; never bypass host
|
|
106
|
+
authentication. Keep secrets out of frontend code and logs. Validate inputs and paths,
|
|
107
|
+
keep persistent data outside the package, and ensure destructive changes or private-data
|
|
108
|
+
transfers require specific approval rather than general permission to build.
|
|
109
|
+
2. **Request budget:** check every fetch, loop, timer, retry, and worker. Prefer events and
|
|
110
|
+
cached reads; do not repeatedly fetch full histories. Default to no added threads;
|
|
111
|
+
necessary concurrency must be bounded. No tight loops or sub-second polling. Necessary
|
|
112
|
+
polling must use a coarse interval, prevent overlap, pause when hidden or finished, and
|
|
113
|
+
have bounded retries and request duration. Check the failure path as well as success.
|
|
114
|
+
3. **Lifecycle and cost:** verify rerenders and session switches do not multiply listeners,
|
|
115
|
+
timers, or requests; disposal releases them and stale responses cannot affect a new
|
|
116
|
+
session. Hidden cached panels must pause unnecessary work without waiting for disposal.
|
|
117
|
+
A tab/session switch does not prove disposal occurred; verify unsubscribe/visibility
|
|
118
|
+
contracts instead of using assumed disposal as a substitute for cleanup.
|
|
119
|
+
Model/media calls need explicit approval, including recurring scope; mounting, refresh,
|
|
120
|
+
and history replay must not initiate paid or destructive actions or external sends.
|
|
121
|
+
Read-only billing queries are not model invocations, but still need request limits.
|
|
122
|
+
4. **Host reuse and evidence:** reuse host capabilities and `btn-*` / `form-*`,
|
|
123
|
+
`Clacky.Modal`, and `var(--color-*)`; use scoped, prefixed custom styles where needed.
|
|
124
|
+
For basic inputs use `form-input` / `form-textarea`. Confirm custom property names in
|
|
125
|
+
the relevant reference or generated scaffold, not by their plausible spelling; do not
|
|
126
|
+
invent fallback token names. If a token is unverified, omit the color override and
|
|
127
|
+
inherit host styling, rather than adding a guessed token with hardcoded fallback colors.
|
|
128
|
+
Prefix tab ids with the extension id to avoid collisions.
|
|
129
|
+
Check light/dark appearance for UI work. Do not add unrequested hooks or patches or
|
|
130
|
+
modify installed packages. Test the applicable boundaries above with controlled data;
|
|
131
|
+
do not use real destructive, disclosure, or paid operations just to prove a safeguard.
|
|
132
|
+
Report which checks were exercised, which were code review only, and which remain open.
|
|
320
133
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
```
|
|
324
|
-
clacky ext new <id>
|
|
325
|
-
```
|
|
326
|
-
|
|
327
|
-
This creates `~/.clacky/ext/local/<id>/` with a working hello panel + handler:
|
|
328
|
-
- `ext.yml` — the manifest
|
|
329
|
-
- `panels/hello/view.js` — a panel that pings the backend
|
|
330
|
-
- `api/handler.rb` — a `Clacky::ApiExtension` subclass mounted at `/api/ext/<id>/`
|
|
331
|
-
- `test/handler_test.rb` — a runnable minitest example (`ruby test/handler_test.rb`)
|
|
332
|
-
|
|
333
|
-
Use `--full` only when the user needs the kitchen-sink reference exercising all eight
|
|
334
|
-
contributes types — it's a lot to read, so prefer the plain scaffold otherwise.
|
|
335
|
-
|
|
336
|
-
### 3 — Reshape to the idea
|
|
337
|
-
|
|
338
|
-
Below is a concrete before → after for a tiny "add a note" panel — use it as
|
|
339
|
-
the shape to copy, not the literal content.
|
|
340
|
-
|
|
341
|
-
**`ext.yml`** — rename the panel id/view to the feature; add `skills:`/`agents:` only if needed:
|
|
342
|
-
|
|
343
|
-
```yaml
|
|
344
|
-
contributes:
|
|
345
|
-
api: api/handler.rb
|
|
346
|
-
panels:
|
|
347
|
-
- id: notes # was: hello
|
|
348
|
-
view: panels/notes/view.js # was: panels/hello/view.js
|
|
349
|
-
attach: ["*"]
|
|
350
|
-
```
|
|
351
|
-
|
|
352
|
-
**`panels/notes/view.js`** — keep the `Clacky.ext.ui.mount(...)` wrapper and host CSS
|
|
353
|
-
classes; swap the body for the real UI, POST to your own route:
|
|
354
|
-
|
|
355
|
-
```js
|
|
356
|
-
Clacky.ext.ui.mount("session.aside", function (container, ctx) {
|
|
357
|
-
var el = document.createElement("div");
|
|
358
|
-
el.style.padding = "16px";
|
|
359
|
-
var input = document.createElement("input");
|
|
360
|
-
input.className = "form-input"; // reuse host theme
|
|
361
|
-
var btn = document.createElement("button");
|
|
362
|
-
btn.className = "btn-primary";
|
|
363
|
-
btn.textContent = "Save note";
|
|
364
|
-
btn.addEventListener("click", async function () {
|
|
365
|
-
await fetch("/api/ext/<id>/notes", { // relative to your mount
|
|
366
|
-
method: "POST",
|
|
367
|
-
headers: { "Content-Type": "application/json" },
|
|
368
|
-
body: JSON.stringify({ text: input.value }),
|
|
369
|
-
});
|
|
370
|
-
Clacky.Modal.toast("Saved", "success"); // host toast, not window.alert
|
|
371
|
-
});
|
|
372
|
-
el.append(input, btn);
|
|
373
|
-
return el;
|
|
374
|
-
}, { tab: { id: "notes", label: () => "Notes" }, order: 500 });
|
|
375
|
-
```
|
|
376
|
-
|
|
377
|
-
**`api/handler.rb`** — stay a `Clacky::ApiExtension` subclass; add the route the panel
|
|
378
|
-
calls. Persist user data with `data_path`, never into the code dir:
|
|
379
|
-
|
|
380
|
-
```ruby
|
|
381
|
-
class <Prefix>Ext < Clacky::ApiExtension
|
|
382
|
-
post "/notes" do # matches /api/ext/<id>/notes
|
|
383
|
-
text = json_body["text"].to_s
|
|
384
|
-
File.write(data_path("notes.txt"), "#{text}\n", mode: "a")
|
|
385
|
-
json(saved: true)
|
|
386
|
-
end
|
|
387
|
-
end
|
|
388
|
-
```
|
|
389
|
-
|
|
390
|
-
Rules while reshaping:
|
|
391
|
-
- Keep the panel `view:` path and the on-disk `view.js` path in sync — mismatched paths
|
|
392
|
-
are the #1 cause of a `loader.error`.
|
|
393
|
-
- Routes in `handler.rb` are **relative** to `/api/ext/<id>/`; the `view.js` `fetch` must
|
|
394
|
-
match. A mismatch is a silent 404, not a verify error.
|
|
395
|
-
- **UI styling: default to host classes; anything the host has no class for, build
|
|
396
|
-
freely.** Colors: only `var(--color-*)` — raw hex breaks the dark theme. For the
|
|
397
|
-
full class/variable list grep the host stylesheet `lib/clacky/web/app.css`.
|
|
398
|
-
|
|
399
|
-
### 4 — Write tests
|
|
400
|
-
|
|
401
|
-
Test the backend before you call it done. Rewrite the scaffolded `test/handler_test.rb`
|
|
402
|
-
to exercise your real routes (parse the JSON response, assert its fields), then run it
|
|
403
|
-
green:
|
|
404
|
-
|
|
405
|
-
```
|
|
406
|
-
ruby test/handler_test.rb
|
|
407
|
-
```
|
|
408
|
-
|
|
409
|
-
- If `test/` is missing from the scaffold, create `test/handler_test.rb` yourself
|
|
410
|
-
(`mkdir -p test` then write it) — do NOT skip tests just because the file is absent.
|
|
411
|
-
- A handler that only returns a static string may keep the scaffold's hello test;
|
|
412
|
-
anything that fetches, transforms, caches, or computes MUST have a real test.
|
|
413
|
-
|
|
414
|
-
### 5 — Confirm it loads
|
|
415
|
-
|
|
416
|
-
Run `clacky ext verify` and confirm the new units resolve with no errors, then have the
|
|
417
|
-
user reload the WebUI page. If verify reports problems, go to **Debug & verify**.
|
|
418
|
-
|
|
419
|
-
## When NOT to build an extension
|
|
420
|
-
|
|
421
|
-
- The user is building features in their own app that just *use* openclacky — that's
|
|
422
|
-
normal coding, no extension container needed.
|
|
423
|
-
- The user wants a skill for *their own* project — use `.clacky/skills/` in their
|
|
424
|
-
project, not a gem-level container.
|
|
425
|
-
- The user wants a custom agent **tool** — contribute it from a local extension
|
|
426
|
-
(`contributes.tools`), which is the supported way to add a tool name to the agent's
|
|
427
|
-
schema. Don't patch a built-in tool to fake new behavior.
|
|
428
|
-
- The change can be made via `clacky config set ...` — prefer config over patches.
|
|
134
|
+
## Scaffold
|
|
429
135
|
|
|
430
|
-
|
|
136
|
+
1. Agree on the smallest implementation. A panel may reuse a host API without a new
|
|
137
|
+
backend; a capability composed from existing tools may only need a skill.
|
|
138
|
+
A user's ordinary app work does not need an extension container, and a project-only
|
|
139
|
+
skill can live in that project's `.clacky/skills/`.
|
|
140
|
+
2. Run `clacky ext new <id>` for a runnable skeleton. Use `--full` only when the task
|
|
141
|
+
needs the broader examples. Read generated files before changing them.
|
|
142
|
+
3. Implement the approved behavior against the referenced contracts. Keep manifest
|
|
143
|
+
paths, unit ids, and actual files aligned; do not retain unused scaffold features.
|
|
144
|
+
4. Adapt the scaffold's tests to the real behavior and run them. If a backend has no
|
|
145
|
+
tests, add them instead of treating missing tests as permission to skip verification.
|
|
146
|
+
Cover invalid input and failures as well as the successful response; apply
|
|
147
|
+
**Engineering checks** to the implementation.
|
|
148
|
+
5. Run `clacky ext verify`; resolve errors and review warnings using its actual
|
|
149
|
+
`code`, `file`, and `hint`. Verify the visible feature or endpoint afterward.
|
|
150
|
+
6. Follow **Handoff** below.
|
|
431
151
|
|
|
432
152
|
## Debug & verify
|
|
433
153
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
spelling. Allowed top-level keys: `id name name_zh display_name display_name_zh title
|
|
475
|
-
description description_zh emoji version origin author homepage license public
|
|
476
|
-
license_required keywords contributes`.
|
|
477
|
-
- **`schema.unknown_field`** → a unit has a field not allowed for its type. **Do:** delete
|
|
478
|
-
or rename that field. Allowed fields per type (this is the authoritative list — do not
|
|
479
|
-
invent others):
|
|
480
|
-
- panel: `id title title_zh description description_zh view order attach entry_points`
|
|
481
|
-
- api: `id handler`
|
|
482
|
-
- skill: `id dir protected`
|
|
483
|
-
- agent: `id title title_zh description description_zh order prompt panels skills avatar`
|
|
484
|
-
- channel: `id platform adapter`
|
|
485
|
-
- patch: `target file fingerprint on_mismatch`
|
|
486
|
-
- hook: `event file`
|
|
487
|
-
- **`schema.bad_attach`** → a panel `attach:` entry isn't a valid token. **Do:** set it to
|
|
488
|
-
an agent id or `"*"` (all).
|
|
489
|
-
- **`ref.missing_panel`** → an agent's `panels: [id]` names a panel that doesn't exist.
|
|
490
|
-
**Do:** fix the id, or use `<ext_id>/<panel_id>` to point at another extension's panel.
|
|
491
|
-
- **`ref.missing_skill`** → an agent's `skills: [id]` names a skill that doesn't exist.
|
|
492
|
-
**Do:** fix the id, or add the `SKILL.md`.
|
|
493
|
-
- **`ref.missing_attach_agent`** → a panel's `attach:` names a nonexistent agent.
|
|
494
|
-
**Do:** fix the agent id.
|
|
495
|
-
- **`override`** (warning) → a higher layer is shadowing a lower one
|
|
496
|
-
(`local > installed > builtin`). **Do:** usually intentional — leave it; confirm with the
|
|
497
|
-
user only if the shadowing is a surprise.
|
|
498
|
-
|
|
499
|
-
Fix one issue, re-run verify, repeat until clean.
|
|
500
|
-
|
|
501
|
-
### 3 — "It verifies but doesn't show up"
|
|
502
|
-
|
|
503
|
-
If verify is clean but a change isn't visible:
|
|
504
|
-
- **Hot reload is per-request.** After editing `view.js`, `handler.rb`, or a `SKILL.md`,
|
|
505
|
-
the user must **reload the WebUI page** — no restart, but a stale tab won't update on
|
|
506
|
-
its own. Editing `ext.yml` also applies on the next load.
|
|
507
|
-
- **Panel not appearing?** In order: (1) the `slot` name in `ui.mount` must be one of the
|
|
508
|
-
valid slots — a typo like `session.aisde` silently renders nothing (check the browser
|
|
509
|
-
console for a "unknown slot" warning); (2) check the panel's `attach:` (or the agent
|
|
510
|
-
that references it via `panels: [id]`) — a panel with no `attach` and no referencing
|
|
511
|
-
agent has nothing to mount onto; (3) a red error box means the render function threw
|
|
512
|
-
(usually a wrong signature) — open the console for the stack.
|
|
513
|
-
- **API 404?** Routes are relative to `/api/ext/<ext_id>/`. Confirm the handler subclasses
|
|
514
|
-
`Clacky::ApiExtension` and the route pattern matches what `view.js` fetches.
|
|
515
|
-
- **Skill not triggering?** The AI selects skills by their `description`. Make the
|
|
516
|
-
description concrete about WHEN to use it.
|
|
517
|
-
|
|
518
|
-
### 4 — Confirm the fix
|
|
519
|
-
|
|
520
|
-
End with a clean `clacky ext verify` and have the user reload to confirm the behavior
|
|
521
|
-
actually works — don't declare success on "should work."
|
|
522
|
-
|
|
523
|
-
---
|
|
524
|
-
|
|
525
|
-
## Publish (optional)
|
|
526
|
-
|
|
527
|
-
Publishing is **not** a required step. Many extensions are built for the user's own use —
|
|
528
|
-
scaffold, verify, and reload is the whole job. Only publish when the user explicitly asks
|
|
529
|
-
to share, ship, or list the extension for others. Never publish on your own initiative or
|
|
530
|
-
as a "wrap up" of the build.
|
|
531
|
-
|
|
532
|
-
The **Creator Center panel** has a Publish button — prefer it for a
|
|
533
|
-
guided flow. Use the CLI below for scripted/CI publishing.
|
|
534
|
-
|
|
535
|
-
### Before publishing
|
|
536
|
-
|
|
537
|
-
- The extension must live in the **local** layer (`~/.clacky/ext/local/<id>/`). Only local
|
|
538
|
-
containers can be packed; encrypted (`SKILL.md.enc`) containers are rejected.
|
|
539
|
-
- Publishing requires the device to be **bound to a platform account** (it attributes the
|
|
540
|
-
extension to that account). If it isn't bound, tell the user to authorize the device
|
|
541
|
-
first — don't try to work around it.
|
|
542
|
-
- Run `clacky ext verify` one last time and confirm no errors.
|
|
543
|
-
- **README check:** If `~/.clacky/ext/local/<id>/README.md` does not exist, ask the user
|
|
544
|
-
before proceeding: "No README.md found — would you like me to write usage instructions
|
|
545
|
-
first?" If yes, read the source files and write a concise README, then publish. If the
|
|
546
|
-
user asks to write a README / usage instructions at any point, do the same.
|
|
547
|
-
|
|
548
|
-
### Publish (first time)
|
|
549
|
-
|
|
550
|
-
```
|
|
551
|
-
clacky ext publish <id>
|
|
552
|
-
```
|
|
553
|
-
|
|
554
|
-
Packs the local container into a zip and uploads it. On success: `Published <id>
|
|
555
|
-
v<version> → status=<status>`. Options:
|
|
556
|
-
- `--status draft` — publish as a draft (not visible on the public marketplace). Omit or
|
|
557
|
-
use `--status published` to go live.
|
|
558
|
-
- `--changelog "..."` — release notes for this version.
|
|
559
|
-
|
|
560
|
-
### Publish a new version
|
|
561
|
-
|
|
562
|
-
If already published, a plain `publish` fails with `Error: <id> already published. Re-run
|
|
563
|
-
with --force to publish a new version.` Re-run with `--force` (and ideally a `--changelog`);
|
|
564
|
-
the patch version auto-increments on the platform side.
|
|
565
|
-
|
|
566
|
-
```
|
|
567
|
-
clacky ext publish <id> --force --changelog "Fixed the weather refresh bug"
|
|
568
|
-
```
|
|
569
|
-
|
|
570
|
-
### List your published extensions
|
|
571
|
-
|
|
572
|
-
```
|
|
573
|
-
clacky ext published
|
|
574
|
-
```
|
|
575
|
-
|
|
576
|
-
Shows each extension with its latest version, status, and unit summary.
|
|
577
|
-
|
|
578
|
-
### Unpublish
|
|
579
|
-
|
|
580
|
-
```
|
|
581
|
-
clacky ext unpublish <id>
|
|
582
|
-
```
|
|
583
|
-
|
|
584
|
-
Soft-deletes (takes down) one of your published extensions. Confirm with the user first —
|
|
585
|
-
it removes it from the marketplace.
|
|
586
|
-
|
|
587
|
-
### Wrap up
|
|
588
|
-
|
|
589
|
-
After a successful publish, tell the user the version and status in plain terms, and
|
|
590
|
-
mention they can run `clacky ext published` to see it, or bump a new version anytime with
|
|
591
|
-
`--force`.
|
|
154
|
+
1. Reproduce the reported symptom; inspect the actual local container and relevant
|
|
155
|
+
reference before proposing a fix.
|
|
156
|
+
2. Run `clacky ext verify` and read its structured findings. Use `clacky ext list`
|
|
157
|
+
to identify the resolved layer and accidental shadowing. Do not maintain a second
|
|
158
|
+
hardcoded list of accepted keys in this skill.
|
|
159
|
+
3. For invisible panels, check documented slots, tab options, manifest associations,
|
|
160
|
+
and the browser error stack. For API failures, check the request method/path,
|
|
161
|
+
handler contract, status, and logs. For stale behavior, check the reload matrix.
|
|
162
|
+
4. Fix the root cause within the agreed scope, rerun relevant tests and verification,
|
|
163
|
+
then check the reported behavior and the affected **Engineering checks**. Do not widen
|
|
164
|
+
scope to unrelated warnings without discussing them with the user.
|
|
165
|
+
5. Follow **Handoff** below.
|
|
166
|
+
|
|
167
|
+
## Publish (only on explicit request)
|
|
168
|
+
|
|
169
|
+
1. Read the overview's current publishing requirements and command options.
|
|
170
|
+
2. Confirm the target local container, intended marketplace status, device binding,
|
|
171
|
+
and version. Do not bypass authentication, ownership, or encrypted-content limits.
|
|
172
|
+
3. Run tests and verification. If `README.md` is missing, ask whether to write usage
|
|
173
|
+
instructions before proceeding; derive them from the actual implemented behavior.
|
|
174
|
+
4. Publish only the approved target/version/status. Updating an existing extension
|
|
175
|
+
requires manually choosing a greater version in `ext.yml`; `--force` does not
|
|
176
|
+
increment it. Explain failures instead of guessing alternate publish behavior.
|
|
177
|
+
5. Report the actual version and status returned. Unpublishing also needs explicit
|
|
178
|
+
approval; it is not routine cleanup.
|
|
179
|
+
|
|
180
|
+
## Handoff
|
|
181
|
+
|
|
182
|
+
- State what changed, what passed, and what the user still needs to check.
|
|
183
|
+
- After extension edits, use the development UI helpers documented in **Calling Host
|
|
184
|
+
APIs** to show the refresh button once; also open the aside for a session-aside panel.
|
|
185
|
+
Use the injected service/session context, not a guessed host, port, or session id.
|
|
186
|
+
- These HTTP helpers are not browser control. If the user will test the browser, keep
|
|
187
|
+
that boundary and report UI checks as pending; do not treat it as permission to inspect
|
|
188
|
+
their tabs. Honor a separate request not to send UI-helper broadcasts.
|
|
189
|
+
- A successful UI-helper response only acknowledges a broadcast. If no matching UI
|
|
190
|
+
is connected, ask for manual refresh. Verify required Ruby reloads separately;
|
|
191
|
+
neither UI helper restarts the server.
|
|
192
|
+
- Stop at the approved outcome. Do not publish or perform other release actions as
|
|
193
|
+
an automatic wrap-up.
|