openclacky 1.5.13 → 1.5.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +51 -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 +38 -97
  6. data/lib/clacky/agent.rb +281 -276
  7. data/lib/clacky/agent_config.rb +1 -1
  8. data/lib/clacky/billing/billing_store.rb +2 -2
  9. data/lib/clacky/billing/platform_billing.rb +6 -0
  10. data/lib/clacky/brand_config.rb +13 -2
  11. data/lib/clacky/cli.rb +27 -0
  12. data/lib/clacky/client.rb +2 -2
  13. data/lib/clacky/default_extensions/ext-studio/agents/ext-developer/system_prompt.md +70 -134
  14. data/lib/clacky/default_extensions/ext-studio/panels/studio/view.js +91 -5
  15. data/lib/clacky/default_extensions/ext-studio/skills/ext-develop/SKILL.md +179 -577
  16. data/lib/clacky/default_extensions/git/panels/git/view.js +34 -14
  17. data/lib/clacky/default_extensions/preview/ext.yml +20 -0
  18. data/lib/clacky/default_extensions/preview/panels/preview/view.js +475 -0
  19. data/lib/clacky/default_extensions/time_machine/panels/time_machine/view.js +1 -10
  20. data/lib/clacky/extension/api_extension.rb +1 -1
  21. data/lib/clacky/extension/verifier.rb +1 -1
  22. data/lib/clacky/media/openai_compat.rb +70 -30
  23. data/lib/clacky/message_format/bedrock.rb +6 -1
  24. data/lib/clacky/prompts/base.md +1 -1
  25. data/lib/clacky/providers.rb +38 -3
  26. data/lib/clacky/rich_ui/rich_ui_controller.rb +1 -1
  27. data/lib/clacky/search_config.rb +3 -3
  28. data/lib/clacky/server/channel/channel_manager.rb +8 -5
  29. data/lib/clacky/server/git_panel.rb +10 -2
  30. data/lib/clacky/server/http_server.rb +161 -14
  31. data/lib/clacky/server/preview.rb +351 -0
  32. data/lib/clacky/server/web_ui_controller.rb +1 -1
  33. data/lib/clacky/skill.rb +48 -0
  34. data/lib/clacky/tools/browser.rb +176 -19
  35. data/lib/clacky/tools/web_search.rb +79 -8
  36. data/lib/clacky/ui2/components/command_suggestions.rb +2 -1
  37. data/lib/clacky/ui2/components/input_area.rb +22 -2
  38. data/lib/clacky/ui2/components/modal_component.rb +35 -6
  39. data/lib/clacky/ui2/ui_controller.rb +44 -7
  40. data/lib/clacky/utils/file_processor.rb +19 -7
  41. data/lib/clacky/utils/mac_app_detector.rb +186 -0
  42. data/lib/clacky/utils/model_pricing.rb +114 -66
  43. data/lib/clacky/utils/windows_app_detector.rb +334 -0
  44. data/lib/clacky/version.rb +1 -1
  45. data/lib/clacky/web/app.css +596 -130
  46. data/lib/clacky/web/components/chat-navigator.js +489 -202
  47. data/lib/clacky/web/components/code-editor.js +191 -5
  48. data/lib/clacky/web/components/model-picker.js +2 -1
  49. data/lib/clacky/web/components/quote-select.js +235 -0
  50. data/lib/clacky/web/core/aside.js +157 -8
  51. data/lib/clacky/web/core/ext.js +16 -0
  52. data/lib/clacky/web/features/billing/view.js +75 -21
  53. data/lib/clacky/web/features/skills/store.js +18 -1
  54. data/lib/clacky/web/features/skills/view.js +128 -7
  55. data/lib/clacky/web/features/workspace/store.js +80 -7
  56. data/lib/clacky/web/features/workspace/view.js +392 -40
  57. data/lib/clacky/web/i18n.js +90 -5
  58. data/lib/clacky/web/index.html +15 -6
  59. data/lib/clacky/web/sessions.js +193 -38
  60. data/lib/clacky/web/utils.js +34 -0
  61. data/lib/clacky/web/vendor/codemirror/codemirror.min.js +24 -19
  62. data/lib/clacky/web/vendor/codemirror/entry.js +130 -0
  63. data/lib/clacky/web/vendor/codemirror/package.json +29 -0
  64. data/lib/clacky/web/ws-dispatcher.js +20 -0
  65. data/lib/clacky.rb +2 -0
  66. metadata +11 -1
@@ -106,6 +106,10 @@ const I18n = (() => {
106
106
  "chat.feedback_next": "Next",
107
107
  "chat.newMessageHint": "New messages ↓",
108
108
  "chat.retry": "Retry",
109
+ "chat.quote.btn": "Quote",
110
+ "chat.quote.roleUser": "You",
111
+ "chat.quote.roleAssistant": "Assistant",
112
+ "chat.quote.sig": "{{role}} · #{{index}}",
109
113
  "chat.resetSession": "Reset session",
110
114
  "chat.resetSessionConfirm": "Reset will start a brand-new session. The current conversation history stays in your sidebar but will no longer be active. Continue?",
111
115
  "chat.copy": "Copy",
@@ -127,7 +131,12 @@ const I18n = (() => {
127
131
  "chat.empty.tip2": "Summarize and organize information",
128
132
  "chat.empty.tip3": "Upload an image or file for me to analyze",
129
133
  "chat.nav.title": "Messages",
134
+ "chat.nav.round": "Message {{number}}",
130
135
  "chat.nav.empty": "(empty)",
136
+ "chat.nav.aiReply": "AI reply",
137
+ "chat.nav.noReply": "No final reply yet",
138
+ "chat.nav.retry": "Navigation could not load. Click to retry.",
139
+ "chat.nav.latest": "Back to latest messages ↓",
131
140
 
132
141
  // ── Session list ──
133
142
  "sessions.empty": "No sessions yet",
@@ -180,6 +189,9 @@ const I18n = (() => {
180
189
  "sib.dir.drives": "Drives",
181
190
  "sib.dir.places.drive": "{{letter}}:",
182
191
  "workspace.title": "Files",
192
+ "workspace.toggleTree": "Toggle file tree",
193
+ "workspace.backToFiles": "Back to files",
194
+ "workspace.splitPreview": "Split preview",
183
195
  "workspace.expand": "Open workspace",
184
196
  "workspace.collapse": "Collapse workspace",
185
197
  "workspace.refresh": "Refresh",
@@ -191,11 +203,20 @@ const I18n = (() => {
191
203
  "workspace.downloadFailed": "Download failed",
192
204
  "workspace.previewFailed": "Failed to preview file",
193
205
  "workspace.previewUnsupported": "Cannot preview this file type",
206
+ "workspace.fallbackHint": "This file type can't be previewed here.",
207
+ "workspace.fallbackSubHint": "Please open this file in another application to view it.",
208
+ "workspace.tableTruncated": "Showing the first %{rows} rows only. Use \"Open\" to view the full file.",
209
+ "workspace.open": "Open",
210
+ "workspace.openDefault": "Open with default app",
211
+ "workspace.openWith": "Open with {{app}}",
212
+ "workspace.openWithFailed": "Failed to open file",
194
213
  "workspace.download": "Download",
195
214
  "workspace.copyPath": "Copy Path",
196
215
  "workspace.copyRelPath": "Copy Relative Path",
197
216
  "aside.collapse": "Collapse panel",
198
217
  "aside.expand": "Open panel",
218
+ "aside.fullscreen": "Fullscreen preview",
219
+ "aside.exitFullscreen": "Exit fullscreen",
199
220
  "workspace.revealInFinder": "Reveal in Finder",
200
221
  "workspace.revealFailed": "Failed to reveal file",
201
222
  "workspace.closeTab": "Close",
@@ -227,6 +248,7 @@ const I18n = (() => {
227
248
  "changes.select.count": "{{n}}/{{total}} selected",
228
249
  "changes.save.btnN": "Save {{n}} selected file(s)",
229
250
  "changes.save.promptMsg": "Describe this snapshot",
251
+ "changes.backToList": "Back to changes",
230
252
  "changes.diff.loading": "Loading diff…",
231
253
  "changes.diff.fail": "Failed to load diff",
232
254
  "changes.diff.same": "No content change in this file.",
@@ -237,7 +259,19 @@ const I18n = (() => {
237
259
  "changes.restore.diffBtn": "Discard changes",
238
260
  "changes.restore.doing": "Reverting…",
239
261
  "changes.restore.done": "Reverted: {{path}}",
240
- "changes.restore.failed": "Revert failed", "tm.tab": "History",
262
+ "changes.restore.failed": "Revert failed",
263
+ "preview.tab": "Preview",
264
+ "preview.empty.title": "Start browsing",
265
+ "preview.empty.sub": "Enter a local file path or localhost address to open the page",
266
+ "preview.address": "Enter a local file path or localhost address",
267
+ "preview.notFound": "File not found",
268
+ "preview.unreachable": "Cannot reach the dev server",
269
+ "preview.openExternal": "Open in new tab",
270
+ "preview.reload": "Reload",
271
+ "preview.back": "Back",
272
+ "preview.forward": "Forward",
273
+ "preview.go": "Go",
274
+ "tm.tab": "History",
241
275
  "sib.model.tooltip": "Click to switch model",
242
276
  "sib.model.tooltip.busy": "Model switching is disabled while the agent is responding",
243
277
  "sib.variant.header": "Quick switch",
@@ -582,6 +616,15 @@ const I18n = (() => {
582
616
  "skills.upload.publishTip": "Publish to cloud",
583
617
  "skills.btn.refresh": "Refresh",
584
618
  "skills.editFail": "Failed to load skill",
619
+ "skills.edit.title": "Edit skill",
620
+ "skills.edit.name": "Name",
621
+ "skills.edit.nameHint": "English slug used as the /command name",
622
+ "skills.edit.nameZh": "Chinese name",
623
+ "skills.edit.description": "Description",
624
+ "skills.edit.descriptionZh": "Chinese description",
625
+ "skills.edit.body": "Content (Markdown)",
626
+ "skills.edit.editMarkdown": "Edit Markdown",
627
+ "skills.edit.saveFail": "Save failed",
585
628
 
586
629
  // ── Channels panel ──
587
630
  "channels.title": "Channels",
@@ -867,9 +910,9 @@ const I18n = (() => {
867
910
  "settings.network.cleared": "Cleared — direct connection",
868
911
  "settings.network.invalidUrl": "Invalid URL — use http://host:port or http://user:pass@host:port",
869
912
  "settings.search.title": "Web Search",
870
- "settings.search.desc": "Free built-in search (DuckDuckGo / Bing) works out of the box. Connect an API provider below for higher-quality results — falls back to built-in if unavailable.",
913
+ "settings.search.desc": "Free built-in search (Parallel / DuckDuckGo / Bing) works out of the box. Select an API provider below to use it instead.",
871
914
  "settings.search.provider": "Provider",
872
- "settings.search.builtin": "Built-in (DuckDuckGo / Bing)",
915
+ "settings.search.builtin": "Built-in (Parallel / DuckDuckGo / Bing)",
873
916
  "settings.search.key": "API Key",
874
917
  "settings.search.save": "Save",
875
918
  "settings.search.saved": "Saved",
@@ -1279,6 +1322,10 @@ const I18n = (() => {
1279
1322
  "chat.feedback_next": "下一题",
1280
1323
  "chat.newMessageHint": "有新消息 ↓",
1281
1324
  "chat.retry": "重试",
1325
+ "chat.quote.btn": "引用",
1326
+ "chat.quote.roleUser": "我",
1327
+ "chat.quote.roleAssistant": "助手",
1328
+ "chat.quote.sig": "{{role}} · 第{{index}}条",
1282
1329
  "chat.copy": "复制",
1283
1330
  "chat.todo.title": "任务清单",
1284
1331
  "chat.todo.spawn": "开干",
@@ -1298,7 +1345,12 @@ const I18n = (() => {
1298
1345
  "chat.empty.tip2": "归纳总结、整理信息",
1299
1346
  "chat.empty.tip3": "上传图片或文件,让我帮你分析",
1300
1347
  "chat.nav.title": "消息导航",
1348
+ "chat.nav.round": "第 {{number}} 条消息",
1301
1349
  "chat.nav.empty": "(空)",
1350
+ "chat.nav.aiReply": "AI 回复",
1351
+ "chat.nav.noReply": "暂无最终回复",
1352
+ "chat.nav.retry": "导航加载失败,点击重试",
1353
+ "chat.nav.latest": "回到最新消息 ↓",
1302
1354
 
1303
1355
  // ── Session list ──
1304
1356
  "sessions.empty": "暂无会话",
@@ -1351,6 +1403,9 @@ const I18n = (() => {
1351
1403
  "sib.dir.drives": "驱动器",
1352
1404
  "sib.dir.places.drive": "{{letter}}盘",
1353
1405
  "workspace.title": "文件",
1406
+ "workspace.toggleTree": "切换目录树",
1407
+ "workspace.backToFiles": "返回文件列表",
1408
+ "workspace.splitPreview": "并排预览",
1354
1409
  "workspace.expand": "打开工作区",
1355
1410
  "workspace.collapse": "收起工作区",
1356
1411
  "workspace.refresh": "刷新",
@@ -1362,11 +1417,20 @@ const I18n = (() => {
1362
1417
  "workspace.downloadFailed": "下载失败",
1363
1418
  "workspace.previewFailed": "文件预览失败",
1364
1419
  "workspace.previewUnsupported": "无法预览此类型文件",
1420
+ "workspace.fallbackHint": "该格式暂不支持在线预览",
1421
+ "workspace.fallbackSubHint": "请在其他应用中打开此文件查看",
1422
+ "workspace.tableTruncated": "仅显示前 %{rows} 行,点击「打开」查看完整文件",
1423
+ "workspace.open": "打开",
1424
+ "workspace.openDefault": "用默认应用打开",
1425
+ "workspace.openWith": "用 {{app}} 打开",
1426
+ "workspace.openWithFailed": "打开文件失败",
1365
1427
  "workspace.download": "下载",
1366
1428
  "workspace.copyPath": "复制路径",
1367
1429
  "workspace.copyRelPath": "复制相对路径",
1368
1430
  "aside.collapse": "收起面板",
1369
1431
  "aside.expand": "打开面板",
1432
+ "aside.fullscreen": "全屏预览",
1433
+ "aside.exitFullscreen": "退出全屏",
1370
1434
  "workspace.revealInFinder": "打开所在文件夹",
1371
1435
  "workspace.revealFailed": "无法打开文件位置",
1372
1436
  "workspace.closeTab": "关闭",
@@ -1398,6 +1462,7 @@ const I18n = (() => {
1398
1462
  "changes.select.count": "已选 {{n}}/{{total}}",
1399
1463
  "changes.save.btnN": "存档选中的 {{n}} 个文件",
1400
1464
  "changes.save.promptMsg": "给这个版本写句说明",
1465
+ "changes.backToList": "返回改动列表",
1401
1466
  "changes.diff.loading": "正在读取差异…",
1402
1467
  "changes.diff.fail": "读取差异失败",
1403
1468
  "changes.diff.same": "这个文件的内容没有变化。",
@@ -1409,6 +1474,17 @@ const I18n = (() => {
1409
1474
  "changes.restore.doing": "正在撤销…",
1410
1475
  "changes.restore.done": "已撤销:{{path}}",
1411
1476
  "changes.restore.failed": "撤销失败",
1477
+ "preview.tab": "预览",
1478
+ "preview.empty.title": "开始浏览",
1479
+ "preview.empty.sub": "输入本地文件路径或 localhost 地址以打开页面",
1480
+ "preview.address": "输入本地文件路径或 localhost 地址",
1481
+ "preview.notFound": "文件不存在",
1482
+ "preview.unreachable": "无法连接到开发服务器",
1483
+ "preview.openExternal": "在新标签页打开",
1484
+ "preview.reload": "刷新",
1485
+ "preview.back": "后退",
1486
+ "preview.forward": "前进",
1487
+ "preview.go": "前往",
1412
1488
  "tm.tab": "时光机",
1413
1489
  "sib.model.tooltip": "点击切换模型",
1414
1490
  "sib.model.tooltip.busy": "Agent 回复中,暂时无法切换模型",
@@ -1753,6 +1829,15 @@ const I18n = (() => {
1753
1829
  "skills.upload.publishTip": "发布到云端",
1754
1830
  "skills.btn.refresh": "刷新",
1755
1831
  "skills.editFail": "加载技能失败",
1832
+ "skills.edit.title": "编辑技能",
1833
+ "skills.edit.name": "名称",
1834
+ "skills.edit.nameHint": "英文标识,同时作为 /命令 名称",
1835
+ "skills.edit.nameZh": "中文名称",
1836
+ "skills.edit.description": "英文描述",
1837
+ "skills.edit.descriptionZh": "中文描述",
1838
+ "skills.edit.body": "内容(Markdown)",
1839
+ "skills.edit.editMarkdown": "编辑 Markdown",
1840
+ "skills.edit.saveFail": "保存失败",
1756
1841
 
1757
1842
  // ── Channels panel ──
1758
1843
  "channels.title": "频道管理",
@@ -2045,9 +2130,9 @@ const I18n = (() => {
2045
2130
  "settings.network.cleared": "已清除 — 直连",
2046
2131
  "settings.network.invalidUrl": "地址格式不正确,请使用 http://host:port 或 http://user:pass@host:port",
2047
2132
  "settings.search.title": "网页搜索",
2048
- "settings.search.desc": "内置免费搜索(DuckDuckGo / Bing)开箱即用。在下方接入 API 服务商可获得更高质量的搜索结果,不可用时自动回退到内置引擎。",
2133
+ "settings.search.desc": "内置免费搜索(Parallel / DuckDuckGo / Bing)开箱即用;也可在下方接入 API 服务商作为替代。",
2049
2134
  "settings.search.provider": "服务商",
2050
- "settings.search.builtin": "内置(DuckDuckGo / Bing)",
2135
+ "settings.search.builtin": "内置(Parallel / DuckDuckGo / Bing)",
2051
2136
  "settings.search.key": "API 密钥",
2052
2137
  "settings.search.save": "保存",
2053
2138
  "settings.search.saved": "已保存",
@@ -570,9 +570,17 @@
570
570
  sits outside the slot container so re-renders never clobber it. -->
571
571
  <div id="session-aside" class="session-aside">
572
572
  <div id="session-aside-resize" class="session-aside-resize"></div>
573
- <button id="btn-aside-collapse" class="session-aside-collapse" data-i18n-title="aside.collapse" title="Collapse">
574
- <svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="18" height="18" x="3" y="3" rx="2"/><path d="M9 3v18"/><path d="m14 9 3 3-3 3"/></svg>
575
- </button>
573
+ <!-- Host-owned actions docked at the right end of the tab bar (the bar
574
+ itself is rendered by Clacky.ext inside the slot below). -->
575
+ <div class="aside-tabbar-actions">
576
+ <button id="btn-aside-fullscreen" class="session-aside-fullscreen" data-i18n-title="aside.fullscreen" title="Fullscreen">
577
+ <svg class="icon-fs-enter" xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M8 3H5a2 2 0 0 0-2 2v3"/><path d="M21 8V5a2 2 0 0 0-2-2h-3"/><path d="M3 16v3a2 2 0 0 0 2 2h3"/><path d="M16 21h3a2 2 0 0 0 2-2v-3"/></svg>
578
+ <svg class="icon-fs-exit" xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M8 3v3a2 2 0 0 1-2 2H3"/><path d="M21 8h-3a2 2 0 0 1-2-2V3"/><path d="M3 16h3a2 2 0 0 1 2 2v3"/><path d="M16 21v-3a2 2 0 0 1 2-2h3"/></svg>
579
+ </button>
580
+ <button id="btn-aside-collapse" class="session-aside-collapse" data-i18n-title="aside.collapse" title="Collapse">
581
+ <svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="18" height="18" x="3" y="3" rx="2"/><path d="M9 3v18"/><path d="m14 9 3 3-3 3"/></svg>
582
+ </button>
583
+ </div>
576
584
  <div id="ext-slot-session-aside" class="session-aside-slot" data-slot="session.aside"></div>
577
585
  </div>
578
586
 
@@ -1156,19 +1164,19 @@
1156
1164
  <span data-i18n="settings.search.title">Web Search</span>
1157
1165
  </div>
1158
1166
  <div class="settings-network">
1159
- <p class="settings-network-desc" data-i18n="settings.search.desc">By default web_search scrapes DuckDuckGo and Bing, which needs no key but returns lower-quality results. Select a search provider to use an API instead — it falls back to the built-in engines if the provider fails.</p>
1167
+ <p class="settings-network-desc" data-i18n="settings.search.desc">Free built-in search uses Parallel, DuckDuckGo, and Bing with no key required. Select a search provider to use a configured API instead.</p>
1160
1168
  <div class="settings-network-url">
1161
1169
  <label class="settings-network-url-label" for="settings-search-provider-trigger" data-i18n="settings.search.provider">Provider</label>
1162
1170
  <div class="settings-network-url-row">
1163
1171
  <div class="custom-select-wrapper" id="settings-search-provider-wrapper">
1164
1172
  <div class="custom-select-trigger" tabindex="0" id="settings-search-provider-trigger">
1165
- <span class="custom-select-value placeholder" id="settings-search-provider-value" data-i18n="settings.search.builtin">Built-in (DuckDuckGo / Bing)</span>
1173
+ <span class="custom-select-value placeholder" id="settings-search-provider-value" data-i18n="settings.search.builtin">Built-in (Parallel / DuckDuckGo / Bing)</span>
1166
1174
  <svg class="custom-select-arrow" fill="none" stroke="currentColor" viewBox="0 0 24 24">
1167
1175
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path>
1168
1176
  </svg>
1169
1177
  </div>
1170
1178
  <div class="custom-select-dropdown" id="settings-search-provider-dropdown">
1171
- <div class="custom-select-option" data-value="" data-i18n="settings.search.builtin">Built-in (DuckDuckGo / Bing)</div>
1179
+ <div class="custom-select-option" data-value="" data-i18n="settings.search.builtin">Built-in (Parallel / DuckDuckGo / Bing)</div>
1172
1180
  </div>
1173
1181
  </div>
1174
1182
  <button type="button" id="btn-save-search" class="btn-settings-action" data-i18n="settings.search.save">Save</button>
@@ -1743,6 +1751,7 @@
1743
1751
  <script src="/ws-dispatcher.js"></script>
1744
1752
  <script src="/components/custom-select.js"></script>
1745
1753
  <script src="/sessions.js"></script>
1754
+ <script src="/components/quote-select.js"></script>
1746
1755
  <script src="/projects.js"></script>
1747
1756
  <script src="/features/workspace/store.js"></script>
1748
1757
  <script src="/features/workspace/view.js"></script>