openclacky 1.3.6 → 1.3.7
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.rb +8 -1
- data/lib/clacky/agent_profile.rb +121 -53
- data/lib/clacky/brand_config.rb +309 -6
- data/lib/clacky/cli.rb +4 -57
- data/lib/clacky/default_extensions/coding/ext.yml +18 -0
- data/lib/clacky/default_extensions/ext-studio/agents/ext-developer/system_prompt.md +95 -0
- data/lib/clacky/default_extensions/ext-studio/api/handler.rb +254 -0
- data/lib/clacky/default_extensions/ext-studio/ext.yml +32 -0
- data/lib/clacky/default_extensions/ext-studio/panels/studio/view.js +1269 -0
- data/lib/clacky/default_extensions/ext-studio/skills/ext-debug/SKILL.md +71 -0
- data/lib/clacky/default_extensions/ext-studio/skills/ext-publish/SKILL.md +74 -0
- data/lib/clacky/default_extensions/ext-studio/skills/ext-scaffold/SKILL.md +65 -0
- data/lib/clacky/default_extensions/general/ext.yml +18 -0
- data/lib/clacky/default_extensions/git/ext.yml +12 -0
- data/lib/clacky/{default_agents/_panels/git/panel.js → default_extensions/git/panels/git/view.js} +1 -2
- data/lib/clacky/default_extensions/meeting/{handler.rb → api/handler.rb} +78 -26
- data/lib/clacky/default_extensions/meeting/ext.yml +15 -0
- data/lib/clacky/default_extensions/meeting/{meeting.js → panels/meeting/view.js} +266 -89
- data/lib/clacky/default_extensions/meeting/skills/meeting-summarizer/SKILL.md +2 -1
- data/lib/clacky/default_extensions/time_machine/ext.yml +12 -0
- data/lib/clacky/{default_agents/_panels/time_machine/panel.js → default_extensions/time_machine/panels/time_machine/view.js} +58 -47
- data/lib/clacky/default_skills/channel-manager/discord_setup.rb +1 -1
- data/lib/clacky/default_skills/extend-openclacky/SKILL.md +83 -18
- data/lib/clacky/{api_extension.rb → extension/api_extension.rb} +27 -11
- data/lib/clacky/extension/api_loader.rb +136 -0
- data/lib/clacky/extension/cli_commands.rb +226 -0
- data/lib/clacky/{server/api_extension_dispatcher.rb → extension/dispatcher.rb} +22 -9
- data/lib/clacky/extension/hook_loader.rb +77 -0
- data/lib/clacky/extension/loader.rb +483 -0
- data/lib/clacky/extension/packager.rb +226 -0
- data/lib/clacky/{patch_loader.rb → extension/patch_loader.rb} +45 -0
- data/lib/clacky/extension/scaffold/template_renderer.rb +64 -0
- data/lib/clacky/extension/scaffold/templates/full/README.md.erb +48 -0
- data/lib/clacky/extension/scaffold/templates/full/agents/designer.md +5 -0
- data/lib/clacky/extension/scaffold/templates/full/api/handler.rb.erb +16 -0
- data/lib/clacky/extension/scaffold/templates/full/channels/noop.rb.erb +40 -0
- data/lib/clacky/extension/scaffold/templates/full/ext.yml.erb +41 -0
- data/lib/clacky/extension/scaffold/templates/full/hooks/audit.rb +9 -0
- data/lib/clacky/extension/scaffold/templates/full/panels/dashboard/view.js.erb +194 -0
- data/lib/clacky/extension/scaffold/templates/full/patches/audit.rb +15 -0
- data/lib/clacky/extension/scaffold/templates/full/skills/__slug__-skill/SKILL.md.erb +8 -0
- data/lib/clacky/extension/scaffold/templates/hello/api/handler.rb.erb +9 -0
- data/lib/clacky/extension/scaffold/templates/hello/ext.yml.erb +12 -0
- data/lib/clacky/extension/scaffold/templates/hello/panels/hello/view.js.erb +31 -0
- data/lib/clacky/extension/scaffold.rb +55 -0
- data/lib/clacky/extension/verifier.rb +196 -0
- data/lib/clacky/identity.rb +70 -0
- data/lib/clacky/locales/en.rb +19 -1
- data/lib/clacky/locales/zh.rb +19 -1
- data/lib/clacky/platform_http_client.rb +18 -15
- data/lib/clacky/server/channel/extension_adapter_loader.rb +32 -0
- data/lib/clacky/server/channel.rb +6 -0
- data/lib/clacky/server/http_server.rb +313 -144
- data/lib/clacky/server/session_registry.rb +9 -2
- data/lib/clacky/skill_loader.rb +28 -1
- data/lib/clacky/ui2/ui_controller.rb +9 -6
- data/lib/clacky/version.rb +1 -1
- data/lib/clacky/web/app.css +748 -573
- data/lib/clacky/web/app.js +63 -15
- data/lib/clacky/web/auth.js +2 -0
- data/lib/clacky/web/components/notify.js +2 -0
- data/lib/clacky/web/components/sidebar.js +1 -5
- data/lib/clacky/web/core/ext.js +316 -79
- data/lib/clacky/web/features/backup/store.js +1 -0
- data/lib/clacky/web/features/backup/view.js +0 -1
- data/lib/clacky/web/features/brand/view.js +13 -5
- data/lib/clacky/web/features/extensions/store.js +184 -0
- data/lib/clacky/web/features/extensions/view.js +389 -0
- data/lib/clacky/web/features/new-session/store.js +186 -0
- data/lib/clacky/web/features/new-session/view.js +319 -0
- data/lib/clacky/web/features/share/view.js +63 -14
- data/lib/clacky/web/features/skills/store.js +3 -1
- data/lib/clacky/web/features/skills/view.js +1 -1
- data/lib/clacky/web/features/tasks/view.js +12 -0
- data/lib/clacky/web/features/trash/store.js +24 -6
- data/lib/clacky/web/features/trash/view.js +46 -9
- data/lib/clacky/web/features/workspace/store.js +2 -0
- data/lib/clacky/web/features/workspace/view.js +0 -1
- data/lib/clacky/web/i18n.js +118 -106
- data/lib/clacky/web/index.html +138 -188
- data/lib/clacky/web/sessions.js +64 -269
- data/lib/clacky/web/settings.js +1 -1
- data/lib/clacky/web/skills.js +2 -0
- data/lib/clacky/web/theme.js +2 -0
- data/lib/clacky/web/ws-dispatcher.js +1 -0
- data/lib/clacky/web/ws.js +2 -0
- data/lib/clacky.rb +21 -10
- metadata +55 -24
- data/benchmark/runner.rb +0 -441
- data/lib/clacky/api_extension_loader.rb +0 -168
- data/lib/clacky/default_agents/SOUL.md +0 -3
- data/lib/clacky/default_agents/USER.md +0 -1
- data/lib/clacky/default_agents/coding/profile.yml +0 -5
- data/lib/clacky/default_agents/coding/webui/.gitkeep +0 -0
- data/lib/clacky/default_agents/general/profile.yml +0 -2
- data/lib/clacky/default_extensions/meeting/meta.yml +0 -3
- data/lib/clacky/web/features/creator/store.js +0 -81
- data/lib/clacky/web/features/creator/view.js +0 -380
- /data/lib/clacky/{default_agents → default_extensions/coding/agents}/coding/system_prompt.md +0 -0
- /data/lib/clacky/{default_agents → default_extensions/general/agents}/general/system_prompt.md +0 -0
- /data/lib/clacky/{default_agents/base_prompt.md → prompts/base.md} +0 -0
|
@@ -76,6 +76,12 @@ const TasksView = (() => {
|
|
|
76
76
|
return isZh ? `每 ${hour.slice(2)} 小时` : `Every ${hour.slice(2)} hr`;
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
|
+
// ── every-N-hours on specific days e.g. 0 */3 * * 1-5 ────────────
|
|
80
|
+
if (isAny(dom) && isAny(month) && !isAny(dow) && hour.startsWith("*/")) {
|
|
81
|
+
const dl = dowLabel(dow);
|
|
82
|
+
const ev = isZh ? `每 ${hour.slice(2)} 小时` : `Every ${hour.slice(2)} hr`;
|
|
83
|
+
if (dl) return `${dl} ${ev}`;
|
|
84
|
+
}
|
|
79
85
|
// ── every minute ──────────────────────────────────────────────────────
|
|
80
86
|
if (isAny(min) && isAny(hour) && isAny(dom) && isAny(month) && isAny(dow)) {
|
|
81
87
|
return isZh ? "每分钟" : "Every minute";
|
|
@@ -84,6 +90,12 @@ const TasksView = (() => {
|
|
|
84
90
|
if (isInt(min) && isAny(hour) && isAny(dom) && isAny(month) && isAny(dow)) {
|
|
85
91
|
return isZh ? `每小时 :${pad(min)}` : `Hourly at :${pad(min)}`;
|
|
86
92
|
}
|
|
93
|
+
// ── hourly at :MM on specific days e.g. 30 * * * 1-5 ─────────────
|
|
94
|
+
if (isInt(min) && isAny(hour) && isAny(dom) && isAny(month) && !isAny(dow)) {
|
|
95
|
+
const dl = dowLabel(dow);
|
|
96
|
+
const tm = isZh ? `每小时 :${pad(min)}` : `Hourly at :${pad(min)}`;
|
|
97
|
+
if (dl) return `${dl} ${tm}`;
|
|
98
|
+
}
|
|
87
99
|
|
|
88
100
|
// ── every-N-min within hour range on certain days e.g. */1 9-14 * * 1-5
|
|
89
101
|
if (min.startsWith("*/") && /^\d+-\d+$/.test(hour) && isAny(dom) && isAny(month)) {
|
|
@@ -13,10 +13,13 @@
|
|
|
13
13
|
// ───────────────────────────────────────────────────────────────────────────
|
|
14
14
|
|
|
15
15
|
const TrashStore = (() => {
|
|
16
|
+
const SOURCES = Object.freeze({ ALL: "all", CRON: "cron", MANUAL: "manual" });
|
|
17
|
+
|
|
16
18
|
let _files = [];
|
|
17
19
|
let _totals = { count: 0, size: 0 };
|
|
18
20
|
let _sessions = [];
|
|
19
21
|
let _sessionTotals = { count: 0, size: 0 };
|
|
22
|
+
let _filterSource = SOURCES.ALL;
|
|
20
23
|
let _loading = false;
|
|
21
24
|
|
|
22
25
|
const _listeners = {};
|
|
@@ -44,8 +47,20 @@ const TrashStore = (() => {
|
|
|
44
47
|
const state = {
|
|
45
48
|
get files() { return _files; },
|
|
46
49
|
get totals() { return _totals; },
|
|
47
|
-
get sessions() {
|
|
48
|
-
|
|
50
|
+
get sessions() {
|
|
51
|
+
if (_filterSource === SOURCES.ALL) return _sessions;
|
|
52
|
+
return _filterSource === SOURCES.CRON
|
|
53
|
+
? _sessions.filter(s => s.source === SOURCES.CRON)
|
|
54
|
+
: _sessions.filter(s => s.source !== SOURCES.CRON);
|
|
55
|
+
},
|
|
56
|
+
get sessionTotals() {
|
|
57
|
+
const filtered = _filterSource === SOURCES.ALL ? _sessions
|
|
58
|
+
: _filterSource === SOURCES.CRON
|
|
59
|
+
? _sessions.filter(s => s.source === SOURCES.CRON)
|
|
60
|
+
: _sessions.filter(s => s.source !== SOURCES.CRON);
|
|
61
|
+
return { count: filtered.length, size: filtered.reduce((sum, s) => sum + (s.file_size || 0), 0) };
|
|
62
|
+
},
|
|
63
|
+
get filterSource() { return _filterSource; },
|
|
49
64
|
orphanCount() { return _files.filter(f => _isOrphanRoot(f.project_root)).length; },
|
|
50
65
|
isOrphan(file) { return _isOrphanRoot(file.project_root); },
|
|
51
66
|
};
|
|
@@ -53,6 +68,13 @@ const TrashStore = (() => {
|
|
|
53
68
|
const Trash = {
|
|
54
69
|
on: _on,
|
|
55
70
|
state,
|
|
71
|
+
SOURCES,
|
|
72
|
+
|
|
73
|
+
setFilterSource(source) {
|
|
74
|
+
if (source === _filterSource) return;
|
|
75
|
+
_filterSource = source;
|
|
76
|
+
_emit("trash:sessionsChanged");
|
|
77
|
+
},
|
|
56
78
|
|
|
57
79
|
async loadFiles() {
|
|
58
80
|
if (_loading) return;
|
|
@@ -230,10 +252,6 @@ const TrashStore = (() => {
|
|
|
230
252
|
|
|
231
253
|
function _removeSessionLocal(session) {
|
|
232
254
|
_sessions = _sessions.filter(s => s.session_id !== session.session_id);
|
|
233
|
-
_sessionTotals = {
|
|
234
|
-
count: Math.max(0, _sessionTotals.count - 1),
|
|
235
|
-
size: Math.max(0, _sessionTotals.size - (session.file_size || 0))
|
|
236
|
-
};
|
|
237
255
|
}
|
|
238
256
|
|
|
239
257
|
return Trash;
|
|
@@ -61,8 +61,13 @@ const TrashView = (() => {
|
|
|
61
61
|
|
|
62
62
|
const filePane = $("trash-tab-file");
|
|
63
63
|
const sessionPane = $("trash-tab-session");
|
|
64
|
+
const filterBar = $("trash-filter-bar");
|
|
64
65
|
if (filePane) filePane.style.display = tab === "file-trash" ? "" : "none";
|
|
65
66
|
if (sessionPane) sessionPane.style.display = tab === "session-trash" ? "" : "none";
|
|
67
|
+
if (filterBar) filterBar.style.display = tab === "session-trash" ? "" : "none";
|
|
68
|
+
|
|
69
|
+
const hint = $("trash-session-hint");
|
|
70
|
+
if (hint) hint.style.display = tab === "session-trash" ? "" : "none";
|
|
66
71
|
|
|
67
72
|
const btnOrphans = $("btn-trash-empty-orphans");
|
|
68
73
|
if (btnOrphans) btnOrphans.style.display = tab === "file-trash" ? "" : "none";
|
|
@@ -73,7 +78,7 @@ const TrashView = (() => {
|
|
|
73
78
|
function _load() {
|
|
74
79
|
if (_activeTab === "file-trash") {
|
|
75
80
|
const list = $("trash-list");
|
|
76
|
-
if (list) list.innerHTML = `<div class="
|
|
81
|
+
if (list) list.innerHTML = `<div class="trash-loading">${_t("trash.loading")}</div>`;
|
|
77
82
|
Trash.loadFiles();
|
|
78
83
|
} else {
|
|
79
84
|
const list = $("trash-session-list");
|
|
@@ -109,7 +114,7 @@ const TrashView = (() => {
|
|
|
109
114
|
if (btnAll) btnAll.disabled = files.length === 0;
|
|
110
115
|
|
|
111
116
|
if (files.length === 0) {
|
|
112
|
-
list.innerHTML = `<div class="
|
|
117
|
+
list.innerHTML = `<div class="trash-empty">${_t("trash.empty")}</div>`;
|
|
113
118
|
return;
|
|
114
119
|
}
|
|
115
120
|
|
|
@@ -176,11 +181,33 @@ const TrashView = (() => {
|
|
|
176
181
|
|
|
177
182
|
// ── Session trash rendering ──────────────────────────────────────────
|
|
178
183
|
|
|
184
|
+
function _renderSkeleton() {
|
|
185
|
+
const list = $("trash-session-list");
|
|
186
|
+
if (!list) return;
|
|
187
|
+
let html = "";
|
|
188
|
+
for (let i = 0; i < 3; i++) {
|
|
189
|
+
html += `
|
|
190
|
+
<div class="trash-session-skeleton">
|
|
191
|
+
<div class="trash-session-skeleton-info">
|
|
192
|
+
<div class="skel skel-title"></div>
|
|
193
|
+
<div class="skel skel-subtitle"></div>
|
|
194
|
+
<div class="skel skel-text-sm"></div>
|
|
195
|
+
</div>
|
|
196
|
+
<div class="trash-skeleton-actions">
|
|
197
|
+
<div class="skel trash-skeleton-btn"></div>
|
|
198
|
+
<div class="skel trash-skeleton-btn"></div>
|
|
199
|
+
</div>
|
|
200
|
+
</div>`;
|
|
201
|
+
}
|
|
202
|
+
list.innerHTML = html;
|
|
203
|
+
}
|
|
204
|
+
|
|
179
205
|
function _renderSessions() {
|
|
180
|
-
const list
|
|
181
|
-
const summary
|
|
182
|
-
const btnOld
|
|
183
|
-
const btnAll
|
|
206
|
+
const list = $("trash-session-list");
|
|
207
|
+
const summary = $("trash-summary");
|
|
208
|
+
const btnOld = $("btn-trash-empty-old");
|
|
209
|
+
const btnAll = $("btn-trash-empty-all");
|
|
210
|
+
const filterBar = $("trash-filter-bar");
|
|
184
211
|
if (!list) return;
|
|
185
212
|
|
|
186
213
|
const sessions = Trash.state.sessions;
|
|
@@ -196,9 +223,10 @@ const TrashView = (() => {
|
|
|
196
223
|
}
|
|
197
224
|
if (btnOld) btnOld.disabled = sessions.length === 0;
|
|
198
225
|
if (btnAll) btnAll.disabled = sessions.length === 0;
|
|
226
|
+
if (filterBar) filterBar.style.display = "";
|
|
199
227
|
|
|
200
228
|
if (sessions.length === 0) {
|
|
201
|
-
list.innerHTML = `<div class="
|
|
229
|
+
list.innerHTML = `<div class="trash-empty">${_t("trash.noSessionTrash")}</div>`;
|
|
202
230
|
return;
|
|
203
231
|
}
|
|
204
232
|
|
|
@@ -385,6 +413,15 @@ const TrashView = (() => {
|
|
|
385
413
|
if (btnAll) btnAll.addEventListener("click",
|
|
386
414
|
() => _emptyBulk(0, _activeTab === "session-trash"
|
|
387
415
|
? "trash.confirmEmptySessionAll" : "trash.confirmEmptyAll"));
|
|
416
|
+
|
|
417
|
+
// Filter chips
|
|
418
|
+
document.querySelectorAll(".trash-filter-chip").forEach(chip => {
|
|
419
|
+
chip.addEventListener("click", () => {
|
|
420
|
+
const val = chip.dataset.filter;
|
|
421
|
+
Trash.setFilterSource(val);
|
|
422
|
+
document.querySelectorAll(".trash-filter-chip").forEach(c => c.classList.toggle("active", c.dataset.filter === val));
|
|
423
|
+
});
|
|
424
|
+
});
|
|
388
425
|
}
|
|
389
426
|
|
|
390
427
|
function _subscribe() {
|
|
@@ -392,11 +429,11 @@ const TrashView = (() => {
|
|
|
392
429
|
Trash.on("trash:sessionsChanged", _renderSessions);
|
|
393
430
|
Trash.on("trash:filesError", (e) => {
|
|
394
431
|
const list = $("trash-list");
|
|
395
|
-
if (list) list.innerHTML = `<div class="
|
|
432
|
+
if (list) list.innerHTML = `<div class="trash-empty trash-error">${escapeHtml(e.message)}</div>`;
|
|
396
433
|
});
|
|
397
434
|
Trash.on("trash:sessionsError", (e) => {
|
|
398
435
|
const list = $("trash-session-list");
|
|
399
|
-
if (list) list.innerHTML = `<div class="
|
|
436
|
+
if (list) list.innerHTML = `<div class="trash-empty trash-error">${escapeHtml(e.message)}</div>`;
|
|
400
437
|
});
|
|
401
438
|
}
|
|
402
439
|
|
|
@@ -302,4 +302,3 @@ if (window.Clacky && Clacky.ext) {
|
|
|
302
302
|
// Workspace.onSession on every session switch). Rendering is driven by the
|
|
303
303
|
// slot re-render, so this only updates state.
|
|
304
304
|
Workspace.onSession = (session) => { Workspace.setSession(session); };
|
|
305
|
-
window.Workspace = Workspace;
|
data/lib/clacky/web/i18n.js
CHANGED
|
@@ -20,28 +20,20 @@ const I18n = (() => {
|
|
|
20
20
|
"sidebar.skills": "Skill Management",
|
|
21
21
|
"sidebar.channels": "Channel Management",
|
|
22
22
|
"sidebar.mcp": "MCP Servers",
|
|
23
|
+
"sidebar.extensions": "Extension Market",
|
|
23
24
|
"sidebar.trash": "File Recall",
|
|
24
25
|
"sidebar.profile": "Assistant Memory",
|
|
25
26
|
"sidebar.memories": "Memories",
|
|
26
27
|
"sidebar.dataSection": "My Data",
|
|
27
|
-
"sidebar.creator": "Creator Hub",
|
|
28
|
-
"sidebar.creatorSection": "Creator",
|
|
29
28
|
"sidebar.settings": "Settings",
|
|
30
29
|
"sidebar.billing": "Usage",
|
|
31
30
|
|
|
32
31
|
// ── Welcome screen ──
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"welcome.chip.code.prompt": "Help me write some code. ",
|
|
39
|
-
"welcome.chip.task.title": "Automate a task",
|
|
40
|
-
"welcome.chip.task.desc": "schedule, run, repeat",
|
|
41
|
-
"welcome.chip.task.prompt": "I want to automate a recurring task. ",
|
|
42
|
-
"welcome.chip.research.title": "Research",
|
|
43
|
-
"welcome.chip.research.desc": "search, read, summarize",
|
|
44
|
-
"welcome.chip.research.prompt":"Research this for me: ",
|
|
32
|
+
"sessions.new.title": "Start a new session",
|
|
33
|
+
"sessions.new.subtitle": "Pick who you want to chat with, then type your first message.",
|
|
34
|
+
"sessions.new.placeholder": "Type your first message to {{agent}}…",
|
|
35
|
+
"sessions.new.moreOptions": "More options",
|
|
36
|
+
"sessions.new.send": "Send",
|
|
45
37
|
|
|
46
38
|
// ── Chat panel ──
|
|
47
39
|
"chat.status.idle": "idle",
|
|
@@ -58,6 +50,11 @@ const I18n = (() => {
|
|
|
58
50
|
"chat.history_load_failed": "Could not load history",
|
|
59
51
|
"chat.history_start": "No more history",
|
|
60
52
|
"chat.image_expired": "Expired",
|
|
53
|
+
"chat.file.tooLarge": "File too large: {{name}} (max {{max}})",
|
|
54
|
+
"chat.file.imageTooLarge": "Image too large: {{name}} (max {{max}})",
|
|
55
|
+
"chat.file.unsupportedType": "Unsupported image type: {{type}}\nSupported: PNG, JPEG, GIF, WEBP",
|
|
56
|
+
"chat.file.processFailed": "Image processing failed: {{msg}}",
|
|
57
|
+
"chat.file.uploadFailed": "Upload failed: {{msg}}",
|
|
61
58
|
"chat.done": "Done — {{n}} iteration(s), {{cost}}",
|
|
62
59
|
"chat.done.duration": " · {{duration}}s",
|
|
63
60
|
"chat.done.cache": "Cache hit {{rate}}% ({{hits}}/{{total}}) · {{tokens}} tokens reused",
|
|
@@ -153,6 +150,7 @@ const I18n = (() => {
|
|
|
153
150
|
"sib.reasoning.low": "Low",
|
|
154
151
|
"sib.reasoning.medium": "Medium",
|
|
155
152
|
"sib.reasoning.high": "High",
|
|
153
|
+
"sib.reasoning.xhigh": "XHigh",
|
|
156
154
|
"sessions.thinking": "Thinking…",
|
|
157
155
|
"sessions.default_name": "Session {{n}}",
|
|
158
156
|
"sessions.cronGroup": "Scheduled Tasks",
|
|
@@ -168,7 +166,6 @@ const I18n = (() => {
|
|
|
168
166
|
"sessions.actions.fork": "Fork",
|
|
169
167
|
"sessions.actions.rename": "Rename",
|
|
170
168
|
"sessions.actions.delete": "Delete",
|
|
171
|
-
"sessions.newSessionAdvanced": "More Options",
|
|
172
169
|
"sessions.loadMore": "Load more sessions",
|
|
173
170
|
"sessions.loadingMore": "Loading…",
|
|
174
171
|
"sessions.search.placeholder": "Search sessions…",
|
|
@@ -194,7 +191,6 @@ const I18n = (() => {
|
|
|
194
191
|
"auth.rateLimited": "Too many failed attempts. Please try again in {{seconds}} seconds.",
|
|
195
192
|
|
|
196
193
|
// ── New Session Modal ──
|
|
197
|
-
"sessions.modal.title": "Create New Session",
|
|
198
194
|
"sessions.modal.agent": "Agent",
|
|
199
195
|
"sessions.modal.agent.general": "General",
|
|
200
196
|
"sessions.modal.agent.coding": "Coding",
|
|
@@ -206,7 +202,6 @@ const I18n = (() => {
|
|
|
206
202
|
"sessions.modal.directory.browse": "Browse folders",
|
|
207
203
|
"sessions.modal.dirpicker.title": "Select Working Directory",
|
|
208
204
|
"sessions.modal.initProject": "Initialize full-stack project (/new)",
|
|
209
|
-
"sessions.modal.create": "Create Session",
|
|
210
205
|
|
|
211
206
|
// ── Offline banner ──
|
|
212
207
|
"offline.banner": "Server disconnected — reconnecting…",
|
|
@@ -264,48 +259,17 @@ const I18n = (() => {
|
|
|
264
259
|
"skills.title": "Skills",
|
|
265
260
|
"skills.subtitle": "Extend your assistant's capabilities with custom skills",
|
|
266
261
|
|
|
267
|
-
// ── Creator panel ──
|
|
268
|
-
"creator.title": "Creator Hub",
|
|
269
|
-
"creator.subtitle": "Manage and publish your skills to the platform",
|
|
270
|
-
"creator.loading": "Loading…",
|
|
271
|
-
|
|
272
|
-
"creator.section.cloud": "Cloud Skills",
|
|
273
|
-
"creator.section.cloudHint": "Published to the platform",
|
|
274
|
-
"creator.section.local": "Local Skills",
|
|
275
|
-
"creator.section.localHint": "Ready to publish",
|
|
276
|
-
"creator.section.new": "Create New Skill",
|
|
277
|
-
|
|
278
|
-
"creator.cloud.empty": "No skills published yet.",
|
|
279
|
-
"creator.local.empty": "All local skills are already published.",
|
|
280
|
-
|
|
281
|
-
"creator.badge.published": "Published",
|
|
282
|
-
"creator.badge.unpublished": "Not published",
|
|
283
|
-
|
|
284
|
-
"creator.changed": "Has local changes",
|
|
285
|
-
"creator.hasLocalChanges": "Local SKILL.md is newer than the last upload",
|
|
286
|
-
"creator.downloads": "Downloads",
|
|
287
|
-
|
|
288
|
-
"creator.btn.publish": "Publish",
|
|
289
|
-
"creator.btn.update": "Update",
|
|
290
|
-
"creator.btn.upToDate": "Up to date",
|
|
291
|
-
"creator.btn.iterate": "Iterate",
|
|
292
|
-
"creator.iterate.prompt": "Update skill:",
|
|
293
|
-
|
|
294
|
-
"creator.shadow.label": "Local override",
|
|
295
|
-
"creator.shadow.tooltip": "Local copy shadows a same-named brand skill",
|
|
296
|
-
|
|
297
|
-
"creator.newSkill.label": "Create a new skill with /skill-creator",
|
|
298
|
-
"creator.promo.text": "Publish your skills & build your own brand on OpenClacky.",
|
|
299
|
-
"creator.promo.link": "Learn more →",
|
|
300
|
-
"creator.cloud.locked": "Brand license required to publish cloud skills.",
|
|
301
|
-
|
|
302
262
|
// ── Creator trash ──
|
|
303
263
|
"trash.title": "File Recall",
|
|
304
264
|
"trash.subtitle": "Files the agent moved to trash across all projects. Recall them back to where they were, or clear the ones you don't need.",
|
|
305
265
|
"trash.refresh": "Refresh",
|
|
266
|
+
"trash.refresh.tooltip": "Reload the trash list",
|
|
306
267
|
"trash.emptyOld": "Empty >7 days",
|
|
268
|
+
"trash.emptyOld.tooltip": "Permanently delete files older than 7 days",
|
|
307
269
|
"trash.emptyOrphans":"Clean orphans",
|
|
270
|
+
"trash.emptyOrphans.tooltip": "Permanently delete entries whose original project no longer exists",
|
|
308
271
|
"trash.emptyAll": "Empty all",
|
|
272
|
+
"trash.emptyAll.tooltip": "Permanently delete all trashed files",
|
|
309
273
|
"trash.empty": "Nothing in the trash.",
|
|
310
274
|
"trash.loading": "Loading trash…",
|
|
311
275
|
"trash.summary": "{{count}} file(s), {{size}}",
|
|
@@ -345,6 +309,12 @@ const I18n = (() => {
|
|
|
345
309
|
"trash.deleteFail": "Delete failed: {{msg}}",
|
|
346
310
|
"trash.cleanFail": "Operation failed: {{msg}}",
|
|
347
311
|
|
|
312
|
+
// ── Session type filter ──
|
|
313
|
+
"trash.filterAll": "All",
|
|
314
|
+
"trash.filterCron": "Scheduled",
|
|
315
|
+
"trash.filterManual": "Regular",
|
|
316
|
+
"trash.sessionAutoCleanHint": "The system keeps the most recent 200 sessions; older ones are moved here.",
|
|
317
|
+
|
|
348
318
|
// ── Relative time (used by _humanTime helper) ──
|
|
349
319
|
"time.justNow": "just now",
|
|
350
320
|
"time.minsAgo": "{{n}}m ago",
|
|
@@ -520,6 +490,37 @@ const I18n = (() => {
|
|
|
520
490
|
// ── MCP panel ──
|
|
521
491
|
"mcp.title": "MCP Servers",
|
|
522
492
|
"mcp.subtitle": "Standard Model Context Protocol servers (Claude Desktop / Cursor compatible). Edit ~/.clacky/mcp.json to add or remove servers.",
|
|
493
|
+
"extensions.title": "Extension Market",
|
|
494
|
+
"extensions.subtitle": "Browse and manage your extensions to enhance OpenClacky with agents, skills, and panels.",
|
|
495
|
+
"extensions.searchPlaceholder": "Search extensions…",
|
|
496
|
+
"extensions.sort.newest": "Newest",
|
|
497
|
+
"extensions.sort.updated": "Recently updated",
|
|
498
|
+
"extensions.sort.downloads": "Most downloaded",
|
|
499
|
+
"extensions.empty": "No extensions available yet.",
|
|
500
|
+
"extensions.noResults": "No extensions match your search.",
|
|
501
|
+
"extensions.loadFailed": "Could not reach the extension store.",
|
|
502
|
+
"extensions.homepage": "Homepage",
|
|
503
|
+
"extensions.installed": "Installed",
|
|
504
|
+
"extensions.unit.skill": "skill",
|
|
505
|
+
"extensions.unit.skills": "skills",
|
|
506
|
+
"extensions.unit.agent": "agent",
|
|
507
|
+
"extensions.unit.agents": "agents",
|
|
508
|
+
"extensions.unit.panel": "panel",
|
|
509
|
+
"extensions.unit.panels": "panels",
|
|
510
|
+
"extensions.unit.api": "API",
|
|
511
|
+
"extensions.unit.apis": "APIs",
|
|
512
|
+
"extensions.detail.back": "Back",
|
|
513
|
+
"extensions.detail.contributes": "What's inside",
|
|
514
|
+
"extensions.detail.versions": "Version history",
|
|
515
|
+
"extensions.section.agents": "Agents",
|
|
516
|
+
"extensions.section.skills": "Skills",
|
|
517
|
+
"extensions.section.panels": "Panels",
|
|
518
|
+
"extensions.section.api": "APIs",
|
|
519
|
+
"extensions.disabled": "Disabled",
|
|
520
|
+
"extensions.action.disable": "Disable",
|
|
521
|
+
"extensions.action.enable": "Enable",
|
|
522
|
+
"extensions.action.remove": "Remove",
|
|
523
|
+
"extensions.action.removeConfirm": "Remove this extension? Its files will be deleted. You can reinstall it from your license package later.",
|
|
523
524
|
"mcp.loading": "Loading…",
|
|
524
525
|
"mcp.empty.title": "No MCP servers configured",
|
|
525
526
|
"mcp.empty.body": "Create ~/.clacky/mcp.json to plug in MCP servers. The format matches Claude Desktop and Cursor, so existing configs work as-is.",
|
|
@@ -800,6 +801,7 @@ const I18n = (() => {
|
|
|
800
801
|
"brand.activate.subtitle": "Enter your serial number to get started.",
|
|
801
802
|
"brand.activate.success": "License activated successfully!",
|
|
802
803
|
"brand.skip.warning": "Brand license not activated — brand-exclusive skills are unavailable. You can activate your license anytime in Settings → Brand & License.",
|
|
804
|
+
"brand.warning.renewBtn": "Renew License",
|
|
803
805
|
|
|
804
806
|
// ── Brand activation banner ──
|
|
805
807
|
"brand.banner.prompt": "{{name}} is not activated yet — some features are unavailable.",
|
|
@@ -811,11 +813,14 @@ const I18n = (() => {
|
|
|
811
813
|
"brand.banner.freePromptOnlyPaid": "Welcome to {{name}} — {{paid}} premium skill{{paidPlural}} can be unlocked with a serial number.",
|
|
812
814
|
"brand.banner.freePromptBoth": "Welcome to {{name}} — {{free}} free skill{{freePlural}} ready to use, plus {{paid}} premium skill{{paidPlural}} unlockable with a serial number.",
|
|
813
815
|
|
|
814
|
-
"header.owner.tooltip": "Creator — click to open
|
|
816
|
+
"header.owner.tooltip": "Creator — click to open Extension & Creation",
|
|
815
817
|
"header.cmdbar.placeholder": "Search sessions…",
|
|
816
818
|
"notify.tooltip.on": "Sound on task complete: ON (click to mute)",
|
|
817
819
|
"notify.tooltip.off": "Sound on task complete: OFF (click to enable)",
|
|
818
820
|
|
|
821
|
+
"header.refresh": "Refresh",
|
|
822
|
+
"header.theme.toDark": "Switch to dark mode",
|
|
823
|
+
"header.theme.toLight": "Switch to light mode",
|
|
819
824
|
"share.tooltip": "Share",
|
|
820
825
|
"share.copy.1": "Been running {{brand}} with domestic models (Kimi, DeepSeek, GLM…) — first-class support, no proxy hacks. Solid.",
|
|
821
826
|
"share.copy.2": "{{brand}} is stingy with tokens in the best way — prompt caching keeps my AI bill tiny. Recommend.",
|
|
@@ -958,28 +963,20 @@ const I18n = (() => {
|
|
|
958
963
|
"sidebar.skills": "技能管理",
|
|
959
964
|
"sidebar.channels": "频道管理",
|
|
960
965
|
"sidebar.mcp": "MCP 工具",
|
|
966
|
+
"sidebar.extensions": "扩展市场",
|
|
961
967
|
"sidebar.trash": "文件召回",
|
|
962
968
|
"sidebar.profile": "助理记忆",
|
|
963
969
|
"sidebar.memories": "记忆",
|
|
964
970
|
"sidebar.dataSection": "我的数据",
|
|
965
|
-
"sidebar.creator": "创作者中心",
|
|
966
|
-
"sidebar.creatorSection": "创作者",
|
|
967
971
|
"sidebar.settings": "设置",
|
|
968
972
|
"sidebar.billing": "用量信息",
|
|
969
973
|
|
|
970
974
|
// ── Welcome screen ──
|
|
971
|
-
"
|
|
972
|
-
"
|
|
973
|
-
"
|
|
974
|
-
"
|
|
975
|
-
"
|
|
976
|
-
"welcome.chip.code.prompt": "帮我写一段代码:",
|
|
977
|
-
"welcome.chip.task.title": "自动化任务",
|
|
978
|
-
"welcome.chip.task.desc": "定时、执行、重复",
|
|
979
|
-
"welcome.chip.task.prompt": "我想把一个重复性任务自动化:",
|
|
980
|
-
"welcome.chip.research.title": "做调研",
|
|
981
|
-
"welcome.chip.research.desc": "搜索、阅读、汇总",
|
|
982
|
-
"welcome.chip.research.prompt":"帮我调研一下:",
|
|
975
|
+
"sessions.new.title": "开始新会话",
|
|
976
|
+
"sessions.new.subtitle": "选一个 Agent,然后输入第一条消息。",
|
|
977
|
+
"sessions.new.placeholder": "输入第一条消息发给 {{agent}}…",
|
|
978
|
+
"sessions.new.moreOptions": "更多选项",
|
|
979
|
+
"sessions.new.send": "发送",
|
|
983
980
|
|
|
984
981
|
// ── Chat panel ──
|
|
985
982
|
"chat.status.idle": "空闲",
|
|
@@ -996,6 +993,11 @@ const I18n = (() => {
|
|
|
996
993
|
"chat.history_load_failed": "历史记录加载失败",
|
|
997
994
|
"chat.history_start": "没有更多历史了",
|
|
998
995
|
"chat.image_expired": "已过期",
|
|
996
|
+
"chat.file.tooLarge": "文件过大:{{name}}(最大 {{max}})",
|
|
997
|
+
"chat.file.imageTooLarge": "图片过大:{{name}}(最大 {{max}})",
|
|
998
|
+
"chat.file.unsupportedType": "不支持的图片格式:{{type}}\n支持:PNG、JPEG、GIF、WEBP",
|
|
999
|
+
"chat.file.processFailed": "图片处理失败:{{msg}}",
|
|
1000
|
+
"chat.file.uploadFailed": "上传失败:{{msg}}",
|
|
999
1001
|
"chat.done": "完成 — {{n}} 步,{{cost}}",
|
|
1000
1002
|
"chat.done.duration": " · {{duration}}s",
|
|
1001
1003
|
"chat.done.cache": "缓存命中 {{rate}}% ({{hits}}/{{total}}) · 复用 {{tokens}} tokens",
|
|
@@ -1089,6 +1091,7 @@ const I18n = (() => {
|
|
|
1089
1091
|
"sib.reasoning.low": "低",
|
|
1090
1092
|
"sib.reasoning.medium": "中",
|
|
1091
1093
|
"sib.reasoning.high": "高",
|
|
1094
|
+
"sib.reasoning.xhigh": "超高",
|
|
1092
1095
|
"sessions.thinking": "思考中…",
|
|
1093
1096
|
"sessions.default_name": "会话 {{n}}",
|
|
1094
1097
|
"sessions.cronGroup": "定时任务",
|
|
@@ -1099,7 +1102,6 @@ const I18n = (() => {
|
|
|
1099
1102
|
"sessions.badge.coding": "Coding",
|
|
1100
1103
|
"sessions.badge.setup": "配置",
|
|
1101
1104
|
"sessions.newSession": "+ 新会话",
|
|
1102
|
-
"sessions.newSessionAdvanced": "更多选项",
|
|
1103
1105
|
"sessions.loadMore": "加载更多会话",
|
|
1104
1106
|
"sessions.actions.pin": "置顶",
|
|
1105
1107
|
"sessions.actions.unpin": "取消置顶",
|
|
@@ -1128,7 +1130,6 @@ const I18n = (() => {
|
|
|
1128
1130
|
"auth.rateLimited": "尝试次数过多,请 {{seconds}} 秒后再试。",
|
|
1129
1131
|
|
|
1130
1132
|
// ── New Session Modal ──
|
|
1131
|
-
"sessions.modal.title": "创建新会话",
|
|
1132
1133
|
"sessions.modal.agent": "助手类型",
|
|
1133
1134
|
"sessions.modal.agent.general": "通用",
|
|
1134
1135
|
"sessions.modal.agent.coding": "编程",
|
|
@@ -1140,7 +1141,6 @@ const I18n = (() => {
|
|
|
1140
1141
|
"sessions.modal.directory.browse": "选择文件夹",
|
|
1141
1142
|
"sessions.modal.dirpicker.title": "选择工作目录",
|
|
1142
1143
|
"sessions.modal.initProject": "初始化全栈项目 (/new)",
|
|
1143
|
-
"sessions.modal.create": "创建会话",
|
|
1144
1144
|
|
|
1145
1145
|
// ── Offline banner ──
|
|
1146
1146
|
"offline.banner": "服务已断开,正在重连…",
|
|
@@ -1198,48 +1198,17 @@ const I18n = (() => {
|
|
|
1198
1198
|
"skills.title": "技能",
|
|
1199
1199
|
"skills.subtitle": "为助手添加自定义能力",
|
|
1200
1200
|
|
|
1201
|
-
// ── Creator panel ──
|
|
1202
|
-
"creator.title": "创作者中心",
|
|
1203
|
-
"creator.subtitle": "管理并发布你的技能到平台",
|
|
1204
|
-
"creator.loading": "加载中…",
|
|
1205
|
-
|
|
1206
|
-
"creator.section.cloud": "云端技能",
|
|
1207
|
-
"creator.section.cloudHint": "已发布到平台",
|
|
1208
|
-
"creator.section.local": "本地技能",
|
|
1209
|
-
"creator.section.localHint": "准备好可以上传",
|
|
1210
|
-
"creator.section.new": "创建新技能",
|
|
1211
|
-
|
|
1212
|
-
"creator.cloud.empty": "还没有发布任何技能。",
|
|
1213
|
-
"creator.local.empty": "所有本地技能均已发布。",
|
|
1214
|
-
|
|
1215
|
-
"creator.badge.published": "已发布",
|
|
1216
|
-
"creator.badge.unpublished": "未发布",
|
|
1217
|
-
|
|
1218
|
-
"creator.changed": "有本地改动",
|
|
1219
|
-
"creator.hasLocalChanges": "本地 SKILL.md 比上次上传更新",
|
|
1220
|
-
"creator.downloads": "下载量",
|
|
1221
|
-
|
|
1222
|
-
"creator.btn.publish": "发布",
|
|
1223
|
-
"creator.btn.update": "更新",
|
|
1224
|
-
"creator.btn.upToDate": "已是最新",
|
|
1225
|
-
"creator.btn.iterate": "迭代",
|
|
1226
|
-
"creator.iterate.prompt": "更新技能:",
|
|
1227
|
-
|
|
1228
|
-
"creator.shadow.label": "本地优先",
|
|
1229
|
-
"creator.shadow.tooltip": "本地版本覆盖了同名的品牌加密技能",
|
|
1230
|
-
|
|
1231
|
-
"creator.newSkill.label": "用 /skill-creator 创建新技能",
|
|
1232
|
-
"creator.promo.text": "发布你的 Skill,在 OpenClacky 上打造自己的品牌。",
|
|
1233
|
-
"creator.promo.link": "了解更多 →",
|
|
1234
|
-
"creator.cloud.locked": "需要品牌授权才能发布云端 Skill。",
|
|
1235
|
-
|
|
1236
1201
|
// ── Creator trash ──
|
|
1237
1202
|
"trash.title": "文件召回",
|
|
1238
1203
|
"trash.subtitle": "AI 代理在各个项目里丢进回收站的文件。可以把它们召回到原位置,或彻底清理不再需要的。",
|
|
1239
1204
|
"trash.refresh": "刷新",
|
|
1205
|
+
"trash.refresh.tooltip": "重新加载回收站列表",
|
|
1240
1206
|
"trash.emptyOld": "清理 >7 天",
|
|
1207
|
+
"trash.emptyOld.tooltip": "永久删除 7 天前的文件",
|
|
1241
1208
|
"trash.emptyOrphans":"清理孤儿",
|
|
1209
|
+
"trash.emptyOrphans.tooltip": "永久删除原始项目目录已不存在的条目",
|
|
1242
1210
|
"trash.emptyAll": "全部清空",
|
|
1211
|
+
"trash.emptyAll.tooltip": "永久删除所有回收站文件",
|
|
1243
1212
|
"trash.empty": "回收站空空如也。",
|
|
1244
1213
|
"trash.loading": "加载回收站…",
|
|
1245
1214
|
"trash.summary": "共 {{count}} 个文件,{{size}}",
|
|
@@ -1281,6 +1250,12 @@ const I18n = (() => {
|
|
|
1281
1250
|
"trash.deleteFail": "删除失败:{{msg}}",
|
|
1282
1251
|
"trash.cleanFail": "操作失败:{{msg}}",
|
|
1283
1252
|
|
|
1253
|
+
// ── Session type filter ──
|
|
1254
|
+
"trash.filterAll": "全部",
|
|
1255
|
+
"trash.filterCron": "定时任务",
|
|
1256
|
+
"trash.filterManual": "普通会话",
|
|
1257
|
+
"trash.sessionAutoCleanHint": "系统自动保留最近 200 个会话,超出后自动移入此处。",
|
|
1258
|
+
|
|
1284
1259
|
// ── Relative time (used by _humanTime helper) ──
|
|
1285
1260
|
"time.justNow": "刚刚",
|
|
1286
1261
|
"time.minsAgo": "{{n}} 分钟前",
|
|
@@ -1455,6 +1430,37 @@ const I18n = (() => {
|
|
|
1455
1430
|
// ── MCP panel ──
|
|
1456
1431
|
"mcp.title": "MCP 工具",
|
|
1457
1432
|
"mcp.subtitle": "标准 Model Context Protocol 服务(与 Claude Desktop / Cursor 兼容)。编辑 ~/.clacky/mcp.json 添加或移除服务。",
|
|
1433
|
+
"extensions.title": "扩展市场",
|
|
1434
|
+
"extensions.subtitle": "浏览并管理你的扩展,用 Agent、技能与面板增强 OpenClacky。",
|
|
1435
|
+
"extensions.searchPlaceholder": "搜索扩展…",
|
|
1436
|
+
"extensions.sort.newest": "最新",
|
|
1437
|
+
"extensions.sort.updated": "最近更新",
|
|
1438
|
+
"extensions.sort.downloads": "下载最多",
|
|
1439
|
+
"extensions.empty": "暂无可用扩展。",
|
|
1440
|
+
"extensions.noResults": "没有匹配的扩展。",
|
|
1441
|
+
"extensions.loadFailed": "无法连接扩展市场。",
|
|
1442
|
+
"extensions.homepage": "主页",
|
|
1443
|
+
"extensions.installed": "已安装",
|
|
1444
|
+
"extensions.unit.skill": "个技能",
|
|
1445
|
+
"extensions.unit.skills": "个技能",
|
|
1446
|
+
"extensions.unit.agent": "个 Agent",
|
|
1447
|
+
"extensions.unit.agents": "个 Agent",
|
|
1448
|
+
"extensions.unit.panel": "个面板",
|
|
1449
|
+
"extensions.unit.panels": "个面板",
|
|
1450
|
+
"extensions.unit.api": "个 API",
|
|
1451
|
+
"extensions.unit.apis": "个 API",
|
|
1452
|
+
"extensions.detail.back": "返回",
|
|
1453
|
+
"extensions.detail.contributes": "包含内容",
|
|
1454
|
+
"extensions.detail.versions": "版本历史",
|
|
1455
|
+
"extensions.section.agents": "Agent",
|
|
1456
|
+
"extensions.section.skills": "技能",
|
|
1457
|
+
"extensions.section.panels": "面板",
|
|
1458
|
+
"extensions.section.api": "API",
|
|
1459
|
+
"extensions.disabled": "已禁用",
|
|
1460
|
+
"extensions.action.disable": "禁用",
|
|
1461
|
+
"extensions.action.enable": "启用",
|
|
1462
|
+
"extensions.action.remove": "移除",
|
|
1463
|
+
"extensions.action.removeConfirm": "确定移除此扩展?相关文件会被删除,之后可从授权包重新安装。",
|
|
1458
1464
|
"mcp.loading": "加载中…",
|
|
1459
1465
|
"mcp.empty.title": "尚未配置 MCP 服务",
|
|
1460
1466
|
"mcp.empty.body": "新建 ~/.clacky/mcp.json 即可接入 MCP 服务。格式与 Claude Desktop、Cursor 一致,现有配置可直接复用。",
|
|
@@ -1742,6 +1748,7 @@ const I18n = (() => {
|
|
|
1742
1748
|
"brand.activate.subtitle": "输入序列号以开始使用。",
|
|
1743
1749
|
"brand.activate.success": "授权激活成功!",
|
|
1744
1750
|
"brand.skip.warning": "品牌授权未激活 — 品牌专属技能暂不可用。可随时在「设置 → 品牌 & 授权」中激活。",
|
|
1751
|
+
"brand.warning.renewBtn": "续期授权",
|
|
1745
1752
|
|
|
1746
1753
|
// ── Brand activation banner ──
|
|
1747
1754
|
"brand.banner.prompt": "{{name}} 尚未激活授权 — 部分功能暂不可用。",
|
|
@@ -1753,11 +1760,14 @@ const I18n = (() => {
|
|
|
1753
1760
|
"brand.banner.freePromptOnlyPaid": "欢迎使用 {{name}} — 还有 {{paid}} 个增值技能,输入序列号后即可解锁。",
|
|
1754
1761
|
"brand.banner.freePromptBoth": "欢迎使用 {{name}} — 已自动安装 {{free}} 个免费技能,还有 {{paid}} 个增值技能可输入序列号解锁。",
|
|
1755
1762
|
|
|
1756
|
-
"header.owner.tooltip": "创作者 —
|
|
1763
|
+
"header.owner.tooltip": "创作者 — 点击进入扩展与创作",
|
|
1757
1764
|
"header.cmdbar.placeholder": "搜索会话…",
|
|
1758
1765
|
"notify.tooltip.on": "任务完成提示音:已开启(点击关闭)",
|
|
1759
1766
|
"notify.tooltip.off": "任务完成提示音:已关闭(点击开启)",
|
|
1760
1767
|
|
|
1768
|
+
"header.refresh": "刷新",
|
|
1769
|
+
"header.theme.toDark": "切换到深色模式",
|
|
1770
|
+
"header.theme.toLight": "切换到浅色模式",
|
|
1761
1771
|
"share.tooltip": "分享",
|
|
1762
1772
|
"share.copy.1": "{{brand}} 对国产模型(Kimi、DeepSeek、智谱…)适配很到位,原生支持不用折腾代理,好用。",
|
|
1763
1773
|
"share.copy.2": "{{brand}} 是真省 Token —— 靠 Prompt 缓存把我的 AI 账单压得很低,推荐。",
|
|
@@ -1980,6 +1990,8 @@ const I18n = (() => {
|
|
|
1980
1990
|
return { lang, setLang, t, tList, applyAll };
|
|
1981
1991
|
})();
|
|
1982
1992
|
|
|
1993
|
+
Clacky.I18n = I18n;
|
|
1994
|
+
|
|
1983
1995
|
// ── Thinking Verbs for Progress Animation ──────────────────────────────────
|
|
1984
1996
|
//
|
|
1985
1997
|
// The primary verb ("Thinking" / "思考中") is chosen 90% of the time inside
|