openclacky 1.3.7 → 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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +24 -0
- data/lib/clacky/agent/hook_manager.rb +10 -1
- data/lib/clacky/agent/system_prompt_builder.rb +1 -1
- data/lib/clacky/agent.rb +9 -2
- data/lib/clacky/agent_profile.rb +7 -4
- data/lib/clacky/billing/billing_store.rb +3 -2
- data/lib/clacky/default_extensions/coding/agents/coding/avatar.png +0 -0
- data/lib/clacky/default_extensions/coding/ext.yml +4 -3
- data/lib/clacky/default_extensions/ext-studio/agents/ext-developer/avatar.png +0 -0
- data/lib/clacky/default_extensions/ext-studio/ext.yml +1 -0
- data/lib/clacky/default_extensions/ext-studio/panels/studio/view.js +24 -5
- data/lib/clacky/default_extensions/general/agents/general/avatar.png +0 -0
- data/lib/clacky/default_extensions/general/ext.yml +4 -3
- data/lib/clacky/default_extensions/git/panels/git/view.js +3 -3
- data/lib/clacky/default_extensions/meeting/panels/meeting/view.js +1 -2
- data/lib/clacky/extension/loader.rb +6 -0
- data/lib/clacky/extension/verifier.rb +1 -1
- data/lib/clacky/server/http_server.rb +129 -5
- data/lib/clacky/shell_hook_loader.rb +266 -22
- data/lib/clacky/ui2/components/welcome_banner.rb +1 -1
- data/lib/clacky/utils/workspace_rules.rb +2 -2
- data/lib/clacky/version.rb +1 -1
- data/lib/clacky/web/app.css +230 -46
- data/lib/clacky/web/core/ext.js +130 -24
- data/lib/clacky/web/features/extensions/view.js +4 -3
- data/lib/clacky/web/features/new-session/store.js +13 -0
- data/lib/clacky/web/features/new-session/view.js +314 -14
- data/lib/clacky/web/features/trash/view.js +4 -5
- data/lib/clacky/web/i18n.js +34 -0
- data/lib/clacky/web/index.html +43 -11
- data/lib/clacky/web/sessions.js +3 -3
- data/lib/clacky/web/skills.js +86 -48
- data/lib/clacky/web/theme.js +3 -0
- data/lib/clacky/web/ws-dispatcher.js +11 -2
- metadata +7 -7
data/lib/clacky/web/skills.js
CHANGED
|
@@ -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 =
|
|
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
|
-
|
|
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
|
-
|
|
252
|
+
_dropdownEl().style.display = "";
|
|
226
253
|
_visible = true;
|
|
227
254
|
_createOverlay();
|
|
228
255
|
}
|
|
229
256
|
|
|
230
257
|
function _hide() {
|
|
231
|
-
|
|
258
|
+
_dropdownEl().style.display = "none";
|
|
232
259
|
_visible = false;
|
|
233
260
|
_activeIndex = -1;
|
|
234
261
|
_items = [];
|
|
235
|
-
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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
|
-
$(
|
|
306
|
-
e.preventDefault(); // keep focus on
|
|
332
|
+
$(cfg.slashBtn).addEventListener("mousedown", e => {
|
|
333
|
+
e.preventDefault(); // keep focus on the input
|
|
307
334
|
});
|
|
308
|
-
$(
|
|
309
|
-
|
|
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
|
-
$(
|
|
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
|
-
|
|
351
|
+
const ime = IME.track($(cfg.input));
|
|
324
352
|
|
|
325
353
|
// Main composer keydown: SkillAC consumes nav keys first, then Enter → send.
|
|
326
|
-
$(
|
|
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 && !
|
|
360
|
+
if (e.key === "Enter" && !e.shiftKey && !ime.isComposing(e)) {
|
|
331
361
|
e.preventDefault();
|
|
332
|
-
|
|
362
|
+
cfg.onSend();
|
|
333
363
|
}
|
|
334
364
|
});
|
|
335
365
|
|
|
336
366
|
// Composer input: auto-grow textarea, normalize full-width slash, drive AC.
|
|
337
|
-
$(
|
|
338
|
-
|
|
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
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
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
|
-
|
|
411
|
-
|
|
412
|
-
|
|
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
|
-
|
|
433
|
-
|
|
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. */
|
data/lib/clacky/web/theme.js
CHANGED
|
@@ -77,6 +77,9 @@ const Theme = (() => {
|
|
|
77
77
|
if (mq.addEventListener) mq.addEventListener("change", onChange);
|
|
78
78
|
else if (mq.addListener) mq.addListener(onChange); // Safari < 14
|
|
79
79
|
}
|
|
80
|
+
|
|
81
|
+
// Re-apply title text when language changes.
|
|
82
|
+
document.addEventListener("langchange", () => _updateToggleIcon(current()));
|
|
80
83
|
}
|
|
81
84
|
|
|
82
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
|
-
|
|
220
|
-
|
|
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
|
}
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: openclacky
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.3.
|
|
4
|
+
version: 1.3.8
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- windy
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: faraday
|
|
@@ -284,8 +283,8 @@ email:
|
|
|
284
283
|
- yafei@dao42.com
|
|
285
284
|
executables:
|
|
286
285
|
- clacky
|
|
287
|
-
- openclacky
|
|
288
286
|
- clarky
|
|
287
|
+
- openclacky
|
|
289
288
|
extensions: []
|
|
290
289
|
extra_rdoc_files: []
|
|
291
290
|
files:
|
|
@@ -364,8 +363,10 @@ files:
|
|
|
364
363
|
- lib/clacky/brand_config.rb
|
|
365
364
|
- lib/clacky/cli.rb
|
|
366
365
|
- lib/clacky/client.rb
|
|
366
|
+
- lib/clacky/default_extensions/coding/agents/coding/avatar.png
|
|
367
367
|
- lib/clacky/default_extensions/coding/agents/coding/system_prompt.md
|
|
368
368
|
- lib/clacky/default_extensions/coding/ext.yml
|
|
369
|
+
- lib/clacky/default_extensions/ext-studio/agents/ext-developer/avatar.png
|
|
369
370
|
- lib/clacky/default_extensions/ext-studio/agents/ext-developer/system_prompt.md
|
|
370
371
|
- lib/clacky/default_extensions/ext-studio/api/handler.rb
|
|
371
372
|
- lib/clacky/default_extensions/ext-studio/ext.yml
|
|
@@ -373,6 +374,7 @@ files:
|
|
|
373
374
|
- lib/clacky/default_extensions/ext-studio/skills/ext-debug/SKILL.md
|
|
374
375
|
- lib/clacky/default_extensions/ext-studio/skills/ext-publish/SKILL.md
|
|
375
376
|
- lib/clacky/default_extensions/ext-studio/skills/ext-scaffold/SKILL.md
|
|
377
|
+
- lib/clacky/default_extensions/general/agents/general/avatar.png
|
|
376
378
|
- lib/clacky/default_extensions/general/agents/general/system_prompt.md
|
|
377
379
|
- lib/clacky/default_extensions/general/ext.yml
|
|
378
380
|
- lib/clacky/default_extensions/git/ext.yml
|
|
@@ -728,7 +730,6 @@ metadata:
|
|
|
728
730
|
homepage_uri: https://github.com/clacky-ai/openclacky
|
|
729
731
|
source_code_uri: https://github.com/clacky-ai/openclacky
|
|
730
732
|
changelog_uri: https://github.com/clacky-ai/openclacky/blob/main/CHANGELOG.md
|
|
731
|
-
post_install_message:
|
|
732
733
|
rdoc_options: []
|
|
733
734
|
require_paths:
|
|
734
735
|
- lib
|
|
@@ -746,8 +747,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
746
747
|
- !ruby/object:Gem::Version
|
|
747
748
|
version: '0'
|
|
748
749
|
requirements: []
|
|
749
|
-
rubygems_version: 3.
|
|
750
|
-
signing_key:
|
|
750
|
+
rubygems_version: 3.6.9
|
|
751
751
|
specification_version: 4
|
|
752
752
|
summary: The most Token-efficient open-source AI Agent — BYOK, Skill-driven, IM-integrated.
|
|
753
753
|
test_files: []
|