@songsid/agend 2.3.2-beta.3 → 2.3.2-beta.5
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/THIRD_PARTY_NOTICES.md +40 -0
- package/dist/agent-cli.js +21 -2
- package/dist/agent-cli.js.map +1 -1
- package/dist/agent-endpoint.js +5 -0
- package/dist/agent-endpoint.js.map +1 -1
- package/dist/antigravity-usage-scan.d.ts +58 -0
- package/dist/antigravity-usage-scan.js +257 -0
- package/dist/antigravity-usage-scan.js.map +1 -0
- package/dist/antigravity-usage-worker.d.ts +1 -0
- package/dist/antigravity-usage-worker.js +10 -0
- package/dist/antigravity-usage-worker.js.map +1 -0
- package/dist/auth-api.js +2 -0
- package/dist/auth-api.js.map +1 -1
- package/dist/backend/kiro-identity.d.ts +45 -0
- package/dist/backend/kiro-identity.js +74 -0
- package/dist/backend/kiro-identity.js.map +1 -1
- package/dist/backend/kiro.d.ts +36 -1
- package/dist/backend/kiro.js +131 -6
- package/dist/backend/kiro.js.map +1 -1
- package/dist/backend/types.d.ts +6 -0
- package/dist/backend/types.js.map +1 -1
- package/dist/backend-signin-guide.d.ts +1 -0
- package/dist/backend-signin-guide.js +9 -0
- package/dist/backend-signin-guide.js.map +1 -0
- package/dist/backend-signin-pending.d.ts +10 -0
- package/dist/backend-signin-pending.js +44 -0
- package/dist/backend-signin-pending.js.map +1 -0
- package/dist/browser-backend-signins.d.ts +56 -0
- package/dist/browser-backend-signins.js +189 -0
- package/dist/browser-backend-signins.js.map +1 -0
- package/dist/cache-ledger.d.ts +38 -2
- package/dist/cache-ledger.js +133 -8
- package/dist/cache-ledger.js.map +1 -1
- package/dist/cache-prices.d.ts +2 -1
- package/dist/cache-prices.js +5 -2
- package/dist/cache-prices.js.map +1 -1
- package/dist/cache-service.d.ts +68 -0
- package/dist/cache-service.js +355 -13
- package/dist/cache-service.js.map +1 -1
- package/dist/channel/adapters/discord.js +7 -4
- package/dist/channel/adapters/discord.js.map +1 -1
- package/dist/channel/mcp-tools.js +7 -1
- package/dist/channel/mcp-tools.js.map +1 -1
- package/dist/classic-channel-manager.d.ts +5 -0
- package/dist/classic-channel-manager.js +14 -1
- package/dist/classic-channel-manager.js.map +1 -1
- package/dist/cli.js +21 -2
- package/dist/cli.js.map +1 -1
- package/dist/config-validator.js +22 -5
- package/dist/config-validator.js.map +1 -1
- package/dist/config.d.ts +19 -0
- package/dist/config.js +31 -1
- package/dist/config.js.map +1 -1
- package/dist/cpu-quota.d.ts +23 -0
- package/dist/cpu-quota.js +86 -0
- package/dist/cpu-quota.js.map +1 -0
- package/dist/daemon.js +22 -7
- package/dist/daemon.js.map +1 -1
- package/dist/dashboard-permissions.d.ts +20 -6
- package/dist/dashboard-permissions.js +58 -9
- package/dist/dashboard-permissions.js.map +1 -1
- package/dist/fleet-manager.d.ts +51 -1
- package/dist/fleet-manager.js +416 -32
- package/dist/fleet-manager.js.map +1 -1
- package/dist/general-knowledge/skills/credential-profiles/SKILL.md +5 -2
- package/dist/general-knowledge/skills/kiro-engine-migration/SKILL.md +14 -1
- package/dist/general-knowledge/skills/web-appearance/SKILL.canvas-worker-off.md +24 -1
- package/dist/general-knowledge/skills/web-appearance/SKILL.md +24 -1
- package/dist/general-knowledge/skills/web-dashboard/SKILL.canvas-worker-off.md +6 -3
- package/dist/general-knowledge/skills/web-dashboard/SKILL.md +12 -5
- package/dist/instance-config-impact.js +10 -5
- package/dist/instance-config-impact.js.map +1 -1
- package/dist/instance-lifecycle.d.ts +17 -0
- package/dist/instance-lifecycle.js +32 -4
- package/dist/instance-lifecycle.js.map +1 -1
- package/dist/kiro-db-reader.d.ts +5 -0
- package/dist/kiro-db-reader.js +18 -0
- package/dist/kiro-db-reader.js.map +1 -1
- package/dist/kiro-engine-status.d.ts +2 -0
- package/dist/kiro-engine-status.js +9 -0
- package/dist/kiro-engine-status.js.map +1 -1
- package/dist/kiro-migrate.d.ts +49 -0
- package/dist/kiro-migrate.js +105 -0
- package/dist/kiro-migrate.js.map +1 -0
- package/dist/kiro-transcript-lane.d.ts +2 -0
- package/dist/kiro-transcript-lane.js.map +1 -1
- package/dist/kiro-transcript-worker.js +1 -0
- package/dist/kiro-transcript-worker.js.map +1 -1
- package/dist/kiro-usage-run.d.ts +7 -0
- package/dist/kiro-usage-run.js +39 -0
- package/dist/kiro-usage-run.js.map +1 -0
- package/dist/kiro-usage-scan.d.ts +49 -0
- package/dist/kiro-usage-scan.js +223 -0
- package/dist/kiro-usage-scan.js.map +1 -0
- package/dist/kiro-usage-worker.d.ts +1 -0
- package/dist/kiro-usage-worker.js +10 -0
- package/dist/kiro-usage-worker.js.map +1 -0
- package/dist/kiro-usage.d.ts +58 -0
- package/dist/kiro-usage.js +310 -0
- package/dist/kiro-usage.js.map +1 -0
- package/dist/locale.js +72 -8
- package/dist/locale.js.map +1 -1
- package/dist/log-service.js +1 -1
- package/dist/log-service.js.map +1 -1
- package/dist/login-url.d.ts +4 -0
- package/dist/login-url.js +22 -0
- package/dist/login-url.js.map +1 -0
- package/dist/needs-you-hub.d.ts +2 -1
- package/dist/needs-you-hub.js +1 -1
- package/dist/needs-you-hub.js.map +1 -1
- package/dist/needs-you.d.ts +8 -2
- package/dist/needs-you.js +6 -0
- package/dist/needs-you.js.map +1 -1
- package/dist/notice-delivery.d.ts +15 -0
- package/dist/notice-delivery.js +37 -0
- package/dist/notice-delivery.js.map +1 -0
- package/dist/opencode-usage-scan.d.ts +28 -0
- package/dist/opencode-usage-scan.js +92 -0
- package/dist/opencode-usage-scan.js.map +1 -0
- package/dist/opencode-usage-worker.d.ts +1 -0
- package/dist/opencode-usage-worker.js +10 -0
- package/dist/opencode-usage-worker.js.map +1 -0
- package/dist/outbound-handlers.js +22 -2
- package/dist/outbound-handlers.js.map +1 -1
- package/dist/outbound-schemas.d.ts +24 -0
- package/dist/outbound-schemas.js +21 -0
- package/dist/outbound-schemas.js.map +1 -1
- package/dist/public-web-gateway.js +1 -1
- package/dist/public-web-gateway.js.map +1 -1
- package/dist/quickstart-api.js +13 -2
- package/dist/quickstart-api.js.map +1 -1
- package/dist/quickstart.js +4 -1
- package/dist/quickstart.js.map +1 -1
- package/dist/reply-triggers.d.ts +2 -0
- package/dist/reply-triggers.js +3 -0
- package/dist/reply-triggers.js.map +1 -0
- package/dist/settings-api.js +27 -4
- package/dist/settings-api.js.map +1 -1
- package/dist/settings-change.js +17 -14
- package/dist/settings-change.js.map +1 -1
- package/dist/settings-effect.js +7 -1
- package/dist/settings-effect.js.map +1 -1
- package/dist/settings-instance-patch.js +4 -1
- package/dist/settings-instance-patch.js.map +1 -1
- package/dist/setup-form.d.ts +1 -1
- package/dist/setup-form.js +7 -1
- package/dist/setup-form.js.map +1 -1
- package/dist/setup-host.d.ts +9 -0
- package/dist/setup-host.js +126 -6
- package/dist/setup-host.js.map +1 -1
- package/dist/setup-signin-assets.d.ts +2 -0
- package/dist/setup-signin-assets.js +6 -0
- package/dist/setup-signin-assets.js.map +1 -0
- package/dist/setup-wizard.js +4 -0
- package/dist/setup-wizard.js.map +1 -1
- package/dist/structured-signin-transport.d.ts +8 -0
- package/dist/structured-signin-transport.js +79 -0
- package/dist/structured-signin-transport.js.map +1 -0
- package/dist/structured-signin.d.ts +131 -0
- package/dist/structured-signin.js +388 -0
- package/dist/structured-signin.js.map +1 -0
- package/dist/tool-permissions.js +12 -0
- package/dist/tool-permissions.js.map +1 -1
- package/dist/topic-commands.js +6 -2
- package/dist/topic-commands.js.map +1 -1
- package/dist/transcript-sources.d.ts +26 -2
- package/dist/transcript-sources.js +87 -40
- package/dist/transcript-sources.js.map +1 -1
- package/dist/turn-reply-guard.d.ts +1 -1
- package/dist/turn-reply-guard.js +1 -1
- package/dist/turn-reply-guard.js.map +1 -1
- package/dist/types.d.ts +19 -8
- package/dist/ui/backend-signin.js +63 -10
- package/dist/ui/fleet-office-editor.js +10 -6
- package/dist/ui/fleet-office-layout.js +34 -28
- package/dist/ui/fleet-office-model.js +6 -3
- package/dist/ui/fleet-office-overview.js +2 -2
- package/dist/ui/fleet-office-pack.d.ts +3 -1
- package/dist/ui/fleet-office-pack.js +58 -7
- package/dist/ui/fleet-office-skin.js +13 -4
- package/dist/ui/fleet-office-store.js +27 -1
- package/dist/ui/fleet-office-view.js +5 -4
- package/dist/ui/fleet-office-zones.js +155 -6
- package/dist/ui/fleet-office.js +169 -41
- package/dist/ui/fleet-usage.js +19 -15
- package/dist/ui/panel-log.js +2 -2
- package/dist/ui/panel-needs.js +4 -4
- package/dist/ui/panel-settings.js +32 -10
- package/dist/ui/settings-dialogs.js +8 -1
- package/dist/ui/settings-model.js +14 -6
- package/dist/ui/settings-registry.js +4 -0
- package/dist/ui/settings-strings.js +14 -0
- package/dist/ui/shared/app-i18n.js +4 -2
- package/dist/ui/shared/app-shell.js +14 -6
- package/dist/ui/shared/app-stream.js +2 -1
- package/dist/ui/shared/app.css +18 -2
- package/dist/ui/shared/side-panel.js +95 -0
- package/dist/ui/structured-signin.js +115 -0
- package/dist/usage-report.d.ts +20 -0
- package/dist/usage-report.js +54 -17
- package/dist/usage-report.js.map +1 -1
- package/dist/usage-rollup.d.ts +9 -1
- package/dist/usage-rollup.js +20 -4
- package/dist/usage-rollup.js.map +1 -1
- package/dist/web-api.d.ts +4 -0
- package/dist/web-api.js +110 -0
- package/dist/web-api.js.map +1 -1
- package/dist/web-auth.js +1 -1
- package/dist/web-auth.js.map +1 -1
- package/dist/web-backend-login.d.ts +1 -7
- package/dist/web-backend-login.js +2 -24
- package/dist/web-backend-login.js.map +1 -1
- package/dist/web-office-acts.d.ts +173 -0
- package/dist/web-office-acts.js +285 -0
- package/dist/web-office-acts.js.map +1 -0
- package/dist/web-office-skins.d.ts +1 -1
- package/dist/web-office-skins.js +1 -1
- package/dist/web-office-skins.js.map +1 -1
- package/dist/web-settings-patch.d.ts +2 -1
- package/dist/web-settings-patch.js +4 -1
- package/dist/web-settings-patch.js.map +1 -1
- package/package.json +2 -1
- package/templates/windows-shortcuts.ps1 +18 -7
package/dist/ui/fleet-usage.js
CHANGED
|
@@ -15,14 +15,15 @@ register("fusage", {
|
|
|
15
15
|
range: "Range", today: "Today", r7d: "7 days", month: "This month", all: "All", custom: "Custom", from: "From", to: "To", apply: "Apply",
|
|
16
16
|
group: "Group by", g_instance: "Agent", g_backend: "Backend", g_model: "Model", g_profile: "Credential profile", g_team: "Team (as configured now)",
|
|
17
17
|
csv: "Download CSV", basis: "API-equivalent at list price (checked {0}) — not money spent. Subscriptions are not billed per token.",
|
|
18
|
-
amount: "API-equivalent", input: "Input", output: "Output", read: "Cache read", write: "Cache write", total: "Total tokens", requests: "Requests", messages: "Messages",
|
|
18
|
+
amount: "API-equivalent", input: "Input", output: "Output", reasoning: "Reasoning", read: "Cache read", write: "Cache write", total: "Total tokens", requests: "Requests", messages: "Messages",
|
|
19
19
|
notPriced: "not priced", partial: "partial", noTeam: "(no team)", unknown: "unknown",
|
|
20
|
-
f_cache_write_not_reported: "cache writes not reported (Codex) — an estimate", f_not_priced: "not priced: {0}", f_source_unknown: "read before backend and profile were recorded",
|
|
20
|
+
f_cache_write_not_reported: "cache writes not reported (Codex, Muse) — an estimate", f_not_priced: "not priced: {0}", f_source_unknown: "read before backend and profile were recorded",
|
|
21
|
+
f_estimated: "estimated from text size — Kiro records no token counts", f_includes_estimates: "includes estimates (Kiro)", f_cost_reported: "amount as the CLI reported it (no list price for this model)", estimatedPart: "of which estimated: {0}",
|
|
21
22
|
scanning: "Scanning — totals may still grow.", updated: "Updated {0} · read every 10 min", since: "Collected since {0}", notYet: "Not collected yet",
|
|
22
23
|
refresh: "Refresh",
|
|
23
24
|
notMeasured: "Not measured", nm_credit_billed: "Kiro is credit-billed and records no tokens", nm_unsupported: "AgEnD can't read this CLI's usage yet", nm_no_data: "nothing read yet",
|
|
24
25
|
shared: "shares its working directory with {0}; their transcripts can't be told apart",
|
|
25
|
-
empty: "Nothing recorded yet", emptyHint: "Usage is read from Claude Code and
|
|
26
|
+
empty: "Nothing recorded yet", emptyHint: "Usage is read from Claude Code, Codex, Grok, Muse, OpenCode and Antigravity, and estimated for Kiro, from when the fleet started.",
|
|
26
27
|
blocked: "Not offered over the public link", blockedHint: "Usage is offered over the public link only when \"Usage report over the public link\" is on in Settings → Web dashboard — on the dashboard reached directly, on the computer running AgEnD.",
|
|
27
28
|
openSettings: "Open Settings → Web dashboard on that computer",
|
|
28
29
|
partialDays: "Daily detail from {0}: the earlier days in this range are too many rows to send. The rows and totals above cover the whole range; the trend, the heatmap and the CSV start at {0}.",
|
|
@@ -42,14 +43,15 @@ register("fusage", {
|
|
|
42
43
|
range: "期間", today: "今天", r7d: "7 天", month: "本月", all: "全部", custom: "自訂", from: "從", to: "到", apply: "套用",
|
|
43
44
|
group: "分組", g_instance: "Agent", g_backend: "Backend", g_model: "模型", g_profile: "憑證 profile", g_team: "Team(依目前設定)",
|
|
44
45
|
csv: "下載 CSV", basis: "依牌價換算的 API 等值(查證日期 {0})——不是實際花費。訂閱方案不按 token 計費。",
|
|
45
|
-
amount: "API 等值", input: "輸入", output: "輸出", read: "快取讀取", write: "快取寫入", total: "token 總計", requests: "請求數", messages: "訊息數",
|
|
46
|
+
amount: "API 等值", input: "輸入", output: "輸出", reasoning: "推理", read: "快取讀取", write: "快取寫入", total: "token 總計", requests: "請求數", messages: "訊息數",
|
|
46
47
|
notPriced: "未定價", partial: "部分", noTeam: "(不屬於任何 team)", unknown: "未知",
|
|
47
|
-
f_cache_write_not_reported: "未回報快取寫入(Codex)——是估算", f_not_priced: "未定價:{0}", f_source_unknown: "讀取時尚未記錄 backend 與 profile",
|
|
48
|
+
f_cache_write_not_reported: "未回報快取寫入(Codex、Muse)——是估算", f_not_priced: "未定價:{0}", f_source_unknown: "讀取時尚未記錄 backend 與 profile",
|
|
49
|
+
f_estimated: "依文字長度估算——Kiro 不記錄 token 數", f_includes_estimates: "含估算值(Kiro)", f_cost_reported: "金額為 CLI 自行回報(價目表沒有此模型)", estimatedPart: "其中估算:{0}",
|
|
48
50
|
scanning: "掃描中——總數可能還會增加。", updated: "更新於 {0} · 每 10 分鐘讀取一次", since: "自 {0} 起收集", notYet: "尚未收集",
|
|
49
51
|
refresh: "重新整理",
|
|
50
52
|
notMeasured: "未量測", nm_credit_billed: "Kiro 以 credit 計費,不記錄 token", nm_unsupported: "AgEnD 目前還讀不到這個 CLI 的用量", nm_no_data: "尚未讀到任何資料",
|
|
51
53
|
shared: "與 {0} 共用工作目錄,無法分辨各自的 transcript",
|
|
52
|
-
empty: "還沒有任何紀錄", emptyHint: "用量從 Claude Code 與
|
|
54
|
+
empty: "還沒有任何紀錄", emptyHint: "用量從 Claude Code、Codex、Grok、Muse、OpenCode 與 Antigravity 讀取,Kiro 則為估算,自 fleet 啟動起計。",
|
|
53
55
|
blocked: "公開連結上不提供", blockedHint: "只有在設定 → 網頁儀表板裡開啟「透過公開連結提供用量報告」時,公開連結才會提供用量;這個設定要在執行 AgEnD 的那台電腦上、直接開啟的儀表板裡變更。",
|
|
54
56
|
openSettings: "在那台電腦上開啟設定 → 網頁儀表板",
|
|
55
57
|
partialDays: "每日明細從 {0} 起:這段期間更早的日子資料列太多,無法一次送出。上方的各列與總計涵蓋整段期間;趨勢、熱度圖與 CSV 則從 {0} 開始。",
|
|
@@ -95,11 +97,11 @@ export function keyText(group, key) {
|
|
|
95
97
|
const writes = (r) => (r.cacheWrite5m || 0) + (r.cacheWrite1h || 0) + (r.cacheWrite || 0);
|
|
96
98
|
function flagText(f, r) {
|
|
97
99
|
if (f === "not_priced") return tu("f_not_priced", (r.unpriced || []).join(", "));
|
|
98
|
-
return ["cache_write_not_reported", "source_unknown"].includes(f) ? tu(`f_${f}`) : f;
|
|
100
|
+
return ["cache_write_not_reported", "source_unknown", "estimated", "includes_estimates", "cost_reported"].includes(f) ? tu(`f_${f}`) : f;
|
|
99
101
|
}
|
|
100
102
|
|
|
101
103
|
// ── CSV (design §4): the daily rows of this same answer; messages on their own rows (they are per agent, not per model).
|
|
102
|
-
const CSV_COLUMNS = ["date", "zone", "instance", "backend", "model", "tier", "profile", "input", "output", "cache_read", "cache_write_5m", "cache_write_1h", "cache_write", "requests", "messages", "amount", "basis", "flags"];
|
|
104
|
+
const CSV_COLUMNS = ["date", "zone", "instance", "backend", "model", "tier", "profile", "input", "output", "reasoning", "cache_read", "cache_write_5m", "cache_write_1h", "cache_write", "requests", "messages", "amount", "basis", "flags", "estimated"];
|
|
103
105
|
/** One CSV field: quoted when it must be, and never read as a formula by a spreadsheet (=, +, -, @, tab, CR first). */
|
|
104
106
|
export function csvField(v) {
|
|
105
107
|
let s = v === null || v === undefined ? "" : String(v);
|
|
@@ -109,11 +111,11 @@ export function csvField(v) {
|
|
|
109
111
|
export function usageCsv(report) {
|
|
110
112
|
const lines = [CSV_COLUMNS.join(",")];
|
|
111
113
|
for (const d of report.daily || []) {
|
|
112
|
-
lines.push([d.date, d.zone, d.instance, d.backend, d.model, d.tier, d.profile, d.input, d.output, d.cacheRead, d.cacheWrite5m, d.cacheWrite1h, d.cacheWrite,
|
|
113
|
-
d.requests, "", d.amount === null ? "" : d.amount.toFixed(6), report.basis, (d.flags || []).join(" ")].map(csvField).join(","));
|
|
114
|
+
lines.push([d.date, d.zone, d.instance, d.backend, d.model, d.tier, d.profile, d.input, d.output, d.reasoning, d.cacheRead, d.cacheWrite5m, d.cacheWrite1h, d.cacheWrite,
|
|
115
|
+
d.requests, "", d.amount === null ? "" : d.amount.toFixed(6), report.basis, (d.flags || []).join(" "), d.estimated ? "yes" : "no"].map(csvField).join(","));
|
|
114
116
|
}
|
|
115
117
|
for (const m of report.messagesDaily || []) {
|
|
116
|
-
lines.push([m.date, report.zone, m.instance, "", "", "", "", "", "", "", "", "", "", "", m.count, "", report.basis, ""].map(csvField).join(","));
|
|
118
|
+
lines.push([m.date, report.zone, m.instance, "", "", "", "", "", "", "", "", "", "", "", "", m.count, "", report.basis, "", ""].map(csvField).join(","));
|
|
117
119
|
}
|
|
118
120
|
return `${lines.join("\r\n")}\r\n`;
|
|
119
121
|
}
|
|
@@ -151,7 +153,7 @@ export function levels(values) {
|
|
|
151
153
|
return (v) => (!(v > 0) ? 0 : v <= cut[0] ? 1 : v <= cut[1] ? 2 : v <= cut[2] ? 3 : 4);
|
|
152
154
|
}
|
|
153
155
|
|
|
154
|
-
const tokensOf = (d) => d.input + d.output + d.cacheRead + d.cacheWrite5m + d.cacheWrite1h + d.cacheWrite;
|
|
156
|
+
const tokensOf = (d) => d.input + d.output + (d.reasoning || 0) + d.cacheRead + d.cacheWrite5m + d.cacheWrite1h + d.cacheWrite;
|
|
155
157
|
/**
|
|
156
158
|
* Each day of the answer: its tokens (whether it was used at all), the priced part of its amount, whether part of it is
|
|
157
159
|
* not priced, and its parts by zone (a day folded before the fleet's timezone changed keeps its own zone, §5.3).
|
|
@@ -218,7 +220,7 @@ export function thinXLabels(n, slotPx, labelWidthPx) {
|
|
|
218
220
|
/** The trend's series: the top `TOP` agents by the measure over the range, then "others"; one value per date. */
|
|
219
221
|
export function trendSeries(report, dates) {
|
|
220
222
|
const priced = report.totals && report.totals.amount !== null && report.totals.amount > 0;
|
|
221
|
-
const measure = (d) => (priced ? d.amount || 0 : d
|
|
223
|
+
const measure = (d) => (priced ? d.amount || 0 : tokensOf(d));
|
|
222
224
|
const byAgent = new Map();
|
|
223
225
|
for (const d of report.daily || []) byAgent.set(d.instance, (byAgent.get(d.instance) || 0) + measure(d));
|
|
224
226
|
const ranked = [...byAgent.entries()].filter(([, v]) => v > 0).sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0]));
|
|
@@ -327,6 +329,7 @@ function Row({ r, group, max, measure }) {
|
|
|
327
329
|
<td data-label=${tu("amount")} class=${`num${r.amount === null ? " muted" : ""}`}>${amountText(r)}</td>
|
|
328
330
|
<td data-label=${tu("input")} class="num">${tokens(r.input)}</td>
|
|
329
331
|
<td data-label=${tu("output")} class="num">${tokens(r.output)}</td>
|
|
332
|
+
<td data-label=${tu("reasoning")} class="num">${r.reasoningReported === false ? "—" : tokens(r.reasoning || 0)}</td>
|
|
330
333
|
<td data-label=${tu("read")} class="num">${tokens(r.cacheRead)}</td>
|
|
331
334
|
<td data-label=${tu("write")} class="num">${r.flags.includes("cache_write_not_reported") && writes(r) === 0 ? "—" : tokens(writes(r))}</td>
|
|
332
335
|
<td data-label=${tu("total")} class="num">${tokens(r.total)}</td>
|
|
@@ -379,13 +382,14 @@ export function UsageReport({ report, choice, setChoice, refresh, fetchedAt }) {
|
|
|
379
382
|
${report.scanning.active && (!report.scanning.caughtUp || report.scanning.pendingBytes > 0) ? html` <span class="us-scan" role="status">${tu("scanning")} <button type="button" class="btn btn-sm" onClick=${refresh}>${tu("refresh")}</button></span>` : null}</p>
|
|
380
383
|
${empty ? html`<${Empty} icon="chart" title=${tu("empty")} hint=${tu("emptyHint")} />` : html`
|
|
381
384
|
<dl class="us-totals card">
|
|
382
|
-
<div class="ch-metric"><dt>${tu("amount")}</dt><dd>${amountText(report.totals)}
|
|
385
|
+
<div class="ch-metric"><dt>${tu("amount")}</dt><dd>${amountText(report.totals)}${report.totals.estimated
|
|
386
|
+
? html`<span class="us-est">${report.totals.amountEstimated !== null && report.totals.amountEstimated !== undefined ? tu("estimatedPart", money(report.totals.amountEstimated)) : tu("f_includes_estimates")}</span>` : null}</dd></div>
|
|
383
387
|
<div class="ch-metric"><dt>${tu("total")}</dt><dd>${tokens(report.totals.total)}</dd></div>
|
|
384
388
|
<div class="ch-metric"><dt>${tu("requests")}</dt><dd>${n(report.totals.requests)}</dd></div>
|
|
385
389
|
<div class="ch-metric"><dt>${tu("messages")}</dt><dd>${report.totals.messages === null ? "—" : n(report.totals.messages)}</dd></div>
|
|
386
390
|
</dl>
|
|
387
391
|
${rows.length ? html`<table class="us-table"><thead><tr><th scope="col">${tu(`g_${group}`)}</th><th scope="col" class="num">${tu("amount")}</th>
|
|
388
|
-
<th scope="col" class="num">${tu("input")}</th><th scope="col" class="num">${tu("output")}</th><th scope="col" class="num">${tu("read")}</th><th scope="col" class="num">${tu("write")}</th>
|
|
392
|
+
<th scope="col" class="num">${tu("input")}</th><th scope="col" class="num">${tu("output")}</th><th scope="col" class="num">${tu("reasoning")}</th><th scope="col" class="num">${tu("read")}</th><th scope="col" class="num">${tu("write")}</th>
|
|
389
393
|
<th scope="col" class="num">${tu("total")}</th><th scope="col" class="num">${tu("requests")}</th><th scope="col" class="num">${tu("messages")}</th></tr></thead>
|
|
390
394
|
<tbody>${rows.map((r) => html`<${Row} key=${r.key} r=${r} group=${group} max=${max} measure=${measure} />`)}</tbody></table>`
|
|
391
395
|
: html`<p class="note">${tu("noRows")}</p>`}
|
package/dist/ui/panel-log.js
CHANGED
|
@@ -62,7 +62,7 @@ register("log", {
|
|
|
62
62
|
ev_backend_unreachable: "CLI unreachable", ev_startup_backend_unreachable: "CLI unreachable at start", ev_backend_launch_warning: "Launch warning",
|
|
63
63
|
ev_clear_action: "Conversation cleared", ev_normal_exit_action: "Exited", ev_reply_drop_detected: "A reply went missing",
|
|
64
64
|
ev_reply_drop_recovered: "Missing reply recovered", ev_reply_drop_unrecovered: "Missing reply not recovered",
|
|
65
|
-
ev_supervision_ended: "Supervision ended", ev_tmux_server_crash: "tmux crashed", ev_malformed_tool_call: "Malformed tool call", ev_health_check_error: "Health check error", ev_working_state: "Working-state journal",
|
|
65
|
+
ev_supervision_ended: "Supervision ended", ev_tmux_server_crash: "tmux crashed", ev_malformed_tool_call: "Malformed tool call", ev_health_check_error: "Health check error", ev_context_lost: "Started fresh: context lost", ev_working_state: "Working-state journal",
|
|
66
66
|
},
|
|
67
67
|
"zh-TW": {
|
|
68
68
|
offTitle: "紀錄未開啟",
|
|
@@ -100,7 +100,7 @@ register("log", {
|
|
|
100
100
|
ev_backend_unreachable: "連不到 CLI", ev_startup_backend_unreachable: "啟動時連不到 CLI", ev_backend_launch_warning: "啟動警告",
|
|
101
101
|
ev_clear_action: "對話已清除", ev_normal_exit_action: "已結束", ev_reply_drop_detected: "有回覆遺失",
|
|
102
102
|
ev_reply_drop_recovered: "遺失的回覆已補回", ev_reply_drop_unrecovered: "遺失的回覆沒有補回",
|
|
103
|
-
ev_supervision_ended: "監督結束", ev_tmux_server_crash: "tmux 當掉", ev_malformed_tool_call: "格式錯誤的工具呼叫", ev_health_check_error: "健康檢查錯誤", ev_working_state: "工作狀態紀錄",
|
|
103
|
+
ev_supervision_ended: "監督結束", ev_tmux_server_crash: "tmux 當掉", ev_malformed_tool_call: "格式錯誤的工具呼叫", ev_health_check_error: "健康檢查錯誤", ev_context_lost: "改用全新對話:context 遺失", ev_working_state: "工作狀態紀錄",
|
|
104
104
|
},
|
|
105
105
|
});
|
|
106
106
|
const tl = (key, ...a) => t(`log.${key}`, ...a);
|
package/dist/ui/panel-needs.js
CHANGED
|
@@ -25,7 +25,7 @@ import { openSignIn, signInOffered } from "./backend-signin.js";
|
|
|
25
25
|
register("needs", {
|
|
26
26
|
en: {
|
|
27
27
|
title: "Needs you", empty: "Nothing needs you right now", emptyHint: "When an agent waits for you, it shows here — and in your chat app's General.", emptyHintWeb: "When an agent waits for you, it shows here.",
|
|
28
|
-
open: "Open chat", openCard: "Open the card", noAssignee: "Task board (nobody assigned)", signIn: "Sign in",
|
|
28
|
+
open: "Open chat", openCard: "Open the card", noAssignee: "Task board (nobody assigned)", fleetSignIns: "Fleet sign-ins", signIn: "Sign in",
|
|
29
29
|
gap: "not wrapped up: {0}", gapUnchecked: "{0} checklist item(s) unchecked", gapNoResult: "no result", gapJoin: ", ", acknowledge: "Acknowledge", acknowledging: "Acknowledging…", answering: "Answering…",
|
|
30
30
|
ageNow: "just now", ageMin: "{0} min", ageHour: "{0} h", ageDay: "{0} d",
|
|
31
31
|
notifyTitle: "Notify me on this device", notifyOn: "Notifications are on for this browser while a tab is open.",
|
|
@@ -38,7 +38,7 @@ register("needs", {
|
|
|
38
38
|
},
|
|
39
39
|
"zh-TW": {
|
|
40
40
|
title: "等你處理", empty: "目前沒有需要你處理的事", emptyHint: "agent 在等你時,會出現在這裡——也會出現在聊天 app 的 General。", emptyHintWeb: "agent 在等你時,會出現在這裡。",
|
|
41
|
-
open: "開啟聊天", openCard: "打開卡片", noAssignee: "任務看板(沒有負責人)", signIn: "登入",
|
|
41
|
+
open: "開啟聊天", openCard: "打開卡片", noAssignee: "任務看板(沒有負責人)", fleetSignIns: "Fleet 登入", signIn: "登入",
|
|
42
42
|
gap: "還沒補齊:{0}", gapUnchecked: "還有 {0} 項沒勾", gapNoResult: "沒有產出總結", gapJoin: "、", acknowledge: "確認", acknowledging: "確認中…", answering: "回覆中…",
|
|
43
43
|
ageNow: "剛剛", ageMin: "{0} 分鐘", ageHour: "{0} 小時", ageDay: "{0} 天",
|
|
44
44
|
notifyTitle: "在這台裝置通知我", notifyOn: "這個瀏覽器的通知已開啟(需要開著分頁)。",
|
|
@@ -143,7 +143,7 @@ export function NeedsPanel({ navKey }) {
|
|
|
143
143
|
<div data-trust="panel-content" class="panel-body"><div class="col">
|
|
144
144
|
${!items.length ? html`<${Empty} icon="check" title=${tn("empty")} hint=${tn(chatApp ? "emptyHint" : "emptyHintWeb")} />`
|
|
145
145
|
: groups.map((g) => html`<section key=${g.instance} class="n-group" aria-label=${g.instance}>
|
|
146
|
-
<h2 class="n-group-head">${g.instance ? html`<a href=${chatPath(g.instance)} title=${g.instance}>${nameFor(g.instance)}</a>` : tn("noAssignee")}</h2>
|
|
146
|
+
<h2 class="n-group-head">${g.instance ? html`<a href=${chatPath(g.instance)} title=${g.instance}>${nameFor(g.instance)}</a>` : tn(g.items.some(i => i.type === "backend") ? "fleetSignIns" : "noAssignee")}</h2>
|
|
147
147
|
${g.items.map((item) => html`<${NeedsItem} key=${item.id} item=${item} nowMs=${nowMs} owner=${owner} />`)}
|
|
148
148
|
</section>`)}
|
|
149
149
|
<${NotifyToggle} />
|
|
@@ -200,7 +200,7 @@ function NeedsItem({ item, nowMs, owner }) {
|
|
|
200
200
|
disabled=${promptBusy} onClick=${() => answer(a.id)}>${(p ? p.busy : fallback === "busy") ? tn("answering") : a.label}</button>`) : null}
|
|
201
201
|
${item.type === "delivery" ? html`<button type="button" class="btn btn-sm" disabled=${!!ack} onClick=${acknowledge}>
|
|
202
202
|
<${Icon} name="check" size=${14} />${ack === "busy" ? tn("acknowledging") : tn("acknowledge")}</button>` : null}
|
|
203
|
-
${item.reason === "auth_paused" && item.signIn && signInOffered() ? html`<button type="button" class="btn btn-sm btn-primary" onClick=${() => openSignIn(item.signIn)}>${tn("signIn")}</button>` : null}
|
|
203
|
+
${(item.reason === "auth_paused" || item.reason === "backend_signin") && item.signIn && signInOffered() ? html`<button type="button" class="btn btn-sm btn-primary" onClick=${() => openSignIn(item.signIn)}>${tn("signIn")}</button>` : null}
|
|
204
204
|
${item.type === "task" && item.card ? html`<a class="btn btn-sm" href=${`/ui/fleet?card=${encodeURIComponent(item.card.code)}`}>${tn("openCard")}</a>` : null}
|
|
205
205
|
${item.instance ? html`<a class="btn btn-sm btn-ghost" href=${chatPath(item.instance)}>${tn("open")}</a>` : null}
|
|
206
206
|
</div>
|
|
@@ -952,8 +952,13 @@ function Classic({ ctx, search, openDialog }) {
|
|
|
952
952
|
})}</div>`;
|
|
953
953
|
}
|
|
954
954
|
|
|
955
|
+
const configuredNoticeMode = (value, route) => value === false ? false : value === "dm" || route === "dm" ? "dm" : true;
|
|
956
|
+
const noticeMode = (v) => v === "dm" ? "dm" : v === "false" || v === false ? false : true;
|
|
957
|
+
const noticeChoices = () => [{ value: "true", label: tn("noticeTopic") }, { value: "dm", label: tn("noticeDm") }, { value: "false", label: tn("noticeOff") }];
|
|
958
|
+
const noticeLabel = (v) => tn(v === "dm" ? "noticeDm" : v === false ? "noticeOff" : "noticeTopic");
|
|
959
|
+
|
|
955
960
|
/** General's form, from the saved defaults (`d`) and ClassicBot's (`c`). */
|
|
956
|
-
function generalForm(d, c, fleet = {}) {
|
|
961
|
+
function generalForm(d, c, fleet = {}, schema = {}) {
|
|
957
962
|
const hang = d.hang_detector || {}, startup = d.startup || {};
|
|
958
963
|
return {
|
|
959
964
|
backend: d.backend || "claude-code", model: d.model || "", locale: d.locale || "", auto: String(d.auto_pause_after ?? 0),
|
|
@@ -966,6 +971,9 @@ function generalForm(d, c, fleet = {}) {
|
|
|
966
971
|
// #2347 §10 review: unset startup concurrency is automatic (deriveSpawnConcurrency: 2–10 by free memory and cores),
|
|
967
972
|
// not 10 — an empty field, and a save that leaves it unset (the defaults merge replaces `startup` whole).
|
|
968
973
|
concurrency: startup.concurrency == null ? "" : String(startup.concurrency), stagger: String(startup.stagger_delay_ms ?? 500),
|
|
974
|
+
tips: String(configuredNoticeMode(d.tips, fleet.web?.notice_delivery?.tips)),
|
|
975
|
+
replyTriggers: Boolean(d.reply_triggers ?? schema.reply_triggers_default),
|
|
976
|
+
classicReplyTriggers: Boolean(c.reply_triggers ?? d.reply_triggers ?? schema.reply_triggers_default), classicReplyTriggersInherit: !hasOwn(c, "reply_triggers"),
|
|
969
977
|
classicBackend: c.backend || d.backend || "claude-code",
|
|
970
978
|
classicToolProgress: c.tool_progress ?? d.tool_progress ?? "off", classicToolProgressInherit: !hasOwn(c, "tool_progress"),
|
|
971
979
|
classicReply: c.reply_completion_guard ?? d.reply_completion_guard ?? true, classicReplyInherit: !hasOwn(c, "reply_completion_guard"),
|
|
@@ -985,7 +993,7 @@ function General({ ctx, part = "all" }) {
|
|
|
985
993
|
const hang = d.hang_detector || {}, startup = d.startup || {};
|
|
986
994
|
const primary = channelsOf(ctx.fleet)[0];
|
|
987
995
|
const original = useMemo(() => ({ c: structuredClone(c) }), []);
|
|
988
|
-
const base = useMemo(() => generalForm(d, c, ctx.fleet), []);
|
|
996
|
+
const base = useMemo(() => generalForm(d, c, ctx.fleet, schema), []);
|
|
989
997
|
const [f, setF] = useDraft(ctx, "general", () => base);
|
|
990
998
|
const set = (k) => (v) => setF((x) => ({ ...x, [k]: v }));
|
|
991
999
|
/** The class of a field's row: `field`, and `s-dirty` while one of its keys differs from what is saved. */
|
|
@@ -1011,27 +1019,31 @@ function General({ ctx, part = "all" }) {
|
|
|
1011
1019
|
const defaultsPatch = changedFields({
|
|
1012
1020
|
backend: f.backend, model: f.model || undefined, locale: f.locale || null, auto_pause_after: num(f.auto),
|
|
1013
1021
|
agent_mode: f.agent_mode, tool_set: f.tool_set || null, tool_progress: f.tool_progress, cross_instance_visibility: f.visibility,
|
|
1014
|
-
reply_completion_guard: f.reply, log_level: f.log_level,
|
|
1015
|
-
// The dashboard features every agent may use unless its own setting says otherwise. All
|
|
1022
|
+
tips: noticeMode(f.tips), reply_triggers: f.replyTriggers, reply_completion_guard: f.reply, log_level: f.log_level,
|
|
1023
|
+
// The dashboard features every agent may use unless its own setting says otherwise. All of them go, because the write
|
|
1016
1024
|
// to the fleet's defaults merges top-level keys only (`dashboard` is replaced whole): the untouched ones as saved.
|
|
1017
|
-
dashboard: Object.fromEntries(DASHBOARD_FEATURES.map((k) => [k, f[`dash_${k}`]])),
|
|
1025
|
+
dashboard: Object.fromEntries(DASHBOARD_FEATURES.filter((k) => k !== "office").map((k) => [k, f[`dash_${k}`]])),
|
|
1026
|
+
office_access: f.dash_office,
|
|
1018
1027
|
hang_detector: { enabled: f.hangOn, timeout_minutes: num(f.hang) },
|
|
1019
1028
|
startup: { ...(f.concurrency.trim() === "" ? {} : { concurrency: num(f.concurrency) }), stagger_delay_ms: num(f.stagger) },
|
|
1020
1029
|
}, {
|
|
1021
1030
|
backend: d.backend || "claude-code", model: d.model || undefined, locale: d.locale || null, auto_pause_after: d.auto_pause_after ?? 0,
|
|
1022
1031
|
agent_mode: d.agent_mode || "mcp", tool_set: TOOL_SETS.includes(d.tool_set) ? d.tool_set : null, tool_progress: d.tool_progress ?? "off",
|
|
1023
|
-
cross_instance_visibility: visibilityDefault(d), reply_completion_guard: d.reply_completion_guard ?? true, log_level: d.log_level || "info",
|
|
1024
|
-
dashboard: Object.fromEntries(DASHBOARD_FEATURES.map((k) => [k, dashboardDefault(d, k)])),
|
|
1032
|
+
tips: configuredNoticeMode(d.tips, ctx.fleet.web?.notice_delivery?.tips), cross_instance_visibility: visibilityDefault(d), reply_triggers: Boolean(d.reply_triggers ?? schema.reply_triggers_default), reply_completion_guard: d.reply_completion_guard ?? true, log_level: d.log_level || "info",
|
|
1033
|
+
dashboard: Object.fromEntries(DASHBOARD_FEATURES.filter((k) => k !== "office").map((k) => [k, dashboardDefault(d, k)])),
|
|
1034
|
+
office_access: dashboardDefault(d, "office"),
|
|
1025
1035
|
hang_detector: { enabled: hang.enabled !== false, timeout_minutes: hang.timeout_minutes ?? HANG_TIMEOUT_DEFAULT_MINUTES },
|
|
1026
1036
|
startup: { ...(startup.concurrency == null ? {} : { concurrency: startup.concurrency }), stagger_delay_ms: startup.stagger_delay_ms ?? 500 },
|
|
1027
1037
|
});
|
|
1028
1038
|
const oc = original.c;
|
|
1029
1039
|
const classicPatch = changedFields({
|
|
1040
|
+
reply_triggers: f.classicReplyTriggersInherit ? null : f.classicReplyTriggers,
|
|
1030
1041
|
backend: f.classicBackend,
|
|
1031
1042
|
tool_progress: f.classicToolProgressInherit ? null : f.classicToolProgress,
|
|
1032
1043
|
reply_completion_guard: f.classicReplyInherit ? null : f.classicReply,
|
|
1033
1044
|
admin_users: f.admins, allowed_guilds: f.guilds,
|
|
1034
1045
|
}, {
|
|
1046
|
+
reply_triggers: hasOwn(oc, "reply_triggers") ? oc.reply_triggers : null,
|
|
1035
1047
|
backend: oc.backend || d.backend || "claude-code",
|
|
1036
1048
|
tool_progress: hasOwn(oc, "tool_progress") ? oc.tool_progress : null,
|
|
1037
1049
|
reply_completion_guard: hasOwn(oc, "reply_completion_guard") ? oc.reply_completion_guard : null,
|
|
@@ -1054,7 +1066,7 @@ function General({ ctx, part = "all" }) {
|
|
|
1054
1066
|
// ClassicBot's inherited ones say what they inherit from Agent defaults.
|
|
1055
1067
|
const unset = {
|
|
1056
1068
|
locale: !d.locale, backend: !d.backend, model: !d.model, auto: !hasOwn(d, "auto_pause_after"), tool_progress: !hasOwn(d, "tool_progress"),
|
|
1057
|
-
visibility: !VISIBILITY_MODES.includes(d.cross_instance_visibility), reply: !hasOwn(d, "reply_completion_guard"), tool_set: !d.tool_set,
|
|
1069
|
+
tips: !hasOwn(d, "tips"), replyTriggers: !hasOwn(d, "reply_triggers"), visibility: !VISIBILITY_MODES.includes(d.cross_instance_visibility), reply: !hasOwn(d, "reply_completion_guard"), tool_set: !d.tool_set,
|
|
1058
1070
|
log_level: !d.log_level, agent_mode: !d.agent_mode, hangOn: !hasOwn(hang, "enabled"), hang: !hasOwn(hang, "timeout_minutes"),
|
|
1059
1071
|
concurrency: !hasOwn(startup, "concurrency"), stagger: !hasOwn(startup, "stagger_delay_ms"),
|
|
1060
1072
|
};
|
|
@@ -1077,6 +1089,8 @@ function General({ ctx, part = "all" }) {
|
|
|
1077
1089
|
<div class=${fc("field", "tool_progress")}>${L(tn("toolProgress"), "defaults.tool_progress", "g-tp", "tool_progress")}<${Select} id="g-tp" value=${f.tool_progress} onChange=${set("tool_progress")} options=${TOOL_PROGRESS} /></div>
|
|
1078
1090
|
<div class=${fc("field", "visibility")}>${L(tn("crossInstanceVisibility"), "defaults.cross_instance_visibility", "g-vis", "visibility")}<${Select} id="g-vis" value=${f.visibility} onChange=${set("visibility")} options=${VISIBILITY_MODES} />
|
|
1079
1091
|
<p class="note">${tn("crossInstanceVisibilityHint")}</p></div>
|
|
1092
|
+
<div class=${fc("field", "tips")}>${L(tn("dailyTips"), "defaults.tips", "g-tips", "tips")}<${Select} id="g-tips" value=${f.tips} onChange=${set("tips")} options=${noticeChoices()} /><${InEffect} text=${noticeLabel(noticeMode(f.tips))} /><p class="note">${tn("dailyTipsHint")}</p></div>
|
|
1093
|
+
<div class=${fc("field", "replyTriggers")}><label class="check"><input id="g-reply-triggers" type="checkbox" checked=${f.replyTriggers} onChange=${(e) => set("replyTriggers")(e.target.checked)} /><span>${tn("replyTriggers")}</span>${dm("replyTriggers")}<${Impact} schema=${schema} field="defaults.reply_triggers" /></label><p class="note">${tn("replyTriggersHint")}</p></div>
|
|
1080
1094
|
<div class=${fc("field", "reply")}><label class="check"><input id="g-reply" type="checkbox" checked=${f.reply} onChange=${(e) => set("reply")(e.target.checked)} /><span>${tn("replyCompletionGuard")}</span>${dm("reply")}<${Impact} schema=${schema} field="defaults.reply_completion_guard" /></label>
|
|
1081
1095
|
<p class="note">${fleetReply}</p></div>
|
|
1082
1096
|
</div>
|
|
@@ -1093,6 +1107,9 @@ function General({ ctx, part = "all" }) {
|
|
|
1093
1107
|
<div class=${fc("field", "classicToolProgress", "classicToolProgressInherit")}>${L(tn("toolProgress"), "classic_defaults.tool_progress", "g-ctp")}
|
|
1094
1108
|
<${Override} inherit=${f.classicToolProgressInherit} onInherit=${set("classicToolProgressInherit")} inherited=${fromDefaults("tool_progress", d.tool_progress ?? "off", "#g-tp")}>
|
|
1095
1109
|
<${Select} id="g-ctp" disabled=${f.classicToolProgressInherit} value=${f.classicToolProgressInherit ? (d.tool_progress ?? "off") : f.classicToolProgress} onChange=${set("classicToolProgress")} options=${TOOL_PROGRESS} /></${Override}></div>
|
|
1110
|
+
<div class=${fc("field", "classicReplyTriggers", "classicReplyTriggersInherit")}>${L(tn("replyTriggers"), "classic_defaults.reply_triggers")}
|
|
1111
|
+
<${Override} inherit=${f.classicReplyTriggersInherit} onInherit=${set("classicReplyTriggersInherit")} inherited=${fromDefaults("reply_triggers", Boolean(d.reply_triggers ?? schema.reply_triggers_default), "#g-reply-triggers")}>
|
|
1112
|
+
<label class="check"><input id="g-creply-triggers" type="checkbox" disabled=${f.classicReplyTriggersInherit} checked=${f.classicReplyTriggersInherit ? Boolean(d.reply_triggers ?? schema.reply_triggers_default) : f.classicReplyTriggers} onChange=${(e) => set("classicReplyTriggers")(e.target.checked)} /><span>${tn("replyTriggers")}</span></label></${Override}><p class="note">${tn("replyTriggersHint")}</p></div>
|
|
1096
1113
|
<div class=${fc("field", "classicReply", "classicReplyInherit")}>${L(tn("replyCompletionGuard"), "classic_defaults.reply_completion_guard")}
|
|
1097
1114
|
<${Override} inherit=${f.classicReplyInherit} onInherit=${set("classicReplyInherit")} inherited=${fromDefaults("reply_completion_guard", d.reply_completion_guard ?? true, "#g-reply")}>
|
|
1098
1115
|
<label class="check"><input id="g-creply" type="checkbox" disabled=${f.classicReplyInherit} checked=${f.classicReplyInherit ? (d.reply_completion_guard ?? true) : f.classicReply} onChange=${(e) => set("classicReply")(e.target.checked)} /><span>${tn("replyCompletionGuard")}</span></label></${Override}>
|
|
@@ -1140,7 +1157,7 @@ function General({ ctx, part = "all" }) {
|
|
|
1140
1157
|
* the temporary public link none of it can be changed — the form says so and stays disabled (the server refuses too).
|
|
1141
1158
|
*/
|
|
1142
1159
|
export const WEB_READ_ONLY = [
|
|
1143
|
-
"web.allowed_hosts", "web.view_access", "web.
|
|
1160
|
+
"web.allowed_hosts", "web.view_access", "web.preview", "web.preview_port", "web.preview_origin", "web.preview_on_public_link",
|
|
1144
1161
|
"web.usage_panel", "web.search", "web.provider_secrets", "web.upload_max_file_mb", "web.upload_max_total_mb", "web_terminal.bind", "web_terminal.tunnel",
|
|
1145
1162
|
];
|
|
1146
1163
|
/**
|
|
@@ -1173,6 +1190,7 @@ function WebSection({ ctx, staged, part = "all" }) {
|
|
|
1173
1190
|
// serves their reads there).
|
|
1174
1191
|
const overPublicLink = globalThis.document?.body?.dataset?.publicLink === "1";
|
|
1175
1192
|
const original = useMemo(() => ({
|
|
1193
|
+
notify: configuredNoticeMode(web.notify_login, web.notice_delivery?.login),
|
|
1176
1194
|
echo: web.echo_to_channel ?? true,
|
|
1177
1195
|
log: web.log_tab === true, // #1218: off by default
|
|
1178
1196
|
usagePub: web.usage_report_on_public_link === true, // #2122: off by default
|
|
@@ -1182,7 +1200,7 @@ function WebSection({ ctx, staged, part = "all" }) {
|
|
|
1182
1200
|
}), []);
|
|
1183
1201
|
const text = (v) => (v === null || v === undefined ? "" : String(v));
|
|
1184
1202
|
/** #2347: a field's row class: `s-dirty` while it differs from what is saved (the draft may come from before). */
|
|
1185
|
-
const savedForm = useMemo(() => ({ echo: original.echo, log: original.log, usagePub: original.usagePub, pub: original.pub.allow_public,
|
|
1203
|
+
const savedForm = useMemo(() => ({ notify: String(original.notify), echo: original.echo, log: original.log, usagePub: original.usagePub, pub: original.pub.allow_public,
|
|
1186
1204
|
ttl: String(original.pub.ttl_minutes), protocol: original.pub.protocol, hostname: original.pub.hostname, originPort: String(original.pub.origin_port),
|
|
1187
1205
|
abs: text(original.session.absolute_hours), idle: text(original.session.idle_hours), termOn: original.terminal.enabled !== false,
|
|
1188
1206
|
termTtl: text(original.terminal.ttl_minutes), autoOpen: original.pub.auto_open }), []);
|
|
@@ -1194,6 +1212,7 @@ function WebSection({ ctx, staged, part = "all" }) {
|
|
|
1194
1212
|
const pub = pending.public_link || {}, session = pending.session?.local || {}, terminal = pending.web_terminal || {};
|
|
1195
1213
|
const pick = (obj, key, fallback) => Object.prototype.hasOwnProperty.call(obj, key) ? obj[key] : fallback;
|
|
1196
1214
|
return {
|
|
1215
|
+
notify: String(pick(pending, "notify_login", original.notify)),
|
|
1197
1216
|
echo: pick(pending, "echo_to_channel", original.echo), log: pick(pending, "log_tab", original.log), usagePub: pick(pending, "usage_report_on_public_link", original.usagePub),
|
|
1198
1217
|
pub: pick(pub, "allow_public", original.pub.allow_public), ttl: String(pick(pub, "ttl_minutes", original.pub.ttl_minutes)), protocol: pick(pub, "protocol", original.pub.protocol),
|
|
1199
1218
|
hostname: pick(pub, "hostname", original.pub.hostname), originPort: String(pick(pub, "origin_port", original.pub.origin_port)), autoOpen: pick(pub, "auto_open", original.pub.auto_open),
|
|
@@ -1242,6 +1261,7 @@ function WebSection({ ctx, staged, part = "all" }) {
|
|
|
1242
1261
|
const terminalPatch = changedFields({ enabled: f.termOn === (original.terminal.enabled !== false) ? original.terminal.enabled : f.termOn ? null : false,
|
|
1243
1262
|
ttl_minutes: value(f.termTtl) }, original.terminal);
|
|
1244
1263
|
const body = {
|
|
1264
|
+
...(noticeMode(f.notify) !== original.notify ? { notify_login: noticeMode(f.notify) } : {}),
|
|
1245
1265
|
...(f.echo !== original.echo ? { echo_to_channel: f.echo } : {}),
|
|
1246
1266
|
...(f.log !== original.log ? { log_tab: f.log } : {}),
|
|
1247
1267
|
...(f.usagePub !== original.usagePub ? { usage_report_on_public_link: f.usagePub } : {}),
|
|
@@ -1250,6 +1270,7 @@ function WebSection({ ctx, staged, part = "all" }) {
|
|
|
1250
1270
|
...(Object.keys(terminalPatch).length ? { web_terminal: terminalPatch } : {}),
|
|
1251
1271
|
};
|
|
1252
1272
|
const fields = [
|
|
1273
|
+
...(body.notify_login !== undefined ? ["web.notify_login"] : []),
|
|
1253
1274
|
...(body.echo_to_channel !== undefined ? ["web.echo_to_channel"] : []),
|
|
1254
1275
|
...(body.log_tab !== undefined ? ["web.log_tab"] : []),
|
|
1255
1276
|
...(body.usage_report_on_public_link !== undefined ? ["web.usage_report_on_public_link"] : []),
|
|
@@ -1297,6 +1318,7 @@ function WebSection({ ctx, staged, part = "all" }) {
|
|
|
1297
1318
|
${overPublicLink && part !== "readonly" ? html`<p class="note" role="status" id="webPublicRefused">${tn("webPublicRefused")}</p>` : null}
|
|
1298
1319
|
${has("access") ? lock(html`<section class="card"><h3>${tn("webSessionTitle")}</h3>
|
|
1299
1320
|
<p class="note">${tn("webSessionHint")}</p>
|
|
1321
|
+
<div class=${fc("field", "notify")}><label for="webNotifyLogin">${tn("webNotifyLogin")}<${Impact} schema=${schema} field="web.notify_login" /></label><${Select} id="webNotifyLogin" value=${f.notify} onChange=${set("notify")} options=${noticeChoices()} /><${InEffect} text=${noticeLabel(noticeMode(f.notify))} />${web.notify_login === undefined ? html`<${DefaultMark} />` : null}<p class="note">${tn("webNotifyLoginHint")}</p></div>
|
|
1300
1322
|
<div class="grid2">
|
|
1301
1323
|
<div class=${fc("field", "abs")}><label for="webSessionAbsolute">${tn("sessionAbsolute")}</label><input id="webSessionAbsolute" type="number" min="1" max="720" step="any"
|
|
1302
1324
|
class=${errors.abs ? "invalid" : ""} value=${f.abs} onInput=${(e) => set("abs")(e.target.value)} /><${Feedback} error=${errors.abs} />
|
|
@@ -642,6 +642,7 @@ export function ClassicDialog({ room, ctx, onClose }) {
|
|
|
642
642
|
const inherited = {
|
|
643
643
|
backend: cd.backend || fd.backend || "claude-code", model: cd.model || fd.model || "",
|
|
644
644
|
auto_pause_after: cd.auto_pause_after ?? fd.auto_pause_after ?? 0, tool_progress: cd.tool_progress ?? fd.tool_progress ?? "off",
|
|
645
|
+
reply_triggers: Boolean(cd.reply_triggers ?? fd.reply_triggers ?? schema.reply_triggers_default),
|
|
645
646
|
reply_completion_guard: cd.reply_completion_guard ?? fd.reply_completion_guard ?? true,
|
|
646
647
|
};
|
|
647
648
|
const c = room;
|
|
@@ -649,8 +650,9 @@ export function ClassicDialog({ room, ctx, onClose }) {
|
|
|
649
650
|
backend: c.backend || inherited.backend, model: c.model || "",
|
|
650
651
|
auto_pause_after: String(c.auto_pause_after ?? inherited.auto_pause_after), tool_progress: c.tool_progress ?? inherited.tool_progress,
|
|
651
652
|
reply_completion_guard: c.reply_completion_guard ?? inherited.reply_completion_guard,
|
|
653
|
+
reply_triggers: c.reply_triggers ?? inherited.reply_triggers,
|
|
652
654
|
collab: !!c.collab, web_echo: classicWebEchoEffective(c, fleet), context_lines: String(c.context_lines ?? cd.context_lines ?? 5),
|
|
653
|
-
inherit: { auto_pause_after: !hasOwn(c, "auto_pause_after"), tool_progress: !hasOwn(c, "tool_progress"), reply_completion_guard: !hasOwn(c, "reply_completion_guard") },
|
|
655
|
+
inherit: { reply_triggers: !hasOwn(c, "reply_triggers"), auto_pause_after: !hasOwn(c, "auto_pause_after"), tool_progress: !hasOwn(c, "tool_progress"), reply_completion_guard: !hasOwn(c, "reply_completion_guard") },
|
|
654
656
|
}));
|
|
655
657
|
const set = (k) => (v) => setF((x) => ({ ...x, [k]: v }));
|
|
656
658
|
const setInherit = (k) => (on) => setF((x) => ({ ...x, inherit: { ...x.inherit, [k]: on } }));
|
|
@@ -664,12 +666,14 @@ export function ClassicDialog({ room, ctx, onClose }) {
|
|
|
664
666
|
auto_pause_after: f.inherit.auto_pause_after ? null : Number(f.auto_pause_after),
|
|
665
667
|
tool_progress: f.inherit.tool_progress ? null : f.tool_progress,
|
|
666
668
|
reply_completion_guard: f.inherit.reply_completion_guard ? null : f.reply_completion_guard,
|
|
669
|
+
reply_triggers: f.inherit.reply_triggers ? null : f.reply_triggers,
|
|
667
670
|
collab: f.collab, context_lines: Number(f.context_lines), web_echo: f.web_echo,
|
|
668
671
|
}, {
|
|
669
672
|
backend: c.backend || inherited.backend, model: (c.model && c.model.trim()) || null,
|
|
670
673
|
auto_pause_after: hasOwn(c, "auto_pause_after") ? c.auto_pause_after : null,
|
|
671
674
|
tool_progress: hasOwn(c, "tool_progress") ? c.tool_progress : null,
|
|
672
675
|
reply_completion_guard: hasOwn(c, "reply_completion_guard") ? c.reply_completion_guard : null,
|
|
676
|
+
reply_triggers: hasOwn(c, "reply_triggers") ? c.reply_triggers : null,
|
|
673
677
|
collab: !!c.collab, context_lines: c.context_lines ?? cd.context_lines ?? 5, web_echo: classicWebEchoEffective(c, fleet),
|
|
674
678
|
});
|
|
675
679
|
const stage = async () => {
|
|
@@ -707,6 +711,9 @@ export function ClassicDialog({ room, ctx, onClose }) {
|
|
|
707
711
|
<label class="check"><input type="checkbox" disabled=${f.inherit.reply_completion_guard} checked=${f.inherit.reply_completion_guard ? inherited.reply_completion_guard : f.reply_completion_guard}
|
|
708
712
|
onChange=${(e) => set("reply_completion_guard")(e.target.checked)} /><span>${tn("replyCompletionGuard")}</span></label></${Override}>
|
|
709
713
|
<p class="note">${replyHint(f.backend, classicMode, fd.kiro_ui)}</p></div>
|
|
714
|
+
<div class="field">${L(tn("replyTriggers"), "classic.reply_triggers")}
|
|
715
|
+
<${Override} inherit=${f.inherit.reply_triggers} onInherit=${setInherit("reply_triggers")} inherited=${roomInh("reply_triggers", "", "#g-creply-triggers", "#g-reply-triggers")}>
|
|
716
|
+
<label class="check"><input type="checkbox" disabled=${f.inherit.reply_triggers} checked=${f.inherit.reply_triggers ? inherited.reply_triggers : f.reply_triggers} onChange=${(e) => set("reply_triggers")(e.target.checked)} /><span>${tn("replyTriggers")}</span></label></${Override}><p class="note">${tn("replyTriggersHint")}</p></div>
|
|
710
717
|
<label class="check"><input type="checkbox" checked=${f.collab} onChange=${(e) => set("collab")(e.target.checked)} /><span>${tn("collabMode")}</span><${Impact} schema=${schema} field="classic.collab" /></label>
|
|
711
718
|
<label class="check"><input type="checkbox" checked=${f.web_echo} onChange=${(e) => set("web_echo")(e.target.checked)} /><span>${tn("webEcho")}</span><${Impact} schema=${schema} field="classic.web_echo" /></label>
|
|
712
719
|
</div>
|
|
@@ -40,19 +40,25 @@ export function changedFields(next, baseline) {
|
|
|
40
40
|
|
|
41
41
|
/**
|
|
42
42
|
* The dashboard features an agent may use (dashboard-permissions.ts): each "inherit" (the fleet default: `defaults.dashboard`,
|
|
43
|
-
* else allowed), "on" or "off". The patch names only the features that changed: null
|
|
43
|
+
* else allowed — off for OFF_UNLESS_ON, `office`), "on" or "off". The patch names only the features that changed: null
|
|
44
|
+
* follows the default again.
|
|
44
45
|
*/
|
|
45
|
-
export const DASHBOARD_FEATURES = ["appearance", "task_board", "web_settings"];
|
|
46
|
+
export const DASHBOARD_FEATURES = ["appearance", "task_board", "web_settings", "office"];
|
|
47
|
+
/** #2578: the features a person switches on — unset is off (dashboard-permissions.ts OFF_UNLESS_ON). */
|
|
48
|
+
export const OFF_UNLESS_ON = ["office"];
|
|
46
49
|
export const DASHBOARD_CHOICES = ["inherit", "on", "off"];
|
|
47
50
|
const dashboardOf = (v) => (v && typeof v === "object" && !Array.isArray(v) ? v : {});
|
|
48
|
-
/** What a feature is for an agent with no setting of its own: the default's, else allowed. */
|
|
49
|
-
export const dashboardDefault = (defaults, feature) =>
|
|
51
|
+
/** What a feature is for an agent with no setting of its own: the default's, else allowed (off for OFF_UNLESS_ON). */
|
|
52
|
+
export const dashboardDefault = (defaults, feature) => {
|
|
53
|
+
const v = feature === "office" && defaults && Object.hasOwn(defaults, "office_access") ? defaults.office_access : dashboardOf(defaults && defaults.dashboard)[feature];
|
|
54
|
+
return OFF_UNLESS_ON.includes(feature) ? v === true : v !== false;
|
|
55
|
+
};
|
|
50
56
|
export function dashboardForm(inst) {
|
|
51
|
-
const own = dashboardOf(inst.dashboard);
|
|
57
|
+
const own = { ...dashboardOf(inst.dashboard), ...(Object.hasOwn(inst, "office_access") ? { office: inst.office_access } : {}) };
|
|
52
58
|
return Object.fromEntries(DASHBOARD_FEATURES.map((f) => [f, own[f] === true ? "on" : own[f] === false ? "off" : "inherit"]));
|
|
53
59
|
}
|
|
54
60
|
export function dashboardPatchValue(choices) {
|
|
55
|
-
return Object.fromEntries(DASHBOARD_FEATURES.map((f) => [f, choices[f] === "on" ? true : choices[f] === "off" ? false : null]));
|
|
61
|
+
return Object.fromEntries(DASHBOARD_FEATURES.filter((f) => f !== "office").map((f) => [f, choices[f] === "on" ? true : choices[f] === "off" ? false : null]));
|
|
56
62
|
}
|
|
57
63
|
|
|
58
64
|
/** #1302: cross-instance notices. Unset, or a value the fleet does not know, means full. */
|
|
@@ -175,6 +181,7 @@ export function agentPatch(form, inst, defaults, visibilityBaseline, statusEmoji
|
|
|
175
181
|
display_name: form.inherit.display_name ? null : form.display_name.trim(),
|
|
176
182
|
status_emojis: form.status_emojis,
|
|
177
183
|
dashboard: dashboardPatchValue(form.dashboard),
|
|
184
|
+
office_access: form.dashboard.office === "on" ? true : form.dashboard.office === "off" ? false : null,
|
|
178
185
|
};
|
|
179
186
|
return changedFields(next, {
|
|
180
187
|
backend: inst.backend || defaults.backend || "claude-code",
|
|
@@ -198,6 +205,7 @@ export function agentPatch(form, inst, defaults, visibilityBaseline, statusEmoji
|
|
|
198
205
|
display_name: hasOwn(inst, "display_name") ? inst.display_name : null,
|
|
199
206
|
status_emojis: statusEmojisBaseline,
|
|
200
207
|
dashboard: dashboardPatchValue(dashboardForm(inst)),
|
|
208
|
+
office_access: dashboardForm(inst).office === "on" ? true : dashboardForm(inst).office === "off" ? false : null,
|
|
201
209
|
});
|
|
202
210
|
}
|
|
203
211
|
|
|
@@ -33,6 +33,8 @@ const ROWS = [
|
|
|
33
33
|
// Fleet · Agents
|
|
34
34
|
["agents.new", "agents", "#newAgentBtn", "settings.newAgent", null, ["new agent", "create", "add agent", "instance"], ["新增 agent", "建立", "新 agent"]],
|
|
35
35
|
["agents.provider-keys", "agents", ".s-provider-keys", "settings.providerKeys", "web.provider_secrets", ["api key", "provider", "openai", "anthropic", "token", "secret"], ["API 金鑰", "金鑰", "供應商", "token"]],
|
|
36
|
+
["defaults.tips", "agent-defaults", "#g-tips", "settings.dailyTips", "defaults.tips", ["daily tips", "dm", "notices"], ["每日提示", "私訊"]],
|
|
37
|
+
["web.notify-login", "access", "#webNotifyLogin", "settings.webNotifyLogin", "web.notify_login", ["sign in", "login", "dm", "notices"], ["登入通知", "私訊"]],
|
|
36
38
|
// Fleet · Agent defaults
|
|
37
39
|
["defaults.locale", "agent-defaults", "#g-locale", "settings.language", "defaults.locale", ["language", "bot language", "reply language", "locale"], ["語言", "回覆語言", "bot 語言"]],
|
|
38
40
|
["defaults.backend", "agent-defaults", "#g-be", "settings.defaultBackend", "defaults.backend", ["backend", "cli", "claude", "codex", "kiro"], ["後端", "CLI"]],
|
|
@@ -40,6 +42,8 @@ const ROWS = [
|
|
|
40
42
|
["defaults.auto-pause", "agent-defaults", "#g-auto", "settings.autoPause", "defaults.auto_pause_after", ["auto pause", "idle", "sleep", "minutes"], ["自動暫停", "閒置", "休眠"]],
|
|
41
43
|
["defaults.tool-progress", "agent-defaults", "#g-tp", "settings.toolProgress", "defaults.tool_progress", ["tool progress", "verbose", "steps"], ["工具進度", "詳細"]],
|
|
42
44
|
["defaults.visibility", "agent-defaults", "#g-vis", "settings.crossInstanceVisibility", "defaults.cross_instance_visibility", ["visibility", "bot to bot", "cross instance", "messages"], ["可見性", "bot 之間", "跨 instance"]],
|
|
45
|
+
["defaults.reply-triggers", "agent-defaults", "#g-reply-triggers", "settings.replyTriggers", "defaults.reply_triggers", ["classic native reply", "reply trigger"], ["原生回覆觸發"]],
|
|
46
|
+
["chat.classic-reply-triggers", "chat", "#g-creply-triggers", "settings.replyTriggers", "classic_defaults.reply_triggers", ["classic native reply"], ["ClassicBot 原生回覆觸發"]],
|
|
43
47
|
["defaults.reply-guard", "agent-defaults", "#g-reply", "settings.replyCompletionGuard", "defaults.reply_completion_guard", ["delivered reply", "reply guard", "require reply"], ["送達回覆", "回覆保護"]],
|
|
44
48
|
["defaults.tool-set", "agent-defaults", "#g-ts", "settings.toolSet", "defaults.tool_set", ["tool set", "tools", "mcp"], ["工具組", "工具"]],
|
|
45
49
|
["defaults.dashboard", "agent-defaults", "#g-dash", "settings.dashboardAccess", "defaults.dashboard", ["dashboard access", "dashboard features", "permissions", "appearance tools", "task board", "web settings"], ["Dashboard 權限", "權限", "外觀", "任務看板", "網頁設定"]],
|
|
@@ -4,6 +4,10 @@ import { register } from "/assets/app-i18n.js";
|
|
|
4
4
|
|
|
5
5
|
register("settings", {
|
|
6
6
|
en: {
|
|
7
|
+
noticeTopic: "Topic", noticeDm: "Direct message (topic fallback)", noticeOff: "Off",
|
|
8
|
+
webNotifyLogin: "Web sign-in notices", dailyTips: "Daily tips",
|
|
9
|
+
webNotifyLoginHint: "DM the signing-in operator or public-link owner; local guest notices go to the owning connection’s first configured admin. Missing account or failed DM falls back to the topic. Off suppresses operator notices only; guest and public-link security notices remain in the topic. Existing default: Topic; new fleets: DM.",
|
|
10
|
+
dailyTipsHint: "DM the General connection’s first configured admin, with topic fallback. Default: Topic. /tips still posts where invoked.",
|
|
7
11
|
title: "Settings",
|
|
8
12
|
myAgents: "My Agents",
|
|
9
13
|
bots: "Bots",
|
|
@@ -108,6 +112,7 @@ register("settings", {
|
|
|
108
112
|
dashboard_appearance: "Its look (theme, pictures, widgets, effects, mod proposals)",
|
|
109
113
|
dashboard_task_board: "The task board",
|
|
110
114
|
dashboard_web_settings: "Your web appearance settings",
|
|
115
|
+
dashboard_office: "Office: walk, speak and act in the Office view",
|
|
111
116
|
dashboardInherit: "Fleet default ({0})",
|
|
112
117
|
dashboardOn: "allowed",
|
|
113
118
|
dashboardOff: "off",
|
|
@@ -570,6 +575,8 @@ register("settings", {
|
|
|
570
575
|
removeItem: "Remove {0}",
|
|
571
576
|
zeroDisabled: "0 = off",
|
|
572
577
|
optional: "optional",
|
|
578
|
+
replyTriggers: "Native replies trigger ClassicBot",
|
|
579
|
+
replyTriggersHint: "Off by default: only an exact @bot mention triggers a collab room. On also accepts one-hop replies to that bot. Forwarded content never counts; fleet-topic traffic is unchanged.",
|
|
573
580
|
collabMode: "Collaboration mode",
|
|
574
581
|
contextLines: "Context lines",
|
|
575
582
|
refresh: "Refresh",
|
|
@@ -672,6 +679,10 @@ register("settings", {
|
|
|
672
679
|
se_externalEmojiHint: "使用其他伺服器的 emoji,bot 在要加反應的頻道需有「使用外部表情符號」權限。",
|
|
673
680
|
se_unavailable: "無法使用",
|
|
674
681
|
se_hint: "留空即使用預設值。預覽由 AgEnD 依 bot 實際 react 的方式解析。進度前綴不是反應,而是進度訊息開頭的 emoji。",
|
|
682
|
+
noticeTopic: "頻道", noticeDm: "私訊(失敗時改送頻道)", noticeOff: "關閉",
|
|
683
|
+
webNotifyLogin: "網頁登入通知", dailyTips: "每日提示",
|
|
684
|
+
webNotifyLoginHint: "私訊登入的管理者或公開連結擁有者;本機訪客登入通知送給所屬連線的第一位設定管理員。帳號不明或私訊失敗時改送原頻道。關閉只停用管理者登入通知;訪客與公開連結安全通知仍送頻道。既有預設:頻道;新 fleet:私訊。",
|
|
685
|
+
dailyTipsHint: "私訊 General 所屬連線的第一位設定管理員,失敗時改送頻道。預設:頻道。/tips 仍送至呼叫的聊天室。",
|
|
675
686
|
title: "設定",
|
|
676
687
|
myAgents: "我的 Agent",
|
|
677
688
|
bots: "機器人",
|
|
@@ -750,6 +761,7 @@ register("settings", {
|
|
|
750
761
|
dashboard_appearance: "它的外觀(主題、圖片、小工具、特效、mod 提案)",
|
|
751
762
|
dashboard_task_board: "任務看板",
|
|
752
763
|
dashboard_web_settings: "你的網頁外觀設定",
|
|
764
|
+
dashboard_office: "辦公室:在辦公室畫面走動、說話、做動作",
|
|
753
765
|
dashboardInherit: "跟 fleet 預設({0})",
|
|
754
766
|
dashboardOn: "允許",
|
|
755
767
|
dashboardOff: "關閉",
|
|
@@ -1210,6 +1222,8 @@ register("settings", {
|
|
|
1210
1222
|
removeItem: "移除 {0}",
|
|
1211
1223
|
zeroDisabled: "0 = 關閉",
|
|
1212
1224
|
optional: "選填",
|
|
1225
|
+
replyTriggers: "原生回覆觸發 ClassicBot",
|
|
1226
|
+
replyTriggersHint: "預設關閉:協作房間只有精確 @bot 提及才觸發。開啟後也接受對該機器人的單層原生回覆;轉發內容不算。Fleet 話題的訊息接收方式不變。",
|
|
1213
1227
|
collabMode: "協作模式",
|
|
1214
1228
|
contextLines: "上下文行數",
|
|
1215
1229
|
refresh: "重新整理",
|
|
@@ -103,8 +103,9 @@ register("app", {
|
|
|
103
103
|
// #2293: global search — chats, cross-instance messages and tasks (not the sidebar's filter of agents).
|
|
104
104
|
search: "Search", searchTitle: "Search chats, messages between agents and tasks ({0})",
|
|
105
105
|
confirmTitle: "Please confirm", confirmOk: "Continue", cancel: "Cancel",
|
|
106
|
+
sidePanelLeave: "Leave {0} without saving? Your changes there will be lost.", sidePanelDiscard: "Discard changes",
|
|
106
107
|
// The server's own wording (src/locale.ts needs.reason.*), so the web says what Discord says.
|
|
107
|
-
needs_reason_hang: "Not responding", needs_reason_exited: "Exited", needs_reason_assist: "Waiting at its terminal", needs_reason_permission: "Permission needed", needs_reason_dangerous_command: "Dangerous command waiting", needs_reason_login: "Sign-in needed", needs_reason_dialog: "Waiting at a dialog", needs_reason_terminal_input: "May be waiting for input", needs_reason_auth_paused: "Paused: sign-in needed", needs_reason_crashed: "Crashed", needs_reason_delivery_uncertain: "Could not confirm delivery", needs_reason_delivery_failed: "Delivery failed", needs_reason_task_review: "Waiting for your confirmation", needs_reason_task_blocked: "Blocked: asks you",
|
|
108
|
+
needs_reason_hang: "Not responding", needs_reason_exited: "Exited", needs_reason_assist: "Waiting at its terminal", needs_reason_permission: "Permission needed", needs_reason_dangerous_command: "Dangerous command waiting", needs_reason_login: "Sign-in needed", needs_reason_dialog: "Waiting at a dialog", needs_reason_terminal_input: "May be waiting for input", needs_reason_auth_paused: "Paused: sign-in needed", needs_reason_backend_signin: "Backend sign-in needed", needs_reason_crashed: "Crashed", needs_reason_delivery_uncertain: "Could not confirm delivery", needs_reason_delivery_failed: "Delivery failed", needs_reason_task_review: "Waiting for your confirmation", needs_reason_task_blocked: "Blocked: asks you",
|
|
108
109
|
},
|
|
109
110
|
"zh-TW": {
|
|
110
111
|
brand: "AgEnD", fleet: "Fleet", fleetOverview: "Fleet 概覽", view: "檢視", settings: "設定", instances: "Instances", newInstance: "新增 instance", newAgent: "新增 Agent",
|
|
@@ -143,6 +144,7 @@ register("app", {
|
|
|
143
144
|
needsNav: "等你處理", needsTab: "待處理", needsCount: "{0} 件待處理",
|
|
144
145
|
search: "搜尋", searchTitle: "搜尋聊天、agent 之間的訊息與任務({0})",
|
|
145
146
|
confirmTitle: "請確認", confirmOk: "繼續", cancel: "取消",
|
|
146
|
-
|
|
147
|
+
sidePanelLeave: "不儲存就離開「{0}」?你在那裡的修改會遺失。", sidePanelDiscard: "捨棄修改",
|
|
148
|
+
needs_reason_hang: "沒有回應", needs_reason_exited: "已結束", needs_reason_assist: "在終端機上等待", needs_reason_permission: "需要權限", needs_reason_dangerous_command: "危險指令待確認", needs_reason_login: "需要登入", needs_reason_dialog: "停在對話框", needs_reason_terminal_input: "可能在等輸入", needs_reason_auth_paused: "已暫停:需要登入", needs_reason_backend_signin: "後端需要登入", needs_reason_crashed: "已崩潰", needs_reason_delivery_uncertain: "無法確認是否送達", needs_reason_delivery_failed: "傳送失敗", needs_reason_task_review: "等你確認", needs_reason_task_blocked: "卡住,在問你",
|
|
147
149
|
},
|
|
148
150
|
});
|