openclacky 1.5.21 → 1.5.22
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 +61 -0
- data/lib/clacky/billing/platform_billing.rb +3 -0
- data/lib/clacky/default_extensions/git/panels/git/view.js +1911 -398
- data/lib/clacky/default_extensions/preview/panels/preview/view.js +199 -34
- data/lib/clacky/providers.rb +43 -17
- data/lib/clacky/search_config.rb +33 -11
- data/lib/clacky/server/git_panel.rb +360 -34
- data/lib/clacky/server/http_server.rb +145 -47
- data/lib/clacky/server/preview.rb +118 -17
- data/lib/clacky/server/scheduler.rb +81 -2
- data/lib/clacky/server/web_ui_controller.rb +35 -27
- data/lib/clacky/session_manager.rb +52 -5
- data/lib/clacky/utils/mac_app_detector.rb +8 -7
- data/lib/clacky/utils/model_pricing.rb +60 -2
- data/lib/clacky/utils/windows_app_detector.rb +3 -1
- data/lib/clacky/version.rb +1 -1
- data/lib/clacky/web/app.css +650 -96
- data/lib/clacky/web/app.js +59 -6
- data/lib/clacky/web/auth.js +1 -1
- data/lib/clacky/web/components/composer.js +107 -8
- data/lib/clacky/web/components/image-zoom.js +165 -0
- data/lib/clacky/web/components/model-picker.js +6 -4
- data/lib/clacky/web/components/notify.js +2 -2
- data/lib/clacky/web/core/aside.js +60 -3
- data/lib/clacky/web/features/billing/view.js +2 -2
- data/lib/clacky/web/features/channels/view.js +5 -2
- data/lib/clacky/web/features/extensions/view.js +2 -2
- data/lib/clacky/web/features/new-session/store.js +79 -2
- data/lib/clacky/web/features/new-session/view.js +496 -58
- data/lib/clacky/web/features/skills/store.js +1 -1
- data/lib/clacky/web/features/tasks/view.js +162 -51
- data/lib/clacky/web/features/workspace/store.js +13 -6
- data/lib/clacky/web/features/workspace/view.js +153 -163
- data/lib/clacky/web/i18n.js +238 -56
- data/lib/clacky/web/index.html +173 -157
- data/lib/clacky/web/projects.js +37 -4
- data/lib/clacky/web/sessions.js +181 -105
- data/lib/clacky/web/settings.js +26 -8
- data/lib/clacky/web/skills.js +2 -2
- data/lib/clacky/web/theme.js +17 -2
- data/lib/clacky/web/utils.js +17 -2
- data/lib/clacky/web/weixin-qr.html +2 -1
- data/lib/clacky/web/ws-dispatcher.js +8 -29
- metadata +2 -1
|
@@ -130,12 +130,14 @@ const ChannelsView = (() => {
|
|
|
130
130
|
row.className = "channel-row";
|
|
131
131
|
row.id = `channel-card-${platform}`;
|
|
132
132
|
|
|
133
|
+
// Rows survive a language switch, so the tooltip also carries the lookup
|
|
134
|
+
// key that I18n.applyAll() rewrites in place.
|
|
133
135
|
const action = hasConfig
|
|
134
136
|
? `${_toggleHtml(platform, !!data.enabled)}
|
|
135
137
|
<button type="button" class="channel-row-btn" data-channel-more="${_esc(platform)}"
|
|
136
138
|
title="${_esc(I18n.t("channels.btn.more"))}" aria-haspopup="menu" aria-expanded="false">${MORE_SVG}</button>`
|
|
137
139
|
: `<button type="button" class="channel-row-btn" data-channel-setup="${_esc(platform)}"
|
|
138
|
-
|
|
140
|
+
data-tooltip="${_esc(I18n.t("channels.btn.setup"))}" data-i18n-tooltip="channels.btn.setup">${PLUS_SVG}</button>`;
|
|
139
141
|
|
|
140
142
|
row.innerHTML = `
|
|
141
143
|
<span class="channel-logo ${_esc(meta.logoClass)}">${meta.logo}</span>
|
|
@@ -177,7 +179,8 @@ const ChannelsView = (() => {
|
|
|
177
179
|
<div class="channel-row-desc" title="${_esc(desc)}">${_esc(desc)}</div>
|
|
178
180
|
</div>
|
|
179
181
|
<div class="channel-row-action">
|
|
180
|
-
<button type="button" class="channel-row-btn" id="btn-custom-dev-guide"
|
|
182
|
+
<button type="button" class="channel-row-btn" id="btn-custom-dev-guide"
|
|
183
|
+
data-tooltip="${_esc(I18n.t("channels.customDev.btn"))}" data-i18n-tooltip="channels.customDev.btn">${PLUS_SVG}</button>
|
|
181
184
|
</div>
|
|
182
185
|
`;
|
|
183
186
|
row.querySelector("#btn-custom-dev-guide").addEventListener("click", () => {
|
|
@@ -192,12 +192,12 @@ const ExtensionsView = (() => {
|
|
|
192
192
|
// keeps the same "+" (enable) affordance as anything waiting to be
|
|
193
193
|
// installed rather than the "…" menu.
|
|
194
194
|
if (ext.layer === "builtin" && ext.disabled === true) {
|
|
195
|
-
return `${failedHtml}<button type="button" class="ext-row-add" data-ext-row-enable="${escapeHtml(id)}"
|
|
195
|
+
return `${failedHtml}<button type="button" class="ext-row-add" data-ext-row-enable="${escapeHtml(id)}" data-tooltip="${escapeHtml(I18n.t("extensions.action.enable"))}">${_plusSvg()}</button>`;
|
|
196
196
|
}
|
|
197
197
|
return `${failedHtml}${_rowMore(id)}`;
|
|
198
198
|
}
|
|
199
199
|
|
|
200
|
-
return `${failedHtml}<button type="button" class="ext-row-add" data-ext-row-install="${escapeHtml(id)}"
|
|
200
|
+
return `${failedHtml}<button type="button" class="ext-row-add" data-ext-row-install="${escapeHtml(id)}" data-tooltip="${escapeHtml(I18n.t("extensions.action.install"))}">${_plusSvg()}</button>`;
|
|
201
201
|
}
|
|
202
202
|
|
|
203
203
|
function _rowMore(id) {
|
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
// ───────────────────────────────────────────────────────────────────────────
|
|
14
14
|
|
|
15
15
|
const NewSessionStore = (() => {
|
|
16
|
-
const LS_AGENT_KEY = "
|
|
17
|
-
const LS_PROJECT_KEY = "
|
|
16
|
+
const LS_AGENT_KEY = "clacky-new-session-last-agent";
|
|
17
|
+
const LS_PROJECT_KEY = "clacky-new-session-last-project";
|
|
18
18
|
|
|
19
19
|
const _state = {
|
|
20
20
|
agents: [],
|
|
@@ -30,6 +30,9 @@ const NewSessionStore = (() => {
|
|
|
30
30
|
},
|
|
31
31
|
advancedOpen: false,
|
|
32
32
|
creating: false,
|
|
33
|
+
// Branch state of the selected project's working dir. `loaded` separates
|
|
34
|
+
// "never fetched" from "fetched, not a repo" so the chip can hide quietly.
|
|
35
|
+
git: { key: null, projectId: null, dir: "", loaded: false, loading: false, repo: false, branch: "", branches: [] },
|
|
33
36
|
};
|
|
34
37
|
|
|
35
38
|
const _listeners = {};
|
|
@@ -138,6 +141,77 @@ const NewSessionStore = (() => {
|
|
|
138
141
|
}
|
|
139
142
|
}
|
|
140
143
|
|
|
144
|
+
// ── Git state of the selected project's working dir ──────────────────────
|
|
145
|
+
// Only the branch chip cares, so failures collapse to `repo: false` rather
|
|
146
|
+
// than surfacing an error the user cannot act on. Keyed by project + dir
|
|
147
|
+
// because a session's working dir may point at a different repo entirely.
|
|
148
|
+
function gitKey(projectId, dir) {
|
|
149
|
+
return `${projectId || ""}\u0000${dir || ""}`;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
async function loadGitInfo(projectId, { dir = "", force = false } = {}) {
|
|
153
|
+
const key = gitKey(projectId, dir);
|
|
154
|
+
if (!projectId) {
|
|
155
|
+
if (_state.git.key || !_state.git.loaded) {
|
|
156
|
+
_state.git = { key: null, projectId: null, dir: "", loaded: true, loading: false, repo: false, branch: "", branches: [] };
|
|
157
|
+
_emit("newSession:git-changed", { git: _state.git });
|
|
158
|
+
}
|
|
159
|
+
return _state.git;
|
|
160
|
+
}
|
|
161
|
+
if (!force && _state.git.loaded && _state.git.key === key) return _state.git;
|
|
162
|
+
if (!force && _state.git.loading && _state.git.key === key) return _state.git;
|
|
163
|
+
|
|
164
|
+
_state.git = {
|
|
165
|
+
key,
|
|
166
|
+
projectId: String(projectId),
|
|
167
|
+
dir: dir || "",
|
|
168
|
+
loaded: false,
|
|
169
|
+
loading: true,
|
|
170
|
+
repo: false,
|
|
171
|
+
branch: "",
|
|
172
|
+
branches: [],
|
|
173
|
+
};
|
|
174
|
+
_emit("newSession:git-changed", { git: _state.git });
|
|
175
|
+
|
|
176
|
+
let data = null;
|
|
177
|
+
try {
|
|
178
|
+
data = await Projects.gitInfo(projectId, dir);
|
|
179
|
+
} catch (e) {
|
|
180
|
+
data = { repo: false };
|
|
181
|
+
}
|
|
182
|
+
// A slow response for a project the user already switched away from must
|
|
183
|
+
// not overwrite the newer one.
|
|
184
|
+
if (_state.git.key !== key) return _state.git;
|
|
185
|
+
|
|
186
|
+
_state.git = {
|
|
187
|
+
key,
|
|
188
|
+
projectId: String(projectId),
|
|
189
|
+
dir: dir || "",
|
|
190
|
+
loaded: true,
|
|
191
|
+
loading: false,
|
|
192
|
+
repo: !!(data && data.repo),
|
|
193
|
+
branch: (data && data.branch) || "",
|
|
194
|
+
branches: (data && data.branches) || [],
|
|
195
|
+
};
|
|
196
|
+
_emit("newSession:git-changed", { git: _state.git });
|
|
197
|
+
return _state.git;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/** Merge a checkout response into the cached git state. */
|
|
201
|
+
function applyGitState(data) {
|
|
202
|
+
if (!data) return _state.git;
|
|
203
|
+
_state.git = {
|
|
204
|
+
..._state.git,
|
|
205
|
+
loaded: true,
|
|
206
|
+
loading: false,
|
|
207
|
+
repo: true,
|
|
208
|
+
branch: data.branch || _state.git.branch,
|
|
209
|
+
branches: data.branches || _state.git.branches,
|
|
210
|
+
};
|
|
211
|
+
_emit("newSession:git-changed", { git: _state.git });
|
|
212
|
+
return _state.git;
|
|
213
|
+
}
|
|
214
|
+
|
|
141
215
|
function _autoName(existingSessions) {
|
|
142
216
|
const maxN = (existingSessions || []).reduce((max, s) => {
|
|
143
217
|
const m = s.name && s.name.match(/^Session (\d+)$/);
|
|
@@ -231,6 +305,9 @@ const NewSessionStore = (() => {
|
|
|
231
305
|
updateAdvanced,
|
|
232
306
|
loadModels,
|
|
233
307
|
loadDefaultDirectory,
|
|
308
|
+
loadGitInfo,
|
|
309
|
+
gitKey,
|
|
310
|
+
applyGitState,
|
|
234
311
|
createSession,
|
|
235
312
|
fetchSkillsForAgent,
|
|
236
313
|
loadAgentName,
|