openclacky 1.3.0 → 1.3.2
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 +30 -0
- data/lib/clacky/agent/session_serializer.rb +16 -6
- data/lib/clacky/brand_config.rb +1 -1
- data/lib/clacky/providers.rb +1 -1
- data/lib/clacky/server/http_server.rb +35 -1
- data/lib/clacky/utils/environment_detector.rb +16 -0
- data/lib/clacky/version.rb +1 -1
- data/lib/clacky/web/app.css +192 -38
- data/lib/clacky/web/app.js +51 -0
- data/lib/clacky/web/billing.js +134 -8
- data/lib/clacky/web/i18n.js +12 -0
- data/lib/clacky/web/index.html +2 -0
- data/lib/clacky/web/onboard.js +8 -1
- data/lib/clacky/web/sessions.js +11 -0
- data/lib/clacky/web/settings.js +8 -8
- data/lib/clacky/web/skills.js +81 -6
- data/lib/clacky/web/tasks.js +18 -10
- data/lib/clacky/web/workspace.js +104 -0
- metadata +4 -7
data/lib/clacky/web/workspace.js
CHANGED
|
@@ -93,9 +93,71 @@ const Workspace = (() => {
|
|
|
93
93
|
row.addEventListener("click", () => downloadFile(entry));
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
+
row.addEventListener("contextmenu", (e) => {
|
|
97
|
+
e.preventDefault();
|
|
98
|
+
showContextMenu(e, entry);
|
|
99
|
+
});
|
|
100
|
+
|
|
96
101
|
return node;
|
|
97
102
|
}
|
|
98
103
|
|
|
104
|
+
function showContextMenu(e, entry) {
|
|
105
|
+
closeContextMenu();
|
|
106
|
+
|
|
107
|
+
const iconFolder = '<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/></svg>';
|
|
108
|
+
|
|
109
|
+
const menu = document.createElement("div");
|
|
110
|
+
menu.className = "wt-context-menu session-context-menu";
|
|
111
|
+
menu.innerHTML = `
|
|
112
|
+
<div class="session-actions-menu-item" data-action="reveal">
|
|
113
|
+
<span class="session-actions-menu-icon">${iconFolder}</span>
|
|
114
|
+
<span class="session-actions-menu-label">${t("workspace.revealInFinder")}</span>
|
|
115
|
+
</div>
|
|
116
|
+
`;
|
|
117
|
+
|
|
118
|
+
document.body.appendChild(menu);
|
|
119
|
+
menu.addEventListener("contextmenu", (e) => e.preventDefault());
|
|
120
|
+
menu.style.position = "fixed";
|
|
121
|
+
menu.style.top = e.clientY + "px";
|
|
122
|
+
menu.style.left = e.clientX + "px";
|
|
123
|
+
requestAnimationFrame(() => {
|
|
124
|
+
const r = menu.getBoundingClientRect();
|
|
125
|
+
if (r.right > window.innerWidth) menu.style.left = (window.innerWidth - r.width - 8) + "px";
|
|
126
|
+
if (r.bottom > window.innerHeight) menu.style.top = (window.innerHeight - r.height - 8) + "px";
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
menu.addEventListener("click", async (ev) => {
|
|
130
|
+
const item = ev.target.closest(".session-actions-menu-item");
|
|
131
|
+
if (!item) return;
|
|
132
|
+
closeContextMenu();
|
|
133
|
+
if (item.dataset.action === "reveal") await revealFile(entry);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
setTimeout(() => {
|
|
137
|
+
document.addEventListener("click", closeContextMenu, { once: true });
|
|
138
|
+
}, 0);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function closeContextMenu() {
|
|
142
|
+
const existing = document.querySelector(".wt-context-menu");
|
|
143
|
+
if (existing) existing.remove();
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
async function revealFile(entry) {
|
|
147
|
+
const fullPath = _workingDir.replace(/\/+$/, "") + "/" + entry.path;
|
|
148
|
+
try {
|
|
149
|
+
const resp = await fetch("/api/file-action", {
|
|
150
|
+
method: "POST",
|
|
151
|
+
headers: { "Content-Type": "application/json" },
|
|
152
|
+
body: JSON.stringify({ path: fullPath, action: "reveal" })
|
|
153
|
+
});
|
|
154
|
+
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
|
|
155
|
+
} catch (err) {
|
|
156
|
+
console.error("reveal failed:", err);
|
|
157
|
+
if (typeof Modal !== "undefined") Modal.toast(t("workspace.revealFailed"), "error");
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
99
161
|
async function toggleDir(entry, caret, children) {
|
|
100
162
|
const isOpen = caret.classList.contains("open");
|
|
101
163
|
if (isOpen) {
|
|
@@ -208,5 +270,47 @@ const Workspace = (() => {
|
|
|
208
270
|
};
|
|
209
271
|
})();
|
|
210
272
|
|
|
273
|
+
(function _initWorkspaceResize() {
|
|
274
|
+
const panel = document.getElementById("workspace-panel");
|
|
275
|
+
const handle = document.getElementById("workspace-resize-handle");
|
|
276
|
+
if (!panel || !handle) return;
|
|
277
|
+
|
|
278
|
+
const MIN_W = 160;
|
|
279
|
+
const MAX_W = 600;
|
|
280
|
+
|
|
281
|
+
const saved = localStorage.getItem("workspace-width");
|
|
282
|
+
if (saved) {
|
|
283
|
+
const w = parseFloat(saved);
|
|
284
|
+
if (w >= MIN_W && w <= MAX_W) panel.style.setProperty("--workspace-width", w + "px");
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
let startX = 0;
|
|
288
|
+
let startW = 0;
|
|
289
|
+
|
|
290
|
+
handle.addEventListener("mousedown", (e) => {
|
|
291
|
+
e.preventDefault();
|
|
292
|
+
startX = e.clientX;
|
|
293
|
+
startW = parseFloat(getComputedStyle(panel).getPropertyValue("--workspace-width"));
|
|
294
|
+
handle.classList.add("active");
|
|
295
|
+
document.body.style.cursor = "col-resize";
|
|
296
|
+
document.body.style.userSelect = "none";
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
document.addEventListener("mousemove", (e) => {
|
|
300
|
+
if (!handle.classList.contains("active")) return;
|
|
301
|
+
const dx = startX - e.clientX;
|
|
302
|
+
const newW = Math.min(MAX_W, Math.max(MIN_W, startW + dx));
|
|
303
|
+
panel.style.setProperty("--workspace-width", newW + "px");
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
document.addEventListener("mouseup", () => {
|
|
307
|
+
if (!handle.classList.contains("active")) return;
|
|
308
|
+
handle.classList.remove("active");
|
|
309
|
+
document.body.style.cursor = "";
|
|
310
|
+
document.body.style.userSelect = "";
|
|
311
|
+
localStorage.setItem("workspace-width", parseFloat(getComputedStyle(panel).getPropertyValue("--workspace-width")));
|
|
312
|
+
});
|
|
313
|
+
})();
|
|
314
|
+
|
|
211
315
|
document.addEventListener("DOMContentLoaded", () => Workspace.init());
|
|
212
316
|
window.Workspace = Workspace;
|
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.2
|
|
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
|
|
@@ -270,8 +269,8 @@ email:
|
|
|
270
269
|
- yafei@dao42.com
|
|
271
270
|
executables:
|
|
272
271
|
- clacky
|
|
273
|
-
- openclacky
|
|
274
272
|
- clarky
|
|
273
|
+
- openclacky
|
|
275
274
|
extensions: []
|
|
276
275
|
extra_rdoc_files: []
|
|
277
276
|
files:
|
|
@@ -632,7 +631,6 @@ metadata:
|
|
|
632
631
|
homepage_uri: https://github.com/clacky-ai/openclacky
|
|
633
632
|
source_code_uri: https://github.com/clacky-ai/openclacky
|
|
634
633
|
changelog_uri: https://github.com/clacky-ai/openclacky/blob/main/CHANGELOG.md
|
|
635
|
-
post_install_message:
|
|
636
634
|
rdoc_options: []
|
|
637
635
|
require_paths:
|
|
638
636
|
- lib
|
|
@@ -650,8 +648,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
650
648
|
- !ruby/object:Gem::Version
|
|
651
649
|
version: '0'
|
|
652
650
|
requirements: []
|
|
653
|
-
rubygems_version: 3.
|
|
654
|
-
signing_key:
|
|
651
|
+
rubygems_version: 3.6.9
|
|
655
652
|
specification_version: 4
|
|
656
653
|
summary: The most Token-efficient open-source AI Agent — BYOK, Skill-driven, IM-integrated.
|
|
657
654
|
test_files: []
|