openclacky 1.5.13 → 1.5.15
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 +96 -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 +53 -98
- data/lib/clacky/agent.rb +477 -297
- data/lib/clacky/agent_config.rb +5 -3
- data/lib/clacky/billing/billing_store.rb +2 -2
- data/lib/clacky/billing/platform_billing.rb +7 -0
- data/lib/clacky/brand_config.rb +27 -19
- data/lib/clacky/cli.rb +92 -12
- data/lib/clacky/cli_guidance.rb +48 -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/api/handler.rb +4 -1
- data/lib/clacky/default_extensions/ext-studio/panels/studio/view.js +307 -98
- 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 +18 -6
- data/lib/clacky/extension/verifier.rb +1 -1
- data/lib/clacky/json_ui_controller.rb +4 -2
- data/lib/clacky/media/openai_compat.rb +70 -30
- data/lib/clacky/message_format/bedrock.rb +6 -1
- data/lib/clacky/message_format/open_ai.rb +22 -5
- data/lib/clacky/message_format/open_ai_responses.rb +7 -3
- data/lib/clacky/plain_ui_controller.rb +1 -1
- data/lib/clacky/prompts/base.md +1 -1
- data/lib/clacky/providers.rb +44 -13
- data/lib/clacky/rich_ui/components/composer_guidance.rb +49 -0
- data/lib/clacky/rich_ui/rich_ui_controller.rb +24 -4
- data/lib/clacky/rich_ui/shell/rich_agent_shell.rb +13 -0
- data/lib/clacky/search_config.rb +3 -3
- data/lib/clacky/server/channel/channel_manager.rb +25 -7
- data/lib/clacky/server/channel/channel_ui_controller.rb +1 -1
- data/lib/clacky/server/dir_picker.rb +67 -4
- data/lib/clacky/server/git_panel.rb +10 -2
- data/lib/clacky/server/http_server.rb +391 -75
- data/lib/clacky/server/preview.rb +351 -0
- data/lib/clacky/server/session_registry.rb +4 -0
- data/lib/clacky/server/web_ui_controller.rb +10 -5
- data/lib/clacky/session_manager.rb +52 -1
- data/lib/clacky/skill.rb +48 -0
- data/lib/clacky/tools/browser.rb +176 -19
- data/lib/clacky/tools/web_search.rb +91 -8
- data/lib/clacky/ui2/components/command_suggestions.rb +3 -1
- data/lib/clacky/ui2/components/input_area.rb +37 -4
- data/lib/clacky/ui2/components/modal_component.rb +35 -6
- data/lib/clacky/ui2/screen_buffer.rb +1 -0
- data/lib/clacky/ui2/ui_controller.rb +72 -12
- data/lib/clacky/ui_interface.rb +1 -1
- 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 +118 -68
- data/lib/clacky/utils/windows_app_detector.rb +334 -0
- data/lib/clacky/version.rb +1 -1
- data/lib/clacky/web/app.css +998 -168
- data/lib/clacky/web/app.js +19 -0
- 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/composer.js +3 -1
- data/lib/clacky/web/components/datepicker.js +19 -19
- data/lib/clacky/web/components/mentions.js +11 -14
- data/lib/clacky/web/components/model-picker.js +66 -23
- data/lib/clacky/web/components/quote-select.js +341 -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/extensions/store.js +4 -1
- data/lib/clacky/web/features/model-tester/store.js +37 -4
- 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 +474 -43
- data/lib/clacky/web/i18n.js +158 -23
- data/lib/clacky/web/index.html +57 -29
- data/lib/clacky/web/sessions.js +517 -127
- data/lib/clacky/web/settings.js +155 -6
- 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 +161 -4
- data/lib/clacky.rb +2 -0
- metadata +13 -1
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
// CodeMirror 6 bundle entry — exposes a single `CM` global with the editor
|
|
2
|
+
// core plus mainstream language support for the workspace file viewer.
|
|
3
|
+
import { EditorState } from "@codemirror/state";
|
|
4
|
+
import {
|
|
5
|
+
EditorView,
|
|
6
|
+
keymap,
|
|
7
|
+
lineNumbers,
|
|
8
|
+
highlightActiveLineGutter,
|
|
9
|
+
highlightSpecialChars,
|
|
10
|
+
drawSelection,
|
|
11
|
+
dropCursor,
|
|
12
|
+
rectangularSelection,
|
|
13
|
+
crosshairCursor,
|
|
14
|
+
highlightActiveLine,
|
|
15
|
+
} from "@codemirror/view";
|
|
16
|
+
import {
|
|
17
|
+
defaultKeymap,
|
|
18
|
+
history,
|
|
19
|
+
historyKeymap,
|
|
20
|
+
indentWithTab,
|
|
21
|
+
} from "@codemirror/commands";
|
|
22
|
+
import { search, searchKeymap, highlightSelectionMatches } from "@codemirror/search";
|
|
23
|
+
import {
|
|
24
|
+
bracketMatching,
|
|
25
|
+
foldGutter,
|
|
26
|
+
foldKeymap,
|
|
27
|
+
indentOnInput,
|
|
28
|
+
syntaxHighlighting,
|
|
29
|
+
defaultHighlightStyle,
|
|
30
|
+
StreamLanguage,
|
|
31
|
+
} from "@codemirror/language";
|
|
32
|
+
import { markdown, markdownLanguage } from "@codemirror/lang-markdown";
|
|
33
|
+
import { oneDark } from "@codemirror/theme-one-dark";
|
|
34
|
+
|
|
35
|
+
// ── Lezer languages (best highlighting quality) ────────────────────────────
|
|
36
|
+
import { python } from "@codemirror/lang-python";
|
|
37
|
+
import {
|
|
38
|
+
javascript,
|
|
39
|
+
typescriptLanguage,
|
|
40
|
+
jsxLanguage,
|
|
41
|
+
tsxLanguage,
|
|
42
|
+
} from "@codemirror/lang-javascript";
|
|
43
|
+
import { html } from "@codemirror/lang-html";
|
|
44
|
+
import { css } from "@codemirror/lang-css";
|
|
45
|
+
import { json } from "@codemirror/lang-json";
|
|
46
|
+
import { sql } from "@codemirror/lang-sql";
|
|
47
|
+
import { xml } from "@codemirror/lang-xml";
|
|
48
|
+
import { rust } from "@codemirror/lang-rust";
|
|
49
|
+
import { java } from "@codemirror/lang-java";
|
|
50
|
+
import { cpp } from "@codemirror/lang-cpp";
|
|
51
|
+
import { php } from "@codemirror/lang-php";
|
|
52
|
+
|
|
53
|
+
// ── Legacy (StreamParser) languages ────────────────────────────────────────
|
|
54
|
+
import { ruby } from "@codemirror/legacy-modes/mode/ruby";
|
|
55
|
+
import { go } from "@codemirror/legacy-modes/mode/go";
|
|
56
|
+
import { shell } from "@codemirror/legacy-modes/mode/shell";
|
|
57
|
+
import { yaml } from "@codemirror/legacy-modes/mode/yaml";
|
|
58
|
+
import { toml } from "@codemirror/legacy-modes/mode/toml";
|
|
59
|
+
import { dockerFile } from "@codemirror/legacy-modes/mode/dockerfile";
|
|
60
|
+
|
|
61
|
+
const rubyLang = StreamLanguage.define(ruby);
|
|
62
|
+
const goLang = StreamLanguage.define(go);
|
|
63
|
+
const shellLang = StreamLanguage.define(shell);
|
|
64
|
+
const yamlLang = StreamLanguage.define(yaml);
|
|
65
|
+
const tomlLang = StreamLanguage.define(toml);
|
|
66
|
+
const dockerfileLang = StreamLanguage.define(dockerFile);
|
|
67
|
+
|
|
68
|
+
// Lezer languages are already functions returning a LanguageSupport.
|
|
69
|
+
// LRLanguage objects and StreamLanguage supports are wrapped so CodeEditor
|
|
70
|
+
// can call every language uniformly as `CM.<lang>()`.
|
|
71
|
+
const typescript = () => typescriptLanguage;
|
|
72
|
+
const jsx = () => jsxLanguage;
|
|
73
|
+
const tsx = () => tsxLanguage;
|
|
74
|
+
const rubyFn = () => rubyLang;
|
|
75
|
+
const goFn = () => goLang;
|
|
76
|
+
const shellFn = () => shellLang;
|
|
77
|
+
const yamlFn = () => yamlLang;
|
|
78
|
+
const tomlFn = () => tomlLang;
|
|
79
|
+
const dockerfileFn = () => dockerfileLang;
|
|
80
|
+
|
|
81
|
+
export {
|
|
82
|
+
EditorState,
|
|
83
|
+
EditorView,
|
|
84
|
+
keymap,
|
|
85
|
+
lineNumbers,
|
|
86
|
+
highlightActiveLineGutter,
|
|
87
|
+
highlightSpecialChars,
|
|
88
|
+
drawSelection,
|
|
89
|
+
dropCursor,
|
|
90
|
+
rectangularSelection,
|
|
91
|
+
crosshairCursor,
|
|
92
|
+
highlightActiveLine,
|
|
93
|
+
highlightSelectionMatches,
|
|
94
|
+
defaultKeymap,
|
|
95
|
+
history,
|
|
96
|
+
historyKeymap,
|
|
97
|
+
indentWithTab,
|
|
98
|
+
search,
|
|
99
|
+
searchKeymap,
|
|
100
|
+
bracketMatching,
|
|
101
|
+
foldGutter,
|
|
102
|
+
foldKeymap,
|
|
103
|
+
indentOnInput,
|
|
104
|
+
syntaxHighlighting,
|
|
105
|
+
defaultHighlightStyle,
|
|
106
|
+
StreamLanguage,
|
|
107
|
+
markdown,
|
|
108
|
+
markdownLanguage,
|
|
109
|
+
oneDark,
|
|
110
|
+
python,
|
|
111
|
+
javascript,
|
|
112
|
+
typescript,
|
|
113
|
+
jsx,
|
|
114
|
+
tsx,
|
|
115
|
+
html,
|
|
116
|
+
css,
|
|
117
|
+
json,
|
|
118
|
+
sql,
|
|
119
|
+
xml,
|
|
120
|
+
rust,
|
|
121
|
+
java,
|
|
122
|
+
cpp,
|
|
123
|
+
php,
|
|
124
|
+
rubyFn as ruby,
|
|
125
|
+
goFn as go,
|
|
126
|
+
shellFn as shell,
|
|
127
|
+
yamlFn as yaml,
|
|
128
|
+
tomlFn as toml,
|
|
129
|
+
dockerfileFn as dockerfile,
|
|
130
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "cm-build",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"dependencies": {
|
|
7
|
+
"@codemirror/commands": "^6.8.1",
|
|
8
|
+
"@codemirror/lang-cpp": "^6.0.2",
|
|
9
|
+
"@codemirror/lang-css": "^6.3.1",
|
|
10
|
+
"@codemirror/lang-html": "^6.4.9",
|
|
11
|
+
"@codemirror/lang-java": "^6.0.1",
|
|
12
|
+
"@codemirror/lang-javascript": "^6.2.3",
|
|
13
|
+
"@codemirror/lang-json": "^6.0.1",
|
|
14
|
+
"@codemirror/lang-markdown": "^6.3.2",
|
|
15
|
+
"@codemirror/lang-php": "^6.0.1",
|
|
16
|
+
"@codemirror/lang-python": "^6.2.0",
|
|
17
|
+
"@codemirror/lang-rust": "^6.0.1",
|
|
18
|
+
"@codemirror/lang-sql": "^6.8.1",
|
|
19
|
+
"@codemirror/lang-xml": "^6.1.0",
|
|
20
|
+
"@codemirror/language": "^6.11.0",
|
|
21
|
+
"@codemirror/legacy-modes": "^6.5.1",
|
|
22
|
+
"@codemirror/search": "^6.5.10",
|
|
23
|
+
"@codemirror/state": "^6.5.2",
|
|
24
|
+
"@codemirror/theme-one-dark": "^6.1.2",
|
|
25
|
+
"@codemirror/view": "^6.36.8",
|
|
26
|
+
"esbuild": "^0.25.0",
|
|
27
|
+
"jsdom": "^30.0.1"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -182,7 +182,7 @@ WS.onEvent(ev => {
|
|
|
182
182
|
// Safety nets:
|
|
183
183
|
// - User just sent a message → any open phase is stale, close it.
|
|
184
184
|
// - Session changed → phase belongs to the previous session, close it.
|
|
185
|
-
if (ev.type === "history_user_message" || ev.type === "subscribed") {
|
|
185
|
+
if ((ev.type === "history_user_message" && !ev.steering) || ev.type === "subscribed") {
|
|
186
186
|
_closeAllPhases("incomplete");
|
|
187
187
|
}
|
|
188
188
|
|
|
@@ -226,6 +226,20 @@ function _dispatchEvent(ev) {
|
|
|
226
226
|
}
|
|
227
227
|
}
|
|
228
228
|
|
|
229
|
+
const eventSession = ev.session_id || ev.session?.id;
|
|
230
|
+
if (eventSession === Sessions.activeId) {
|
|
231
|
+
if (["history_user_message", "task_finished", "interrupted"].includes(ev.type) ||
|
|
232
|
+
(ev.type === "session_update" && (ev.status || ev.session))) {
|
|
233
|
+
window.ChatNavigator?.refresh();
|
|
234
|
+
}
|
|
235
|
+
// Keep live output out of a detached historical window. Session status,
|
|
236
|
+
// notifications and extension delivery above continue normally.
|
|
237
|
+
const historyOutput = ["history_user_message", "assistant_message", "tool_call", "tool_result",
|
|
238
|
+
"tool_error", "tool_stdout", "phase_start", "phase_end", "request_feedback", "progress",
|
|
239
|
+
"complete", "interrupted", "info", "warning", "success", "error", "token_usage"];
|
|
240
|
+
if (historyOutput.includes(ev.type) && Sessions.deferLiveHistory(ev)) return;
|
|
241
|
+
}
|
|
242
|
+
|
|
229
243
|
switch (ev.type) {
|
|
230
244
|
|
|
231
245
|
// ── Phase grouping ─────────────────────────────────────────────────
|
|
@@ -300,6 +314,7 @@ function _dispatchEvent(ev) {
|
|
|
300
314
|
|
|
301
315
|
// ── Session lifecycle ──────────────────────────────────────────────
|
|
302
316
|
case "subscribed": {
|
|
317
|
+
if ($("input-queue")) { $("input-queue").replaceChildren(); $("input-queue").hidden = true; }
|
|
303
318
|
// Re-enable send button now that the server has confirmed the subscription.
|
|
304
319
|
$("btn-send").disabled = false;
|
|
305
320
|
$("user-input").focus();
|
|
@@ -353,7 +368,23 @@ function _dispatchEvent(ev) {
|
|
|
353
368
|
if (ev.latency !== undefined) patch.latest_latency = ev.latency;
|
|
354
369
|
}
|
|
355
370
|
if (!sid) break;
|
|
356
|
-
|
|
371
|
+
// A creation update is emitted only after the session's initial metadata
|
|
372
|
+
// has been persisted. Promote it into the canonical list; ordinary full
|
|
373
|
+
// snapshots remain patches so reconnects and old-session updates cannot
|
|
374
|
+
// disturb the pagination boundary.
|
|
375
|
+
//
|
|
376
|
+
// Exception: the session the user is currently viewing. It may have been
|
|
377
|
+
// opened from search / a deep link and live only in the `_extraSessions`
|
|
378
|
+
// cache (outside the loaded page), which the sidebar does not render —
|
|
379
|
+
// patching it would leave the list without a row until a reload. A full
|
|
380
|
+
// snapshot carries every column the list needs, and its fresh
|
|
381
|
+
// `updated_at` sorts it to the top, exactly where a reload would put it.
|
|
382
|
+
const listed = Sessions.all.some(s => s.id === sid);
|
|
383
|
+
if (ev.session && (ev.created || (sid === Sessions.activeId && !listed))) {
|
|
384
|
+
Sessions.add(ev.session);
|
|
385
|
+
} else {
|
|
386
|
+
Sessions.patch(sid, patch);
|
|
387
|
+
}
|
|
357
388
|
Sessions.renderList();
|
|
358
389
|
Projects.renderSection();
|
|
359
390
|
if (sid === Sessions.activeId) {
|
|
@@ -411,7 +442,125 @@ function _dispatchEvent(ev) {
|
|
|
411
442
|
break;
|
|
412
443
|
|
|
413
444
|
// ── Chat messages ──────────────────────────────────────────────────
|
|
445
|
+
case "input_queue_notice":
|
|
446
|
+
if (ev.session_id === Sessions.activeId) Modal.toast(I18n.t(ev.key));
|
|
447
|
+
break;
|
|
448
|
+
|
|
449
|
+
case "input_behavior":
|
|
450
|
+
if ($("input-behavior")) $("input-behavior").value = ev.value;
|
|
451
|
+
Sessions.updateInputBehavior();
|
|
452
|
+
break;
|
|
453
|
+
|
|
454
|
+
case "input_queue": {
|
|
455
|
+
if (ev.session_id !== Sessions.activeId) break;
|
|
456
|
+
const panel = $("input-queue");
|
|
457
|
+
if (!panel) break;
|
|
458
|
+
panel.replaceChildren();
|
|
459
|
+
panel.hidden = !ev.entries?.length;
|
|
460
|
+
for (const entry of ev.entries || []) {
|
|
461
|
+
const row = document.createElement("div");
|
|
462
|
+
row.className = "input-queue-row";
|
|
463
|
+
const body = document.createElement("div");
|
|
464
|
+
body.className = "input-queue-body";
|
|
465
|
+
const status = document.createElement("span");
|
|
466
|
+
status.className = "input-queue-status";
|
|
467
|
+
status.textContent = I18n.t(entry.delivery === "steer" ? "chat.input.guidancePending" : "chat.input.queued");
|
|
468
|
+
const label = document.createElement("div");
|
|
469
|
+
label.className = "input-queue-content";
|
|
470
|
+
label.textContent = entry.options?.display_text || entry.content || "";
|
|
471
|
+
label.title = label.textContent;
|
|
472
|
+
body.append(status, label);
|
|
473
|
+
const files = (entry.options?.files || []).map(file => file.name).filter(Boolean);
|
|
474
|
+
if (files.length) {
|
|
475
|
+
const attachments = document.createElement("div");
|
|
476
|
+
attachments.className = "input-queue-files";
|
|
477
|
+
attachments.textContent = files.join(" · ");
|
|
478
|
+
attachments.title = attachments.textContent;
|
|
479
|
+
body.append(attachments);
|
|
480
|
+
}
|
|
481
|
+
const actions = document.createElement("div");
|
|
482
|
+
actions.className = "input-queue-actions";
|
|
483
|
+
function iconButton(key, paths) {
|
|
484
|
+
const button = document.createElement("button");
|
|
485
|
+
button.type = "button";
|
|
486
|
+
button.className = "btn-icon-sm";
|
|
487
|
+
button.title = I18n.t(key);
|
|
488
|
+
button.setAttribute("aria-label", I18n.t(key));
|
|
489
|
+
button.innerHTML = `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">${paths}</svg>`;
|
|
490
|
+
return button;
|
|
491
|
+
}
|
|
492
|
+
const remove = iconButton("chat.input.removeQueued", '<path d="M3 6h18M9 6V4h6v2M5 6l1 14h12l1-14M10 10v6M14 10v6"/>');
|
|
493
|
+
remove.classList.add("input-queue-remove");
|
|
494
|
+
remove.onclick = () => {
|
|
495
|
+
if (WS.ready) WS.send({ type: "remove_pending_input", session_id: ev.session_id, id: entry.id });
|
|
496
|
+
};
|
|
497
|
+
const edit = iconButton("chat.input.editQueued", '<path d="M12 20h9M16.5 3.5a2.121 2.121 0 1 1 3 3L7 19l-4 1 1-4z"/>');
|
|
498
|
+
edit.onclick = () => {
|
|
499
|
+
if (row.classList.contains("editing")) return;
|
|
500
|
+
row.classList.add("editing");
|
|
501
|
+
actions.hidden = true;
|
|
502
|
+
const editor = document.createElement("textarea");
|
|
503
|
+
editor.className = "msg-user-edit-textarea";
|
|
504
|
+
editor.value = entry.content;
|
|
505
|
+
editor.setAttribute("aria-label", I18n.t("chat.input.editQueued"));
|
|
506
|
+
label.replaceWith(editor);
|
|
507
|
+
const editActions = document.createElement("div");
|
|
508
|
+
editActions.className = "msg-user-edit-actions";
|
|
509
|
+
const cancel = document.createElement("button");
|
|
510
|
+
cancel.type = "button";
|
|
511
|
+
cancel.className = "msg-user-edit-cancel";
|
|
512
|
+
cancel.textContent = I18n.t("chat.cancel");
|
|
513
|
+
const save = document.createElement("button");
|
|
514
|
+
save.type = "button";
|
|
515
|
+
save.className = "msg-user-edit-send";
|
|
516
|
+
save.textContent = I18n.t("chat.input.saveQueued");
|
|
517
|
+
cancel.onclick = () => {
|
|
518
|
+
editor.replaceWith(label);
|
|
519
|
+
editActions.remove();
|
|
520
|
+
row.classList.remove("editing");
|
|
521
|
+
actions.hidden = false;
|
|
522
|
+
edit.focus();
|
|
523
|
+
};
|
|
524
|
+
save.onclick = () => {
|
|
525
|
+
if (WS.ready) WS.send({ type: "edit_pending_input", session_id: ev.session_id, id: entry.id, content: editor.value });
|
|
526
|
+
};
|
|
527
|
+
editor.rows = 1;
|
|
528
|
+
editor.wrap = "off";
|
|
529
|
+
editor.addEventListener("keydown", event => {
|
|
530
|
+
if (event.key === "Escape") { event.preventDefault(); event.stopPropagation(); cancel.click(); }
|
|
531
|
+
if (event.key === "Enter" && (event.metaKey || event.ctrlKey) && !event.isComposing) { event.preventDefault(); save.click(); }
|
|
532
|
+
});
|
|
533
|
+
editActions.append(cancel, save);
|
|
534
|
+
body.append(editActions);
|
|
535
|
+
editor.focus();
|
|
536
|
+
};
|
|
537
|
+
const sendNow = iconButton("chat.input.sendQueued", '<path d="M12 19V5M5 12l7-7 7 7"/>');
|
|
538
|
+
sendNow.onclick = () => {
|
|
539
|
+
if (!WS.ready) return;
|
|
540
|
+
sendNow.disabled = true;
|
|
541
|
+
status.textContent = I18n.t("chat.input.stopping");
|
|
542
|
+
WS.send({ type: "send_pending_input", session_id: ev.session_id, id: entry.id, lang: I18n.lang() });
|
|
543
|
+
};
|
|
544
|
+
const guide = iconButton("chat.input.steerMode", '<path d="M4 12h16M14 6l6 6-6 6"/>');
|
|
545
|
+
guide.disabled = !entry.steer_target || entry.delivery === "steer" || entry.content.trimStart().startsWith("/");
|
|
546
|
+
guide.title = I18n.t(entry.steer_target ? "chat.input.steerDescription" : "chat.input.guidanceClosed");
|
|
547
|
+
guide.onclick = () => {
|
|
548
|
+
if (!WS.ready) return;
|
|
549
|
+
guide.disabled = true;
|
|
550
|
+
WS.send({ type: "steer_pending_input", session_id: ev.session_id, id: entry.id, task_id: entry.steer_target });
|
|
551
|
+
};
|
|
552
|
+
actions.append(edit, guide, sendNow, remove);
|
|
553
|
+
row.append(body, actions);
|
|
554
|
+
panel.append(row);
|
|
555
|
+
}
|
|
556
|
+
break;
|
|
557
|
+
}
|
|
558
|
+
|
|
414
559
|
case "history_user_message":
|
|
560
|
+
if (ev.steering && ev.session_id === Sessions.activeId) {
|
|
561
|
+
Sessions.appendMsg("user", escapeHtml(ev.content || "") + (ev.images || []).map(value =>
|
|
562
|
+
value.startsWith("pdf:") ? "<br>" + escapeHtml(value.slice(4)) : `<br><img class="msg-image-thumb" src="${escapeHtml(value)}">`).join(""));
|
|
563
|
+
}
|
|
415
564
|
// Emitted by show_user_message before agent.run; stamp the authoritative
|
|
416
565
|
// created_at onto the optimistically-rendered bubble and register it in
|
|
417
566
|
// the dedup set so the subsequent history fetch skips this round.
|
|
@@ -424,6 +573,7 @@ function _dispatchEvent(ev) {
|
|
|
424
573
|
if (ev.session_id !== Sessions.activeId) break;
|
|
425
574
|
Sessions.clearProgress();
|
|
426
575
|
Sessions.appendMsg("assistant", ev.content);
|
|
576
|
+
if (!ev.phase_id && !ev.interim) window.ChatNavigator?.refresh();
|
|
427
577
|
break;
|
|
428
578
|
|
|
429
579
|
case "tool_call":
|
|
@@ -434,7 +584,7 @@ function _dispatchEvent(ev) {
|
|
|
434
584
|
|
|
435
585
|
case "tool_result":
|
|
436
586
|
if (ev.session_id !== Sessions.activeId) break;
|
|
437
|
-
Sessions.appendToolResult(ev.result);
|
|
587
|
+
Sessions.appendToolResult(ev.result, ev.ui || null);
|
|
438
588
|
break;
|
|
439
589
|
|
|
440
590
|
case "tool_stdout":
|
|
@@ -470,6 +620,11 @@ function _dispatchEvent(ev) {
|
|
|
470
620
|
break;
|
|
471
621
|
|
|
472
622
|
case "complete":
|
|
623
|
+
// The agent may have created/edited files under the working dir; notify
|
|
624
|
+
// the workspace store so the Files tree reloads on completion.
|
|
625
|
+
if (typeof Workspace !== "undefined" && Workspace.notifyTaskCompleted) {
|
|
626
|
+
Workspace.notifyTaskCompleted(ev.session_id);
|
|
627
|
+
}
|
|
473
628
|
if (ev.session_id !== Sessions.activeId) break;
|
|
474
629
|
Sessions.clearProgress();
|
|
475
630
|
Sessions.collapseToolGroup();
|
|
@@ -520,7 +675,9 @@ function _dispatchEvent(ev) {
|
|
|
520
675
|
Sessions.clearProgress();
|
|
521
676
|
Sessions.collapseToolGroup();
|
|
522
677
|
_closeAllPhases("incomplete");
|
|
523
|
-
|
|
678
|
+
if (ev.reason !== "replacement") {
|
|
679
|
+
Sessions.appendMsg("stopped", escapeHtml(I18n.t("chat.interrupted")));
|
|
680
|
+
}
|
|
524
681
|
break;
|
|
525
682
|
|
|
526
683
|
// ── Info / errors ──────────────────────────────────────────────────
|
data/lib/clacky.rb
CHANGED
|
@@ -105,6 +105,8 @@ require_relative "clacky/identity"
|
|
|
105
105
|
require_relative "clacky/access_key"
|
|
106
106
|
require_relative "clacky/utils/encoding"
|
|
107
107
|
require_relative "clacky/utils/environment_detector"
|
|
108
|
+
require_relative "clacky/utils/mac_app_detector"
|
|
109
|
+
require_relative "clacky/utils/windows_app_detector"
|
|
108
110
|
require_relative "clacky/utils/browser_detector"
|
|
109
111
|
require_relative "clacky/utils/scripts_manager"
|
|
110
112
|
require_relative "clacky/utils/searcher_manager"
|
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.5.
|
|
4
|
+
version: 1.5.15
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- windy
|
|
@@ -342,10 +342,12 @@ files:
|
|
|
342
342
|
- lib/clacky/access_key.rb
|
|
343
343
|
- lib/clacky/aes_gcm.rb
|
|
344
344
|
- lib/clacky/agent.rb
|
|
345
|
+
- lib/clacky/agent/chunk_index.rb
|
|
345
346
|
- lib/clacky/agent/cost_tracker.rb
|
|
346
347
|
- lib/clacky/agent/fake_tool_call_detector.rb
|
|
347
348
|
- lib/clacky/agent/goal_manager.rb
|
|
348
349
|
- lib/clacky/agent/goal_state.rb
|
|
350
|
+
- lib/clacky/agent/history_navigation.rb
|
|
349
351
|
- lib/clacky/agent/hook_manager.rb
|
|
350
352
|
- lib/clacky/agent/llm_caller.rb
|
|
351
353
|
- lib/clacky/agent/memory_updater.rb
|
|
@@ -372,6 +374,7 @@ files:
|
|
|
372
374
|
- lib/clacky/brand_config.rb
|
|
373
375
|
- lib/clacky/cancel_flag.rb
|
|
374
376
|
- lib/clacky/cli.rb
|
|
377
|
+
- lib/clacky/cli_guidance.rb
|
|
375
378
|
- lib/clacky/client.rb
|
|
376
379
|
- lib/clacky/default_extensions/advisor/advisors/general.md
|
|
377
380
|
- lib/clacky/default_extensions/advisor/api/handler.rb
|
|
@@ -398,6 +401,8 @@ files:
|
|
|
398
401
|
- lib/clacky/default_extensions/meeting/ext.yml
|
|
399
402
|
- lib/clacky/default_extensions/meeting/panels/meeting/view.js
|
|
400
403
|
- lib/clacky/default_extensions/meeting/skills/meeting-summarizer/SKILL.md
|
|
404
|
+
- lib/clacky/default_extensions/preview/ext.yml
|
|
405
|
+
- lib/clacky/default_extensions/preview/panels/preview/view.js
|
|
401
406
|
- lib/clacky/default_extensions/time_machine/ext.yml
|
|
402
407
|
- lib/clacky/default_extensions/time_machine/panels/time_machine/view.js
|
|
403
408
|
- lib/clacky/default_parsers/doc_parser.rb
|
|
@@ -520,6 +525,7 @@ files:
|
|
|
520
525
|
- lib/clacky/proxy_config.rb
|
|
521
526
|
- lib/clacky/rich_ui.rb
|
|
522
527
|
- lib/clacky/rich_ui/components/base_component.rb
|
|
528
|
+
- lib/clacky/rich_ui/components/composer_guidance.rb
|
|
523
529
|
- lib/clacky/rich_ui/components/dialogs/approval_dialog.rb
|
|
524
530
|
- lib/clacky/rich_ui/components/dialogs/config_menu_dialog.rb
|
|
525
531
|
- lib/clacky/rich_ui/components/dialogs/form_dialog.rb
|
|
@@ -568,6 +574,7 @@ files:
|
|
|
568
574
|
- lib/clacky/server/git_panel.rb
|
|
569
575
|
- lib/clacky/server/http_server.rb
|
|
570
576
|
- lib/clacky/server/model_prices.rb
|
|
577
|
+
- lib/clacky/server/preview.rb
|
|
571
578
|
- lib/clacky/server/project_manager.rb
|
|
572
579
|
- lib/clacky/server/scheduler.rb
|
|
573
580
|
- lib/clacky/server/server_master.rb
|
|
@@ -638,6 +645,7 @@ files:
|
|
|
638
645
|
- lib/clacky/utils/limit_stack.rb
|
|
639
646
|
- lib/clacky/utils/logger.rb
|
|
640
647
|
- lib/clacky/utils/login_shell.rb
|
|
648
|
+
- lib/clacky/utils/mac_app_detector.rb
|
|
641
649
|
- lib/clacky/utils/model_pricing.rb
|
|
642
650
|
- lib/clacky/utils/parser_manager.rb
|
|
643
651
|
- lib/clacky/utils/path_helper.rb
|
|
@@ -645,6 +653,7 @@ files:
|
|
|
645
653
|
- lib/clacky/utils/searcher_manager.rb
|
|
646
654
|
- lib/clacky/utils/string_matcher.rb
|
|
647
655
|
- lib/clacky/utils/trash_directory.rb
|
|
656
|
+
- lib/clacky/utils/windows_app_detector.rb
|
|
648
657
|
- lib/clacky/utils/workspace_rules.rb
|
|
649
658
|
- lib/clacky/version.rb
|
|
650
659
|
- lib/clacky/vision/resolver.rb
|
|
@@ -662,6 +671,7 @@ files:
|
|
|
662
671
|
- lib/clacky/web/components/model-picker.js
|
|
663
672
|
- lib/clacky/web/components/notify.js
|
|
664
673
|
- lib/clacky/web/components/onboard.js
|
|
674
|
+
- lib/clacky/web/components/quote-select.js
|
|
665
675
|
- lib/clacky/web/components/sidebar.js
|
|
666
676
|
- lib/clacky/web/core/aside.js
|
|
667
677
|
- lib/clacky/web/core/ext.js
|
|
@@ -711,6 +721,8 @@ files:
|
|
|
711
721
|
- lib/clacky/web/theme.js
|
|
712
722
|
- lib/clacky/web/utils.js
|
|
713
723
|
- lib/clacky/web/vendor/codemirror/codemirror.min.js
|
|
724
|
+
- lib/clacky/web/vendor/codemirror/entry.js
|
|
725
|
+
- lib/clacky/web/vendor/codemirror/package.json
|
|
714
726
|
- lib/clacky/web/vendor/hljs/highlight.min.js
|
|
715
727
|
- lib/clacky/web/vendor/hljs/hljs-theme.css
|
|
716
728
|
- lib/clacky/web/vendor/katex/auto-render.min.js
|