getkova 2026.4.21 → 2026.4.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.
- package/dist/control-ui/apple-touch-icon.png +0 -0
- package/dist/control-ui/assets/agents-CLtFQRXd.js +918 -0
- package/dist/control-ui/assets/agents-CLtFQRXd.js.map +1 -0
- package/dist/control-ui/assets/anthropic-CFEPAL-v.js +37 -0
- package/dist/control-ui/assets/anthropic-CFEPAL-v.js.map +1 -0
- package/dist/control-ui/assets/azure-openai-responses-CxiWQLmZ.js +2 -0
- package/dist/control-ui/assets/azure-openai-responses-CxiWQLmZ.js.map +1 -0
- package/dist/control-ui/assets/briefing-DS4VWpUL.js +121 -0
- package/dist/control-ui/assets/briefing-DS4VWpUL.js.map +1 -0
- package/dist/control-ui/assets/canvas-BfC_2Nqy.js +17 -0
- package/dist/control-ui/assets/canvas-BfC_2Nqy.js.map +1 -0
- package/dist/control-ui/assets/channel-config-extras-YNNd-4PG.js +2 -0
- package/dist/control-ui/assets/channel-config-extras-YNNd-4PG.js.map +1 -0
- package/dist/control-ui/assets/channels-BKdM7i5r.js +471 -0
- package/dist/control-ui/assets/channels-BKdM7i5r.js.map +1 -0
- package/dist/control-ui/assets/cron-C11m3yJi.js +928 -0
- package/dist/control-ui/assets/cron-C11m3yJi.js.map +1 -0
- package/dist/control-ui/assets/de-rLAkQOBc.js +2 -0
- package/dist/control-ui/assets/de-rLAkQOBc.js.map +1 -0
- package/dist/control-ui/assets/debug-DFf2qCcM.js +94 -0
- package/dist/control-ui/assets/debug-DFf2qCcM.js.map +1 -0
- package/dist/control-ui/assets/dist-D8DZLmCF.js +18 -0
- package/dist/control-ui/assets/dist-D8DZLmCF.js.map +1 -0
- package/dist/control-ui/assets/employees-DV-5FV4K.js +104 -0
- package/dist/control-ui/assets/employees-DV-5FV4K.js.map +1 -0
- package/dist/control-ui/assets/es-CIeD3O54.js +2 -0
- package/dist/control-ui/assets/es-CIeD3O54.js.map +1 -0
- package/dist/control-ui/assets/event-stream-B8X6sYaV.js +2 -0
- package/dist/control-ui/assets/event-stream-B8X6sYaV.js.map +1 -0
- package/dist/control-ui/assets/format-BahKhiOC.js +2 -0
- package/dist/control-ui/assets/format-BahKhiOC.js.map +1 -0
- package/dist/control-ui/assets/github-copilot-headers-CrI0CIJ7.js +2 -0
- package/dist/control-ui/assets/github-copilot-headers-CrI0CIJ7.js.map +1 -0
- package/dist/control-ui/assets/google-BT0bmsh5.js +2 -0
- package/dist/control-ui/assets/google-BT0bmsh5.js.map +1 -0
- package/dist/control-ui/assets/google-gemini-cli-BpxbH95Q.js +3 -0
- package/dist/control-ui/assets/google-gemini-cli-BpxbH95Q.js.map +1 -0
- package/dist/control-ui/assets/google-shared-CbPHVnPr.js +12 -0
- package/dist/control-ui/assets/google-shared-CbPHVnPr.js.map +1 -0
- package/dist/control-ui/assets/google-vertex-lQwbjEII.js +2 -0
- package/dist/control-ui/assets/google-vertex-lQwbjEII.js.map +1 -0
- package/dist/control-ui/assets/hash-Bt1aVMQ3.js +2 -0
- package/dist/control-ui/assets/hash-Bt1aVMQ3.js.map +1 -0
- package/dist/control-ui/assets/inbox-C4tOnlJr.js +100 -0
- package/dist/control-ui/assets/inbox-C4tOnlJr.js.map +1 -0
- package/dist/control-ui/assets/index-DYMuTfvX.css +1 -0
- package/dist/control-ui/assets/index-XGDpaFxG.js +5482 -0
- package/dist/control-ui/assets/index-XGDpaFxG.js.map +1 -0
- package/dist/control-ui/assets/instances-Cyr-tbN6.js +57 -0
- package/dist/control-ui/assets/instances-Cyr-tbN6.js.map +1 -0
- package/dist/control-ui/assets/kova-logo.png +0 -0
- package/dist/control-ui/assets/lit-zdTgzAJI.js +3 -0
- package/dist/control-ui/assets/lit-zdTgzAJI.js.map +1 -0
- package/dist/control-ui/assets/local-storage-D3baoRWx.js +2 -0
- package/dist/control-ui/assets/local-storage-D3baoRWx.js.map +1 -0
- package/dist/control-ui/assets/logs-B7--7dYP.js +74 -0
- package/dist/control-ui/assets/logs-B7--7dYP.js.map +1 -0
- package/dist/control-ui/assets/meetings-DSqn6s7n.js +185 -0
- package/dist/control-ui/assets/meetings-DSqn6s7n.js.map +1 -0
- package/dist/control-ui/assets/mistral-CBrDC_Gv.js +8 -0
- package/dist/control-ui/assets/mistral-CBrDC_Gv.js.map +1 -0
- package/dist/control-ui/assets/nodes-Cvq_sAqT.js +430 -0
- package/dist/control-ui/assets/nodes-Cvq_sAqT.js.map +1 -0
- package/dist/control-ui/assets/openai-Cn7eGqwa.js +17 -0
- package/dist/control-ui/assets/openai-Cn7eGqwa.js.map +1 -0
- package/dist/control-ui/assets/openai-codex-responses-DuhESMYF.js +8 -0
- package/dist/control-ui/assets/openai-codex-responses-DuhESMYF.js.map +1 -0
- package/dist/control-ui/assets/openai-completions-Bv33lqKL.js +6 -0
- package/dist/control-ui/assets/openai-completions-Bv33lqKL.js.map +1 -0
- package/dist/control-ui/assets/openai-responses-BPxpapOg.js +2 -0
- package/dist/control-ui/assets/openai-responses-BPxpapOg.js.map +1 -0
- package/dist/control-ui/assets/openai-responses-shared-8nKH8ywL.js +11 -0
- package/dist/control-ui/assets/openai-responses-shared-8nKH8ywL.js.map +1 -0
- package/dist/control-ui/assets/pdf-BwYFZMZM.js +57 -0
- package/dist/control-ui/assets/pdf-BwYFZMZM.js.map +1 -0
- package/dist/control-ui/assets/pdf.worker.min-BmpgcBpm.js +2 -0
- package/dist/control-ui/assets/pdf.worker.min-BmpgcBpm.js.map +1 -0
- package/dist/control-ui/assets/pdf.worker.min-C8PGFc0r.mjs +28 -0
- package/dist/control-ui/assets/preload-helper-Chd9yIcd.js +1 -0
- package/dist/control-ui/assets/pt-BR-lSsBb08k.js +2 -0
- package/dist/control-ui/assets/pt-BR-lSsBb08k.js.map +1 -0
- package/dist/control-ui/assets/routing-DizI_FiJ.js +157 -0
- package/dist/control-ui/assets/routing-DizI_FiJ.js.map +1 -0
- package/dist/control-ui/assets/sessions-N9rgJP2R.js +236 -0
- package/dist/control-ui/assets/sessions-N9rgJP2R.js.map +1 -0
- package/dist/control-ui/assets/skills-D1vP4MkL.js +280 -0
- package/dist/control-ui/assets/skills-D1vP4MkL.js.map +1 -0
- package/dist/control-ui/assets/skills-shared-Bg0Qcnkp.js +11 -0
- package/dist/control-ui/assets/skills-shared-Bg0Qcnkp.js.map +1 -0
- package/dist/control-ui/assets/transform-messages-XKqwKV3D.js +2 -0
- package/dist/control-ui/assets/transform-messages-XKqwKV3D.js.map +1 -0
- package/dist/control-ui/assets/zh-CN-C5tPG8Eu.js +2 -0
- package/dist/control-ui/assets/zh-CN-C5tPG8Eu.js.map +1 -0
- package/dist/control-ui/assets/zh-TW-CPSoC7Wz.js +2 -0
- package/dist/control-ui/assets/zh-TW-CPSoC7Wz.js.map +1 -0
- package/dist/control-ui/favicon-32.png +0 -0
- package/dist/control-ui/favicon.ico +0 -0
- package/dist/control-ui/favicon.png +0 -0
- package/dist/control-ui/favicon.svg +22 -0
- package/dist/control-ui/index.html +73 -0
- package/dist/control-ui/openclaw-canvas-auth-sw.js +57 -0
- package/package.json +1 -1
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
import{i as e,n as t}from"./lit-zdTgzAJI.js";import{t as n}from"./format-BahKhiOC.js";import{N as r,R as i}from"./index-XGDpaFxG.js";import{i as a,n as o,r as s,t as c}from"./skills-shared-Bg0Qcnkp.js";function l(e){return e?r(e,window.location.href):null}var u=[{id:`all`,label:`All`},{id:`ready`,label:`Ready`},{id:`needs-setup`,label:`Needs Setup`},{id:`disabled`,label:`Disabled`},{id:`marketplace`,label:`Marketplace`}],d=[{id:`all`,label:`All`},{id:`Productivity`,label:`Productivity`},{id:`News`,label:`News`},{id:`Finance`,label:`Finance`},{id:`Developer`,label:`Developer`},{id:`Social`,label:`Social`}];function f(e,t){switch(t){case`all`:return!0;case`ready`:return!e.disabled&&e.eligible;case`needs-setup`:return!e.disabled&&!e.eligible;case`disabled`:return e.disabled}}function p(e){return e.disabled?`muted`:e.eligible?`ok`:`warn`}function m(e,t){return t?[e.name,e.description].join(` `).toLowerCase().includes(t):!0}function h(e,t){return t===`all`||e.category===t}function g(n){let r=n.filter.trim().toLowerCase(),i=n.kova_marketplaceSkills.filter(e=>h(e,n.kova_marketplaceCategory)&&m(e,r));return e`
|
|
2
|
+
<div
|
|
3
|
+
class="filters"
|
|
4
|
+
style="display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-top: 12px;"
|
|
5
|
+
>
|
|
6
|
+
<label class="field" style="flex: 1; min-width: 180px;">
|
|
7
|
+
<input
|
|
8
|
+
.value=${n.filter}
|
|
9
|
+
@input=${e=>n.onFilterChange(e.target.value)}
|
|
10
|
+
placeholder="Search marketplace"
|
|
11
|
+
autocomplete="off"
|
|
12
|
+
name="skills-filter"
|
|
13
|
+
/>
|
|
14
|
+
</label>
|
|
15
|
+
<div class="muted">${i.length} shown</div>
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
<div class="agent-tabs" style="margin-top: 12px; flex-wrap: wrap;">
|
|
19
|
+
${d.map(t=>e`
|
|
20
|
+
<button
|
|
21
|
+
class="agent-tab ${n.kova_marketplaceCategory===t.id?`active`:``}"
|
|
22
|
+
@click=${()=>n.onKovaMarketplaceCategoryChange(t.id)}
|
|
23
|
+
>
|
|
24
|
+
${t.label}
|
|
25
|
+
</button>
|
|
26
|
+
`)}
|
|
27
|
+
</div>
|
|
28
|
+
|
|
29
|
+
${n.kova_marketplaceError?e`<div class="callout danger" style="margin-top: 12px;">${n.kova_marketplaceError}</div>`:t}
|
|
30
|
+
|
|
31
|
+
${i.length===0?e`
|
|
32
|
+
<div class="muted" style="margin-top: 16px;">
|
|
33
|
+
${n.kova_marketplaceLoading?`Loading marketplace...`:`No marketplace skills found.`}
|
|
34
|
+
</div>
|
|
35
|
+
`:e`
|
|
36
|
+
<div
|
|
37
|
+
class="kova-marketplace-grid"
|
|
38
|
+
style="display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 12px; margin-top: 16px;"
|
|
39
|
+
>
|
|
40
|
+
${i.map(e=>_(e,n))}
|
|
41
|
+
</div>
|
|
42
|
+
`}
|
|
43
|
+
`}function _(n,r){let i=r.kova_marketplaceInstalledIds.includes(n.id),a=r.kova_marketplaceBusyId===n.id,o=i?`Installed`:a?`Installing...`:`Install`;return e`
|
|
44
|
+
<div
|
|
45
|
+
class="list-item"
|
|
46
|
+
style="display: grid; grid-template-columns: minmax(0, 3fr) minmax(96px, 1fr); gap: 14px; align-items: start; border: 1px solid var(--border);"
|
|
47
|
+
>
|
|
48
|
+
<div class="list-main" style="min-width: 0;">
|
|
49
|
+
<div class="list-title" style="display: flex; align-items: center; gap: 8px; flex-wrap: wrap;">
|
|
50
|
+
<span>${n.name}</span>
|
|
51
|
+
<span class="chip">${n.category}</span>
|
|
52
|
+
${n.free?e`<span class="chip chip-ok">Free</span>`:t}
|
|
53
|
+
${i?e`<span class="chip">Installed</span>`:t}
|
|
54
|
+
</div>
|
|
55
|
+
<div
|
|
56
|
+
class="list-sub"
|
|
57
|
+
style="margin-top: 6px; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;"
|
|
58
|
+
>
|
|
59
|
+
${n.description||`No description provided.`}
|
|
60
|
+
</div>
|
|
61
|
+
<div class="muted" style="margin-top: 8px; font-size: 12px;">By ${n.author}</div>
|
|
62
|
+
</div>
|
|
63
|
+
<div style="display: flex; justify-content: flex-end;">
|
|
64
|
+
<button
|
|
65
|
+
class="btn ${i?``:`primary`}"
|
|
66
|
+
?disabled=${i||a||!r.connected}
|
|
67
|
+
@click=${()=>r.onKovaMarketplaceInstall(n)}
|
|
68
|
+
>
|
|
69
|
+
${o}
|
|
70
|
+
</button>
|
|
71
|
+
</div>
|
|
72
|
+
</div>
|
|
73
|
+
`}function v(n){let r=n.report?.skills??[],i={all:r.length,ready:0,"needs-setup":0,disabled:0,marketplace:n.kova_marketplaceSkills.length};for(let e of r)e.disabled?i.disabled++:e.eligible?i.ready++:i[`needs-setup`]++;let o=n.statusFilter===`marketplace`||n.statusFilter===`all`?r:r.filter(e=>f(e,n.statusFilter)),s=n.filter.trim().toLowerCase(),c=s?o.filter(e=>[e.name,e.description,e.source].join(` `).toLowerCase().includes(s)):o,l=a(c),d=n.statusFilter!==`marketplace`&&n.detailKey?r.find(e=>e.skillKey===n.detailKey)??null:null;return e`
|
|
74
|
+
<section class="card">
|
|
75
|
+
<div class="row" style="justify-content: space-between;">
|
|
76
|
+
<div>
|
|
77
|
+
<div class="card-title">Skills</div>
|
|
78
|
+
<div class="card-sub">
|
|
79
|
+
${n.statusFilter===`marketplace`?`Discover and install marketplace skills.`:`Installed skills and their status.`}
|
|
80
|
+
</div>
|
|
81
|
+
</div>
|
|
82
|
+
<button class="btn" ?disabled=${n.loading} @click=${n.onRefresh}>
|
|
83
|
+
${n.loading?`Loading...`:`Refresh`}
|
|
84
|
+
</button>
|
|
85
|
+
</div>
|
|
86
|
+
|
|
87
|
+
<div class="agent-tabs" style="margin-top: 14px;">
|
|
88
|
+
${u.map(t=>e`
|
|
89
|
+
<button
|
|
90
|
+
class="agent-tab ${n.statusFilter===t.id?`active`:``}"
|
|
91
|
+
@click=${()=>n.onStatusFilterChange(t.id)}
|
|
92
|
+
>
|
|
93
|
+
${t.label}<span class="agent-tab-count">${i[t.id]}</span>
|
|
94
|
+
</button>
|
|
95
|
+
`)}
|
|
96
|
+
</div>
|
|
97
|
+
|
|
98
|
+
${n.statusFilter===`marketplace`?g(n):e`
|
|
99
|
+
<div
|
|
100
|
+
class="filters"
|
|
101
|
+
style="display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-top: 12px;"
|
|
102
|
+
>
|
|
103
|
+
<label class="field" style="flex: 1; min-width: 180px;">
|
|
104
|
+
<input
|
|
105
|
+
.value=${n.filter}
|
|
106
|
+
@input=${e=>n.onFilterChange(e.target.value)}
|
|
107
|
+
placeholder="Search skills"
|
|
108
|
+
autocomplete="off"
|
|
109
|
+
name="skills-filter"
|
|
110
|
+
/>
|
|
111
|
+
</label>
|
|
112
|
+
<div class="muted">${c.length} shown</div>
|
|
113
|
+
</div>
|
|
114
|
+
|
|
115
|
+
${n.error?e`<div class="callout danger" style="margin-top: 12px;">${n.error}</div>`:t}
|
|
116
|
+
${c.length===0?e`
|
|
117
|
+
<div class="muted" style="margin-top: 16px">
|
|
118
|
+
${!n.connected&&!n.report?`Not connected to gateway.`:`No skills found.`}
|
|
119
|
+
</div>
|
|
120
|
+
`:e`
|
|
121
|
+
<div class="agent-skills-groups" style="margin-top: 16px;">
|
|
122
|
+
${l.map(t=>e`
|
|
123
|
+
<details class="agent-skills-group" open>
|
|
124
|
+
<summary class="agent-skills-header">
|
|
125
|
+
<span>${t.label}</span>
|
|
126
|
+
<span class="muted">${t.skills.length}</span>
|
|
127
|
+
</summary>
|
|
128
|
+
<div class="list skills-grid">
|
|
129
|
+
${t.skills.map(e=>y(e,n))}
|
|
130
|
+
</div>
|
|
131
|
+
</details>
|
|
132
|
+
`)}
|
|
133
|
+
</div>
|
|
134
|
+
`}
|
|
135
|
+
`}
|
|
136
|
+
</section>
|
|
137
|
+
|
|
138
|
+
${d?b(d,n):t}
|
|
139
|
+
`}function y(r,i){let a=i.busyKey===r.skillKey;return e`
|
|
140
|
+
<div class="list-item list-item-clickable" @click=${()=>i.onDetailOpen(r.skillKey)}>
|
|
141
|
+
<div class="list-main">
|
|
142
|
+
<div class="list-title" style="display: flex; align-items: center; gap: 8px;">
|
|
143
|
+
<span class="statusDot ${p(r)}"></span>
|
|
144
|
+
${r.emoji?e`<span>${r.emoji}</span>`:t}
|
|
145
|
+
<span>${r.name}</span>
|
|
146
|
+
</div>
|
|
147
|
+
<div class="list-sub">${n(r.description,140)}</div>
|
|
148
|
+
</div>
|
|
149
|
+
<div
|
|
150
|
+
class="list-meta"
|
|
151
|
+
style="display: flex; align-items: center; justify-content: flex-end; gap: 10px;"
|
|
152
|
+
>
|
|
153
|
+
<label class="skill-toggle-wrap" @click=${e=>e.stopPropagation()}>
|
|
154
|
+
<input
|
|
155
|
+
type="checkbox"
|
|
156
|
+
class="skill-toggle"
|
|
157
|
+
.checked=${!r.disabled}
|
|
158
|
+
?disabled=${a}
|
|
159
|
+
@change=${e=>{e.stopPropagation(),i.onToggle(r.skillKey,r.disabled)}}
|
|
160
|
+
/>
|
|
161
|
+
</label>
|
|
162
|
+
</div>
|
|
163
|
+
</div>
|
|
164
|
+
`}function b(n,r){let a=r.busyKey===n.skillKey,u=r.edits[n.skillKey]??``,d=r.messages[n.skillKey]??null,f=n.install.length>0&&n.missing.bins.length>0,m=!!(n.bundled&&n.source!==`openclaw-bundled`),h=c(n),g=o(n);return e`
|
|
165
|
+
<dialog
|
|
166
|
+
class="md-preview-dialog"
|
|
167
|
+
${i(e=>{!(e instanceof HTMLDialogElement)||e.open||e.showModal()})}
|
|
168
|
+
@click=${e=>{let t=e.currentTarget;e.target===t&&t.close()}}
|
|
169
|
+
@close=${r.onDetailClose}
|
|
170
|
+
>
|
|
171
|
+
<div class="md-preview-dialog__panel">
|
|
172
|
+
<div class="md-preview-dialog__header">
|
|
173
|
+
<div
|
|
174
|
+
class="md-preview-dialog__title"
|
|
175
|
+
style="display: flex; align-items: center; gap: 8px;"
|
|
176
|
+
>
|
|
177
|
+
<span class="statusDot ${p(n)}"></span>
|
|
178
|
+
${n.emoji?e`<span style="font-size: 18px;">${n.emoji}</span>`:t}
|
|
179
|
+
<span>${n.name}</span>
|
|
180
|
+
</div>
|
|
181
|
+
<button
|
|
182
|
+
class="btn btn--sm"
|
|
183
|
+
@click=${e=>{e.currentTarget.closest(`dialog`)?.close()}}
|
|
184
|
+
>
|
|
185
|
+
Close
|
|
186
|
+
</button>
|
|
187
|
+
</div>
|
|
188
|
+
<div class="md-preview-dialog__body" style="display: grid; gap: 16px;">
|
|
189
|
+
<div>
|
|
190
|
+
<div style="font-size: 14px; line-height: 1.5; color: var(--text);">
|
|
191
|
+
${n.description}
|
|
192
|
+
</div>
|
|
193
|
+
${s({skill:n,showBundledBadge:m})}
|
|
194
|
+
</div>
|
|
195
|
+
|
|
196
|
+
${h.length>0?e`
|
|
197
|
+
<div
|
|
198
|
+
class="callout"
|
|
199
|
+
style="border-color: var(--warn-subtle); background: var(--warn-subtle); color: var(--warn);"
|
|
200
|
+
>
|
|
201
|
+
<div style="font-weight: 600; margin-bottom: 4px;">Missing requirements</div>
|
|
202
|
+
<div>${h.join(`, `)}</div>
|
|
203
|
+
</div>
|
|
204
|
+
`:t}
|
|
205
|
+
${g.length>0?e`
|
|
206
|
+
<div class="muted" style="font-size: 13px;">Reason: ${g.join(`, `)}</div>
|
|
207
|
+
`:t}
|
|
208
|
+
|
|
209
|
+
<div style="display: flex; align-items: center; gap: 12px;">
|
|
210
|
+
<label class="skill-toggle-wrap">
|
|
211
|
+
<input
|
|
212
|
+
type="checkbox"
|
|
213
|
+
class="skill-toggle"
|
|
214
|
+
.checked=${!n.disabled}
|
|
215
|
+
?disabled=${a}
|
|
216
|
+
@change=${()=>r.onToggle(n.skillKey,n.disabled)}
|
|
217
|
+
/>
|
|
218
|
+
</label>
|
|
219
|
+
<span style="font-size: 13px; font-weight: 500;">
|
|
220
|
+
${n.disabled?`Disabled`:`Enabled`}
|
|
221
|
+
</span>
|
|
222
|
+
${f?e`<button
|
|
223
|
+
class="btn"
|
|
224
|
+
?disabled=${a}
|
|
225
|
+
@click=${()=>r.onInstall(n.skillKey,n.name,n.install[0].id)}
|
|
226
|
+
>
|
|
227
|
+
${a?`Installing...`:n.install[0].label}
|
|
228
|
+
</button>`:t}
|
|
229
|
+
</div>
|
|
230
|
+
|
|
231
|
+
${d?e`<div class="callout ${d.kind===`error`?`danger`:`success`}">
|
|
232
|
+
${d.message}
|
|
233
|
+
</div>`:t}
|
|
234
|
+
${n.primaryEnv?e`
|
|
235
|
+
<div style="display: grid; gap: 8px;">
|
|
236
|
+
<div class="field">
|
|
237
|
+
<span
|
|
238
|
+
>API key
|
|
239
|
+
<span class="muted" style="font-weight: normal; font-size: 0.88em;"
|
|
240
|
+
>(${n.primaryEnv})</span
|
|
241
|
+
></span
|
|
242
|
+
>
|
|
243
|
+
<input
|
|
244
|
+
type="password"
|
|
245
|
+
.value=${u}
|
|
246
|
+
@input=${e=>r.onEdit(n.skillKey,e.target.value)}
|
|
247
|
+
/>
|
|
248
|
+
</div>
|
|
249
|
+
${(()=>{let r=l(n.homepage);return r?e`<div class="muted" style="font-size: 13px;">
|
|
250
|
+
Get your key:
|
|
251
|
+
<a href="${r}" target="_blank" rel="noopener noreferrer"
|
|
252
|
+
>${n.homepage}</a
|
|
253
|
+
>
|
|
254
|
+
</div>`:t})()}
|
|
255
|
+
<button
|
|
256
|
+
class="btn primary"
|
|
257
|
+
?disabled=${a}
|
|
258
|
+
@click=${()=>r.onSaveKey(n.skillKey)}
|
|
259
|
+
>
|
|
260
|
+
Save key
|
|
261
|
+
</button>
|
|
262
|
+
</div>
|
|
263
|
+
`:t}
|
|
264
|
+
|
|
265
|
+
<div
|
|
266
|
+
style="border-top: 1px solid var(--border); padding-top: 12px; display: grid; gap: 6px; font-size: 12px; color: var(--muted);"
|
|
267
|
+
>
|
|
268
|
+
<div><span style="font-weight: 600;">Source:</span> ${n.source}</div>
|
|
269
|
+
<div style="font-family: var(--mono); word-break: break-all;">${n.filePath}</div>
|
|
270
|
+
${(()=>{let r=l(n.homepage);return r?e`<div>
|
|
271
|
+
<a href="${r}" target="_blank" rel="noopener noreferrer"
|
|
272
|
+
>${n.homepage}</a
|
|
273
|
+
>
|
|
274
|
+
</div>`:t})()}
|
|
275
|
+
</div>
|
|
276
|
+
</div>
|
|
277
|
+
</div>
|
|
278
|
+
</dialog>
|
|
279
|
+
`}export{v as renderSkills};
|
|
280
|
+
//# sourceMappingURL=skills-D1vP4MkL.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skills-D1vP4MkL.js","names":[],"sources":["../../../ui/src/ui/views/skills.ts"],"sourcesContent":["import { html, nothing } from \"lit\";\nimport { ref } from \"lit/directives/ref.js\";\nimport type {\n KovaMarketplaceCategory,\n KovaMarketplaceSkill,\n SkillMessageMap,\n} from \"../controllers/skills.ts\";\nimport { clampText } from \"../format.ts\";\nimport { resolveSafeExternalUrl } from \"../open-external-url.ts\";\nimport type { SkillStatusEntry, SkillStatusReport } from \"../types.ts\";\nimport { groupSkills } from \"./skills-grouping.ts\";\nimport {\n computeSkillMissing,\n computeSkillReasons,\n renderSkillStatusChips,\n} from \"./skills-shared.ts\";\n\nfunction safeExternalHref(raw?: string): string | null {\n if (!raw) {\n return null;\n }\n return resolveSafeExternalUrl(raw, window.location.href);\n}\n\nexport type SkillsStatusFilter = \"all\" | \"ready\" | \"needs-setup\" | \"disabled\" | \"marketplace\";\n\nexport type SkillsProps = {\n connected: boolean;\n loading: boolean;\n report: SkillStatusReport | null;\n error: string | null;\n filter: string;\n statusFilter: SkillsStatusFilter;\n edits: Record<string, string>;\n busyKey: string | null;\n messages: SkillMessageMap;\n detailKey: string | null;\n kova_marketplaceLoading: boolean;\n kova_marketplaceSkills: KovaMarketplaceSkill[];\n kova_marketplaceError: string | null;\n kova_marketplaceCategory: KovaMarketplaceCategory;\n kova_marketplaceInstalledIds: string[];\n kova_marketplaceBusyId: string | null;\n onFilterChange: (next: string) => void;\n onStatusFilterChange: (next: SkillsStatusFilter) => void;\n onRefresh: () => void;\n onToggle: (skillKey: string, enabled: boolean) => void;\n onEdit: (skillKey: string, value: string) => void;\n onSaveKey: (skillKey: string) => void;\n onInstall: (skillKey: string, name: string, installId: string) => void;\n onDetailOpen: (skillKey: string) => void;\n onDetailClose: () => void;\n onKovaMarketplaceCategoryChange: (next: KovaMarketplaceCategory) => void;\n onKovaMarketplaceInstall: (skill: KovaMarketplaceSkill) => void;\n};\n\ntype StatusTabDef = { id: SkillsStatusFilter; label: string };\ntype KovaCategoryTabDef = { id: KovaMarketplaceCategory; label: string };\n\nconst STATUS_TABS: StatusTabDef[] = [\n { id: \"all\", label: \"All\" },\n { id: \"ready\", label: \"Ready\" },\n { id: \"needs-setup\", label: \"Needs Setup\" },\n { id: \"disabled\", label: \"Disabled\" },\n { id: \"marketplace\", label: \"Marketplace\" },\n];\n\nconst KOVA_CATEGORY_TABS: KovaCategoryTabDef[] = [\n { id: \"all\", label: \"All\" },\n { id: \"Productivity\", label: \"Productivity\" },\n { id: \"News\", label: \"News\" },\n { id: \"Finance\", label: \"Finance\" },\n { id: \"Developer\", label: \"Developer\" },\n { id: \"Social\", label: \"Social\" },\n];\n\nfunction skillMatchesStatus(skill: SkillStatusEntry, status: Exclude<SkillsStatusFilter, \"marketplace\">): boolean {\n switch (status) {\n case \"all\":\n return true;\n case \"ready\":\n return !skill.disabled && skill.eligible;\n case \"needs-setup\":\n return !skill.disabled && !skill.eligible;\n case \"disabled\":\n return skill.disabled;\n }\n}\n\nfunction skillStatusClass(skill: SkillStatusEntry): string {\n if (skill.disabled) {\n return \"muted\";\n }\n return skill.eligible ? \"ok\" : \"warn\";\n}\n\nfunction kova_marketplaceMatchesFilter(skill: KovaMarketplaceSkill, filter: string): boolean {\n if (!filter) {\n return true;\n }\n const haystack = [skill.name, skill.description].join(\" \").toLowerCase();\n return haystack.includes(filter);\n}\n\nfunction kova_marketplaceMatchesCategory(\n skill: KovaMarketplaceSkill,\n category: KovaMarketplaceCategory,\n): boolean {\n return category === \"all\" || skill.category === category;\n}\n\nfunction kova_renderMarketplace(props: SkillsProps) {\n const filter = props.filter.trim().toLowerCase();\n const filtered = props.kova_marketplaceSkills.filter(\n (skill) =>\n kova_marketplaceMatchesCategory(skill, props.kova_marketplaceCategory) &&\n kova_marketplaceMatchesFilter(skill, filter),\n );\n\n return html`\n <div\n class=\"filters\"\n style=\"display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-top: 12px;\"\n >\n <label class=\"field\" style=\"flex: 1; min-width: 180px;\">\n <input\n .value=${props.filter}\n @input=${(e: Event) => props.onFilterChange((e.target as HTMLInputElement).value)}\n placeholder=\"Search marketplace\"\n autocomplete=\"off\"\n name=\"skills-filter\"\n />\n </label>\n <div class=\"muted\">${filtered.length} shown</div>\n </div>\n\n <div class=\"agent-tabs\" style=\"margin-top: 12px; flex-wrap: wrap;\">\n ${KOVA_CATEGORY_TABS.map(\n (tab) => html`\n <button\n class=\"agent-tab ${props.kova_marketplaceCategory === tab.id ? \"active\" : \"\"}\"\n @click=${() => props.onKovaMarketplaceCategoryChange(tab.id)}\n >\n ${tab.label}\n </button>\n `,\n )}\n </div>\n\n ${props.kova_marketplaceError\n ? html`<div class=\"callout danger\" style=\"margin-top: 12px;\">${props.kova_marketplaceError}</div>`\n : nothing}\n\n ${filtered.length === 0\n ? html`\n <div class=\"muted\" style=\"margin-top: 16px;\">\n ${props.kova_marketplaceLoading ? \"Loading marketplace...\" : \"No marketplace skills found.\"}\n </div>\n `\n : html`\n <div\n class=\"kova-marketplace-grid\"\n style=\"display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 12px; margin-top: 16px;\"\n >\n ${filtered.map((skill) => kova_renderMarketplaceCard(skill, props))}\n </div>\n `}\n `;\n}\n\nfunction kova_renderMarketplaceCard(skill: KovaMarketplaceSkill, props: SkillsProps) {\n const installed = props.kova_marketplaceInstalledIds.includes(skill.id);\n const busy = props.kova_marketplaceBusyId === skill.id;\n const buttonLabel = installed ? \"Installed\" : busy ? \"Installing...\" : \"Install\";\n\n return html`\n <div\n class=\"list-item\"\n style=\"display: grid; grid-template-columns: minmax(0, 3fr) minmax(96px, 1fr); gap: 14px; align-items: start; border: 1px solid var(--border);\"\n >\n <div class=\"list-main\" style=\"min-width: 0;\">\n <div class=\"list-title\" style=\"display: flex; align-items: center; gap: 8px; flex-wrap: wrap;\">\n <span>${skill.name}</span>\n <span class=\"chip\">${skill.category}</span>\n ${skill.free ? html`<span class=\"chip chip-ok\">Free</span>` : nothing}\n ${installed ? html`<span class=\"chip\">Installed</span>` : nothing}\n </div>\n <div\n class=\"list-sub\"\n style=\"margin-top: 6px; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;\"\n >\n ${skill.description || \"No description provided.\"}\n </div>\n <div class=\"muted\" style=\"margin-top: 8px; font-size: 12px;\">By ${skill.author}</div>\n </div>\n <div style=\"display: flex; justify-content: flex-end;\">\n <button\n class=\"btn ${installed ? \"\" : \"primary\"}\"\n ?disabled=${installed || busy || !props.connected}\n @click=${() => props.onKovaMarketplaceInstall(skill)}\n >\n ${buttonLabel}\n </button>\n </div>\n </div>\n `;\n}\n\nexport function renderSkills(props: SkillsProps) {\n const skills = props.report?.skills ?? [];\n\n const statusCounts: Record<SkillsStatusFilter, number> = {\n all: skills.length,\n ready: 0,\n \"needs-setup\": 0,\n disabled: 0,\n marketplace: props.kova_marketplaceSkills.length,\n };\n for (const s of skills) {\n if (s.disabled) {\n statusCounts.disabled++;\n } else if (s.eligible) {\n statusCounts.ready++;\n } else {\n statusCounts[\"needs-setup\"]++;\n }\n }\n\n const afterStatus =\n props.statusFilter === \"marketplace\"\n ? skills\n : props.statusFilter === \"all\"\n ? skills\n : skills.filter((s) => skillMatchesStatus(s, props.statusFilter));\n\n const filter = props.filter.trim().toLowerCase();\n const filtered = filter\n ? afterStatus.filter((skill) =>\n [skill.name, skill.description, skill.source].join(\" \").toLowerCase().includes(filter),\n )\n : afterStatus;\n const groups = groupSkills(filtered);\n\n const detailSkill =\n props.statusFilter !== \"marketplace\" && props.detailKey\n ? (skills.find((s) => s.skillKey === props.detailKey) ?? null)\n : null;\n\n return html`\n <section class=\"card\">\n <div class=\"row\" style=\"justify-content: space-between;\">\n <div>\n <div class=\"card-title\">Skills</div>\n <div class=\"card-sub\">\n ${props.statusFilter === \"marketplace\"\n ? \"Discover and install marketplace skills.\"\n : \"Installed skills and their status.\"}\n </div>\n </div>\n <button class=\"btn\" ?disabled=${props.loading} @click=${props.onRefresh}>\n ${props.loading ? \"Loading...\" : \"Refresh\"}\n </button>\n </div>\n\n <div class=\"agent-tabs\" style=\"margin-top: 14px;\">\n ${STATUS_TABS.map(\n (tab) => html`\n <button\n class=\"agent-tab ${props.statusFilter === tab.id ? \"active\" : \"\"}\"\n @click=${() => props.onStatusFilterChange(tab.id)}\n >\n ${tab.label}<span class=\"agent-tab-count\">${statusCounts[tab.id]}</span>\n </button>\n `,\n )}\n </div>\n\n ${props.statusFilter === \"marketplace\"\n ? kova_renderMarketplace(props)\n : html`\n <div\n class=\"filters\"\n style=\"display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-top: 12px;\"\n >\n <label class=\"field\" style=\"flex: 1; min-width: 180px;\">\n <input\n .value=${props.filter}\n @input=${(e: Event) => props.onFilterChange((e.target as HTMLInputElement).value)}\n placeholder=\"Search skills\"\n autocomplete=\"off\"\n name=\"skills-filter\"\n />\n </label>\n <div class=\"muted\">${filtered.length} shown</div>\n </div>\n\n ${props.error\n ? html`<div class=\"callout danger\" style=\"margin-top: 12px;\">${props.error}</div>`\n : nothing}\n ${filtered.length === 0\n ? html`\n <div class=\"muted\" style=\"margin-top: 16px\">\n ${!props.connected && !props.report\n ? \"Not connected to gateway.\"\n : \"No skills found.\"}\n </div>\n `\n : html`\n <div class=\"agent-skills-groups\" style=\"margin-top: 16px;\">\n ${groups.map(\n (group) => html`\n <details class=\"agent-skills-group\" open>\n <summary class=\"agent-skills-header\">\n <span>${group.label}</span>\n <span class=\"muted\">${group.skills.length}</span>\n </summary>\n <div class=\"list skills-grid\">\n ${group.skills.map((skill) => renderSkill(skill, props))}\n </div>\n </details>\n `,\n )}\n </div>\n `}\n `}\n </section>\n\n ${detailSkill ? renderSkillDetail(detailSkill, props) : nothing}\n `;\n}\n\nfunction renderSkill(skill: SkillStatusEntry, props: SkillsProps) {\n const busy = props.busyKey === skill.skillKey;\n const dotClass = skillStatusClass(skill);\n\n return html`\n <div class=\"list-item list-item-clickable\" @click=${() => props.onDetailOpen(skill.skillKey)}>\n <div class=\"list-main\">\n <div class=\"list-title\" style=\"display: flex; align-items: center; gap: 8px;\">\n <span class=\"statusDot ${dotClass}\"></span>\n ${skill.emoji ? html`<span>${skill.emoji}</span>` : nothing}\n <span>${skill.name}</span>\n </div>\n <div class=\"list-sub\">${clampText(skill.description, 140)}</div>\n </div>\n <div\n class=\"list-meta\"\n style=\"display: flex; align-items: center; justify-content: flex-end; gap: 10px;\"\n >\n <label class=\"skill-toggle-wrap\" @click=${(e: Event) => e.stopPropagation()}>\n <input\n type=\"checkbox\"\n class=\"skill-toggle\"\n .checked=${!skill.disabled}\n ?disabled=${busy}\n @change=${(e: Event) => {\n e.stopPropagation();\n props.onToggle(skill.skillKey, skill.disabled);\n }}\n />\n </label>\n </div>\n </div>\n `;\n}\n\nfunction renderSkillDetail(skill: SkillStatusEntry, props: SkillsProps) {\n const busy = props.busyKey === skill.skillKey;\n const apiKey = props.edits[skill.skillKey] ?? \"\";\n const message = props.messages[skill.skillKey] ?? null;\n const canInstall = skill.install.length > 0 && skill.missing.bins.length > 0;\n const showBundledBadge = Boolean(skill.bundled && skill.source !== \"openclaw-bundled\");\n const missing = computeSkillMissing(skill);\n const reasons = computeSkillReasons(skill);\n const ensureModalOpen = (el?: Element) => {\n if (!(el instanceof HTMLDialogElement) || el.open) {\n return;\n }\n el.showModal();\n };\n\n return html`\n <dialog\n class=\"md-preview-dialog\"\n ${ref(ensureModalOpen)}\n @click=${(e: Event) => {\n const dialog = e.currentTarget as HTMLDialogElement;\n if (e.target === dialog) {\n dialog.close();\n }\n }}\n @close=${props.onDetailClose}\n >\n <div class=\"md-preview-dialog__panel\">\n <div class=\"md-preview-dialog__header\">\n <div\n class=\"md-preview-dialog__title\"\n style=\"display: flex; align-items: center; gap: 8px;\"\n >\n <span class=\"statusDot ${skillStatusClass(skill)}\"></span>\n ${skill.emoji ? html`<span style=\"font-size: 18px;\">${skill.emoji}</span>` : nothing}\n <span>${skill.name}</span>\n </div>\n <button\n class=\"btn btn--sm\"\n @click=${(e: Event) => {\n (e.currentTarget as HTMLElement).closest(\"dialog\")?.close();\n }}\n >\n Close\n </button>\n </div>\n <div class=\"md-preview-dialog__body\" style=\"display: grid; gap: 16px;\">\n <div>\n <div style=\"font-size: 14px; line-height: 1.5; color: var(--text);\">\n ${skill.description}\n </div>\n ${renderSkillStatusChips({ skill, showBundledBadge })}\n </div>\n\n ${missing.length > 0\n ? html`\n <div\n class=\"callout\"\n style=\"border-color: var(--warn-subtle); background: var(--warn-subtle); color: var(--warn);\"\n >\n <div style=\"font-weight: 600; margin-bottom: 4px;\">Missing requirements</div>\n <div>${missing.join(\", \")}</div>\n </div>\n `\n : nothing}\n ${reasons.length > 0\n ? html`\n <div class=\"muted\" style=\"font-size: 13px;\">Reason: ${reasons.join(\", \")}</div>\n `\n : nothing}\n\n <div style=\"display: flex; align-items: center; gap: 12px;\">\n <label class=\"skill-toggle-wrap\">\n <input\n type=\"checkbox\"\n class=\"skill-toggle\"\n .checked=${!skill.disabled}\n ?disabled=${busy}\n @change=${() => props.onToggle(skill.skillKey, skill.disabled)}\n />\n </label>\n <span style=\"font-size: 13px; font-weight: 500;\">\n ${skill.disabled ? \"Disabled\" : \"Enabled\"}\n </span>\n ${canInstall\n ? html`<button\n class=\"btn\"\n ?disabled=${busy}\n @click=${() => props.onInstall(skill.skillKey, skill.name, skill.install[0].id)}\n >\n ${busy ? \"Installing...\" : skill.install[0].label}\n </button>`\n : nothing}\n </div>\n\n ${message\n ? html`<div class=\"callout ${message.kind === \"error\" ? \"danger\" : \"success\"}\">\n ${message.message}\n </div>`\n : nothing}\n ${skill.primaryEnv\n ? html`\n <div style=\"display: grid; gap: 8px;\">\n <div class=\"field\">\n <span\n >API key\n <span class=\"muted\" style=\"font-weight: normal; font-size: 0.88em;\"\n >(${skill.primaryEnv})</span\n ></span\n >\n <input\n type=\"password\"\n .value=${apiKey}\n @input=${(e: Event) =>\n props.onEdit(skill.skillKey, (e.target as HTMLInputElement).value)}\n />\n </div>\n ${(() => {\n const href = safeExternalHref(skill.homepage);\n return href\n ? html`<div class=\"muted\" style=\"font-size: 13px;\">\n Get your key:\n <a href=\"${href}\" target=\"_blank\" rel=\"noopener noreferrer\"\n >${skill.homepage}</a\n >\n </div>`\n : nothing;\n })()}\n <button\n class=\"btn primary\"\n ?disabled=${busy}\n @click=${() => props.onSaveKey(skill.skillKey)}\n >\n Save key\n </button>\n </div>\n `\n : nothing}\n\n <div\n style=\"border-top: 1px solid var(--border); padding-top: 12px; display: grid; gap: 6px; font-size: 12px; color: var(--muted);\"\n >\n <div><span style=\"font-weight: 600;\">Source:</span> ${skill.source}</div>\n <div style=\"font-family: var(--mono); word-break: break-all;\">${skill.filePath}</div>\n ${(() => {\n const safeHref = safeExternalHref(skill.homepage);\n return safeHref\n ? html`<div>\n <a href=\"${safeHref}\" target=\"_blank\" rel=\"noopener noreferrer\"\n >${skill.homepage}</a\n >\n </div>`\n : nothing;\n })()}\n </div>\n </div>\n </div>\n </dialog>\n `;\n}"],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import{i as e,n as t}from"./lit-zdTgzAJI.js";var n=[{id:`workspace`,label:`Workspace Skills`,sources:[`openclaw-workspace`]},{id:`built-in`,label:`Built-in Skills`,sources:[`openclaw-bundled`]},{id:`installed`,label:`Installed Skills`,sources:[`openclaw-managed`]},{id:`extra`,label:`Extra Skills`,sources:[`openclaw-extra`]}];function r(e){let t=new Map;for(let e of n)t.set(e.id,{id:e.id,label:e.label,skills:[]});let r=n.find(e=>e.id===`built-in`),i={id:`other`,label:`Other Skills`,skills:[]};for(let a of e){let e=a.bundled?r:n.find(e=>e.sources.includes(a.source));e?t.get(e.id)?.skills.push(a):i.skills.push(a)}let a=n.map(e=>t.get(e.id)).filter(e=>!!(e&&e.skills.length>0));return i.skills.length>0&&a.push(i),a}function i(e){return[...e.missing.bins.map(e=>`bin:${e}`),...e.missing.env.map(e=>`env:${e}`),...e.missing.config.map(e=>`config:${e}`),...e.missing.os.map(e=>`os:${e}`)]}function a(e){let t=[];return e.disabled&&t.push(`disabled`),e.blockedByAllowlist&&t.push(`blocked by allowlist`),t}function o(n){let r=n.skill,i=!!n.showBundledBadge;return e`
|
|
2
|
+
<div class="chip-row" style="margin-top: 6px;">
|
|
3
|
+
<span class="chip">${r.source}</span>
|
|
4
|
+
${i?e` <span class="chip">bundled</span> `:t}
|
|
5
|
+
<span class="chip ${r.eligible?`chip-ok`:`chip-warn`}">
|
|
6
|
+
${r.eligible?`eligible`:`blocked`}
|
|
7
|
+
</span>
|
|
8
|
+
${r.disabled?e` <span class="chip chip-warn">disabled</span> `:t}
|
|
9
|
+
</div>
|
|
10
|
+
`}export{r as i,a as n,o as r,i as t};
|
|
11
|
+
//# sourceMappingURL=skills-shared-Bg0Qcnkp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skills-shared-Bg0Qcnkp.js","names":[],"sources":["../../../ui/src/ui/views/skills-grouping.ts","../../../ui/src/ui/views/skills-shared.ts"],"sourcesContent":["import type { SkillStatusEntry } from \"../types.ts\";\n\nexport type SkillGroup = {\n id: string;\n label: string;\n skills: SkillStatusEntry[];\n};\n\nconst SKILL_SOURCE_GROUPS: Array<{ id: string; label: string; sources: string[] }> = [\n { id: \"workspace\", label: \"Workspace Skills\", sources: [\"openclaw-workspace\"] },\n { id: \"built-in\", label: \"Built-in Skills\", sources: [\"openclaw-bundled\"] },\n { id: \"installed\", label: \"Installed Skills\", sources: [\"openclaw-managed\"] },\n { id: \"extra\", label: \"Extra Skills\", sources: [\"openclaw-extra\"] },\n];\n\nexport function groupSkills(skills: SkillStatusEntry[]): SkillGroup[] {\n const groups = new Map<string, SkillGroup>();\n for (const def of SKILL_SOURCE_GROUPS) {\n groups.set(def.id, { id: def.id, label: def.label, skills: [] });\n }\n const builtInGroup = SKILL_SOURCE_GROUPS.find((group) => group.id === \"built-in\");\n const other: SkillGroup = { id: \"other\", label: \"Other Skills\", skills: [] };\n for (const skill of skills) {\n const match = skill.bundled\n ? builtInGroup\n : SKILL_SOURCE_GROUPS.find((group) => group.sources.includes(skill.source));\n if (match) {\n groups.get(match.id)?.skills.push(skill);\n } else {\n other.skills.push(skill);\n }\n }\n const ordered = SKILL_SOURCE_GROUPS.map((group) => groups.get(group.id)).filter(\n (group): group is SkillGroup => Boolean(group && group.skills.length > 0),\n );\n if (other.skills.length > 0) {\n ordered.push(other);\n }\n return ordered;\n}\n","import { html, nothing } from \"lit\";\nimport type { SkillStatusEntry } from \"../types.ts\";\n\nexport function computeSkillMissing(skill: SkillStatusEntry): string[] {\n return [\n ...skill.missing.bins.map((b) => `bin:${b}`),\n ...skill.missing.env.map((e) => `env:${e}`),\n ...skill.missing.config.map((c) => `config:${c}`),\n ...skill.missing.os.map((o) => `os:${o}`),\n ];\n}\n\nexport function computeSkillReasons(skill: SkillStatusEntry): string[] {\n const reasons: string[] = [];\n if (skill.disabled) {\n reasons.push(\"disabled\");\n }\n if (skill.blockedByAllowlist) {\n reasons.push(\"blocked by allowlist\");\n }\n return reasons;\n}\n\nexport function renderSkillStatusChips(params: {\n skill: SkillStatusEntry;\n showBundledBadge?: boolean;\n}) {\n const skill = params.skill;\n const showBundledBadge = Boolean(params.showBundledBadge);\n return html`\n <div class=\"chip-row\" style=\"margin-top: 6px;\">\n <span class=\"chip\">${skill.source}</span>\n ${showBundledBadge ? html` <span class=\"chip\">bundled</span> ` : nothing}\n <span class=\"chip ${skill.eligible ? \"chip-ok\" : \"chip-warn\"}\">\n ${skill.eligible ? \"eligible\" : \"blocked\"}\n </span>\n ${skill.disabled ? html` <span class=\"chip chip-warn\">disabled</span> ` : nothing}\n </div>\n `;\n}\n"],"mappings":"6CAQA,IAAM,EAA+E,CACnF,CAAE,GAAI,YAAa,MAAO,mBAAoB,QAAS,CAAC,qBAAqB,CAAE,CAC/E,CAAE,GAAI,WAAY,MAAO,kBAAmB,QAAS,CAAC,mBAAmB,CAAE,CAC3E,CAAE,GAAI,YAAa,MAAO,mBAAoB,QAAS,CAAC,mBAAmB,CAAE,CAC7E,CAAE,GAAI,QAAS,MAAO,eAAgB,QAAS,CAAC,iBAAiB,CAAE,CACpE,CAED,SAAgB,EAAY,EAA0C,CACpE,IAAM,EAAS,IAAI,IACnB,IAAK,IAAM,KAAO,EAChB,EAAO,IAAI,EAAI,GAAI,CAAE,GAAI,EAAI,GAAI,MAAO,EAAI,MAAO,OAAQ,EAAE,CAAE,CAAC,CAElE,IAAM,EAAe,EAAoB,KAAM,GAAU,EAAM,KAAO,WAAW,CAC3E,EAAoB,CAAE,GAAI,QAAS,MAAO,eAAgB,OAAQ,EAAE,CAAE,CAC5E,IAAK,IAAM,KAAS,EAAQ,CAC1B,IAAM,EAAQ,EAAM,QAChB,EACA,EAAoB,KAAM,GAAU,EAAM,QAAQ,SAAS,EAAM,OAAO,CAAC,CACzE,EACF,EAAO,IAAI,EAAM,GAAG,EAAE,OAAO,KAAK,EAAM,CAExC,EAAM,OAAO,KAAK,EAAM,CAG5B,IAAM,EAAU,EAAoB,IAAK,GAAU,EAAO,IAAI,EAAM,GAAG,CAAC,CAAC,OACtE,GAA+B,GAAQ,GAAS,EAAM,OAAO,OAAS,GACxE,CAID,OAHI,EAAM,OAAO,OAAS,GACxB,EAAQ,KAAK,EAAM,CAEd,ECnCT,SAAgB,EAAoB,EAAmC,CACrE,MAAO,CACL,GAAG,EAAM,QAAQ,KAAK,IAAK,GAAM,OAAO,IAAI,CAC5C,GAAG,EAAM,QAAQ,IAAI,IAAK,GAAM,OAAO,IAAI,CAC3C,GAAG,EAAM,QAAQ,OAAO,IAAK,GAAM,UAAU,IAAI,CACjD,GAAG,EAAM,QAAQ,GAAG,IAAK,GAAM,MAAM,IAAI,CAC1C,CAGH,SAAgB,EAAoB,EAAmC,CACrE,IAAM,EAAoB,EAAE,CAO5B,OANI,EAAM,UACR,EAAQ,KAAK,WAAW,CAEtB,EAAM,oBACR,EAAQ,KAAK,uBAAuB,CAE/B,EAGT,SAAgB,EAAuB,EAGpC,CACD,IAAM,EAAQ,EAAO,MACf,EAAmB,EAAQ,EAAO,iBACxC,MAAO,EAAI;;2BAEc,EAAM,OAAO;QAChC,EAAmB,CAAI,sCAAwC,EAAQ;0BACrD,EAAM,SAAW,UAAY,YAAY;UACzD,EAAM,SAAW,WAAa,UAAU;;QAE1C,EAAM,SAAW,CAAI,iDAAmD,EAAQ"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
function e(e){return e.replace(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g,``)}function t(e,t,n){return{temperature:t?.temperature,maxTokens:t?.maxTokens||Math.min(e.maxTokens,32e3),signal:t?.signal,apiKey:n||t?.apiKey,cacheRetention:t?.cacheRetention,sessionId:t?.sessionId,headers:t?.headers,onPayload:t?.onPayload,maxRetryDelayMs:t?.maxRetryDelayMs,metadata:t?.metadata}}function n(e){return e===`xhigh`?`high`:e}function r(e,t,r,i){let a={minimal:1024,low:2048,medium:8192,high:16384,...i}[n(r)],o=Math.min(e+a,t);return o<=a&&(a=Math.max(0,o-1024)),{maxTokens:o,thinkingBudget:a}}function i(e,t,n){let r=new Map,i=e.map(e=>{if(e.role===`user`)return e;if(e.role===`toolResult`){let t=r.get(e.toolCallId);return t&&t!==e.toolCallId?{...e,toolCallId:t}:e}if(e.role===`assistant`){let i=e,a=i.provider===t.provider&&i.api===t.api&&i.model===t.id,o=i.content.flatMap(e=>{if(e.type===`thinking`)return e.redacted?a?e:[]:a&&e.thinkingSignature?e:!e.thinking||e.thinking.trim()===``?[]:a?e:{type:`text`,text:e.thinking};if(e.type===`text`)return a?e:{type:`text`,text:e.text};if(e.type===`toolCall`){let o=e,s=o;if(!a&&o.thoughtSignature&&(s={...o},delete s.thoughtSignature),!a&&n){let e=n(o.id,t,i);e!==o.id&&(r.set(o.id,e),s={...s,id:e})}return s}return e});return{...i,content:o}}return e}),a=[],o=[],s=new Set;for(let e=0;e<i.length;e++){let t=i[e];if(t.role===`assistant`){if(o.length>0){for(let e of o)s.has(e.id)||a.push({role:`toolResult`,toolCallId:e.id,toolName:e.name,content:[{type:`text`,text:`No result provided`}],isError:!0,timestamp:Date.now()});o=[],s=new Set}let e=t;if(e.stopReason===`error`||e.stopReason===`aborted`)continue;let n=e.content.filter(e=>e.type===`toolCall`);n.length>0&&(o=n,s=new Set),a.push(t)}else if(t.role===`toolResult`)s.add(t.toolCallId),a.push(t);else if(t.role===`user`){if(o.length>0){for(let e of o)s.has(e.id)||a.push({role:`toolResult`,toolCallId:e.id,toolName:e.name,content:[{type:`text`,text:`No result provided`}],isError:!0,timestamp:Date.now()});o=[],s=new Set}a.push(t)}else a.push(t)}return a}export{e as a,n as i,r as n,t as r,i as t};
|
|
2
|
+
//# sourceMappingURL=transform-messages-XKqwKV3D.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transform-messages-XKqwKV3D.js","names":[],"sources":["../../../node_modules/@mariozechner/pi-ai/dist/utils/sanitize-unicode.js","../../../node_modules/@mariozechner/pi-ai/dist/providers/simple-options.js","../../../node_modules/@mariozechner/pi-ai/dist/providers/transform-messages.js"],"sourcesContent":["/**\n * Removes unpaired Unicode surrogate characters from a string.\n *\n * Unpaired surrogates (high surrogates 0xD800-0xDBFF without matching low surrogates 0xDC00-0xDFFF,\n * or vice versa) cause JSON serialization errors in many API providers.\n *\n * Valid emoji and other characters outside the Basic Multilingual Plane use properly paired\n * surrogates and will NOT be affected by this function.\n *\n * @param text - The text to sanitize\n * @returns The sanitized text with unpaired surrogates removed\n *\n * @example\n * // Valid emoji (properly paired surrogates) are preserved\n * sanitizeSurrogates(\"Hello 🙈 World\") // => \"Hello 🙈 World\"\n *\n * // Unpaired high surrogate is removed\n * const unpaired = String.fromCharCode(0xD83D); // high surrogate without low\n * sanitizeSurrogates(`Text ${unpaired} here`) // => \"Text here\"\n */\nexport function sanitizeSurrogates(text) {\n // Replace unpaired high surrogates (0xD800-0xDBFF not followed by low surrogate)\n // Replace unpaired low surrogates (0xDC00-0xDFFF not preceded by high surrogate)\n return text.replace(/[\\uD800-\\uDBFF](?![\\uDC00-\\uDFFF])|(?<![\\uD800-\\uDBFF])[\\uDC00-\\uDFFF]/g, \"\");\n}\n//# sourceMappingURL=sanitize-unicode.js.map","export function buildBaseOptions(model, options, apiKey) {\n return {\n temperature: options?.temperature,\n maxTokens: options?.maxTokens || Math.min(model.maxTokens, 32000),\n signal: options?.signal,\n apiKey: apiKey || options?.apiKey,\n cacheRetention: options?.cacheRetention,\n sessionId: options?.sessionId,\n headers: options?.headers,\n onPayload: options?.onPayload,\n maxRetryDelayMs: options?.maxRetryDelayMs,\n metadata: options?.metadata,\n };\n}\nexport function clampReasoning(effort) {\n return effort === \"xhigh\" ? \"high\" : effort;\n}\nexport function adjustMaxTokensForThinking(baseMaxTokens, modelMaxTokens, reasoningLevel, customBudgets) {\n const defaultBudgets = {\n minimal: 1024,\n low: 2048,\n medium: 8192,\n high: 16384,\n };\n const budgets = { ...defaultBudgets, ...customBudgets };\n const minOutputTokens = 1024;\n const level = clampReasoning(reasoningLevel);\n let thinkingBudget = budgets[level];\n const maxTokens = Math.min(baseMaxTokens + thinkingBudget, modelMaxTokens);\n if (maxTokens <= thinkingBudget) {\n thinkingBudget = Math.max(0, maxTokens - minOutputTokens);\n }\n return { maxTokens, thinkingBudget };\n}\n//# sourceMappingURL=simple-options.js.map","/**\n * Normalize tool call ID for cross-provider compatibility.\n * OpenAI Responses API generates IDs that are 450+ chars with special characters like `|`.\n * Anthropic APIs require IDs matching ^[a-zA-Z0-9_-]+$ (max 64 chars).\n */\nexport function transformMessages(messages, model, normalizeToolCallId) {\n // Build a map of original tool call IDs to normalized IDs\n const toolCallIdMap = new Map();\n // First pass: transform messages (thinking blocks, tool call ID normalization)\n const transformed = messages.map((msg) => {\n // User messages pass through unchanged\n if (msg.role === \"user\") {\n return msg;\n }\n // Handle toolResult messages - normalize toolCallId if we have a mapping\n if (msg.role === \"toolResult\") {\n const normalizedId = toolCallIdMap.get(msg.toolCallId);\n if (normalizedId && normalizedId !== msg.toolCallId) {\n return { ...msg, toolCallId: normalizedId };\n }\n return msg;\n }\n // Assistant messages need transformation check\n if (msg.role === \"assistant\") {\n const assistantMsg = msg;\n const isSameModel = assistantMsg.provider === model.provider &&\n assistantMsg.api === model.api &&\n assistantMsg.model === model.id;\n const transformedContent = assistantMsg.content.flatMap((block) => {\n if (block.type === \"thinking\") {\n // Redacted thinking is opaque encrypted content, only valid for the same model.\n // Drop it for cross-model to avoid API errors.\n if (block.redacted) {\n return isSameModel ? block : [];\n }\n // For same model: keep thinking blocks with signatures (needed for replay)\n // even if the thinking text is empty (OpenAI encrypted reasoning)\n if (isSameModel && block.thinkingSignature)\n return block;\n // Skip empty thinking blocks, convert others to plain text\n if (!block.thinking || block.thinking.trim() === \"\")\n return [];\n if (isSameModel)\n return block;\n return {\n type: \"text\",\n text: block.thinking,\n };\n }\n if (block.type === \"text\") {\n if (isSameModel)\n return block;\n return {\n type: \"text\",\n text: block.text,\n };\n }\n if (block.type === \"toolCall\") {\n const toolCall = block;\n let normalizedToolCall = toolCall;\n if (!isSameModel && toolCall.thoughtSignature) {\n normalizedToolCall = { ...toolCall };\n delete normalizedToolCall.thoughtSignature;\n }\n if (!isSameModel && normalizeToolCallId) {\n const normalizedId = normalizeToolCallId(toolCall.id, model, assistantMsg);\n if (normalizedId !== toolCall.id) {\n toolCallIdMap.set(toolCall.id, normalizedId);\n normalizedToolCall = { ...normalizedToolCall, id: normalizedId };\n }\n }\n return normalizedToolCall;\n }\n return block;\n });\n return {\n ...assistantMsg,\n content: transformedContent,\n };\n }\n return msg;\n });\n // Second pass: insert synthetic empty tool results for orphaned tool calls\n // This preserves thinking signatures and satisfies API requirements\n const result = [];\n let pendingToolCalls = [];\n let existingToolResultIds = new Set();\n for (let i = 0; i < transformed.length; i++) {\n const msg = transformed[i];\n if (msg.role === \"assistant\") {\n // If we have pending orphaned tool calls from a previous assistant, insert synthetic results now\n if (pendingToolCalls.length > 0) {\n for (const tc of pendingToolCalls) {\n if (!existingToolResultIds.has(tc.id)) {\n result.push({\n role: \"toolResult\",\n toolCallId: tc.id,\n toolName: tc.name,\n content: [{ type: \"text\", text: \"No result provided\" }],\n isError: true,\n timestamp: Date.now(),\n });\n }\n }\n pendingToolCalls = [];\n existingToolResultIds = new Set();\n }\n // Skip errored/aborted assistant messages entirely.\n // These are incomplete turns that shouldn't be replayed:\n // - May have partial content (reasoning without message, incomplete tool calls)\n // - Replaying them can cause API errors (e.g., OpenAI \"reasoning without following item\")\n // - The model should retry from the last valid state\n const assistantMsg = msg;\n if (assistantMsg.stopReason === \"error\" || assistantMsg.stopReason === \"aborted\") {\n continue;\n }\n // Track tool calls from this assistant message\n const toolCalls = assistantMsg.content.filter((b) => b.type === \"toolCall\");\n if (toolCalls.length > 0) {\n pendingToolCalls = toolCalls;\n existingToolResultIds = new Set();\n }\n result.push(msg);\n }\n else if (msg.role === \"toolResult\") {\n existingToolResultIds.add(msg.toolCallId);\n result.push(msg);\n }\n else if (msg.role === \"user\") {\n // User message interrupts tool flow - insert synthetic results for orphaned calls\n if (pendingToolCalls.length > 0) {\n for (const tc of pendingToolCalls) {\n if (!existingToolResultIds.has(tc.id)) {\n result.push({\n role: \"toolResult\",\n toolCallId: tc.id,\n toolName: tc.name,\n content: [{ type: \"text\", text: \"No result provided\" }],\n isError: true,\n timestamp: Date.now(),\n });\n }\n }\n pendingToolCalls = [];\n existingToolResultIds = new Set();\n }\n result.push(msg);\n }\n else {\n result.push(msg);\n }\n }\n return result;\n}\n//# sourceMappingURL=transform-messages.js.map"],"x_google_ignoreList":[0,1,2],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var e={common:{health:`健康状况`,ok:`正常`,online:`在线`,offline:`离线`,connect:`连接`,refresh:`刷新`,enabled:`已启用`,disabled:`已禁用`,na:`不适用`,version:`版本`,docs:`文档`,resources:`资源`,search:`搜索`},nav:{chat:`聊天`,control:`控制`,agent:`代理`,settings:`设置`,expand:`展开侧边栏`,collapse:`折叠侧边栏`,resize:`调整侧边栏大小`},tabs:{employees:`员工`,agents:`代理`,overview:`概览`,channels:`频道`,instances:`实例`,sessions:`会话`,usage:`使用情况`,cron:`定时任务`,skills:`技能`,nodes:`节点`,chat:`聊天`,config:`配置`,apiKeys:`API Keys`,communications:`通信`,appearance:`外观与设置`,automation:`自动化`,infrastructure:`基础设施`,aiAgents:`AI 与代理`,debug:`调试`,logs:`日志`},subtitles:{employees:`AI 团队与最近活动。`,agents:`工作区、工具、身份。`,overview:`状态、入口点、健康。`,channels:`频道和设置。`,instances:`已连接客户端和节点。`,sessions:`活动会话和默认设置。`,usage:`API 使用情况和成本。`,cron:`唤醒和重复运行。`,skills:`技能和 API 密钥。`,nodes:`配对设备和命令。`,chat:`网关聊天,快速干预。`,config:`编辑 openclaw.json。`,apiKeys:`OpenRouter key and model defaults.`,communications:`频道、消息和音频设置。`,appearance:`主题、界面和设置向导设置。`,automation:`命令、钩子、定时任务和插件设置。`,infrastructure:`网关、Web、浏览器和媒体设置。`,aiAgents:`代理、模型、技能、工具、记忆和会话设置。`,debug:`快照、事件、RPC。`,logs:`实时网关日志。`},overview:{access:{title:`网关访问`,subtitle:`仪表板连接的位置及其身份验证方式。`,wsUrl:`WebSocket URL`,token:`网关令牌`,password:`密码 (不存储)`,sessionKey:`默认会话密钥`,language:`语言`,connectHint:`点击连接以应用连接更改。`,trustedProxy:`通过受信任代理认证。`},snapshot:{title:`快照`,subtitle:`最新的网关握手信息。`,status:`状态`,uptime:`运行时间`,tickInterval:`刻度间隔`,lastChannelsRefresh:`最后频道刷新`,channelsHint:`使用频道链接 WhatsApp、Telegram、Discord、Signal 或 iMessage。`},stats:{instances:`实例`,instancesHint:`过去 5 分钟内的在线信号。`,sessions:`会话`,sessionsHint:`网关跟踪的最近会话密钥。`,cron:`定时任务`,cronNext:`下次唤醒 {time}`},notes:{title:`备注`,subtitle:`远程控制设置的快速提醒。`,tailscaleTitle:`Tailscale serve`,tailscaleText:`首选 serve 模式以通过 tailnet 身份验证将网关保持在回环地址。`,sessionTitle:`会话清理`,sessionText:`使用 /new 或 sessions.patch 重置上下文。`,cronTitle:`定时任务提醒`,cronText:`为重复运行使用隔离的会话。`},auth:{required:`此网关需要身份验证。添加令牌或密码,然后点击连接。`,failed:`身份验证失败。请使用 {command} 重新复制令牌化 URL,或更新令牌,然后点击连接。`},pairing:{hint:`此设备需要网关主机的配对批准。`,mobileHint:`在手机上?从桌面运行 kova dashboard --no-open 复制完整 URL(包括 #token=...)。`},insecure:{hint:`此页面为 HTTP,因此浏览器阻止设备标识。请使用 HTTPS (Tailscale Serve) 或在网关主机上打开 {url}。`,stayHttp:`如果您必须保持 HTTP,请设置 {config} (仅限令牌)。`},connection:{title:`如何连接`,step1:`在主机上启动网关:`,step2:`获取带令牌的仪表盘 URL:`,step3:`将 WebSocket URL 和令牌粘贴到上方,或直接打开带令牌的 URL。`,step4:`或生成可重复使用的令牌:`,docsHint:`如需远程访问,建议使用 Tailscale Serve。`,docsLink:`查看文档 →`},cards:{cost:`费用`,skills:`技能`,recentSessions:`最近会话`},attention:{title:`注意事项`},eventLog:{title:`事件日志`},logTail:{title:`网关日志`},quickActions:{newSession:`新建会话`,automation:`自动化`,refreshAll:`全部刷新`,terminal:`终端`},palette:{placeholder:`输入命令…`,noResults:`无结果`}},login:{subtitle:`网关仪表盘`,passwordPlaceholder:`可选`},chat:{disconnected:`已断开与网关的连接。`,refreshTitle:`刷新聊天数据`,thinkingToggle:`切换助手思考/工作输出`,focusToggle:`切换专注模式 (隐藏侧边栏 + 页面页眉)`,hideCronSessions:`隐藏定时任务会话`,showCronSessions:`显示定时任务会话`,showCronSessionsHidden:`显示定时任务会话 (已隐藏 {count} 个)`,onboardingDisabled:`引导期间禁用`},languages:{en:`English`,zhCN:`简体中文 (简体中文)`,zhTW:`繁體中文 (繁体中文)`,ptBR:`Português (巴西葡萄牙语)`,de:`Deutsch (德语)`,es:`Español (西班牙语)`},cron:{summary:{enabled:`已启用`,yes:`是`,no:`否`,jobs:`任务数`,nextWake:`下次唤醒`,refreshing:`刷新中...`,refresh:`刷新`},jobs:{title:`任务列表`,subtitle:`网关中存储的所有定时任务。`,shownOf:`显示 {shown} / 共 {total}`,searchJobs:`搜索任务`,searchPlaceholder:`名称、描述或代理`,enabled:`启用状态`,all:`全部`,sort:`排序`,nextRun:`下次运行`,recentlyUpdated:`最近更新`,name:`名称`,direction:`方向`,ascending:`升序`,descending:`降序`,noMatching:`没有匹配的任务。`,loading:`加载中...`,loadMore:`加载更多任务`},runs:{title:`运行历史`,subtitleAll:`所有任务的最新运行记录。`,subtitleJob:`{title} 的最新运行记录。`,scope:`范围`,allJobs:`所有任务`,selectedJob:`已选任务`,searchRuns:`搜索运行`,searchPlaceholder:`摘要、错误或任务`,newestFirst:`最新优先`,oldestFirst:`最早优先`,status:`状态`,delivery:`投递`,clear:`清除`,allStatuses:`全部状态`,allDelivery:`全部投递`,selectJobHint:`请选择一个任务以查看运行历史。`,noMatching:`没有匹配的运行记录。`,loadMore:`加载更多运行`,runStatusOk:`成功`,runStatusError:`错误`,runStatusSkipped:`已跳过`,runStatusUnknown:`未知`,deliveryDelivered:`已投递`,deliveryNotDelivered:`未投递`,deliveryUnknown:`未知`,deliveryNotRequested:`未请求`},form:{editJob:`编辑任务`,newJob:`新建任务`,updateSubtitle:`更新所选定时任务。`,createSubtitle:`创建定时唤醒或代理运行。`,required:`必填`,requiredSr:`必填`,basics:`基本信息`,basicsSub:`命名、选择助手并设置启用状态。`,fieldName:`名称`,description:`描述`,agentId:`代理 ID`,namePlaceholder:`晨间简报`,descriptionPlaceholder:`此任务的可选说明`,agentPlaceholder:`main 或 ops`,agentHelp:`输入以选择已知代理,或输入自定义 ID。`,schedule:`调度`,scheduleSub:`控制任务运行时间。`,every:`每隔`,at:`指定时间`,cronOption:`Cron`,runAt:`运行时间`,unit:`单位`,minutes:`分钟`,hours:`小时`,days:`天`,expression:`表达式`,expressionPlaceholder:`0 7 * * *`,everyAmountPlaceholder:`30`,timezoneOptional:`时区(可选)`,timezonePlaceholder:`America/Los_Angeles`,timezoneHelp:`选择常用时区或输入有效的 IANA 时区。`,jitterHelp:`需要抖动?使用高级 → 抖动窗口 / 抖动单位。`,execution:`执行`,executionSub:`选择唤醒时机和任务执行内容。`,session:`会话`,main:`主会话`,isolated:`隔离会话`,sessionHelp:`主会话发布系统事件。隔离会话运行独立的代理轮次。`,wakeMode:`唤醒模式`,now:`立即`,nextHeartbeat:`下次心跳`,wakeModeHelp:`立即模式立即触发。下次心跳等待下一个周期。`,payloadKind:`执行内容`,systemEvent:`发布消息到主时间线`,agentTurn:`运行助手任务(隔离)`,systemEventHelp:`将文本发送到网关主时间线(适用于提醒/触发)。`,agentTurnHelp:`使用您的提示在独立会话中启动助手运行。`,timeoutSeconds:`超时(秒)`,timeoutPlaceholder:`可选,如 90`,timeoutHelp:`可选。留空以使用网关默认超时行为。`,mainTimelineMessage:`主时间线消息`,assistantTaskPrompt:`助手任务提示`,deliverySection:`投递`,deliverySub:`选择运行摘要的发送位置。`,resultDelivery:`结果投递`,announceDefault:`发布摘要(默认)`,webhookPost:`Webhook POST`,noneInternal:`无(仅内部)`,deliveryHelp:`发布将摘要发送到聊天。无保持执行仅内部。`,webhookUrl:`Webhook URL`,channel:`频道`,webhookPlaceholder:`https://example.com/cron`,channelHelp:`选择接收摘要的已连接频道。`,webhookHelp:`将运行摘要发送到 Webhook 端点。`,to:`收件人`,toPlaceholder:`+1555... 或聊天 ID`,toHelp:`可选收件人覆盖(聊天 ID、电话或用户 ID)。`,advanced:`高级`,advancedHelp:`投递保证、调度抖动和模型控制的可选覆盖。`,deleteAfterRun:`运行后删除`,deleteAfterRunHelp:`适用于应自动清理的一次性提醒。`,clearAgentOverride:`清除代理覆盖`,clearAgentHelp:`强制此任务使用网关默认助手。`,exactTiming:`精确时间(无抖动)`,exactTimingHelp:`在精确的 cron 边界运行,无分散。`,staggerWindow:`抖动窗口`,staggerUnit:`抖动单位`,staggerPlaceholder:`30`,seconds:`秒`,model:`模型`,modelPlaceholder:`openai/gpt-5.2`,modelHelp:`输入以选择已知模型,或输入自定义模型。`,thinking:`思考`,thinkingPlaceholder:`low`,thinkingHelp:`使用建议级别或输入提供商特定值。`,bestEffortDelivery:`尽力投递`,bestEffortHelp:`投递失败时不使任务失败。`,cantAddYet:`暂无法添加任务`,fillRequired:`填写下方必填项以启用提交。`,fixFields:`修复 {count} 个字段以继续。`,fixFieldsPlural:`修复 {count} 个字段以继续。`,saving:`保存中...`,saveChanges:`保存更改`,addJob:`添加任务`,cancel:`取消`},jobList:{allJobs:`所有任务`,selectJob:`(选择任务)`,enabled:`已启用`,disabled:`已禁用`,edit:`编辑`,clone:`克隆`,disable:`禁用`,enable:`启用`,run:`运行`,history:`历史`,remove:`删除`},jobDetail:{system:`系统`,prompt:`提示`,delivery:`投递`,agent:`代理`},jobState:{status:`状态`,next:`下次`,last:`上次`},runEntry:{noSummary:`无摘要。`,runAt:`运行于`,openRunChat:`打开运行聊天`,next:`下次 {rel}`,due:`到期 {rel}`},errors:{nameRequired:`名称为必填项。`,scheduleAtInvalid:`请输入有效的日期/时间。`,everyAmountInvalid:`间隔必须大于 0。`,cronExprRequired:`Cron 表达式为必填项。`,staggerAmountInvalid:`抖动值必须大于 0。`,systemTextRequired:`系统文本为必填项。`,agentMessageRequired:`代理消息为必填项。`,timeoutInvalid:`若设置超时,必须大于 0 秒。`,webhookUrlRequired:`Webhook URL 为必填项。`,webhookUrlInvalid:`Webhook URL 必须以 http:// 或 https:// 开头。`,invalidRunTime:`无效的运行时间。`,invalidIntervalAmount:`无效的间隔值。`,cronExprRequiredShort:`Cron 表达式为必填。`,invalidStaggerAmount:`无效的抖动值。`,systemEventTextRequired:`系统事件文本为必填。`,agentMessageRequiredShort:`代理消息为必填。`,nameRequiredShort:`名称为必填。`}}};export{e as zh_CN};
|
|
2
|
+
//# sourceMappingURL=zh-CN-C5tPG8Eu.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zh-CN-C5tPG8Eu.js","names":[],"sources":["../../../ui/src/i18n/locales/zh-CN.ts"],"sourcesContent":["import type { TranslationMap } from \"../lib/types.ts\";\n\nexport const zh_CN: TranslationMap = {\n common: {\n health: \"健康状况\",\n ok: \"正常\",\n online: \"在线\",\n offline: \"离线\",\n connect: \"连接\",\n refresh: \"刷新\",\n enabled: \"已启用\",\n disabled: \"已禁用\",\n na: \"不适用\",\n version: \"版本\",\n docs: \"文档\",\n resources: \"资源\",\n search: \"搜索\",\n },\n nav: {\n chat: \"聊天\",\n control: \"控制\",\n agent: \"代理\",\n settings: \"设置\",\n expand: \"展开侧边栏\",\n collapse: \"折叠侧边栏\",\n resize: \"调整侧边栏大小\",\n },\n tabs: {\n employees: \"员工\",\n agents: \"代理\",\n overview: \"概览\",\n channels: \"频道\",\n instances: \"实例\",\n sessions: \"会话\",\n usage: \"使用情况\",\n cron: \"定时任务\",\n skills: \"技能\",\n nodes: \"节点\",\n chat: \"聊天\",\n config: \"配置\",\n apiKeys: \"API Keys\",\n communications: \"通信\",\n appearance: \"外观与设置\",\n automation: \"自动化\",\n infrastructure: \"基础设施\",\n aiAgents: \"AI 与代理\",\n debug: \"调试\",\n logs: \"日志\",\n },\n subtitles: {\n employees: \"AI 团队与最近活动。\",\n agents: \"工作区、工具、身份。\",\n overview: \"状态、入口点、健康。\",\n channels: \"频道和设置。\",\n instances: \"已连接客户端和节点。\",\n sessions: \"活动会话和默认设置。\",\n usage: \"API 使用情况和成本。\",\n cron: \"唤醒和重复运行。\",\n skills: \"技能和 API 密钥。\",\n nodes: \"配对设备和命令。\",\n chat: \"网关聊天,快速干预。\",\n config: \"编辑 openclaw.json。\",\n apiKeys: \"OpenRouter key and model defaults.\",\n communications: \"频道、消息和音频设置。\",\n appearance: \"主题、界面和设置向导设置。\",\n automation: \"命令、钩子、定时任务和插件设置。\",\n infrastructure: \"网关、Web、浏览器和媒体设置。\",\n aiAgents: \"代理、模型、技能、工具、记忆和会话设置。\",\n debug: \"快照、事件、RPC。\",\n logs: \"实时网关日志。\",\n },\n overview: {\n access: {\n title: \"网关访问\",\n subtitle: \"仪表板连接的位置及其身份验证方式。\",\n wsUrl: \"WebSocket URL\",\n token: \"网关令牌\",\n password: \"密码 (不存储)\",\n sessionKey: \"默认会话密钥\",\n language: \"语言\",\n connectHint: \"点击连接以应用连接更改。\",\n trustedProxy: \"通过受信任代理认证。\",\n },\n snapshot: {\n title: \"快照\",\n subtitle: \"最新的网关握手信息。\",\n status: \"状态\",\n uptime: \"运行时间\",\n tickInterval: \"刻度间隔\",\n lastChannelsRefresh: \"最后频道刷新\",\n channelsHint: \"使用频道链接 WhatsApp、Telegram、Discord、Signal 或 iMessage。\",\n },\n stats: {\n instances: \"实例\",\n instancesHint: \"过去 5 分钟内的在线信号。\",\n sessions: \"会话\",\n sessionsHint: \"网关跟踪的最近会话密钥。\",\n cron: \"定时任务\",\n cronNext: \"下次唤醒 {time}\",\n },\n notes: {\n title: \"备注\",\n subtitle: \"远程控制设置的快速提醒。\",\n tailscaleTitle: \"Tailscale serve\",\n tailscaleText: \"首选 serve 模式以通过 tailnet 身份验证将网关保持在回环地址。\",\n sessionTitle: \"会话清理\",\n sessionText: \"使用 /new 或 sessions.patch 重置上下文。\",\n cronTitle: \"定时任务提醒\",\n cronText: \"为重复运行使用隔离的会话。\",\n },\n auth: {\n required: \"此网关需要身份验证。添加令牌或密码,然后点击连接。\",\n failed: \"身份验证失败。请使用 {command} 重新复制令牌化 URL,或更新令牌,然后点击连接。\",\n },\n pairing: {\n hint: \"此设备需要网关主机的配对批准。\",\n mobileHint: \"在手机上?从桌面运行 kova dashboard --no-open 复制完整 URL(包括 #token=...)。\",\n },\n insecure: {\n hint: \"此页面为 HTTP,因此浏览器阻止设备标识。请使用 HTTPS (Tailscale Serve) 或在网关主机上打开 {url}。\",\n stayHttp: \"如果您必须保持 HTTP,请设置 {config} (仅限令牌)。\",\n },\n connection: {\n title: \"如何连接\",\n step1: \"在主机上启动网关:\",\n step2: \"获取带令牌的仪表盘 URL:\",\n step3: \"将 WebSocket URL 和令牌粘贴到上方,或直接打开带令牌的 URL。\",\n step4: \"或生成可重复使用的令牌:\",\n docsHint: \"如需远程访问,建议使用 Tailscale Serve。\",\n docsLink: \"查看文档 →\",\n },\n cards: {\n cost: \"费用\",\n skills: \"技能\",\n recentSessions: \"最近会话\",\n },\n attention: {\n title: \"注意事项\",\n },\n eventLog: {\n title: \"事件日志\",\n },\n logTail: {\n title: \"网关日志\",\n },\n quickActions: {\n newSession: \"新建会话\",\n automation: \"自动化\",\n refreshAll: \"全部刷新\",\n terminal: \"终端\",\n },\n palette: {\n placeholder: \"输入命令…\",\n noResults: \"无结果\",\n },\n },\n login: {\n subtitle: \"网关仪表盘\",\n passwordPlaceholder: \"可选\",\n },\n chat: {\n disconnected: \"已断开与网关的连接。\",\n refreshTitle: \"刷新聊天数据\",\n thinkingToggle: \"切换助手思考/工作输出\",\n focusToggle: \"切换专注模式 (隐藏侧边栏 + 页面页眉)\",\n hideCronSessions: \"隐藏定时任务会话\",\n showCronSessions: \"显示定时任务会话\",\n showCronSessionsHidden: \"显示定时任务会话 (已隐藏 {count} 个)\",\n onboardingDisabled: \"引导期间禁用\",\n },\n languages: {\n en: \"English\",\n zhCN: \"简体中文 (简体中文)\",\n zhTW: \"繁體中文 (繁体中文)\",\n ptBR: \"Português (巴西葡萄牙语)\",\n de: \"Deutsch (德语)\",\n es: \"Español (西班牙语)\",\n },\n cron: {\n summary: {\n enabled: \"已启用\",\n yes: \"是\",\n no: \"否\",\n jobs: \"任务数\",\n nextWake: \"下次唤醒\",\n refreshing: \"刷新中...\",\n refresh: \"刷新\",\n },\n jobs: {\n title: \"任务列表\",\n subtitle: \"网关中存储的所有定时任务。\",\n shownOf: \"显示 {shown} / 共 {total}\",\n searchJobs: \"搜索任务\",\n searchPlaceholder: \"名称、描述或代理\",\n enabled: \"启用状态\",\n all: \"全部\",\n sort: \"排序\",\n nextRun: \"下次运行\",\n recentlyUpdated: \"最近更新\",\n name: \"名称\",\n direction: \"方向\",\n ascending: \"升序\",\n descending: \"降序\",\n noMatching: \"没有匹配的任务。\",\n loading: \"加载中...\",\n loadMore: \"加载更多任务\",\n },\n runs: {\n title: \"运行历史\",\n subtitleAll: \"所有任务的最新运行记录。\",\n subtitleJob: \"{title} 的最新运行记录。\",\n scope: \"范围\",\n allJobs: \"所有任务\",\n selectedJob: \"已选任务\",\n searchRuns: \"搜索运行\",\n searchPlaceholder: \"摘要、错误或任务\",\n newestFirst: \"最新优先\",\n oldestFirst: \"最早优先\",\n status: \"状态\",\n delivery: \"投递\",\n clear: \"清除\",\n allStatuses: \"全部状态\",\n allDelivery: \"全部投递\",\n selectJobHint: \"请选择一个任务以查看运行历史。\",\n noMatching: \"没有匹配的运行记录。\",\n loadMore: \"加载更多运行\",\n runStatusOk: \"成功\",\n runStatusError: \"错误\",\n runStatusSkipped: \"已跳过\",\n runStatusUnknown: \"未知\",\n deliveryDelivered: \"已投递\",\n deliveryNotDelivered: \"未投递\",\n deliveryUnknown: \"未知\",\n deliveryNotRequested: \"未请求\",\n },\n form: {\n editJob: \"编辑任务\",\n newJob: \"新建任务\",\n updateSubtitle: \"更新所选定时任务。\",\n createSubtitle: \"创建定时唤醒或代理运行。\",\n required: \"必填\",\n requiredSr: \"必填\",\n basics: \"基本信息\",\n basicsSub: \"命名、选择助手并设置启用状态。\",\n fieldName: \"名称\",\n description: \"描述\",\n agentId: \"代理 ID\",\n namePlaceholder: \"晨间简报\",\n descriptionPlaceholder: \"此任务的可选说明\",\n agentPlaceholder: \"main 或 ops\",\n agentHelp: \"输入以选择已知代理,或输入自定义 ID。\",\n schedule: \"调度\",\n scheduleSub: \"控制任务运行时间。\",\n every: \"每隔\",\n at: \"指定时间\",\n cronOption: \"Cron\",\n runAt: \"运行时间\",\n unit: \"单位\",\n minutes: \"分钟\",\n hours: \"小时\",\n days: \"天\",\n expression: \"表达式\",\n expressionPlaceholder: \"0 7 * * *\",\n everyAmountPlaceholder: \"30\",\n timezoneOptional: \"时区(可选)\",\n timezonePlaceholder: \"America/Los_Angeles\",\n timezoneHelp: \"选择常用时区或输入有效的 IANA 时区。\",\n jitterHelp: \"需要抖动?使用高级 → 抖动窗口 / 抖动单位。\",\n execution: \"执行\",\n executionSub: \"选择唤醒时机和任务执行内容。\",\n session: \"会话\",\n main: \"主会话\",\n isolated: \"隔离会话\",\n sessionHelp: \"主会话发布系统事件。隔离会话运行独立的代理轮次。\",\n wakeMode: \"唤醒模式\",\n now: \"立即\",\n nextHeartbeat: \"下次心跳\",\n wakeModeHelp: \"立即模式立即触发。下次心跳等待下一个周期。\",\n payloadKind: \"执行内容\",\n systemEvent: \"发布消息到主时间线\",\n agentTurn: \"运行助手任务(隔离)\",\n systemEventHelp: \"将文本发送到网关主时间线(适用于提醒/触发)。\",\n agentTurnHelp: \"使用您的提示在独立会话中启动助手运行。\",\n timeoutSeconds: \"超时(秒)\",\n timeoutPlaceholder: \"可选,如 90\",\n timeoutHelp: \"可选。留空以使用网关默认超时行为。\",\n mainTimelineMessage: \"主时间线消息\",\n assistantTaskPrompt: \"助手任务提示\",\n deliverySection: \"投递\",\n deliverySub: \"选择运行摘要的发送位置。\",\n resultDelivery: \"结果投递\",\n announceDefault: \"发布摘要(默认)\",\n webhookPost: \"Webhook POST\",\n noneInternal: \"无(仅内部)\",\n deliveryHelp: \"发布将摘要发送到聊天。无保持执行仅内部。\",\n webhookUrl: \"Webhook URL\",\n channel: \"频道\",\n webhookPlaceholder: \"https://example.com/cron\",\n channelHelp: \"选择接收摘要的已连接频道。\",\n webhookHelp: \"将运行摘要发送到 Webhook 端点。\",\n to: \"收件人\",\n toPlaceholder: \"+1555... 或聊天 ID\",\n toHelp: \"可选收件人覆盖(聊天 ID、电话或用户 ID)。\",\n advanced: \"高级\",\n advancedHelp: \"投递保证、调度抖动和模型控制的可选覆盖。\",\n deleteAfterRun: \"运行后删除\",\n deleteAfterRunHelp: \"适用于应自动清理的一次性提醒。\",\n clearAgentOverride: \"清除代理覆盖\",\n clearAgentHelp: \"强制此任务使用网关默认助手。\",\n exactTiming: \"精确时间(无抖动)\",\n exactTimingHelp: \"在精确的 cron 边界运行,无分散。\",\n staggerWindow: \"抖动窗口\",\n staggerUnit: \"抖动单位\",\n staggerPlaceholder: \"30\",\n seconds: \"秒\",\n model: \"模型\",\n modelPlaceholder: \"openai/gpt-5.2\",\n modelHelp: \"输入以选择已知模型,或输入自定义模型。\",\n thinking: \"思考\",\n thinkingPlaceholder: \"low\",\n thinkingHelp: \"使用建议级别或输入提供商特定值。\",\n bestEffortDelivery: \"尽力投递\",\n bestEffortHelp: \"投递失败时不使任务失败。\",\n cantAddYet: \"暂无法添加任务\",\n fillRequired: \"填写下方必填项以启用提交。\",\n fixFields: \"修复 {count} 个字段以继续。\",\n fixFieldsPlural: \"修复 {count} 个字段以继续。\",\n saving: \"保存中...\",\n saveChanges: \"保存更改\",\n addJob: \"添加任务\",\n cancel: \"取消\",\n },\n jobList: {\n allJobs: \"所有任务\",\n selectJob: \"(选择任务)\",\n enabled: \"已启用\",\n disabled: \"已禁用\",\n edit: \"编辑\",\n clone: \"克隆\",\n disable: \"禁用\",\n enable: \"启用\",\n run: \"运行\",\n history: \"历史\",\n remove: \"删除\",\n },\n jobDetail: {\n system: \"系统\",\n prompt: \"提示\",\n delivery: \"投递\",\n agent: \"代理\",\n },\n jobState: {\n status: \"状态\",\n next: \"下次\",\n last: \"上次\",\n },\n runEntry: {\n noSummary: \"无摘要。\",\n runAt: \"运行于\",\n openRunChat: \"打开运行聊天\",\n next: \"下次 {rel}\",\n due: \"到期 {rel}\",\n },\n errors: {\n nameRequired: \"名称为必填项。\",\n scheduleAtInvalid: \"请输入有效的日期/时间。\",\n everyAmountInvalid: \"间隔必须大于 0。\",\n cronExprRequired: \"Cron 表达式为必填项。\",\n staggerAmountInvalid: \"抖动值必须大于 0。\",\n systemTextRequired: \"系统文本为必填项。\",\n agentMessageRequired: \"代理消息为必填项。\",\n timeoutInvalid: \"若设置超时,必须大于 0 秒。\",\n webhookUrlRequired: \"Webhook URL 为必填项。\",\n webhookUrlInvalid: \"Webhook URL 必须以 http:// 或 https:// 开头。\",\n invalidRunTime: \"无效的运行时间。\",\n invalidIntervalAmount: \"无效的间隔值。\",\n cronExprRequiredShort: \"Cron 表达式为必填。\",\n invalidStaggerAmount: \"无效的抖动值。\",\n systemEventTextRequired: \"系统事件文本为必填。\",\n agentMessageRequiredShort: \"代理消息为必填。\",\n nameRequiredShort: \"名称为必填。\",\n },\n },\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var e={common:{health:`健康狀況`,ok:`正常`,online:`在線`,offline:`離線`,connect:`連接`,refresh:`刷新`,enabled:`已啟用`,disabled:`已禁用`,na:`不適用`,version:`版本`,docs:`文檔`,resources:`資源`,search:`搜尋`},nav:{chat:`聊天`,control:`控制`,agent:`代理`,settings:`設置`,expand:`展開側邊欄`,collapse:`折疊側邊欄`,resize:`調整側邊欄大小`},tabs:{employees:`員工`,agents:`代理`,overview:`概覽`,channels:`頻道`,instances:`實例`,sessions:`會話`,usage:`使用情況`,cron:`定時任務`,skills:`技能`,nodes:`節點`,chat:`聊天`,config:`配置`,apiKeys:`API Keys`,communications:`通訊`,appearance:`外觀與設置`,automation:`自動化`,infrastructure:`基礎設施`,aiAgents:`AI 與代理`,debug:`調試`,logs:`日誌`},subtitles:{employees:`AI 團隊與最近活動。`,agents:`工作區、工具、身份。`,overview:`狀態、入口點、健康。`,channels:`頻道和設置。`,instances:`已連接客戶端和節點。`,sessions:`活動會話和默認設置。`,usage:`API 使用情況和成本。`,cron:`喚醒和重複運行。`,skills:`技能和 API 密鑰。`,nodes:`配對設備和命令。`,chat:`網關聊天,快速干預。`,config:`編輯 openclaw.json。`,apiKeys:`OpenRouter key and model defaults.`,communications:`頻道、消息和音頻設置。`,appearance:`主題、界面和設置向導設置。`,automation:`命令、鉤子、定時任務和插件設置。`,infrastructure:`網關、Web、瀏覽器和媒體設置。`,aiAgents:`代理、模型、技能、工具、記憶和會話設置。`,debug:`快照、事件、RPC。`,logs:`實時網關日誌。`},overview:{access:{title:`網關訪問`,subtitle:`儀表板連接的位置及其身份驗證方式。`,wsUrl:`WebSocket URL`,token:`網關令牌`,password:`密碼 (不存儲)`,sessionKey:`默認會話密鑰`,language:`語言`,connectHint:`點擊連接以應用連接更改。`,trustedProxy:`通過受信任代理身份驗證。`},snapshot:{title:`快照`,subtitle:`最新的網關握手信息。`,status:`狀態`,uptime:`運行時間`,tickInterval:`刻度間隔`,lastChannelsRefresh:`最後頻道刷新`,channelsHint:`使用頻道鏈接 WhatsApp、Telegram、Discord、Signal 或 iMessage。`},stats:{instances:`實例`,instancesHint:`過去 5 分鐘內的在線信號。`,sessions:`會話`,sessionsHint:`網關跟蹤的最近會話密鑰。`,cron:`定時任務`,cronNext:`下次喚醒 {time}`},notes:{title:`備註`,subtitle:`遠程控制設置的快速提醒。`,tailscaleTitle:`Tailscale serve`,tailscaleText:`首選 serve 模式以通過 tailnet 身份驗證將網關保持在回環地址。`,sessionTitle:`會話清理`,sessionText:`使用 /new 或 sessions.patch 重置上下文。`,cronTitle:`定時任務提醒`,cronText:`為重複運行使用隔離的會話。`},auth:{required:`此網關需要身份驗證。添加令牌或密碼,然後點擊連接。`,failed:`身份驗證失敗。請使用 {command} 重新複製令牌化 URL,或更新令牌,然後點擊連接。`},pairing:{hint:`此裝置需要閘道主機的配對批准。`,mobileHint:`在手機上?從桌面執行 kova dashboard --no-open 複製完整 URL(包括 #token=...)。`},insecure:{hint:`此頁面為 HTTP,因此瀏覽器阻止設備標識。請使用 HTTPS (Tailscale Serve) 或在網關主機上打開 {url}。`,stayHttp:`如果您必須保持 HTTP,請設置 {config} (僅限令牌)。`},connection:{title:`如何連接`,step1:`在主機上啟動閘道:`,step2:`取得帶令牌的儀表板 URL:`,step3:`將 WebSocket URL 和令牌貼到上方,或直接開啟帶令牌的 URL。`,step4:`或產生可重複使用的令牌:`,docsHint:`如需遠端存取,建議使用 Tailscale Serve。`,docsLink:`查看文件 →`},cards:{cost:`費用`,skills:`技能`,recentSessions:`最近會話`},attention:{title:`注意事項`},eventLog:{title:`事件日誌`},logTail:{title:`閘道日誌`},quickActions:{newSession:`新建會話`,automation:`自動化`,refreshAll:`全部刷新`,terminal:`終端`},palette:{placeholder:`輸入指令…`,noResults:`無結果`}},login:{subtitle:`閘道儀表板`,passwordPlaceholder:`可選`},chat:{disconnected:`已斷開與網關的連接。`,refreshTitle:`刷新聊天數據`,thinkingToggle:`切換助手思考/工作輸出`,focusToggle:`切換專注模式 (隱藏側邊欄 + 頁面頁眉)`,hideCronSessions:`隱藏定時任務會話`,showCronSessions:`顯示定時任務會話`,showCronSessionsHidden:`顯示定時任務會話 (已隱藏 {count} 個)`,onboardingDisabled:`引導期間禁用`},languages:{en:`English`,zhCN:`简体中文 (簡體中文)`,zhTW:`繁體中文 (繁體中文)`,ptBR:`Português (巴西葡萄牙語)`,de:`Deutsch (德語)`,es:`Español (西班牙語)`}};export{e as zh_TW};
|
|
2
|
+
//# sourceMappingURL=zh-TW-CPSoC7Wz.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zh-TW-CPSoC7Wz.js","names":[],"sources":["../../../ui/src/i18n/locales/zh-TW.ts"],"sourcesContent":["import type { TranslationMap } from \"../lib/types.ts\";\n\nexport const zh_TW: TranslationMap = {\n common: {\n health: \"健康狀況\",\n ok: \"正常\",\n online: \"在線\",\n offline: \"離線\",\n connect: \"連接\",\n refresh: \"刷新\",\n enabled: \"已啟用\",\n disabled: \"已禁用\",\n na: \"不適用\",\n version: \"版本\",\n docs: \"文檔\",\n resources: \"資源\",\n search: \"搜尋\",\n },\n nav: {\n chat: \"聊天\",\n control: \"控制\",\n agent: \"代理\",\n settings: \"設置\",\n expand: \"展開側邊欄\",\n collapse: \"折疊側邊欄\",\n resize: \"調整側邊欄大小\",\n },\n tabs: {\n employees: \"員工\",\n agents: \"代理\",\n overview: \"概覽\",\n channels: \"頻道\",\n instances: \"實例\",\n sessions: \"會話\",\n usage: \"使用情況\",\n cron: \"定時任務\",\n skills: \"技能\",\n nodes: \"節點\",\n chat: \"聊天\",\n config: \"配置\",\n apiKeys: \"API Keys\",\n communications: \"通訊\",\n appearance: \"外觀與設置\",\n automation: \"自動化\",\n infrastructure: \"基礎設施\",\n aiAgents: \"AI 與代理\",\n debug: \"調試\",\n logs: \"日誌\",\n },\n subtitles: {\n employees: \"AI 團隊與最近活動。\",\n agents: \"工作區、工具、身份。\",\n overview: \"狀態、入口點、健康。\",\n channels: \"頻道和設置。\",\n instances: \"已連接客戶端和節點。\",\n sessions: \"活動會話和默認設置。\",\n usage: \"API 使用情況和成本。\",\n cron: \"喚醒和重複運行。\",\n skills: \"技能和 API 密鑰。\",\n nodes: \"配對設備和命令。\",\n chat: \"網關聊天,快速干預。\",\n config: \"編輯 openclaw.json。\",\n apiKeys: \"OpenRouter key and model defaults.\",\n communications: \"頻道、消息和音頻設置。\",\n appearance: \"主題、界面和設置向導設置。\",\n automation: \"命令、鉤子、定時任務和插件設置。\",\n infrastructure: \"網關、Web、瀏覽器和媒體設置。\",\n aiAgents: \"代理、模型、技能、工具、記憶和會話設置。\",\n debug: \"快照、事件、RPC。\",\n logs: \"實時網關日誌。\",\n },\n overview: {\n access: {\n title: \"網關訪問\",\n subtitle: \"儀表板連接的位置及其身份驗證方式。\",\n wsUrl: \"WebSocket URL\",\n token: \"網關令牌\",\n password: \"密碼 (不存儲)\",\n sessionKey: \"默認會話密鑰\",\n language: \"語言\",\n connectHint: \"點擊連接以應用連接更改。\",\n trustedProxy: \"通過受信任代理身份驗證。\",\n },\n snapshot: {\n title: \"快照\",\n subtitle: \"最新的網關握手信息。\",\n status: \"狀態\",\n uptime: \"運行時間\",\n tickInterval: \"刻度間隔\",\n lastChannelsRefresh: \"最後頻道刷新\",\n channelsHint: \"使用頻道鏈接 WhatsApp、Telegram、Discord、Signal 或 iMessage。\",\n },\n stats: {\n instances: \"實例\",\n instancesHint: \"過去 5 分鐘內的在線信號。\",\n sessions: \"會話\",\n sessionsHint: \"網關跟蹤的最近會話密鑰。\",\n cron: \"定時任務\",\n cronNext: \"下次喚醒 {time}\",\n },\n notes: {\n title: \"備註\",\n subtitle: \"遠程控制設置的快速提醒。\",\n tailscaleTitle: \"Tailscale serve\",\n tailscaleText: \"首選 serve 模式以通過 tailnet 身份驗證將網關保持在回環地址。\",\n sessionTitle: \"會話清理\",\n sessionText: \"使用 /new 或 sessions.patch 重置上下文。\",\n cronTitle: \"定時任務提醒\",\n cronText: \"為重複運行使用隔離的會話。\",\n },\n auth: {\n required: \"此網關需要身份驗證。添加令牌或密碼,然後點擊連接。\",\n failed: \"身份驗證失敗。請使用 {command} 重新複製令牌化 URL,或更新令牌,然後點擊連接。\",\n },\n pairing: {\n hint: \"此裝置需要閘道主機的配對批准。\",\n mobileHint: \"在手機上?從桌面執行 kova dashboard --no-open 複製完整 URL(包括 #token=...)。\",\n },\n insecure: {\n hint: \"此頁面為 HTTP,因此瀏覽器阻止設備標識。請使用 HTTPS (Tailscale Serve) 或在網關主機上打開 {url}。\",\n stayHttp: \"如果您必須保持 HTTP,請設置 {config} (僅限令牌)。\",\n },\n connection: {\n title: \"如何連接\",\n step1: \"在主機上啟動閘道:\",\n step2: \"取得帶令牌的儀表板 URL:\",\n step3: \"將 WebSocket URL 和令牌貼到上方,或直接開啟帶令牌的 URL。\",\n step4: \"或產生可重複使用的令牌:\",\n docsHint: \"如需遠端存取,建議使用 Tailscale Serve。\",\n docsLink: \"查看文件 →\",\n },\n cards: {\n cost: \"費用\",\n skills: \"技能\",\n recentSessions: \"最近會話\",\n },\n attention: {\n title: \"注意事項\",\n },\n eventLog: {\n title: \"事件日誌\",\n },\n logTail: {\n title: \"閘道日誌\",\n },\n quickActions: {\n newSession: \"新建會話\",\n automation: \"自動化\",\n refreshAll: \"全部刷新\",\n terminal: \"終端\",\n },\n palette: {\n placeholder: \"輸入指令…\",\n noResults: \"無結果\",\n },\n },\n login: {\n subtitle: \"閘道儀表板\",\n passwordPlaceholder: \"可選\",\n },\n chat: {\n disconnected: \"已斷開與網關的連接。\",\n refreshTitle: \"刷新聊天數據\",\n thinkingToggle: \"切換助手思考/工作輸出\",\n focusToggle: \"切換專注模式 (隱藏側邊欄 + 頁面頁眉)\",\n hideCronSessions: \"隱藏定時任務會話\",\n showCronSessions: \"顯示定時任務會話\",\n showCronSessionsHidden: \"顯示定時任務會話 (已隱藏 {count} 個)\",\n onboardingDisabled: \"引導期間禁用\",\n },\n languages: {\n en: \"English\",\n zhCN: \"简体中文 (簡體中文)\",\n zhTW: \"繁體中文 (繁體中文)\",\n ptBR: \"Português (巴西葡萄牙語)\",\n de: \"Deutsch (德語)\",\n es: \"Español (西班牙語)\",\n },\n};\n"],"mappings":"AAEA,IAAa,EAAwB,CACnC,OAAQ,CACN,OAAQ,OACR,GAAI,KACJ,OAAQ,KACR,QAAS,KACT,QAAS,KACT,QAAS,KACT,QAAS,MACT,SAAU,MACV,GAAI,MACJ,QAAS,KACT,KAAM,KACN,UAAW,KACX,OAAQ,KACT,CACD,IAAK,CACH,KAAM,KACN,QAAS,KACT,MAAO,KACP,SAAU,KACV,OAAQ,QACR,SAAU,QACV,OAAQ,UACT,CACD,KAAM,CACJ,UAAW,KACX,OAAQ,KACR,SAAU,KACV,SAAU,KACV,UAAW,KACX,SAAU,KACV,MAAO,OACP,KAAM,OACN,OAAQ,KACR,MAAO,KACP,KAAM,KACN,OAAQ,KACR,QAAS,WACT,eAAgB,KAChB,WAAY,QACZ,WAAY,MACZ,eAAgB,OAChB,SAAU,SACV,MAAO,KACP,KAAM,KACP,CACD,UAAW,CACT,UAAW,cACX,OAAQ,aACR,SAAU,aACV,SAAU,SACV,UAAW,aACX,SAAU,aACV,MAAO,eACP,KAAM,WACN,OAAQ,cACR,MAAO,WACP,KAAM,aACN,OAAQ,oBACR,QAAS,qCACT,eAAgB,cAChB,WAAY,gBACZ,WAAY,mBACZ,eAAgB,mBAChB,SAAU,uBACV,MAAO,aACP,KAAM,UACP,CACD,SAAU,CACR,OAAQ,CACN,MAAO,OACP,SAAU,oBACV,MAAO,gBACP,MAAO,OACP,SAAU,WACV,WAAY,SACZ,SAAU,KACV,YAAa,eACb,aAAc,eACf,CACD,SAAU,CACR,MAAO,KACP,SAAU,aACV,OAAQ,KACR,OAAQ,OACR,aAAc,OACd,oBAAqB,SACrB,aAAc,sDACf,CACD,MAAO,CACL,UAAW,KACX,cAAe,iBACf,SAAU,KACV,aAAc,eACd,KAAM,OACN,SAAU,cACX,CACD,MAAO,CACL,MAAO,KACP,SAAU,eACV,eAAgB,kBAChB,cAAe,yCACf,aAAc,OACd,YAAa,kCACb,UAAW,SACX,SAAU,gBACX,CACD,KAAM,CACJ,SAAU,4BACV,OAAQ,iDACT,CACD,QAAS,CACP,KAAM,kBACN,WAAY,+DACb,CACD,SAAU,CACR,KAAM,qEACN,SAAU,oCACX,CACD,WAAY,CACV,MAAO,OACP,MAAO,YACP,MAAO,iBACP,MAAO,yCACP,MAAO,eACP,SAAU,+BACV,SAAU,SACX,CACD,MAAO,CACL,KAAM,KACN,OAAQ,KACR,eAAgB,OACjB,CACD,UAAW,CACT,MAAO,OACR,CACD,SAAU,CACR,MAAO,OACR,CACD,QAAS,CACP,MAAO,OACR,CACD,aAAc,CACZ,WAAY,OACZ,WAAY,MACZ,WAAY,OACZ,SAAU,KACX,CACD,QAAS,CACP,YAAa,QACb,UAAW,MACZ,CACF,CACD,MAAO,CACL,SAAU,QACV,oBAAqB,KACtB,CACD,KAAM,CACJ,aAAc,aACd,aAAc,SACd,eAAgB,cAChB,YAAa,wBACb,iBAAkB,WAClB,iBAAkB,WAClB,uBAAwB,2BACxB,mBAAoB,SACrB,CACD,UAAW,CACT,GAAI,UACJ,KAAM,cACN,KAAM,cACN,KAAM,qBACN,GAAI,eACJ,GAAI,iBACL,CACF"}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<svg viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<defs>
|
|
3
|
+
<linearGradient id="lobster-gradient" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
4
|
+
<stop offset="0%" stop-color="#ff4d4d"/>
|
|
5
|
+
<stop offset="100%" stop-color="#991b1b"/>
|
|
6
|
+
</linearGradient>
|
|
7
|
+
</defs>
|
|
8
|
+
<!-- Body -->
|
|
9
|
+
<path d="M60 10 C30 10 15 35 15 55 C15 75 30 95 45 100 L45 110 L55 110 L55 100 C55 100 60 102 65 100 L65 110 L75 110 L75 100 C90 95 105 75 105 55 C105 35 90 10 60 10Z" fill="url(#lobster-gradient)"/>
|
|
10
|
+
<!-- Left Claw -->
|
|
11
|
+
<path d="M20 45 C5 40 0 50 5 60 C10 70 20 65 25 55 C28 48 25 45 20 45Z" fill="url(#lobster-gradient)"/>
|
|
12
|
+
<!-- Right Claw -->
|
|
13
|
+
<path d="M100 45 C115 40 120 50 115 60 C110 70 100 65 95 55 C92 48 95 45 100 45Z" fill="url(#lobster-gradient)"/>
|
|
14
|
+
<!-- Antenna -->
|
|
15
|
+
<path d="M45 15 Q35 5 30 8" stroke="#ff4d4d" stroke-width="3" stroke-linecap="round"/>
|
|
16
|
+
<path d="M75 15 Q85 5 90 8" stroke="#ff4d4d" stroke-width="3" stroke-linecap="round"/>
|
|
17
|
+
<!-- Eyes -->
|
|
18
|
+
<circle cx="45" cy="35" r="6" fill="#050810"/>
|
|
19
|
+
<circle cx="75" cy="35" r="6" fill="#050810"/>
|
|
20
|
+
<circle cx="46" cy="34" r="2.5" fill="#00e5cc"/>
|
|
21
|
+
<circle cx="76" cy="34" r="2.5" fill="#00e5cc"/>
|
|
22
|
+
</svg>
|