openclacky 1.3.6 → 1.3.8

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.
Files changed (112) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +54 -0
  3. data/lib/clacky/agent/hook_manager.rb +10 -1
  4. data/lib/clacky/agent/system_prompt_builder.rb +1 -1
  5. data/lib/clacky/agent.rb +17 -3
  6. data/lib/clacky/agent_profile.rb +124 -53
  7. data/lib/clacky/billing/billing_store.rb +3 -2
  8. data/lib/clacky/brand_config.rb +309 -6
  9. data/lib/clacky/cli.rb +4 -57
  10. data/lib/clacky/default_extensions/coding/agents/coding/avatar.png +0 -0
  11. data/lib/clacky/default_extensions/coding/ext.yml +19 -0
  12. data/lib/clacky/default_extensions/ext-studio/agents/ext-developer/avatar.png +0 -0
  13. data/lib/clacky/default_extensions/ext-studio/agents/ext-developer/system_prompt.md +95 -0
  14. data/lib/clacky/default_extensions/ext-studio/api/handler.rb +254 -0
  15. data/lib/clacky/default_extensions/ext-studio/ext.yml +33 -0
  16. data/lib/clacky/default_extensions/ext-studio/panels/studio/view.js +1288 -0
  17. data/lib/clacky/default_extensions/ext-studio/skills/ext-debug/SKILL.md +71 -0
  18. data/lib/clacky/default_extensions/ext-studio/skills/ext-publish/SKILL.md +74 -0
  19. data/lib/clacky/default_extensions/ext-studio/skills/ext-scaffold/SKILL.md +65 -0
  20. data/lib/clacky/default_extensions/general/agents/general/avatar.png +0 -0
  21. data/lib/clacky/default_extensions/general/ext.yml +19 -0
  22. data/lib/clacky/default_extensions/git/ext.yml +12 -0
  23. data/lib/clacky/{default_agents/_panels/git/panel.js → default_extensions/git/panels/git/view.js} +4 -5
  24. data/lib/clacky/default_extensions/meeting/{handler.rb → api/handler.rb} +78 -26
  25. data/lib/clacky/default_extensions/meeting/ext.yml +15 -0
  26. data/lib/clacky/default_extensions/meeting/{meeting.js → panels/meeting/view.js} +266 -90
  27. data/lib/clacky/default_extensions/meeting/skills/meeting-summarizer/SKILL.md +2 -1
  28. data/lib/clacky/default_extensions/time_machine/ext.yml +12 -0
  29. data/lib/clacky/{default_agents/_panels/time_machine/panel.js → default_extensions/time_machine/panels/time_machine/view.js} +58 -47
  30. data/lib/clacky/default_skills/channel-manager/discord_setup.rb +1 -1
  31. data/lib/clacky/default_skills/extend-openclacky/SKILL.md +83 -18
  32. data/lib/clacky/{api_extension.rb → extension/api_extension.rb} +27 -11
  33. data/lib/clacky/extension/api_loader.rb +136 -0
  34. data/lib/clacky/extension/cli_commands.rb +226 -0
  35. data/lib/clacky/{server/api_extension_dispatcher.rb → extension/dispatcher.rb} +22 -9
  36. data/lib/clacky/extension/hook_loader.rb +77 -0
  37. data/lib/clacky/extension/loader.rb +489 -0
  38. data/lib/clacky/extension/packager.rb +226 -0
  39. data/lib/clacky/{patch_loader.rb → extension/patch_loader.rb} +45 -0
  40. data/lib/clacky/extension/scaffold/template_renderer.rb +64 -0
  41. data/lib/clacky/extension/scaffold/templates/full/README.md.erb +48 -0
  42. data/lib/clacky/extension/scaffold/templates/full/agents/designer.md +5 -0
  43. data/lib/clacky/extension/scaffold/templates/full/api/handler.rb.erb +16 -0
  44. data/lib/clacky/extension/scaffold/templates/full/channels/noop.rb.erb +40 -0
  45. data/lib/clacky/extension/scaffold/templates/full/ext.yml.erb +41 -0
  46. data/lib/clacky/extension/scaffold/templates/full/hooks/audit.rb +9 -0
  47. data/lib/clacky/extension/scaffold/templates/full/panels/dashboard/view.js.erb +194 -0
  48. data/lib/clacky/extension/scaffold/templates/full/patches/audit.rb +15 -0
  49. data/lib/clacky/extension/scaffold/templates/full/skills/__slug__-skill/SKILL.md.erb +8 -0
  50. data/lib/clacky/extension/scaffold/templates/hello/api/handler.rb.erb +9 -0
  51. data/lib/clacky/extension/scaffold/templates/hello/ext.yml.erb +12 -0
  52. data/lib/clacky/extension/scaffold/templates/hello/panels/hello/view.js.erb +31 -0
  53. data/lib/clacky/extension/scaffold.rb +55 -0
  54. data/lib/clacky/extension/verifier.rb +196 -0
  55. data/lib/clacky/identity.rb +70 -0
  56. data/lib/clacky/locales/en.rb +19 -1
  57. data/lib/clacky/locales/zh.rb +19 -1
  58. data/lib/clacky/platform_http_client.rb +18 -15
  59. data/lib/clacky/server/channel/extension_adapter_loader.rb +32 -0
  60. data/lib/clacky/server/channel.rb +6 -0
  61. data/lib/clacky/server/http_server.rb +439 -146
  62. data/lib/clacky/server/session_registry.rb +9 -2
  63. data/lib/clacky/shell_hook_loader.rb +266 -22
  64. data/lib/clacky/skill_loader.rb +28 -1
  65. data/lib/clacky/ui2/components/welcome_banner.rb +1 -1
  66. data/lib/clacky/ui2/ui_controller.rb +9 -6
  67. data/lib/clacky/utils/workspace_rules.rb +2 -2
  68. data/lib/clacky/version.rb +1 -1
  69. data/lib/clacky/web/app.css +1034 -675
  70. data/lib/clacky/web/app.js +63 -15
  71. data/lib/clacky/web/auth.js +2 -0
  72. data/lib/clacky/web/components/notify.js +2 -0
  73. data/lib/clacky/web/components/sidebar.js +1 -5
  74. data/lib/clacky/web/core/ext.js +432 -89
  75. data/lib/clacky/web/features/backup/store.js +1 -0
  76. data/lib/clacky/web/features/backup/view.js +0 -1
  77. data/lib/clacky/web/features/brand/view.js +13 -5
  78. data/lib/clacky/web/features/extensions/store.js +184 -0
  79. data/lib/clacky/web/features/extensions/view.js +390 -0
  80. data/lib/clacky/web/features/new-session/store.js +199 -0
  81. data/lib/clacky/web/features/new-session/view.js +619 -0
  82. data/lib/clacky/web/features/share/view.js +63 -14
  83. data/lib/clacky/web/features/skills/store.js +3 -1
  84. data/lib/clacky/web/features/skills/view.js +1 -1
  85. data/lib/clacky/web/features/tasks/view.js +12 -0
  86. data/lib/clacky/web/features/trash/store.js +24 -6
  87. data/lib/clacky/web/features/trash/view.js +48 -12
  88. data/lib/clacky/web/features/workspace/store.js +2 -0
  89. data/lib/clacky/web/features/workspace/view.js +0 -1
  90. data/lib/clacky/web/i18n.js +152 -106
  91. data/lib/clacky/web/index.html +172 -190
  92. data/lib/clacky/web/sessions.js +67 -272
  93. data/lib/clacky/web/settings.js +1 -1
  94. data/lib/clacky/web/skills.js +88 -48
  95. data/lib/clacky/web/theme.js +5 -0
  96. data/lib/clacky/web/ws-dispatcher.js +12 -2
  97. data/lib/clacky/web/ws.js +2 -0
  98. data/lib/clacky.rb +21 -10
  99. metadata +52 -21
  100. data/benchmark/runner.rb +0 -441
  101. data/lib/clacky/api_extension_loader.rb +0 -168
  102. data/lib/clacky/default_agents/SOUL.md +0 -3
  103. data/lib/clacky/default_agents/USER.md +0 -1
  104. data/lib/clacky/default_agents/coding/profile.yml +0 -5
  105. data/lib/clacky/default_agents/coding/webui/.gitkeep +0 -0
  106. data/lib/clacky/default_agents/general/profile.yml +0 -2
  107. data/lib/clacky/default_extensions/meeting/meta.yml +0 -3
  108. data/lib/clacky/web/features/creator/store.js +0 -81
  109. data/lib/clacky/web/features/creator/view.js +0 -380
  110. /data/lib/clacky/{default_agents → default_extensions/coding/agents}/coding/system_prompt.md +0 -0
  111. /data/lib/clacky/{default_agents → default_extensions/general/agents}/general/system_prompt.md +0 -0
  112. /data/lib/clacky/{default_agents/base_prompt.md → prompts/base.md} +0 -0
@@ -30,6 +30,25 @@ const SkillAC = (() => {
30
30
 
31
31
  let _ime = null; // IME tracker for #user-input, set up in _initDOMBindings
32
32
 
33
+ // The active DOM/behavior config. Defaults to the chat composer; `attach()`
34
+ // can swap in a different set of element ids (e.g. the new-session page).
35
+ // `fetchSkills` returns the skill list; `onSend` fires on bare Enter.
36
+ const _chatCfg = {
37
+ input: "user-input",
38
+ dropdown: "skill-autocomplete",
39
+ list: "skill-autocomplete-list",
40
+ slashBtn: "btn-slash",
41
+ systemChk: "chk-ac-show-system-skills",
42
+ fetchSkills: null, // null → use session-scoped default fetch
43
+ onSend: () => Sessions.sendMessage(),
44
+ };
45
+ let _cfg = _chatCfg;
46
+
47
+ const _inputEl = () => $(_cfg.input);
48
+ const _dropdownEl = () => $(_cfg.dropdown);
49
+ const _listEl = () => $(_cfg.list);
50
+ const _slashBtnEl = () => $(_cfg.slashBtn);
51
+
33
52
  /** Called whenever the active session changes — just store the id, no prefetch. */
34
53
  function _loadForSession(sessionId) {
35
54
  _currentSession = sessionId || null;
@@ -37,6 +56,14 @@ const SkillAC = (() => {
37
56
 
38
57
  /** Fetch live skill list from server for the current session. */
39
58
  async function _fetchSkills() {
59
+ if (_cfg.fetchSkills) {
60
+ try {
61
+ return (await _cfg.fetchSkills()) || [];
62
+ } catch (e) {
63
+ console.error("[SkillAC] custom fetchSkills failed", e);
64
+ return [];
65
+ }
66
+ }
40
67
  if (!_currentSession) return [];
41
68
  try {
42
69
  const res = await fetch(`/api/sessions/${_currentSession}/skills`);
@@ -130,7 +157,7 @@ const SkillAC = (() => {
130
157
 
131
158
  _items = scored.map(({ skill }) => skill);
132
159
 
133
- const list = $("skill-autocomplete-list");
160
+ const list = _listEl();
134
161
  list.innerHTML = "";
135
162
 
136
163
  if (_items.length === 0) {
@@ -139,7 +166,7 @@ const SkillAC = (() => {
139
166
  emptyEl.className = "skill-ac-empty";
140
167
  emptyEl.textContent = I18n.t("skills.ac.empty");
141
168
  list.appendChild(emptyEl);
142
- $("skill-autocomplete").style.display = "";
169
+ _dropdownEl().style.display = "";
143
170
  _visible = true;
144
171
  _createOverlay();
145
172
  return;
@@ -222,17 +249,17 @@ const SkillAC = (() => {
222
249
  list.appendChild(item);
223
250
  });
224
251
 
225
- $("skill-autocomplete").style.display = "";
252
+ _dropdownEl().style.display = "";
226
253
  _visible = true;
227
254
  _createOverlay();
228
255
  }
229
256
 
230
257
  function _hide() {
231
- $("skill-autocomplete").style.display = "none";
258
+ _dropdownEl().style.display = "none";
232
259
  _visible = false;
233
260
  _activeIndex = -1;
234
261
  _items = [];
235
- $("btn-slash")?.classList.remove("active");
262
+ _slashBtnEl()?.classList.remove("active");
236
263
  _removeOverlay();
237
264
  }
238
265
 
@@ -260,7 +287,7 @@ const SkillAC = (() => {
260
287
  function _select(idx) {
261
288
  const skill = _items[idx];
262
289
  if (!skill) return;
263
- const input = $("user-input");
290
+ const input = _inputEl();
264
291
  input.value = "/" + skill.name + " ";
265
292
  input.style.height = "auto";
266
293
  input.style.height = Math.min(input.scrollHeight, 200) + "px";
@@ -272,7 +299,7 @@ const SkillAC = (() => {
272
299
  if (!_visible || _items.length === 0) return;
273
300
  _activeIndex = (_activeIndex + delta + _items.length) % _items.length;
274
301
  // Re-render to apply active class
275
- const list = $("skill-autocomplete-list");
302
+ const list = _listEl();
276
303
  list.querySelectorAll(".skill-ac-item").forEach((el, i) => {
277
304
  el.classList.toggle("active", i === _activeIndex);
278
305
  if (i === _activeIndex) el.scrollIntoView({ block: "nearest" });
@@ -283,7 +310,7 @@ const SkillAC = (() => {
283
310
  async function _openAll() {
284
311
  _activeIndex = 0; // Default to first item
285
312
  await _render("");
286
- $("user-input").focus();
313
+ _inputEl().focus();
287
314
  }
288
315
 
289
316
  /** Toggle the dropdown (open if hidden, close if visible). */
@@ -297,16 +324,17 @@ const SkillAC = (() => {
297
324
 
298
325
  // ── DOM bindings: composer keyboard/composition/input + slash button + ────
299
326
  // ── skill-panel create/import buttons. Called once from init(). ──
300
- function _initDOMBindings() {
327
+ function _initDOMBindings(cfg) {
301
328
  // / button: set input to "/" and open skill autocomplete.
302
329
  // mousedown + preventDefault prevents the textarea from losing focus
303
330
  // (which would trigger the blur→hide timer and immediately close
304
331
  // the dropdown we're about to open).
305
- $("btn-slash").addEventListener("mousedown", e => {
306
- e.preventDefault(); // keep focus on user-input
332
+ $(cfg.slashBtn).addEventListener("mousedown", e => {
333
+ e.preventDefault(); // keep focus on the input
307
334
  });
308
- $("btn-slash").addEventListener("click", () => {
309
- const input = $("user-input");
335
+ $(cfg.slashBtn).addEventListener("click", () => {
336
+ _cfg = cfg;
337
+ const input = $(cfg.input);
310
338
  if (input.value === "" || input.value === "/") {
311
339
  input.value = "/";
312
340
  input.style.height = "auto";
@@ -314,28 +342,31 @@ const SkillAC = (() => {
314
342
  }
315
343
  _toggle(); // Toggle dropdown instead of always opening
316
344
  if (_visible) {
317
- $("btn-slash").classList.add("active");
345
+ $(cfg.slashBtn).classList.add("active");
318
346
  }
319
347
  input.focus();
320
348
  });
321
349
 
322
350
  // IME composition tracker: shared by main keydown + AC _handleKey.
323
- _ime = IME.track($("user-input"));
351
+ const ime = IME.track($(cfg.input));
324
352
 
325
353
  // Main composer keydown: SkillAC consumes nav keys first, then Enter → send.
326
- $("user-input").addEventListener("keydown", e => {
354
+ $(cfg.input).addEventListener("keydown", e => {
355
+ _cfg = cfg;
356
+ _ime = ime;
327
357
  // Let skill autocomplete consume arrow/enter/escape first
328
358
  if (_handleKey(e)) return;
329
359
 
330
- if (e.key === "Enter" && !e.shiftKey && !_ime.isComposing(e)) {
360
+ if (e.key === "Enter" && !e.shiftKey && !ime.isComposing(e)) {
331
361
  e.preventDefault();
332
- Sessions.sendMessage();
362
+ cfg.onSend();
333
363
  }
334
364
  });
335
365
 
336
366
  // Composer input: auto-grow textarea, normalize full-width slash, drive AC.
337
- $("user-input").addEventListener("input", () => {
338
- const el = $("user-input");
367
+ $(cfg.input).addEventListener("input", () => {
368
+ _cfg = cfg;
369
+ const el = $(cfg.input);
339
370
  el.style.height = "auto";
340
371
  el.style.height = Math.min(el.scrollHeight, 200) + "px";
341
372
 
@@ -350,11 +381,25 @@ const SkillAC = (() => {
350
381
  _update(el.value);
351
382
  });
352
383
 
353
- // Skills panel action buttons (domain belongs to Skills, but the
354
- // bindings live here because this is where all composer/skill-related
355
- // DOM wiring was historically colocated).
356
- $("btn-create-skill").addEventListener("click", () => Skills.createInSession());
357
- $("btn-import-skill").addEventListener("click", () => Skills.toggleImportBar());
384
+ const chk = $(cfg.systemChk);
385
+ if (chk) {
386
+ chk.checked = _showSystemSkills;
387
+ chk.addEventListener("change", async () => {
388
+ _cfg = cfg;
389
+ _showSystemSkills = chk.checked;
390
+ localStorage.setItem("skill-ac-show-system", _showSystemSkills ? "true" : "false");
391
+ if (_visible) {
392
+ const query = _getSlashQuery($(cfg.input).value);
393
+ if (query !== null) await _render(query);
394
+ }
395
+ });
396
+ }
397
+
398
+ // Skills panel action buttons only exist in the chat composer.
399
+ if (cfg === _chatCfg) {
400
+ $("btn-create-skill").addEventListener("click", () => Skills.createInSession());
401
+ $("btn-import-skill").addEventListener("click", () => Skills.toggleImportBar());
402
+ }
358
403
  }
359
404
 
360
405
  // Update handler — driven from the input event above. Exposed on the
@@ -407,30 +452,23 @@ const SkillAC = (() => {
407
452
  if (_initialized) return;
408
453
  _initialized = true;
409
454
 
410
- const chk = $("chk-ac-show-system-skills");
411
-
412
- if (chk) {
413
- // Restore state from localStorage
414
- chk.checked = _showSystemSkills;
415
-
416
- chk.addEventListener("change", async () => {
417
- _showSystemSkills = chk.checked;
418
- // Persist to localStorage
419
- localStorage.setItem("skill-ac-show-system", _showSystemSkills ? "true" : "false");
420
-
421
- // If dropdown is visible, re-fetch and re-render
422
- if (_visible) {
423
- const input = $("user-input");
424
- const query = _getSlashQuery(input.value);
425
- if (query !== null) {
426
- await _render(query);
427
- }
428
- }
429
- });
430
- }
455
+ // Wire up all composer/slash DOM bindings for the chat composer.
456
+ _initDOMBindings(_chatCfg);
457
+ },
431
458
 
432
- // Wire up all composer/slash DOM bindings.
433
- _initDOMBindings();
459
+ /**
460
+ * Attach the autocomplete to a second composer (e.g. the new-session page).
461
+ * `config` overrides element ids and provides `fetchSkills` / `onSend`.
462
+ */
463
+ attach(config) {
464
+ const cfg = Object.assign({}, _chatCfg, config);
465
+ _initDOMBindings(cfg);
466
+ return {
467
+ /** Programmatic input handler (call from the input event if needed). */
468
+ update: (value) => { _cfg = cfg; _update(value); },
469
+ hide: _hide,
470
+ get visible() { return _visible; },
471
+ };
434
472
  },
435
473
 
436
474
  /** Called on every `input` event — decide whether to show/hide/update. */
@@ -452,3 +490,5 @@ const SkillAC = (() => {
452
490
  handleKey: _handleKey,
453
491
  };
454
492
  })();
493
+
494
+ Clacky.SkillAC = SkillAC;
@@ -30,11 +30,13 @@ const Theme = (() => {
30
30
  // Icon shows what you'd switch TO, not what you are on.
31
31
  if (theme === "light") {
32
32
  // In light mode → show moon (click to go dark)
33
+ headerToggle.title = I18n.t("header.theme.toDark");
33
34
  headerToggle.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon-sm">
34
35
  <path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z"/>
35
36
  </svg>`;
36
37
  } else {
37
38
  // In dark mode → show sun (click to go light)
39
+ headerToggle.title = I18n.t("header.theme.toLight");
38
40
  headerToggle.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon-sm">
39
41
  <circle cx="12" cy="12" r="4"/>
40
42
  <path d="M12 2v2"/>
@@ -75,6 +77,9 @@ const Theme = (() => {
75
77
  if (mq.addEventListener) mq.addEventListener("change", onChange);
76
78
  else if (mq.addListener) mq.addListener(onChange); // Safari < 14
77
79
  }
80
+
81
+ // Re-apply title text when language changes.
82
+ document.addEventListener("langchange", () => _updateToggleIcon(current()));
78
83
  }
79
84
 
80
85
  // Explicit apply (used by toggle). Persists the choice unless it equals
@@ -216,8 +216,17 @@ WS.onEvent(ev => {
216
216
  // send it now — after restoreFromHash has settled — so appendMsg won't be wiped.
217
217
  const pendingMsg = Sessions.takePendingMessage();
218
218
  if (pendingMsg && pendingMsg.session_id === ev.session_id) {
219
- Sessions.appendMsg("user", escapeHtml(pendingMsg.display || pendingMsg.content), { time: new Date() });
220
- WS.send({ type: "message", session_id: pendingMsg.session_id, content: pendingMsg.content, lang: I18n.lang() });
219
+ const html = pendingMsg.files && pendingMsg.files.length
220
+ ? (pendingMsg.display || escapeHtml(pendingMsg.content))
221
+ : escapeHtml(pendingMsg.display || pendingMsg.content);
222
+ Sessions.appendMsg("user", html, { time: new Date() });
223
+ WS.send({
224
+ type: "message",
225
+ session_id: pendingMsg.session_id,
226
+ content: pendingMsg.content,
227
+ files: pendingMsg.files || undefined,
228
+ lang: I18n.lang(),
229
+ });
221
230
  }
222
231
  break;
223
232
  }
@@ -281,6 +290,7 @@ WS.onEvent(ev => {
281
290
  }
282
291
 
283
292
  case "session_deleted":
293
+ if (window.Clacky && Clacky.ext) Clacky.ext.notifySessionRemoved(ev.session_id);
284
294
  Sessions.remove(ev.session_id);
285
295
  if (ev.session_id === Sessions.activeId) Router.navigate("welcome");
286
296
  Sessions.renderList();
data/lib/clacky/web/ws.js CHANGED
@@ -126,3 +126,5 @@ const WS = (() => {
126
126
  get ready() { return _ready; },
127
127
  };
128
128
  })();
129
+
130
+ Clacky.WS = WS;
data/lib/clacky.rb CHANGED
@@ -95,6 +95,7 @@ require_relative "clacky/ui2/progress_indicator"
95
95
  require_relative "clacky/utils/logger"
96
96
  require_relative "clacky/proxy_config"
97
97
  require_relative "clacky/platform_http_client"
98
+ require_relative "clacky/identity"
98
99
  require_relative "clacky/utils/encoding"
99
100
  require_relative "clacky/utils/environment_detector"
100
101
  require_relative "clacky/utils/browser_detector"
@@ -140,18 +141,28 @@ require_relative "clacky/server/browser_manager"
140
141
  require_relative "clacky/server/backup_manager"
141
142
  require_relative "clacky/cli"
142
143
 
143
- # Runtime patch layer: load user/AI patches from ~/.clacky/patches/ after all
144
- # gem code is defined, so fingerprints reflect the actual installed source.
145
- require_relative "clacky/patch_loader"
144
+ # Extension architecture: define the base class + container loader + scaffolding
145
+ # + dispatcher up front so the patch / hook loaders below can read its result.
146
+ require_relative "clacky/extension/api_extension"
147
+ require_relative "clacky/extension/api_loader"
148
+ require_relative "clacky/extension/loader"
149
+ require_relative "clacky/extension/scaffold/template_renderer"
150
+ require_relative "clacky/extension/scaffold"
151
+ require_relative "clacky/extension/packager"
152
+ require_relative "clacky/extension/dispatcher"
153
+ require_relative "clacky/extension/hook_loader"
154
+ require_relative "clacky/extension/verifier"
155
+ Clacky::ExtensionLoader.load_all
156
+
157
+ # Runtime patch layer: load user/AI patches from ~/.clacky/patches/ AND patches
158
+ # contributed by ext.yml containers (contributes.patches). Runs after all gem
159
+ # code is defined, so fingerprints reflect the actual installed source.
160
+ require_relative "clacky/extension/patch_loader"
146
161
  Clacky::PatchLoader.load_all
147
162
 
148
- # HTTP API extension layer: define the base class + loader + dispatcher.
149
- # Loading of user extensions is deferred to HttpServer#start so the host
150
- # process is fully initialized before extension handlers can resolve helpers
151
- # like session_manager or agent_config.
152
- require_relative "clacky/api_extension"
153
- require_relative "clacky/api_extension_loader"
154
- require_relative "clacky/server/api_extension_dispatcher"
163
+ # Process-wide registry of hook callbacks contributed by ext.yml containers
164
+ # (contributes.hooks). Each agent copies them onto its own HookManager at init.
165
+ Clacky::ExtensionHookLoader.load_all
155
166
 
156
167
  module Clacky
157
168
  class AgentInterrupted < Exception; end # Inherit from Exception to bypass rescue StandardError
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openclacky
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.6
4
+ version: 1.3.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - windy
@@ -315,7 +315,6 @@ files:
315
315
  - benchmark/results/report_20260511_175256.json
316
316
  - benchmark/results/report_20260511_175444.json
317
317
  - benchmark/results/treatment_20260511_175103.json
318
- - benchmark/runner.rb
319
318
  - bin/clacky
320
319
  - bin/clarky
321
320
  - bin/openclacky
@@ -356,8 +355,6 @@ files:
356
355
  - lib/clacky/agent_config.rb
357
356
  - lib/clacky/agent_profile.rb
358
357
  - lib/clacky/anthropic_stream_aggregator.rb
359
- - lib/clacky/api_extension.rb
360
- - lib/clacky/api_extension_loader.rb
361
358
  - lib/clacky/banner.rb
362
359
  - lib/clacky/bedrock_stream_aggregator.rb
363
360
  - lib/clacky/billing/billing_record.rb
@@ -366,20 +363,28 @@ files:
366
363
  - lib/clacky/brand_config.rb
367
364
  - lib/clacky/cli.rb
368
365
  - lib/clacky/client.rb
369
- - lib/clacky/default_agents/SOUL.md
370
- - lib/clacky/default_agents/USER.md
371
- - lib/clacky/default_agents/_panels/git/panel.js
372
- - lib/clacky/default_agents/_panels/time_machine/panel.js
373
- - lib/clacky/default_agents/base_prompt.md
374
- - lib/clacky/default_agents/coding/profile.yml
375
- - lib/clacky/default_agents/coding/system_prompt.md
376
- - lib/clacky/default_agents/coding/webui/.gitkeep
377
- - lib/clacky/default_agents/general/profile.yml
378
- - lib/clacky/default_agents/general/system_prompt.md
379
- - lib/clacky/default_extensions/meeting/handler.rb
380
- - lib/clacky/default_extensions/meeting/meeting.js
381
- - lib/clacky/default_extensions/meeting/meta.yml
366
+ - lib/clacky/default_extensions/coding/agents/coding/avatar.png
367
+ - lib/clacky/default_extensions/coding/agents/coding/system_prompt.md
368
+ - lib/clacky/default_extensions/coding/ext.yml
369
+ - lib/clacky/default_extensions/ext-studio/agents/ext-developer/avatar.png
370
+ - lib/clacky/default_extensions/ext-studio/agents/ext-developer/system_prompt.md
371
+ - lib/clacky/default_extensions/ext-studio/api/handler.rb
372
+ - lib/clacky/default_extensions/ext-studio/ext.yml
373
+ - lib/clacky/default_extensions/ext-studio/panels/studio/view.js
374
+ - lib/clacky/default_extensions/ext-studio/skills/ext-debug/SKILL.md
375
+ - lib/clacky/default_extensions/ext-studio/skills/ext-publish/SKILL.md
376
+ - lib/clacky/default_extensions/ext-studio/skills/ext-scaffold/SKILL.md
377
+ - lib/clacky/default_extensions/general/agents/general/avatar.png
378
+ - lib/clacky/default_extensions/general/agents/general/system_prompt.md
379
+ - lib/clacky/default_extensions/general/ext.yml
380
+ - lib/clacky/default_extensions/git/ext.yml
381
+ - lib/clacky/default_extensions/git/panels/git/view.js
382
+ - lib/clacky/default_extensions/meeting/api/handler.rb
383
+ - lib/clacky/default_extensions/meeting/ext.yml
384
+ - lib/clacky/default_extensions/meeting/panels/meeting/view.js
382
385
  - lib/clacky/default_extensions/meeting/skills/meeting-summarizer/SKILL.md
386
+ - lib/clacky/default_extensions/time_machine/ext.yml
387
+ - lib/clacky/default_extensions/time_machine/panels/time_machine/view.js
383
388
  - lib/clacky/default_parsers/doc_parser.rb
384
389
  - lib/clacky/default_parsers/docx_parser.rb
385
390
  - lib/clacky/default_parsers/pdf_parser.rb
@@ -434,6 +439,30 @@ files:
434
439
  - lib/clacky/default_skills/skill-creator/scripts/run_loop.py
435
440
  - lib/clacky/default_skills/skill-creator/scripts/utils.py
436
441
  - lib/clacky/default_skills/skill-creator/scripts/validate_skill_frontmatter.rb
442
+ - lib/clacky/extension/api_extension.rb
443
+ - lib/clacky/extension/api_loader.rb
444
+ - lib/clacky/extension/cli_commands.rb
445
+ - lib/clacky/extension/dispatcher.rb
446
+ - lib/clacky/extension/hook_loader.rb
447
+ - lib/clacky/extension/loader.rb
448
+ - lib/clacky/extension/packager.rb
449
+ - lib/clacky/extension/patch_loader.rb
450
+ - lib/clacky/extension/scaffold.rb
451
+ - lib/clacky/extension/scaffold/template_renderer.rb
452
+ - lib/clacky/extension/scaffold/templates/full/README.md.erb
453
+ - lib/clacky/extension/scaffold/templates/full/agents/designer.md
454
+ - lib/clacky/extension/scaffold/templates/full/api/handler.rb.erb
455
+ - lib/clacky/extension/scaffold/templates/full/channels/noop.rb.erb
456
+ - lib/clacky/extension/scaffold/templates/full/ext.yml.erb
457
+ - lib/clacky/extension/scaffold/templates/full/hooks/audit.rb
458
+ - lib/clacky/extension/scaffold/templates/full/panels/dashboard/view.js.erb
459
+ - lib/clacky/extension/scaffold/templates/full/patches/audit.rb
460
+ - lib/clacky/extension/scaffold/templates/full/skills/__slug__-skill/SKILL.md.erb
461
+ - lib/clacky/extension/scaffold/templates/hello/api/handler.rb.erb
462
+ - lib/clacky/extension/scaffold/templates/hello/ext.yml.erb
463
+ - lib/clacky/extension/scaffold/templates/hello/panels/hello/view.js.erb
464
+ - lib/clacky/extension/verifier.rb
465
+ - lib/clacky/identity.rb
437
466
  - lib/clacky/idle_compression_timer.rb
438
467
  - lib/clacky/json_ui_controller.rb
439
468
  - lib/clacky/locales/en.rb
@@ -457,9 +486,9 @@ files:
457
486
  - lib/clacky/message_history.rb
458
487
  - lib/clacky/null_ui_controller.rb
459
488
  - lib/clacky/openai_stream_aggregator.rb
460
- - lib/clacky/patch_loader.rb
461
489
  - lib/clacky/plain_ui_controller.rb
462
490
  - lib/clacky/platform_http_client.rb
491
+ - lib/clacky/prompts/base.md
463
492
  - lib/clacky/providers.rb
464
493
  - lib/clacky/proxy_config.rb
465
494
  - lib/clacky/rich_ui.rb
@@ -478,7 +507,6 @@ files:
478
507
  - lib/clacky/rich_ui/shell/rich_agent_shell.rb
479
508
  - lib/clacky/rich_ui/view_renderer.rb
480
509
  - lib/clacky/rich_ui_controller.rb
481
- - lib/clacky/server/api_extension_dispatcher.rb
482
510
  - lib/clacky/server/backup_manager.rb
483
511
  - lib/clacky/server/browser_manager.rb
484
512
  - lib/clacky/server/channel.rb
@@ -504,6 +532,7 @@ files:
504
532
  - lib/clacky/server/channel/channel_config.rb
505
533
  - lib/clacky/server/channel/channel_manager.rb
506
534
  - lib/clacky/server/channel/channel_ui_controller.rb
535
+ - lib/clacky/server/channel/extension_adapter_loader.rb
507
536
  - lib/clacky/server/channel/user_adapter_loader.rb
508
537
  - lib/clacky/server/discover.rb
509
538
  - lib/clacky/server/epipe_safe_io.rb
@@ -608,12 +637,14 @@ files:
608
637
  - lib/clacky/web/features/brand/view.js
609
638
  - lib/clacky/web/features/channels/store.js
610
639
  - lib/clacky/web/features/channels/view.js
611
- - lib/clacky/web/features/creator/store.js
612
- - lib/clacky/web/features/creator/view.js
640
+ - lib/clacky/web/features/extensions/store.js
641
+ - lib/clacky/web/features/extensions/view.js
613
642
  - lib/clacky/web/features/mcp/store.js
614
643
  - lib/clacky/web/features/mcp/view.js
615
644
  - lib/clacky/web/features/model-tester/store.js
616
645
  - lib/clacky/web/features/model-tester/view.js
646
+ - lib/clacky/web/features/new-session/store.js
647
+ - lib/clacky/web/features/new-session/view.js
617
648
  - lib/clacky/web/features/profile/store.js
618
649
  - lib/clacky/web/features/profile/view.js
619
650
  - lib/clacky/web/features/share/store.js