openclacky 1.5.7 → 1.5.8
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 +33 -0
- data/README.md +2 -2
- data/README_CN.md +1 -1
- data/README_JA.md +1 -1
- data/lib/clacky/agent.rb +2 -3
- data/lib/clacky/agent_config.rb +40 -18
- data/lib/clacky/cli.rb +0 -1
- data/lib/clacky/default_extensions/ext-studio/panels/studio/view.js +23 -10
- data/lib/clacky/default_extensions/ext-studio/skills/ext-develop/SKILL.md +3 -2
- data/lib/clacky/default_extensions/general/ext.yml +1 -1
- data/lib/clacky/extension/api_loader.rb +4 -11
- data/lib/clacky/extension/packager.rb +1 -1
- data/lib/clacky/extension/verifier.rb +1 -1
- data/lib/clacky/media/generator.rb +3 -3
- data/lib/clacky/message_history.rb +1 -1
- data/lib/clacky/providers.rb +2 -1
- data/lib/clacky/server/http_server.rb +60 -76
- data/lib/clacky/session_manager.rb +7 -0
- data/lib/clacky/ui2/components/inline_input.rb +1 -0
- data/lib/clacky/ui2/components/input_area.rb +1 -0
- data/lib/clacky/ui2/components/modal_component.rb +0 -1
- data/lib/clacky/ui2/components/todo_area.rb +1 -0
- data/lib/clacky/ui2/line_editor.rb +1 -0
- data/lib/clacky/ui2/markdown_renderer.rb +5 -1
- data/lib/clacky/ui2/ui_controller.rb +1 -0
- data/lib/clacky/version.rb +1 -1
- data/lib/clacky/web/app.css +134 -210
- data/lib/clacky/web/components/chat-navigator.js +1 -1
- data/lib/clacky/web/features/billing/store.js +3 -3
- data/lib/clacky/web/features/billing/view.js +5 -61
- data/lib/clacky/web/features/extensions/store.js +1 -1
- data/lib/clacky/web/features/extensions/view.js +28 -5
- data/lib/clacky/web/features/new-session/view.js +24 -0
- data/lib/clacky/web/i18n.js +20 -18
- data/lib/clacky/web/index.html +12 -13
- data/lib/clacky/web/projects.js +73 -282
- data/lib/clacky/web/settings.js +6 -1
- metadata +1 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// ── Billing · view — dashboard rendering, charts, tooltips, DOM wiring ─────
|
|
2
2
|
//
|
|
3
3
|
// Owns every render function (stats, heatmap, trend, breakdowns, sessions),
|
|
4
|
-
// tooltip binding
|
|
5
|
-
// and currency helpers; period / model /
|
|
4
|
+
// tooltip binding. Reads through BillingStore.state
|
|
5
|
+
// and currency helpers; period / model / share go through store actions.
|
|
6
6
|
//
|
|
7
7
|
// Augments the `Billing` facade with onPanelShow.
|
|
8
8
|
//
|
|
@@ -10,7 +10,6 @@
|
|
|
10
10
|
// ───────────────────────────────────────────────────────────────────────────
|
|
11
11
|
|
|
12
12
|
const BillingView = (() => {
|
|
13
|
-
let _clearPopupVisible = false;
|
|
14
13
|
|
|
15
14
|
// ── Loading / error ───────────────────────────────────────────────────────
|
|
16
15
|
|
|
@@ -118,7 +117,7 @@ const BillingView = (() => {
|
|
|
118
117
|
|
|
119
118
|
const periods = ["day", "week", "month", "year", "all"];
|
|
120
119
|
const periodBtns = periods.map(p =>
|
|
121
|
-
`<button class="
|
|
120
|
+
`<button class="segmented-control__btn ${p === BillingStore.state.currentPeriod ? 'active' : ''}" data-period="${p}">${_periodLabel(p)}</button>`
|
|
122
121
|
).join("");
|
|
123
122
|
|
|
124
123
|
const allModels = BillingStore.state.allModels;
|
|
@@ -135,21 +134,12 @@ const BillingView = (() => {
|
|
|
135
134
|
<span class="billing-subtitle">${_getSummaryHint()}</span>
|
|
136
135
|
</div>
|
|
137
136
|
<div class="billing-controls">
|
|
138
|
-
<div class="
|
|
137
|
+
<div class="segmented-control">${periodBtns}</div>
|
|
139
138
|
<select id="billing-model-filter" class="billing-model-filter">${modelOptions}</select>
|
|
140
139
|
<button id="billing-share-btn" class="billing-share-btn" title="${I18n.t('billing.share.tooltip') || 'Share scorecard'}">
|
|
141
140
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M4 12v8a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><polyline points="16 6 12 2 8 6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><line x1="12" y1="2" x2="12" y2="15" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
|
142
141
|
${I18n.t('billing.share.btn') || 'Share scorecard'}
|
|
143
142
|
</button>
|
|
144
|
-
<div class="billing-clear-container">
|
|
145
|
-
<button id="billing-clear-btn" class="billing-clear-btn" title="${I18n.t('billing.clearData') || 'Clear Data'}">
|
|
146
|
-
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><polyline points="3 6 5 6 21 6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><path d="M10 11v6M14 11v6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><path d="M9 6V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
|
147
|
-
</button>
|
|
148
|
-
<div id="billing-clear-popup" class="billing-clear-popup" style="display: none;">
|
|
149
|
-
<button id="billing-clear-today" class="billing-clear-option">${I18n.t('billing.clearToday') || 'Clear Today'}</button>
|
|
150
|
-
<button id="billing-clear-all" class="billing-clear-option billing-clear-danger">${I18n.t('billing.clearAll') || 'Clear All'}</button>
|
|
151
|
-
</div>
|
|
152
|
-
</div>
|
|
153
143
|
</div>
|
|
154
144
|
</div>
|
|
155
145
|
|
|
@@ -217,7 +207,7 @@ const BillingView = (() => {
|
|
|
217
207
|
</div>
|
|
218
208
|
`;
|
|
219
209
|
|
|
220
|
-
document.querySelectorAll(".
|
|
210
|
+
document.querySelectorAll(".segmented-control__btn").forEach(btn => {
|
|
221
211
|
btn.addEventListener("click", (e) => Billing.setPeriod(e.target.dataset.period));
|
|
222
212
|
});
|
|
223
213
|
|
|
@@ -225,7 +215,6 @@ const BillingView = (() => {
|
|
|
225
215
|
Billing.setModel(e.target.value);
|
|
226
216
|
});
|
|
227
217
|
|
|
228
|
-
_bindClearHandlers();
|
|
229
218
|
document.getElementById("billing-share-btn")?.addEventListener("click", _openScorecardShare);
|
|
230
219
|
|
|
231
220
|
_bindChartTooltip();
|
|
@@ -416,50 +405,6 @@ const BillingView = (() => {
|
|
|
416
405
|
});
|
|
417
406
|
}
|
|
418
407
|
|
|
419
|
-
// ── Clear popup ────────────────────────────────────────────────────────────
|
|
420
|
-
|
|
421
|
-
function _bindClearHandlers() {
|
|
422
|
-
const clearBtn = document.getElementById("billing-clear-btn");
|
|
423
|
-
const clearPopup = document.getElementById("billing-clear-popup");
|
|
424
|
-
const clearToday = document.getElementById("billing-clear-today");
|
|
425
|
-
const clearAll = document.getElementById("billing-clear-all");
|
|
426
|
-
|
|
427
|
-
if (!clearBtn || !clearPopup) return;
|
|
428
|
-
|
|
429
|
-
clearBtn.addEventListener("click", (e) => {
|
|
430
|
-
e.stopPropagation();
|
|
431
|
-
_clearPopupVisible = !_clearPopupVisible;
|
|
432
|
-
clearPopup.style.display = _clearPopupVisible ? "flex" : "none";
|
|
433
|
-
});
|
|
434
|
-
|
|
435
|
-
clearToday?.addEventListener("click", (e) => {
|
|
436
|
-
e.stopPropagation();
|
|
437
|
-
_hideClearPopup();
|
|
438
|
-
Billing.clearData("today");
|
|
439
|
-
});
|
|
440
|
-
|
|
441
|
-
clearAll?.addEventListener("click", (e) => {
|
|
442
|
-
e.stopPropagation();
|
|
443
|
-
_hideClearPopup();
|
|
444
|
-
Billing.clearData("all");
|
|
445
|
-
});
|
|
446
|
-
|
|
447
|
-
document.addEventListener("click", _closeClearPopup);
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
function _hideClearPopup() {
|
|
451
|
-
const clearPopup = document.getElementById("billing-clear-popup");
|
|
452
|
-
if (clearPopup) clearPopup.style.display = "none";
|
|
453
|
-
_clearPopupVisible = false;
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
function _closeClearPopup(e) {
|
|
457
|
-
const clearPopup = document.getElementById("billing-clear-popup");
|
|
458
|
-
const clearBtn = document.getElementById("billing-clear-btn");
|
|
459
|
-
if (!clearPopup || !clearBtn) return;
|
|
460
|
-
if (!clearPopup.contains(e.target) && !clearBtn.contains(e.target)) _hideClearPopup();
|
|
461
|
-
}
|
|
462
|
-
|
|
463
408
|
// ── Section renderers ────────────────────────────────────────────────────────
|
|
464
409
|
|
|
465
410
|
function _getSummaryHint() {
|
|
@@ -678,7 +623,6 @@ const BillingView = (() => {
|
|
|
678
623
|
<div class="billing-chart-card billing-trend-card">
|
|
679
624
|
<div class="billing-chart-header">
|
|
680
625
|
<h4>${I18n.t("billing.costTrend") || "Cost Trend"}</h4>
|
|
681
|
-
<span class="billing-trend-total">${currencySymbol}${_formatCost(costs.reduce((a, b) => a + b, 0))}</span>
|
|
682
626
|
</div>
|
|
683
627
|
<div class="billing-trend-chart">
|
|
684
628
|
<svg viewBox="0 0 ${w} ${h}" preserveAspectRatio="xMidYMid meet" class="billing-trend-svg">
|
|
@@ -362,7 +362,7 @@ const ExtensionsStore = (() => {
|
|
|
362
362
|
});
|
|
363
363
|
const data = await res.json();
|
|
364
364
|
if (!res.ok || !data.ok) throw new Error(data.error || "toggle failed");
|
|
365
|
-
const activeTab = _filterSystem ? "system" : _filterBrand ? "brand" : "market";
|
|
365
|
+
const activeTab = _filterSystem ? "system" : _filterBrand ? "brand" : _filterInstalled ? "installed" : "market";
|
|
366
366
|
try { sessionStorage.setItem(EXT_TAB_KEY, activeTab); } catch (_) {}
|
|
367
367
|
location.reload();
|
|
368
368
|
} catch (e) {
|
|
@@ -108,6 +108,8 @@ const ExtensionsView = (() => {
|
|
|
108
108
|
? `<span class="extension-updatable">${escapeHtml(I18n.t("extensions.updatable"))}</span>` : "";
|
|
109
109
|
const unlistedHtml = (ext.unlisted && ext.installed)
|
|
110
110
|
? `<span class="extension-unlisted">${escapeHtml(I18n.t("extensions.unlisted"))}</span>` : "";
|
|
111
|
+
const verifiedHtml = (ext.verified && !ext.installed)
|
|
112
|
+
? `<span class="extension-verified">${escapeHtml(I18n.t("extensions.verified"))}</span>` : "";
|
|
111
113
|
const unitsText = _formatUnits(ext.units);
|
|
112
114
|
const unitsHtml = unitsText
|
|
113
115
|
? `<span class="extension-units">${escapeHtml(unitsText)}</span>` : "";
|
|
@@ -137,6 +139,7 @@ const ExtensionsView = (() => {
|
|
|
137
139
|
${installedHtml}
|
|
138
140
|
${updatableHtml}
|
|
139
141
|
${unlistedHtml}
|
|
142
|
+
${verifiedHtml}
|
|
140
143
|
${unitsHtml}
|
|
141
144
|
${authorHtml}
|
|
142
145
|
${installsHtml}
|
|
@@ -160,6 +163,7 @@ const ExtensionsView = (() => {
|
|
|
160
163
|
} else {
|
|
161
164
|
card.addEventListener("click", (e) => {
|
|
162
165
|
if (e.target.closest("a")) return;
|
|
166
|
+
_saveCurrentTab();
|
|
163
167
|
const router = window.Clacky && window.Clacky.Router;
|
|
164
168
|
const isBrand = card.dataset.extOrigin === "self" || Extensions.state.filterBrand;
|
|
165
169
|
const source = isBrand ? "brand" : null;
|
|
@@ -181,6 +185,17 @@ const ExtensionsView = (() => {
|
|
|
181
185
|
</button>`;
|
|
182
186
|
}
|
|
183
187
|
|
|
188
|
+
function _saveCurrentTab() {
|
|
189
|
+
try {
|
|
190
|
+
var s = ExtensionsStore.state;
|
|
191
|
+
var tab = "market";
|
|
192
|
+
if (s.filterSystem) tab = "system";
|
|
193
|
+
else if (s.filterBrand) tab = "brand";
|
|
194
|
+
else if (s.filterInstalled) tab = "installed";
|
|
195
|
+
sessionStorage.setItem(EXT_TAB_KEY, tab);
|
|
196
|
+
} catch (_) {}
|
|
197
|
+
}
|
|
198
|
+
|
|
184
199
|
// Returns a human-readable button label for a given install job state.
|
|
185
200
|
function _installJobLabel(job) {
|
|
186
201
|
if (!job) return I18n.t("extensions.action.install");
|
|
@@ -300,13 +315,14 @@ const ExtensionsView = (() => {
|
|
|
300
315
|
|
|
301
316
|
const installBtn = document.querySelector("[data-ext-install]");
|
|
302
317
|
if (installBtn) {
|
|
303
|
-
installBtn.addEventListener("click", () => {
|
|
318
|
+
installBtn.addEventListener("click", async () => {
|
|
304
319
|
const id = installBtn.getAttribute("data-ext-install");
|
|
320
|
+
const ext = ExtensionsStore.state.detail;
|
|
321
|
+
if (ext && !ext.verified && !(typeof Brand !== "undefined" && Brand.branded)) {
|
|
322
|
+
const confirmed = await Modal.confirm(I18n.t("extensions.unverifiedInstallWarning"));
|
|
323
|
+
if (!confirmed) return;
|
|
324
|
+
}
|
|
305
325
|
installBtn.disabled = true;
|
|
306
|
-
// Show a "downloading" placeholder rather than a generic "installing" —
|
|
307
|
-
// the next real state is always the download starting, so this avoids
|
|
308
|
-
// a jarring "installing → downloading → installing" flash before any
|
|
309
|
-
// real progress data has arrived.
|
|
310
326
|
installBtn.textContent = _installJobLabel({ stage: "downloading", progress: null });
|
|
311
327
|
Extensions.install(id);
|
|
312
328
|
});
|
|
@@ -350,6 +366,10 @@ const ExtensionsView = (() => {
|
|
|
350
366
|
? `<span class="extension-installed">${installedLabel}</span>` : "";
|
|
351
367
|
const unlistedHtml = ext.unlisted
|
|
352
368
|
? `<span class="extension-unlisted">${escapeHtml(I18n.t("extensions.unlisted"))}</span>` : "";
|
|
369
|
+
const verifiedHtml = ext.verified
|
|
370
|
+
? `<span class="extension-verified">${escapeHtml(I18n.t("extensions.verified"))}</span>` : "";
|
|
371
|
+
const unverifiedBannerHtml = (!ext.verified && !ext.installed && !(typeof Brand !== "undefined" && Brand.branded))
|
|
372
|
+
? `<div class="extension-unverified-banner"><svg class="extension-unverified-icon" width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg"><circle cx="7" cy="7" r="6.25" stroke="currentColor" stroke-width="1.2"/><path d="M7 4V7.5" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/><circle cx="7" cy="10" r="0.7" fill="currentColor"/></svg>${escapeHtml(I18n.t("extensions.unverifiedBanner"))}</div>` : "";
|
|
353
373
|
const unitsText = _formatUnits(ext.units);
|
|
354
374
|
const unitsHtml = unitsText
|
|
355
375
|
? `<span class="extension-units">${escapeHtml(unitsText)}</span>` : "";
|
|
@@ -370,12 +390,14 @@ const ExtensionsView = (() => {
|
|
|
370
390
|
${versionHtml}
|
|
371
391
|
${installedHtml}
|
|
372
392
|
${unlistedHtml}
|
|
393
|
+
${verifiedHtml}
|
|
373
394
|
${unitsHtml}
|
|
374
395
|
${authorHtml}
|
|
375
396
|
${installsHtml}
|
|
376
397
|
</div>
|
|
377
398
|
${description ? `<div class="extension-desc extension-desc-detail">${escapeHtml(description)}</div>` : ""}
|
|
378
399
|
${homepageHtml ? `<div class="extension-meta">${homepageHtml}</div>` : ""}
|
|
400
|
+
${unverifiedBannerHtml}
|
|
379
401
|
${_renderActions(ext)}
|
|
380
402
|
</div>
|
|
381
403
|
</div>
|
|
@@ -584,6 +606,7 @@ const ExtensionsView = (() => {
|
|
|
584
606
|
if (e.target.closest("a")) return;
|
|
585
607
|
const card = e.target.closest(".extension-card-clickable");
|
|
586
608
|
if (card && card.dataset.extId) {
|
|
609
|
+
_saveCurrentTab();
|
|
587
610
|
const router = window.Clacky && window.Clacky.Router;
|
|
588
611
|
// Use origin stored on the card; origin="self" means brand-private extension.
|
|
589
612
|
const isBrand = card.dataset.extOrigin === "self" || Extensions.state.filterBrand;
|
|
@@ -620,6 +620,27 @@ const NewSessionView = (() => {
|
|
|
620
620
|
_renderContextBar();
|
|
621
621
|
});
|
|
622
622
|
pop.appendChild(clearItem);
|
|
623
|
+
|
|
624
|
+
// "Create new project" action
|
|
625
|
+
const actionSep = document.createElement("div");
|
|
626
|
+
actionSep.style.cssText = "height:1px;background:var(--color-border-primary);margin:4px 8px";
|
|
627
|
+
pop.appendChild(actionSep);
|
|
628
|
+
const createItem = document.createElement("button");
|
|
629
|
+
createItem.type = "button";
|
|
630
|
+
createItem.className = "ns-ctx-popover-item";
|
|
631
|
+
createItem.style.cssText = "display:flex;align-items:center;gap:6px";
|
|
632
|
+
const plusIcon = '<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="flex-shrink:0"><path d="M12 5v14M5 12h14"/></svg>';
|
|
633
|
+
createItem.innerHTML = plusIcon + `<span>${zh ? "新建项目" : "New project"}</span>`;
|
|
634
|
+
createItem.addEventListener("click", async () => {
|
|
635
|
+
_dismissCtxPopover();
|
|
636
|
+
const project = await Projects.promptCreate();
|
|
637
|
+
if (project) {
|
|
638
|
+
const dir = project.working_dir || NewSessionStore.state.defaultDir || "";
|
|
639
|
+
NewSessionStore.updateAdvanced({ projectId: project.id, workingDir: dir });
|
|
640
|
+
_renderContextBar();
|
|
641
|
+
}
|
|
642
|
+
});
|
|
643
|
+
pop.appendChild(createItem);
|
|
623
644
|
});
|
|
624
645
|
}
|
|
625
646
|
|
|
@@ -786,6 +807,9 @@ const NewSessionView = (() => {
|
|
|
786
807
|
const display = hasFiles ? _buildBubbleHtml(finalContent) : null;
|
|
787
808
|
|
|
788
809
|
Sessions.add(session);
|
|
810
|
+
if (session.project_id && typeof Projects !== "undefined" && Projects.expand) {
|
|
811
|
+
Projects.expand(session.project_id);
|
|
812
|
+
}
|
|
789
813
|
Sessions.setPendingMessage(session.id, finalContent, display, files);
|
|
790
814
|
input.value = "";
|
|
791
815
|
_pendingImages.length = 0;
|
data/lib/clacky/web/i18n.js
CHANGED
|
@@ -40,26 +40,26 @@ const I18n = (() => {
|
|
|
40
40
|
"projects.create.dirPlaceholder": "Working directory (optional)",
|
|
41
41
|
"projects.create.sourceFolders": "Source folders",
|
|
42
42
|
"projects.create.folderHint": "Add a working folder",
|
|
43
|
+
"projects.create.folderDefaultHint": "If not set, the default working directory ~/clacky_workspace will be used",
|
|
43
44
|
"projects.create.submit": "Create Project",
|
|
44
45
|
"projects.create.colorLabel": "Color",
|
|
45
46
|
"projects.create.iconLabel": "Icon",
|
|
46
47
|
"projects.picker.done": "Done",
|
|
47
48
|
"projects.emptyHint": "No projects yet",
|
|
48
49
|
"projects.noSessions": "No sessions",
|
|
49
|
-
"projects.tooltip.sessions": "{n} sessions",
|
|
50
50
|
"projects.organize.grouped": "By Project",
|
|
51
51
|
"projects.organize.flat": "In a flat list",
|
|
52
52
|
"projects.organize.sortLabel": "Sort by",
|
|
53
53
|
"projects.organize.sortPriority": "Priority",
|
|
54
54
|
"projects.organize.sortRecent": "Last updated",
|
|
55
55
|
"projects.menu.rename": "Rename",
|
|
56
|
-
"projects.menu.edit": "Edit",
|
|
57
|
-
"projects.menu.delete": "Delete",
|
|
58
|
-
"projects.menu.deleteSessions": "
|
|
56
|
+
"projects.menu.edit": "Edit Project",
|
|
57
|
+
"projects.menu.delete": "Delete Project",
|
|
58
|
+
"projects.menu.deleteSessions": "Clear Sessions",
|
|
59
59
|
"projects.edit.title": "Edit Project",
|
|
60
60
|
"projects.edit.submit": "Save",
|
|
61
61
|
"projects.delete.confirm": "Delete project \"{{name}}\"? All sessions in this project will also be deleted.",
|
|
62
|
-
"projects.deleteSessions.confirm": "
|
|
62
|
+
"projects.deleteSessions.confirm": "Clear all sessions in project \"{{name}}\"? The project itself will be kept.",
|
|
63
63
|
"projects.modal.name": "Project Name",
|
|
64
64
|
|
|
65
65
|
// ── Welcome screen ──
|
|
@@ -575,6 +575,10 @@ const I18n = (() => {
|
|
|
575
575
|
"extensions.homepage": "Homepage",
|
|
576
576
|
"extensions.by": "by ",
|
|
577
577
|
"extensions.installs": "installs",
|
|
578
|
+
"extensions.verified": "Verified",
|
|
579
|
+
"extensions.unverified": "Unverified",
|
|
580
|
+
"extensions.unverifiedBanner": "This extension has not been verified by the platform. It may contain un-reviewed code or behaviors. Install at your own risk.",
|
|
581
|
+
"extensions.unverifiedInstallWarning": "This extension has not been verified by the platform. It may contain un-reviewed code or behaviors. Install anyway?",
|
|
578
582
|
"extensions.installed": "Installed",
|
|
579
583
|
"extensions.updatable": "Update available",
|
|
580
584
|
"extensions.unlisted": "Unlisted",
|
|
@@ -1064,9 +1068,6 @@ const I18n = (() => {
|
|
|
1064
1068
|
"billing.period.month": "This Month",
|
|
1065
1069
|
"billing.period.year": "This Year",
|
|
1066
1070
|
"billing.period.all": "All Time",
|
|
1067
|
-
"billing.clearData": "Clear Data",
|
|
1068
|
-
"billing.clearToday": "Clear Today",
|
|
1069
|
-
"billing.clearAll": "Clear All",
|
|
1070
1071
|
"billing.allModels": "All Models",
|
|
1071
1072
|
"billing.cacheHit": "Cache Hit",
|
|
1072
1073
|
"billing.inputCacheHit": "Input (Cache Hit)",
|
|
@@ -1090,7 +1091,7 @@ const I18n = (() => {
|
|
|
1090
1091
|
"billing.headerHit": "Hit",
|
|
1091
1092
|
"billing.headerMiss": "Miss",
|
|
1092
1093
|
"billing.headerOutput": "Output",
|
|
1093
|
-
"billing.disclaimer": "Costs are estimated based on token usage and may differ from your provider's actual bill.",
|
|
1094
|
+
"billing.disclaimer": "Costs are estimated based on token usage and may differ from your provider's actual bill. If you notice discrepancies, please check your provider's billing dashboard.",
|
|
1094
1095
|
},
|
|
1095
1096
|
zh: {
|
|
1096
1097
|
// ── Phases ──
|
|
@@ -1119,26 +1120,26 @@ const I18n = (() => {
|
|
|
1119
1120
|
"projects.create.placeholder": "项目名称",
|
|
1120
1121
|
"projects.create.sourceFolders": "工作目录",
|
|
1121
1122
|
"projects.create.folderHint": "添加工作文件夹",
|
|
1123
|
+
"projects.create.folderDefaultHint": "不设置时将使用默认工作目录 ~/clacky_workspace",
|
|
1122
1124
|
"projects.create.submit": "创建项目",
|
|
1123
1125
|
"projects.create.colorLabel": "颜色",
|
|
1124
1126
|
"projects.create.iconLabel": "图标",
|
|
1125
1127
|
"projects.picker.done": "完成",
|
|
1126
1128
|
"projects.emptyHint": "暂无项目",
|
|
1127
1129
|
"projects.noSessions": "暂无会话",
|
|
1128
|
-
"projects.tooltip.sessions": "{n} 个会话",
|
|
1129
1130
|
"projects.organize.grouped": "按项目分组",
|
|
1130
1131
|
"projects.organize.flat": "在一个列表中",
|
|
1131
1132
|
"projects.organize.sortLabel": "排序方式",
|
|
1132
1133
|
"projects.organize.sortPriority": "优先级",
|
|
1133
1134
|
"projects.organize.sortRecent": "最近更新",
|
|
1134
1135
|
"projects.menu.rename": "重命名",
|
|
1135
|
-
"projects.menu.edit": "
|
|
1136
|
-
"projects.menu.delete": "
|
|
1137
|
-
"projects.menu.deleteSessions": "
|
|
1136
|
+
"projects.menu.edit": "编辑项目",
|
|
1137
|
+
"projects.menu.delete": "删除项目",
|
|
1138
|
+
"projects.menu.deleteSessions": "清空会话",
|
|
1138
1139
|
"projects.edit.title": "编辑项目",
|
|
1139
1140
|
"projects.edit.submit": "保存",
|
|
1140
1141
|
"projects.delete.confirm": "删除项目「{{name}}」?该项目下的所有会话也将被删除。",
|
|
1141
|
-
"projects.deleteSessions.confirm": "
|
|
1142
|
+
"projects.deleteSessions.confirm": "清空项目「{{name}}」下的所有会话?项目本身会被保留。",
|
|
1142
1143
|
"projects.modal.name": "项目名称",
|
|
1143
1144
|
|
|
1144
1145
|
// ── Welcome screen ──
|
|
@@ -1651,6 +1652,10 @@ const I18n = (() => {
|
|
|
1651
1652
|
"extensions.homepage": "主页",
|
|
1652
1653
|
"extensions.by": "作者:",
|
|
1653
1654
|
"extensions.installs": "次安装",
|
|
1655
|
+
"extensions.verified": "已验证",
|
|
1656
|
+
"extensions.unverified": "未验证",
|
|
1657
|
+
"extensions.unverifiedBanner": "此扩展尚未通过平台审核验证,可能包含未经审查的代码或行为,建议谨慎安装。",
|
|
1658
|
+
"extensions.unverifiedInstallWarning": "此扩展尚未通过平台审核验证,可能包含未经审查的代码或行为。确定安装?",
|
|
1654
1659
|
"extensions.installed": "已安装",
|
|
1655
1660
|
"extensions.updatable": "有更新",
|
|
1656
1661
|
"extensions.unlisted": "已下架",
|
|
@@ -2147,9 +2152,6 @@ const I18n = (() => {
|
|
|
2147
2152
|
"billing.period.month": "本月",
|
|
2148
2153
|
"billing.period.year": "今年",
|
|
2149
2154
|
"billing.period.all": "全部",
|
|
2150
|
-
"billing.clearData": "清除数据",
|
|
2151
|
-
"billing.clearToday": "清除今日",
|
|
2152
|
-
"billing.clearAll": "全部清除",
|
|
2153
2155
|
"billing.allModels": "所有模型",
|
|
2154
2156
|
"billing.cacheHit": "缓存命中",
|
|
2155
2157
|
"billing.inputCacheHit": "输入(命中缓存)",
|
|
@@ -2173,7 +2175,7 @@ const I18n = (() => {
|
|
|
2173
2175
|
"billing.headerHit": "命中",
|
|
2174
2176
|
"billing.headerMiss": "未命中",
|
|
2175
2177
|
"billing.headerOutput": "输出",
|
|
2176
|
-
"billing.disclaimer": "费用为估算值,基于 Token 用量和模型定价计算,可能与 API
|
|
2178
|
+
"billing.disclaimer": "费用为估算值,基于 Token 用量和模型定价计算,可能与 API 提供商实际账单有所差异。如有异常,请前往 API 提供商查看实际账单。",
|
|
2177
2179
|
}
|
|
2178
2180
|
};
|
|
2179
2181
|
// ── State ──────────────────────────────────────────────────────────────────
|
data/lib/clacky/web/index.html
CHANGED
|
@@ -126,7 +126,7 @@
|
|
|
126
126
|
<span class="chat-section-title">
|
|
127
127
|
<span data-i18n="sidebar.chat">Sessions</span>
|
|
128
128
|
<!-- Chevron: hidden by default, shown on hover or when collapsed -->
|
|
129
|
-
<svg class="chat-section-chevron" width="
|
|
129
|
+
<svg class="chat-section-chevron" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg">
|
|
130
130
|
<path d="M6 9l6 6 6-6"/>
|
|
131
131
|
</svg>
|
|
132
132
|
</span>
|
|
@@ -177,7 +177,7 @@
|
|
|
177
177
|
<div class="sidebar-divider" id="projects-section-header">
|
|
178
178
|
<span class="projects-section-title">
|
|
179
179
|
<span data-i18n="sidebar.projects">Projects</span>
|
|
180
|
-
<svg class="projects-section-chevron" width="
|
|
180
|
+
<svg class="projects-section-chevron" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
|
181
181
|
<path d="M6 9l6 6 6-6"/>
|
|
182
182
|
</svg>
|
|
183
183
|
</span>
|
|
@@ -219,7 +219,7 @@
|
|
|
219
219
|
<div id="skills-sidebar-item" class="task-item task-item-summary">
|
|
220
220
|
<div class="task-row">
|
|
221
221
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="task-icon">
|
|
222
|
-
<path d="
|
|
222
|
+
<path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.106-3.105c.32-.322.863-.22.983.218a6 6 0 0 1-8.259 7.057l-7.91 7.91a1 1 0 0 1-2.999-3l7.91-7.91a6 6 0 0 1 7.057-8.259c.438.12.54.662.219.984z"/>
|
|
223
223
|
</svg>
|
|
224
224
|
<div class="task-info">
|
|
225
225
|
<span class="task-name" id="skills-sidebar-label" data-i18n="sidebar.skills">Skill Management</span>
|
|
@@ -229,8 +229,7 @@
|
|
|
229
229
|
<div id="extensions-sidebar-item" class="task-item task-item-summary">
|
|
230
230
|
<div class="task-row">
|
|
231
231
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="task-icon">
|
|
232
|
-
<path d="
|
|
233
|
-
<circle cx="17" cy="17" r="3"/><circle cx="7" cy="7" r="3"/>
|
|
232
|
+
<path d="M19.439 7.85c-.049.322.059.648.289.878l1.568 1.568c.47.47.706 1.087.706 1.704s-.235 1.233-.706 1.704l-1.611 1.611a.98.98 0 0 1-.837.276c-.47-.07-.802-.48-.968-.925a2.501 2.501 0 1 0-3.214 3.214c.446.166.855.497.925.968a.979.979 0 0 1-.276.837l-1.61 1.61a2.404 2.404 0 0 1-1.705.707 2.402 2.402 0 0 1-1.704-.706l-1.568-1.568a1.026 1.026 0 0 0-.877-.29c-.493.074-.84.504-1.02.968a2.5 2.5 0 1 1-3.237-3.237c.464-.18.894-.527.967-1.02a1.026 1.026 0 0 0-.289-.877l-1.568-1.568A2.402 2.402 0 0 1 1.998 12c0-.617.236-1.234.706-1.704L4.23 8.77c.24-.24.581-.353.917-.303.515.077.877.528 1.073 1.01a2.5 2.5 0 1 0 3.259-3.259c-.482-.196-.933-.558-1.01-1.073-.05-.336.062-.676.303-.917l1.525-1.525A2.402 2.402 0 0 1 12 1.998c.617 0 1.234.236 1.704.706l1.568 1.568c.23.23.556.338.877.29.493-.074.84-.504 1.02-.968a2.5 2.5 0 1 1 3.237 3.237c-.464.18-.894.527-.967 1.02Z"/>
|
|
234
233
|
</svg>
|
|
235
234
|
<div class="task-info">
|
|
236
235
|
<span class="task-name" id="extensions-sidebar-label" data-i18n="sidebar.extensions">Extension Management</span>
|
|
@@ -240,7 +239,7 @@
|
|
|
240
239
|
<div id="channels-sidebar-item" class="task-item task-item-summary">
|
|
241
240
|
<div class="task-row">
|
|
242
241
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="task-icon">
|
|
243
|
-
<rect x="
|
|
242
|
+
<rect x="4" y="2" width="16" height="20" rx="2"/>
|
|
244
243
|
<path d="M12 18h.01"/>
|
|
245
244
|
</svg>
|
|
246
245
|
<div class="task-info">
|
|
@@ -270,8 +269,9 @@
|
|
|
270
269
|
<div id="profile-sidebar-item" class="task-item task-item-summary">
|
|
271
270
|
<div class="task-row">
|
|
272
271
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="task-icon">
|
|
273
|
-
<path d="
|
|
274
|
-
<
|
|
272
|
+
<path d="M2 21a8 8 0 0 1 10.821-7.487"/>
|
|
273
|
+
<path d="M21.378 16.626a1 1 0 0 0-3.004-3.004l-4.01 4.012a2 2 0 0 0-.506.854l-.837 2.87a.5.5 0 0 0 .62.62l2.87-.837a2 2 0 0 0 .854-.506z"/>
|
|
274
|
+
<circle cx="10" cy="8" r="5"/>
|
|
275
275
|
</svg>
|
|
276
276
|
<div class="task-info">
|
|
277
277
|
<span class="task-name" id="profile-sidebar-label" data-i18n="sidebar.profile">Profile & Soul</span>
|
|
@@ -286,10 +286,9 @@
|
|
|
286
286
|
<div id="trash-sidebar-item" class="task-item task-item-summary">
|
|
287
287
|
<div class="task-row">
|
|
288
288
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="task-icon">
|
|
289
|
-
<
|
|
290
|
-
<path d="
|
|
291
|
-
<path d="M10
|
|
292
|
-
<path d="M9 6V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2"/>
|
|
289
|
+
<rect x="2" y="3" width="20" height="5" rx="1"/>
|
|
290
|
+
<path d="M4 8v11a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8"/>
|
|
291
|
+
<path d="M10 12h4"/>
|
|
293
292
|
</svg>
|
|
294
293
|
<div class="task-info">
|
|
295
294
|
<span class="task-name" id="trash-sidebar-label" data-i18n="sidebar.trash">File Recall</span>
|
|
@@ -299,7 +298,7 @@
|
|
|
299
298
|
<div id="billing-sidebar-item" class="task-item task-item-summary">
|
|
300
299
|
<div class="task-row">
|
|
301
300
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="task-icon">
|
|
302
|
-
<line x1="12"
|
|
301
|
+
<line x1="12" x2="12" y1="2" y2="22"/>
|
|
303
302
|
<path d="M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"/>
|
|
304
303
|
</svg>
|
|
305
304
|
<div class="task-info">
|