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.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +96 -0
  3. data/lib/clacky/agent/chunk_index.rb +83 -0
  4. data/lib/clacky/agent/history_navigation.rb +239 -0
  5. data/lib/clacky/agent/session_serializer.rb +53 -98
  6. data/lib/clacky/agent.rb +477 -297
  7. data/lib/clacky/agent_config.rb +5 -3
  8. data/lib/clacky/billing/billing_store.rb +2 -2
  9. data/lib/clacky/billing/platform_billing.rb +7 -0
  10. data/lib/clacky/brand_config.rb +27 -19
  11. data/lib/clacky/cli.rb +92 -12
  12. data/lib/clacky/cli_guidance.rb +48 -0
  13. data/lib/clacky/client.rb +2 -2
  14. data/lib/clacky/default_extensions/ext-studio/agents/ext-developer/system_prompt.md +70 -134
  15. data/lib/clacky/default_extensions/ext-studio/api/handler.rb +4 -1
  16. data/lib/clacky/default_extensions/ext-studio/panels/studio/view.js +307 -98
  17. data/lib/clacky/default_extensions/ext-studio/skills/ext-develop/SKILL.md +179 -577
  18. data/lib/clacky/default_extensions/git/panels/git/view.js +34 -14
  19. data/lib/clacky/default_extensions/preview/ext.yml +20 -0
  20. data/lib/clacky/default_extensions/preview/panels/preview/view.js +475 -0
  21. data/lib/clacky/default_extensions/time_machine/panels/time_machine/view.js +1 -10
  22. data/lib/clacky/extension/api_extension.rb +18 -6
  23. data/lib/clacky/extension/verifier.rb +1 -1
  24. data/lib/clacky/json_ui_controller.rb +4 -2
  25. data/lib/clacky/media/openai_compat.rb +70 -30
  26. data/lib/clacky/message_format/bedrock.rb +6 -1
  27. data/lib/clacky/message_format/open_ai.rb +22 -5
  28. data/lib/clacky/message_format/open_ai_responses.rb +7 -3
  29. data/lib/clacky/plain_ui_controller.rb +1 -1
  30. data/lib/clacky/prompts/base.md +1 -1
  31. data/lib/clacky/providers.rb +44 -13
  32. data/lib/clacky/rich_ui/components/composer_guidance.rb +49 -0
  33. data/lib/clacky/rich_ui/rich_ui_controller.rb +24 -4
  34. data/lib/clacky/rich_ui/shell/rich_agent_shell.rb +13 -0
  35. data/lib/clacky/search_config.rb +3 -3
  36. data/lib/clacky/server/channel/channel_manager.rb +25 -7
  37. data/lib/clacky/server/channel/channel_ui_controller.rb +1 -1
  38. data/lib/clacky/server/dir_picker.rb +67 -4
  39. data/lib/clacky/server/git_panel.rb +10 -2
  40. data/lib/clacky/server/http_server.rb +391 -75
  41. data/lib/clacky/server/preview.rb +351 -0
  42. data/lib/clacky/server/session_registry.rb +4 -0
  43. data/lib/clacky/server/web_ui_controller.rb +10 -5
  44. data/lib/clacky/session_manager.rb +52 -1
  45. data/lib/clacky/skill.rb +48 -0
  46. data/lib/clacky/tools/browser.rb +176 -19
  47. data/lib/clacky/tools/web_search.rb +91 -8
  48. data/lib/clacky/ui2/components/command_suggestions.rb +3 -1
  49. data/lib/clacky/ui2/components/input_area.rb +37 -4
  50. data/lib/clacky/ui2/components/modal_component.rb +35 -6
  51. data/lib/clacky/ui2/screen_buffer.rb +1 -0
  52. data/lib/clacky/ui2/ui_controller.rb +72 -12
  53. data/lib/clacky/ui_interface.rb +1 -1
  54. data/lib/clacky/utils/file_processor.rb +19 -7
  55. data/lib/clacky/utils/mac_app_detector.rb +186 -0
  56. data/lib/clacky/utils/model_pricing.rb +118 -68
  57. data/lib/clacky/utils/windows_app_detector.rb +334 -0
  58. data/lib/clacky/version.rb +1 -1
  59. data/lib/clacky/web/app.css +998 -168
  60. data/lib/clacky/web/app.js +19 -0
  61. data/lib/clacky/web/components/chat-navigator.js +489 -202
  62. data/lib/clacky/web/components/code-editor.js +191 -5
  63. data/lib/clacky/web/components/composer.js +3 -1
  64. data/lib/clacky/web/components/datepicker.js +19 -19
  65. data/lib/clacky/web/components/mentions.js +11 -14
  66. data/lib/clacky/web/components/model-picker.js +66 -23
  67. data/lib/clacky/web/components/quote-select.js +341 -0
  68. data/lib/clacky/web/core/aside.js +157 -8
  69. data/lib/clacky/web/core/ext.js +16 -0
  70. data/lib/clacky/web/features/billing/view.js +75 -21
  71. data/lib/clacky/web/features/extensions/store.js +4 -1
  72. data/lib/clacky/web/features/model-tester/store.js +37 -4
  73. data/lib/clacky/web/features/skills/store.js +18 -1
  74. data/lib/clacky/web/features/skills/view.js +128 -7
  75. data/lib/clacky/web/features/workspace/store.js +80 -7
  76. data/lib/clacky/web/features/workspace/view.js +474 -43
  77. data/lib/clacky/web/i18n.js +158 -23
  78. data/lib/clacky/web/index.html +57 -29
  79. data/lib/clacky/web/sessions.js +517 -127
  80. data/lib/clacky/web/settings.js +155 -6
  81. data/lib/clacky/web/utils.js +34 -0
  82. data/lib/clacky/web/vendor/codemirror/codemirror.min.js +24 -19
  83. data/lib/clacky/web/vendor/codemirror/entry.js +130 -0
  84. data/lib/clacky/web/vendor/codemirror/package.json +29 -0
  85. data/lib/clacky/web/ws-dispatcher.js +161 -4
  86. data/lib/clacky.rb +2 -0
  87. 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
- Sessions.patch(sid, patch);
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
- Sessions.appendInfo(I18n.t("chat.interrupted"));
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.13
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