@songsid/agend 2.3.4-beta.1 → 2.3.4-beta.10
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 +37 -0
- package/dist/agend-home.d.ts +13 -0
- package/dist/agend-home.js +42 -0
- package/dist/agend-home.js.map +1 -1
- package/dist/agent-cli-instructions.md +1 -1
- package/dist/agent-credentials.d.ts +24 -0
- package/dist/agent-credentials.js +66 -0
- package/dist/agent-credentials.js.map +1 -0
- package/dist/agent-endpoint.d.ts +3 -1
- package/dist/agent-endpoint.js +13 -0
- package/dist/agent-endpoint.js.map +1 -1
- package/dist/auth-api.js +10 -2
- package/dist/auth-api.js.map +1 -1
- package/dist/authority/session-authorizations.d.ts +28 -4
- package/dist/authority/session-authorizations.js +63 -17
- package/dist/authority/session-authorizations.js.map +1 -1
- package/dist/backend/antigravity.js +3 -1
- package/dist/backend/antigravity.js.map +1 -1
- package/dist/backend/claude-code.d.ts +3 -0
- package/dist/backend/claude-code.js +89 -4
- package/dist/backend/claude-code.js.map +1 -1
- package/dist/backend/codex-footer-hints.d.ts +4 -0
- package/dist/backend/codex-footer-hints.js +27 -0
- package/dist/backend/codex-footer-hints.js.map +1 -0
- package/dist/backend/codex-session-lookup.d.ts +35 -0
- package/dist/backend/codex-session-lookup.js +93 -0
- package/dist/backend/codex-session-lookup.js.map +1 -1
- package/dist/backend/codex.d.ts +27 -0
- package/dist/backend/codex.js +124 -23
- package/dist/backend/codex.js.map +1 -1
- package/dist/backend/kiro-identity.d.ts +2 -0
- package/dist/backend/kiro-identity.js +13 -6
- package/dist/backend/kiro-identity.js.map +1 -1
- package/dist/backend/kiro.d.ts +3 -0
- package/dist/backend/kiro.js +68 -5
- package/dist/backend/kiro.js.map +1 -1
- package/dist/backend/muse.js +5 -3
- package/dist/backend/muse.js.map +1 -1
- package/dist/backend/types.d.ts +6 -1
- package/dist/backend/types.js +3 -0
- package/dist/backend/types.js.map +1 -1
- package/dist/backend-availability.d.ts +6 -0
- package/dist/backend-availability.js +13 -5
- package/dist/backend-availability.js.map +1 -1
- package/dist/cache-ledger.d.ts +85 -0
- package/dist/cache-ledger.js +236 -1
- package/dist/cache-ledger.js.map +1 -1
- package/dist/cache-service.d.ts +5 -0
- package/dist/cache-service.js +16 -4
- package/dist/cache-service.js.map +1 -1
- package/dist/channel/adapters/discord.js +27 -4
- package/dist/channel/adapters/discord.js.map +1 -1
- package/dist/channel/adapters/telegram.d.ts +51 -0
- package/dist/channel/adapters/telegram.js +238 -18
- package/dist/channel/adapters/telegram.js.map +1 -1
- package/dist/channel/inbox-temp-name.d.ts +9 -0
- package/dist/channel/inbox-temp-name.js +13 -0
- package/dist/channel/inbox-temp-name.js.map +1 -0
- package/dist/channel/mcp-tools.js +3 -3
- package/dist/channel/mcp-tools.js.map +1 -1
- package/dist/channel/types.d.ts +2 -0
- package/dist/chat-log-ids.d.ts +48 -0
- package/dist/chat-log-ids.js +182 -0
- package/dist/chat-log-ids.js.map +1 -0
- package/dist/classic-channel-manager.d.ts +8 -1
- package/dist/classic-channel-manager.js +24 -2
- package/dist/classic-channel-manager.js.map +1 -1
- package/dist/cli.js +4 -6
- package/dist/cli.js.map +1 -1
- package/dist/cross-instance-notice.d.ts +10 -0
- package/dist/cross-instance-notice.js +67 -5
- package/dist/cross-instance-notice.js.map +1 -1
- package/dist/daemon.d.ts +52 -0
- package/dist/daemon.js +530 -34
- package/dist/daemon.js.map +1 -1
- package/dist/delivery-consumed-watch.d.ts +23 -1
- package/dist/delivery-consumed-watch.js +30 -3
- package/dist/delivery-consumed-watch.js.map +1 -1
- package/dist/delivery-reconciliation.d.ts +7 -0
- package/dist/delivery-reconciliation.js +9 -1
- package/dist/delivery-reconciliation.js.map +1 -1
- package/dist/dialog-screen-text.d.ts +16 -0
- package/dist/dialog-screen-text.js +51 -0
- package/dist/dialog-screen-text.js.map +1 -0
- package/dist/export-import.d.ts +7 -0
- package/dist/export-import.js +44 -10
- package/dist/export-import.js.map +1 -1
- package/dist/fleet-context.d.ts +2 -0
- package/dist/fleet-manager.d.ts +147 -11
- package/dist/fleet-manager.js +747 -118
- package/dist/fleet-manager.js.map +1 -1
- package/dist/fleet-yaml-patch.d.ts +3 -0
- package/dist/fleet-yaml-patch.js +103 -0
- package/dist/fleet-yaml-patch.js.map +1 -0
- package/dist/general-knowledge/skills/concepts/SKILL.md +393 -0
- package/dist/general-knowledge/skills/cross-instance-messaging/SKILL.md +1 -0
- package/dist/general-knowledge/skills/instance-lifecycle/SKILL.md +3 -1
- package/dist/general-knowledge/skills/kiro-engine-migration/SKILL.md +41 -4
- package/dist/general-knowledge/skills/model-discovery/SKILL.md +2 -0
- package/dist/general-knowledge/skills/web-appearance/SKILL.md +1 -1
- package/dist/general-knowledge/skills/web-dashboard/SKILL.md +10 -4
- package/dist/general-knowledge/skills/worker-collaboration/SKILL.md +1 -1
- package/dist/install-stream.d.ts +53 -0
- package/dist/install-stream.js +134 -0
- package/dist/install-stream.js.map +1 -0
- package/dist/instance-lifecycle.d.ts +20 -2
- package/dist/instance-lifecycle.js +80 -12
- package/dist/instance-lifecycle.js.map +1 -1
- package/dist/instance-topic-delete.d.ts +77 -0
- package/dist/instance-topic-delete.js +123 -0
- package/dist/instance-topic-delete.js.map +1 -0
- package/dist/instructions.d.ts +1 -1
- package/dist/instructions.js +1 -1
- package/dist/instructions.js.map +1 -1
- package/dist/kiro-engine-status.d.ts +11 -0
- package/dist/kiro-engine-status.js +6 -0
- package/dist/kiro-engine-status.js.map +1 -1
- package/dist/kiro-resume-summary.d.ts +37 -0
- package/dist/kiro-resume-summary.js +85 -0
- package/dist/kiro-resume-summary.js.map +1 -0
- package/dist/locale.js +82 -6
- package/dist/locale.js.map +1 -1
- package/dist/log-service.d.ts +30 -0
- package/dist/log-service.js +36 -3
- package/dist/log-service.js.map +1 -1
- package/dist/log-steps.d.ts +4 -3
- package/dist/log-steps.js +32 -7
- package/dist/log-steps.js.map +1 -1
- package/dist/logger.d.ts +12 -0
- package/dist/logger.js +43 -1
- package/dist/logger.js.map +1 -1
- package/dist/login-controller.js +9 -1
- package/dist/login-controller.js.map +1 -1
- package/dist/login-flows.d.ts +2 -0
- package/dist/login-flows.js +5 -2
- package/dist/login-flows.js.map +1 -1
- package/dist/login-manager.d.ts +6 -0
- package/dist/login-manager.js +10 -1
- package/dist/login-manager.js.map +1 -1
- package/dist/missed-offline.d.ts +25 -0
- package/dist/missed-offline.js +79 -0
- package/dist/missed-offline.js.map +1 -0
- package/dist/needs-you-hub.d.ts +6 -1
- package/dist/needs-you-hub.js +31 -8
- package/dist/needs-you-hub.js.map +1 -1
- package/dist/needs-you.d.ts +22 -2
- package/dist/needs-you.js +17 -3
- package/dist/needs-you.js.map +1 -1
- package/dist/office-share-page.d.ts +1 -1
- package/dist/office-share-page.js +6 -2
- package/dist/office-share-page.js.map +1 -1
- package/dist/outbound-handlers.js +59 -3
- package/dist/outbound-handlers.js.map +1 -1
- package/dist/outbound-schemas.d.ts +1 -0
- package/dist/outbound-schemas.js +9 -3
- package/dist/outbound-schemas.js.map +1 -1
- package/dist/package-preimage.js +27 -2
- package/dist/package-preimage.js.map +1 -1
- package/dist/queued-handoffs.d.ts +33 -0
- package/dist/queued-handoffs.js +75 -0
- package/dist/queued-handoffs.js.map +1 -0
- package/dist/reply-buttons-controller.js +10 -0
- package/dist/reply-buttons-controller.js.map +1 -1
- package/dist/scheduler/db.d.ts +2 -1
- package/dist/scheduler/db.js +23 -9
- package/dist/scheduler/db.js.map +1 -1
- package/dist/selection-card.d.ts +2 -3
- package/dist/selection-card.js +99 -26
- package/dist/selection-card.js.map +1 -1
- package/dist/settings-api.d.ts +13 -0
- package/dist/settings-api.js +12 -1
- package/dist/settings-api.js.map +1 -1
- package/dist/stall-reporter.d.ts +21 -0
- package/dist/stall-reporter.js +82 -0
- package/dist/stall-reporter.js.map +1 -0
- package/dist/tmux-control.d.ts +2 -2
- package/dist/tmux-control.js +4 -2
- package/dist/tmux-control.js.map +1 -1
- package/dist/tmux-exec-helper.d.ts +6 -3
- package/dist/tmux-exec-helper.js +115 -53
- package/dist/tmux-exec-helper.js.map +1 -1
- package/dist/tmux-manager.d.ts +6 -0
- package/dist/tmux-manager.js +17 -0
- package/dist/tmux-manager.js.map +1 -1
- package/dist/tool-permissions.d.ts +5 -2
- package/dist/tool-permissions.js +6 -5
- package/dist/tool-permissions.js.map +1 -1
- package/dist/tool-progress.d.ts +2 -0
- package/dist/tool-progress.js +19 -3
- package/dist/tool-progress.js.map +1 -1
- package/dist/topic-commands.js +4 -0
- package/dist/topic-commands.js.map +1 -1
- package/dist/tunnel/cloudflared-install.d.ts +4 -0
- package/dist/tunnel/cloudflared-install.js +20 -1
- package/dist/tunnel/cloudflared-install.js.map +1 -1
- package/dist/tunnel/cloudflared.d.ts +8 -1
- package/dist/tunnel/cloudflared.js +34 -6
- package/dist/tunnel/cloudflared.js.map +1 -1
- package/dist/tunnel/lease.d.ts +3 -3
- package/dist/tunnel/lease.js +23 -19
- package/dist/tunnel/lease.js.map +1 -1
- package/dist/tunnel/manager.js +6 -7
- package/dist/tunnel/manager.js.map +1 -1
- package/dist/ui/chat-store.js +20 -3
- package/dist/ui/chat-strings.js +4 -4
- package/dist/ui/chat-thread.js +52 -10
- package/dist/ui/fleet-canvas.js +4 -3
- package/dist/ui/fleet-office-model.js +55 -22
- package/dist/ui/fleet-office-overview.js +6 -38
- package/dist/ui/fleet-office-pack.js +4 -3
- package/dist/ui/fleet-office-skin.js +114 -21
- package/dist/ui/fleet-office-store.js +5 -0
- package/dist/ui/fleet-office-zones.js +2 -2
- package/dist/ui/fleet-office.js +41 -9
- package/dist/ui/fleet-usage.js +90 -27
- package/dist/ui/panel-chat.js +2 -0
- package/dist/ui/panel-log.js +7 -1
- package/dist/ui/panel-needs.js +17 -8
- package/dist/ui/settings-strings.js +2 -2
- package/dist/ui/shared/app-i18n.js +4 -4
- package/dist/ui/shared/app-needs.js +1 -1
- package/dist/ui/shared/app-shell.js +4 -2
- package/dist/ui/shared/app-stream.js +26 -0
- package/dist/ui/shared/app.css +51 -3
- package/dist/ui/shared/office/guild.png +0 -0
- package/dist/ui/shared/office/school.png +0 -0
- package/dist/ui/shared/panel-view.js +339 -17
- package/dist/ui/shared/usage-dialog.js +18 -1
- package/dist/ui/shared/view-history.css +17 -0
- package/dist/ui/shared/view-history.js +438 -0
- package/dist/ui/shared/view-strings.js +42 -0
- package/dist/unattended-install.d.ts +6 -0
- package/dist/unattended-install.js +79 -0
- package/dist/unattended-install.js.map +1 -0
- package/dist/usage/capacity.d.ts +69 -0
- package/dist/usage/capacity.js +119 -0
- package/dist/usage/capacity.js.map +1 -0
- package/dist/usage/i18n-keys.d.ts +1 -1
- package/dist/usage/i18n-keys.js +3 -0
- package/dist/usage/i18n-keys.js.map +1 -1
- package/dist/usage/profile-timeline.d.ts +16 -0
- package/dist/usage/profile-timeline.js +58 -0
- package/dist/usage/profile-timeline.js.map +1 -0
- package/dist/usage/quota-history.d.ts +43 -0
- package/dist/usage/quota-history.js +168 -0
- package/dist/usage/quota-history.js.map +1 -0
- package/dist/usage/usage-api.d.ts +31 -0
- package/dist/usage/usage-api.js +80 -1
- package/dist/usage/usage-api.js.map +1 -1
- package/dist/usage-report.d.ts +25 -1
- package/dist/usage-report.js +55 -4
- package/dist/usage-report.js.map +1 -1
- package/dist/usage-rollup.d.ts +4 -1
- package/dist/usage-rollup.js +12 -3
- package/dist/usage-rollup.js.map +1 -1
- package/dist/view-api.d.ts +31 -0
- package/dist/view-api.js +186 -41
- package/dist/view-api.js.map +1 -1
- package/dist/view-history.d.ts +84 -0
- package/dist/view-history.js +116 -0
- package/dist/view-history.js.map +1 -0
- package/dist/web-api.d.ts +6 -0
- package/dist/web-api.js +15 -4
- package/dist/web-api.js.map +1 -1
- package/dist/web-chat-history.d.ts +20 -0
- package/dist/web-chat-history.js +21 -0
- package/dist/web-chat-history.js.map +1 -1
- package/dist/web-guest-access.js +5 -1
- package/dist/web-guest-access.js.map +1 -1
- package/dist/web-login.d.ts +4 -3
- package/dist/web-login.js +23 -14
- package/dist/web-login.js.map +1 -1
- package/dist/web-office-pack-tools.d.ts +1 -1
- package/dist/web-office-pack-tools.js +1 -1
- package/dist/web-office-pack-tools.js.map +1 -1
- package/dist/web-session-authorization.d.ts +13 -2
- package/dist/web-session-authorization.js +10 -3
- package/dist/web-session-authorization.js.map +1 -1
- package/dist/web-session.d.ts +5 -0
- package/dist/web-session.js +20 -8
- package/dist/web-session.js.map +1 -1
- package/launcher/agend-install.cjs +16 -2
- package/launcher/private-home.cjs +1 -1
- package/package.json +1 -1
|
@@ -19,6 +19,8 @@ import { levelsOk } from "./fleet-office-levels.js";
|
|
|
19
19
|
const CHOICE_KEY = "agend_org_office", FILTER_KEY = "agend_org_office_filter", SKIN_KEY = "agend_org_office_skin", ASLEEP_KEY = "agend_org_office_hide_asleep", NIGHT_KEY = "agend_org_office_night";
|
|
20
20
|
/** #2554: "0" when All offices leaves the lobby tile out (default: shown). */
|
|
21
21
|
const LOBBY_KEY = "agend_org_office_lobby";
|
|
22
|
+
/** #2946: whether the key to the items in the air is open here (default: folded). */
|
|
23
|
+
const KEY_OPEN_KEY = "agend_org_office_key";
|
|
22
24
|
/** #2540: { "<office>@<style>": [k, cx, cy] (and a 1 after them: a fit) } — the last VIEWS_MAX views, the most recent last. */
|
|
23
25
|
const VIEW_KEY = "agend_org_office_view", VIEWS_MAX = 32;
|
|
24
26
|
/** #2540: { "<office>@<style>": "cover" } — the offices whose fit fills the panel (the rest: "contain"), the last VIEWS_MAX. */
|
|
@@ -195,6 +197,9 @@ export function createOfficeStore({ fetch: get = globalThis.fetch, storage } = {
|
|
|
195
197
|
saveNightOn: (v) => write(NIGHT_KEY, v ? "1" : "0"),
|
|
196
198
|
/** #2554: whether All offices shows the lobby tile (the instances in no stored office) here (default: shown). */
|
|
197
199
|
lobbyTile: () => read(LOBBY_KEY) !== "0",
|
|
200
|
+
/** #2946: whether the key to the items carried between desks is open here (default: folded). */
|
|
201
|
+
keyOpen: () => read(KEY_OPEN_KEY) === "1",
|
|
202
|
+
saveKeyOpen: (v) => write(KEY_OPEN_KEY, v ? "1" : "0"),
|
|
198
203
|
saveLobbyTile: (v) => write(LOBBY_KEY, v ? "1" : "0"),
|
|
199
204
|
/** The view kept for `key` (an office and its style): { k, cx, cy } (fleet-office-view.js savedOf), or null. */
|
|
200
205
|
view: (key) => {
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// changes it walks (along the pack's waypoints) to the new area. Pure — fleet-office.js draws it. Also here: what a
|
|
4
4
|
// character says in its speech bubble, and which furniture is active.
|
|
5
5
|
import { LOGICAL, own } from "./fleet-office-pack.js";
|
|
6
|
-
import {
|
|
6
|
+
import { flightMs, nameHash, pathLength, along, routeVia } from "./fleet-office-model.js";
|
|
7
7
|
import { hue } from "./fleet-traffic.js";
|
|
8
8
|
|
|
9
9
|
/** The area for a state: the pack's own, else its "default", else its first area. */
|
|
@@ -281,7 +281,7 @@ export function createMail({ max = MAIL.MAX } = {}) {
|
|
|
281
281
|
if (!drop) continue; // nowhere off the seats: not delivered here
|
|
282
282
|
const pts = [{ x: L.door.x, y: L.door.y }, drop];
|
|
283
283
|
letters.push({ id: it.id, from: it.from, to: it.to, kind: it.kind, hue: hue(it.kind), start: now, drop, pts,
|
|
284
|
-
ms:
|
|
284
|
+
ms: flightMs(pathLength(pts)) });
|
|
285
285
|
started++;
|
|
286
286
|
}
|
|
287
287
|
if (letters.length > max) letters = letters.slice(letters.length - max);
|
package/dist/ui/fleet-office.js
CHANGED
|
@@ -64,7 +64,7 @@ import { nodeText, stateWords } from "./fleet-org.js";
|
|
|
64
64
|
import { hits, needle } from "./fleet-canvas-layout.js";
|
|
65
65
|
import { AUTO_ID, LOBBY, autoLayout, backingScale, coatOf, createFlights, customLayout, deskAt, desksOf, filterOk, lampOf, layoutOk, lightOf, membersOf,
|
|
66
66
|
officePose, officeRooms, signOf, workOn } from "./fleet-office-model.js";
|
|
67
|
-
import { BUILT_IN_SKINS, CHAR_DEPTH, DEFAULT_PAL, bubbleBox,
|
|
67
|
+
import { BUILT_IN_SKINS, CHAR_DEPTH, DEFAULT_PAL, PICTURE_SKINS, bubbleBox, pixelSkin, loadBuiltInSkin, loadPackSkin, modeOf, skinFor, tagBox, tagFootprint } from "./fleet-office-skin.js";
|
|
68
68
|
import { CALLING, activeFurniture, bubbleAt, hiddenBy, bubbleRank, NIGHT, WANDER, createMail, createWalkers, isNight, linesFor, npcKey, personAt, placeBubbles, thinBubbles, walkTargets, zonesLayout } from "./fleet-office-zones.js";
|
|
69
69
|
import { actsOk, createOfficeStore } from "./fleet-office-store.js";
|
|
70
70
|
import { badgeOf, fixedOf } from "./fleet-office-levels.js";
|
|
@@ -86,7 +86,7 @@ register("orgo", {
|
|
|
86
86
|
people: "People", peopleN: "People ({0})", findPerson: "Find a person", everyone: "Show everyone", nobody: "No one here matches this filter.",
|
|
87
87
|
unseated: "{0} without a seat", skinUnknown: "Its style “{0}” is not available here: drawn as Desks.", closed: "Closed", desks: "Desks", tapAgain: "Tap again to open the chat",
|
|
88
88
|
capWorking: "Typing away", capIdle: "Tea break", capPaused: "Asleep", capNeeds: "Calling for you", capAway: "Desk empty", capStarting: "Just arriving", capQueued: "Waiting to start",
|
|
89
|
-
styleLabel: "Style", style_pixel: "Desks", style_studio: "Studio", style_cozy: "Cozy", cozyNotice: "Add your skin", area_desks: "Work", area_lounge: "Lounge", area_alert: "Help desk", area_nap: "Nap corner",
|
|
89
|
+
styleLabel: "Style", style_pixel: "Desks", style_studio: "Studio", style_cozy: "Cozy", style_guild: "Guild", style_school: "School", cozyNotice: "Add your skin", area_desks: "Work", area_lounge: "Lounge", area_alert: "Help desk", area_nap: "Nap corner",
|
|
90
90
|
b_working: "On it.|Typing…|Almost there|In the zone|One more test", b_idle: "Tea time|Ready when you are|Stretching|Anything for me?",
|
|
91
91
|
b_paused: "Zzz…|Back later", b_stopped: "Off duty|Zzz…", b_needs: "Need you!|A question for you|Over here!",
|
|
92
92
|
b_crashed: "Ouch, crashed|Help!", b_stuck: "Hmm, stuck?|Still thinking…",
|
|
@@ -96,6 +96,8 @@ register("orgo", {
|
|
|
96
96
|
fit: "Fit the office", overview: "Overview: click to move there", fullscreen: "Fullscreen", exitFullscreen: "Exit fullscreen",
|
|
97
97
|
fill: "Fill", fillTitle: "Fill the panel (the scene's overflow is cropped; drag to see it)", zoomLevel: "Zoom {0}",
|
|
98
98
|
allOffices: "All offices", labelAll: "All offices: each office is a tile, drawn in its own style. Drag to pan; the wheel, a pinch, + and − zoom, 0 fits, F is fullscreen. Double-click a tile to open that office.",
|
|
99
|
+
key: "Key", keyTitle: "What the items carried between desks are", keyLabel: "Carried between desks",
|
|
100
|
+
keyTask: "Folder: a task", keySend: "Envelope: a message", keyReport: "Paper: a report", keyBroadcast: "Horn: a broadcast",
|
|
99
101
|
tileLabel: "{0} ({1})", openOffice: "Open the office {0}", lobbyTile: "Lobby tile (in no office)", lobbyEveryone: "Everyone is in an office", overviewNoEdit: "Pick one office to edit offices or a layout",
|
|
100
102
|
},
|
|
101
103
|
"zh-TW": {
|
|
@@ -104,7 +106,7 @@ register("orgo", {
|
|
|
104
106
|
people: "成員", peopleN: "成員({0})", findPerson: "尋找成員", everyone: "顯示全部", nobody: "沒有符合這個篩選的成員。",
|
|
105
107
|
unseated: "{0} 位沒有座位", skinUnknown: "這裡沒有它的風格「{0}」:以辦公桌顯示。", closed: "休息中", desks: "桌子", tapAgain: "再點一下開啟聊天",
|
|
106
108
|
capWorking: "埋頭打字中", capIdle: "喝茶休息", capPaused: "睡著了", capNeeds: "在呼叫你", capAway: "空位", capStarting: "剛到座位", capQueued: "等待啟動",
|
|
107
|
-
styleLabel: "風格", style_pixel: "辦公桌", style_studio: "工作室", style_cozy: "溫馨", cozyNotice: "換上你的外觀包", area_desks: "工作區", area_lounge: "休息區", area_alert: "求救區", area_nap: "午睡角",
|
|
109
|
+
styleLabel: "風格", style_pixel: "辦公桌", style_studio: "工作室", style_cozy: "溫馨", style_guild: "冒險者公會", style_school: "學校", cozyNotice: "換上你的外觀包", area_desks: "工作區", area_lounge: "休息區", area_alert: "求救區", area_nap: "午睡角",
|
|
108
110
|
b_working: "處理中|打字中…|快好了|專心中|再測一次", b_idle: "喝茶中|隨時可以開工|伸個懶腰|有事找我嗎?",
|
|
109
111
|
b_paused: "Zzz…|晚點回來", b_stopped: "下班了|Zzz…", b_needs: "需要你!|有個問題|在這裡!",
|
|
110
112
|
b_crashed: "糟糕,當掉了|救命!", b_stuck: "嗯,卡住了?|還在想…",
|
|
@@ -114,6 +116,8 @@ register("orgo", {
|
|
|
114
116
|
fit: "顯示整個辦公室", overview: "總覽:點一下移到那裡", fullscreen: "全螢幕", exitFullscreen: "結束全螢幕",
|
|
115
117
|
fill: "填滿", fillTitle: "填滿整個面板(超出的部分會被裁切,拖曳即可看到)", zoomLevel: "縮放 {0}",
|
|
116
118
|
allOffices: "所有辦公室", labelAll: "所有辦公室:每間辦公室是一格,以它自己的風格顯示。拖曳平移;滾輪、雙指、+ 和 − 縮放,0 顯示全部,F 切換全螢幕。雙擊一格即可開啟那間辦公室。",
|
|
119
|
+
key: "圖例", keyTitle: "桌子之間傳遞的物品代表什麼", keyLabel: "桌子之間傳遞的物品",
|
|
120
|
+
keyTask: "資料夾:任務", keySend: "信封:訊息", keyReport: "紙張:回報", keyBroadcast: "喇叭:廣播",
|
|
117
121
|
tileLabel: "{0}({1})", openOffice: "開啟辦公室「{0}」", lobbyTile: "大廳格(不在任何辦公室)", lobbyEveryone: "每個成員都已在某間辦公室", overviewNoEdit: "請先選一間辦公室,再編輯辦公室或配置",
|
|
118
122
|
},
|
|
119
123
|
});
|
|
@@ -584,6 +588,28 @@ function People({ nodes, pinned, onChange }) {
|
|
|
584
588
|
</div>`;
|
|
585
589
|
}
|
|
586
590
|
|
|
591
|
+
/** #2946: the key's rows — each kind's item as the scene draws it (the built-in prop, in the theme's colour), and its words. */
|
|
592
|
+
export const KEY_KINDS = [["task", "keyTask"], ["send", "keySend"], ["report", "keyReport"], ["broadcast", "keyBroadcast"]];
|
|
593
|
+
const KEY_PX = 32;
|
|
594
|
+
/**
|
|
595
|
+
* #2946 (hxhsandy): the key to the items carried between desks — a strip under the Office's bar (never over the scene),
|
|
596
|
+
* opened by its Key toggle. The shapes are drawn by the built-in skin, so they are the ones in the air, at their size.
|
|
597
|
+
*/
|
|
598
|
+
export function OfficeKey({ pal }) {
|
|
599
|
+
const paint = (hue) => (cv) => {
|
|
600
|
+
const g = cv && typeof cv.getContext === "function" ? cv.getContext("2d") : null;
|
|
601
|
+
if (!g) return;
|
|
602
|
+
const r = Math.max(1, Math.round(globalThis.devicePixelRatio || 1));
|
|
603
|
+
if (cv.width !== KEY_PX * r) { cv.width = KEY_PX * r; cv.height = KEY_PX * r; }
|
|
604
|
+
g.setTransform(r, 0, 0, r, 0, 0); g.clearRect(0, 0, KEY_PX, KEY_PX);
|
|
605
|
+
try { pixelSkin.drawProp(g, { hue, kind: hue, x: KEY_PX / 2, y: KEY_PX / 2 + 4, t: 0 }, 0, { pal }); } catch { /* left blank */ }
|
|
606
|
+
};
|
|
607
|
+
return html`<div class="oo-key" role="region" aria-label=${to("keyLabel")}>
|
|
608
|
+
<ul class="oo-key-rows">${KEY_KINDS.map(([hue, k]) => html`<li key=${hue} class="oo-key-row" data-kind=${hue}>
|
|
609
|
+
<canvas class="oo-key-icon" width=${KEY_PX} height=${KEY_PX} aria-hidden="true" ref=${paint(hue)}></canvas><span>${to(k)}</span></li>`)}</ul>
|
|
610
|
+
</div>`;
|
|
611
|
+
}
|
|
612
|
+
|
|
587
613
|
/**
|
|
588
614
|
* The view: `view` buildOrgView's answer; `traffic` the live items (null: Live is off); `q` the Find box's needle;
|
|
589
615
|
* `lease` the tab's (its reads); `onOpen(name)` what a desk opens (the canvas's: the chat; none: a desk opens nothing,
|
|
@@ -609,13 +635,14 @@ export function Office({ view, traffic, q = "", lease, onOpen, assetUrl, assetIm
|
|
|
609
635
|
const [hideAsleep, setHideAsleep] = useState(() => store.hideAsleep());
|
|
610
636
|
// Bedtime (#2568), when it is on here: the idle sleep from NIGHT.FROM to NIGHT.TO on this device's clock (read every NIGHT.TICK).
|
|
611
637
|
const [nightOn, setNightOn] = useState(() => store.nightOn());
|
|
638
|
+
const [keyOpen, setKeyOpen] = useState(() => store.keyOpen());
|
|
612
639
|
const [nightNow, setNightNow] = useState(() => isNight());
|
|
613
640
|
useEffect(() => { if (!nightOn) return undefined; setNightNow(isNight()); const h = setInterval(() => setNightNow(isNight()), NIGHT.TICK); return () => clearInterval(h); }, [nightOn]);
|
|
614
641
|
const night = nightOn && nightNow;
|
|
615
642
|
const [lobbyOn, setLobbyOn] = useState(() => store.lobbyTile()); // #2554: All offices' lobby tile
|
|
616
643
|
const [packs, setPacks] = useState([]); // the skin packs the host keeps: [{ id, name, sha }]
|
|
617
644
|
const [packSkins, setPackSkins] = useState(() => new Map()); // id@sha → a loaded skin, or null (not a pack)
|
|
618
|
-
const [cozyRev, setCozyRev] = useState(0); // #2631:
|
|
645
|
+
const [cozyRev, setCozyRev] = useState(0); // #2631/#2947: a built-in's picture came in (skinFor has it)
|
|
619
646
|
// Edit layout's session while it is open: { id, officeId, skin, pack (the style's identity), base (the pack as kept),
|
|
620
647
|
// start, draft, rev, list (the offices and rev read when it opened — what Save sends) }; null when closed.
|
|
621
648
|
const [layout, setLayout] = useState(null);
|
|
@@ -801,14 +828,16 @@ export function Office({ view, traffic, q = "", lease, onOpen, assetUrl, assetIm
|
|
|
801
828
|
}, [neededKey]);
|
|
802
829
|
const loading = !!packInfo && !packSkins.has(packKey);
|
|
803
830
|
const baseSkin = packInfo ? packSkins.get(packKey) || skinFor("pixel") : skinFor(STYLES.includes(wanted) ? wanted : custom ? wanted : "pixel");
|
|
804
|
-
// #2631:
|
|
805
|
-
|
|
831
|
+
// #2631/#2947: a picture-backed built-in's picture (cozy, guild, school), once, when this office (or a tile, or the lobby
|
|
832
|
+
// tile) is drawn in it and no kept pack has its id; until then its bare floors.
|
|
833
|
+
const picturesWanted = [...new Set((overview ? [...stored.map((o) => o.skin), ...(lobbyOn ? [style] : [])] : [wanted])
|
|
834
|
+
.filter((id) => PICTURE_SKINS.includes(id) && !packOf(id)))].sort().join(",");
|
|
806
835
|
useEffect(() => {
|
|
807
|
-
if (!
|
|
836
|
+
if (!picturesWanted) return undefined;
|
|
808
837
|
let live = true;
|
|
809
|
-
|
|
838
|
+
for (const id of picturesWanted.split(",")) loadBuiltInSkin(id).then((sk) => { if (live && sk) setCozyRev((n) => n + 1); });
|
|
810
839
|
return () => { live = false; };
|
|
811
|
-
}, [
|
|
840
|
+
}, [picturesWanted]);
|
|
812
841
|
const zones = !!(baseSkin.pack && baseSkin.pack.stateZones);
|
|
813
842
|
/** The style's identity: a pack's id and sha (a pack replaced is another), or the built-in skin's id. */
|
|
814
843
|
const styleKey = packKey || baseSkin.id;
|
|
@@ -1456,6 +1485,8 @@ export function Office({ view, traffic, q = "", lease, onOpen, assetUrl, assetIm
|
|
|
1456
1485
|
${custom && baseSkin.id !== custom.skin && !loading ? html`<span class="muted oo-note">${to("skinUnknown", styleName(custom.skin))}</span>` : null}
|
|
1457
1486
|
${placed.ignored ? html`<span class="muted oo-note">${to("layoutIgnored")}</span>` : null}
|
|
1458
1487
|
${styleErr && auto ? html`<span class="note oo-note oo-style-err" role="status">${styleErr}</span>` : null}
|
|
1488
|
+
${traffic ? html`<button type="button" class=${`btn btn-sm oo-key-btn${keyOpen ? " on" : ""}`} aria-expanded=${keyOpen ? "true" : "false"} title=${to("keyTitle")}
|
|
1489
|
+
onClick=${() => { const v = !keyOpen; store.saveKeyOpen(v); setKeyOpen(v); }}>${to("key")}</button>` : null}
|
|
1459
1490
|
${L.unseated ? html`<span class="muted oo-note">${to("unseated", L.unseated)}</span>` : null}
|
|
1460
1491
|
${canEdit && storedRev !== null ? html`<button type="button" class="btn btn-sm oo-edit" onClick=${() => { if (!overview) setEditing(true); }} disabled=${!!layout || overview}
|
|
1461
1492
|
title=${overview ? to("overviewNoEdit") : undefined}>${t("orge.edit")}</button>` : null}
|
|
@@ -1463,6 +1494,7 @@ export function Office({ view, traffic, q = "", lease, onOpen, assetUrl, assetIm
|
|
|
1463
1494
|
${canShare ? html`<${ShareButton} offices=${stored} current=${overview ? "all" : custom ? custom.id : null} disabled=${!!layout}
|
|
1464
1495
|
get=${lease ? (path, o) => lease.fetch(path, o) : undefined} />` : null}
|
|
1465
1496
|
</div>
|
|
1497
|
+
${traffic && keyOpen ? html`<${OfficeKey} pal=${pal} />` : null}
|
|
1466
1498
|
${editing && !overview ? html`<${OfficeEditor} offices=${stored} rev=${storedRev} view=${view} store=${store} packs=${packs}
|
|
1467
1499
|
ask=${ask} current=${() => shown.current} onSaved=${adopt} onClose=${() => setEditing(false)} />` : null}
|
|
1468
1500
|
${overview || people.length || L.rooms.length ? null : html`<p class="note oo-empty">${to("nobody")} ${auto && (f.team || f.pinned.length) ? html`<button type="button" class="btn btn-sm" onClick=${() => setF({ team: "", pinned: [] })}>${to("everyone")}</button>` : null}</p>`}
|
package/dist/ui/fleet-usage.js
CHANGED
|
@@ -14,11 +14,20 @@ register("fusage", {
|
|
|
14
14
|
en: {
|
|
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
|
-
csv: "Download CSV", basis: "API-equivalent at list price (
|
|
17
|
+
csv: "Download CSV", basis: "API-equivalent at list price ({0}) — not money spent.", basisMore: "Subscriptions are not billed per token.",
|
|
18
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
|
-
|
|
21
|
-
|
|
20
|
+
// #3066 §3: what a row's numbers are, said once each as a small mark with its tooltip (never a pill per row).
|
|
21
|
+
t_not_priced: "Not priced: {0}", t_partial: "Part of this row's models have no price", t_write_unreported: "Codex/Muse don't report cache writes",
|
|
22
|
+
t_cost_reported: "Amount as the CLI reported it", t_estimated: "Estimated from text size (Kiro records no token counts)", t_reasoning_none: "Not reported by this CLI",
|
|
23
|
+
sourceNote: "Some hours were read before AgEnD recorded their backend and profile.", profileUnrecorded: "profile not recorded",
|
|
24
|
+
l_partial: "◐ partly priced", l_cost_reported: "† amount from the CLI", l_estimated: "≈ estimated",
|
|
25
|
+
// #3066 §2: output speed (Claude after the first token, Codex over the response window).
|
|
26
|
+
speed: "Speed", speedUnit: "{0} tok/s", speedCoverage: "{0} of {1} requests timed", speedSpread: "p10–p90: {0}–{1} tok/s",
|
|
27
|
+
speedNone: "no timing in its transcripts", speedByModel: "Speed by model",
|
|
28
|
+
speedBasis: "Output tokens ÷ the model's own response time (tool time excluded); method after tokdash.",
|
|
29
|
+
|
|
30
|
+
f_includes_estimates: "includes estimates (Kiro)", estimatedPart: "of which estimated: {0}",
|
|
22
31
|
scanning: "Scanning — totals may still grow.", updated: "Updated {0} · read every 10 min", since: "Collected since {0}", notYet: "Not collected yet",
|
|
23
32
|
refresh: "Refresh",
|
|
24
33
|
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",
|
|
@@ -42,11 +51,18 @@ register("fusage", {
|
|
|
42
51
|
"zh-TW": {
|
|
43
52
|
range: "期間", today: "今天", r7d: "7 天", month: "本月", all: "全部", custom: "自訂", from: "從", to: "到", apply: "套用",
|
|
44
53
|
group: "分組", g_instance: "Agent", g_backend: "Backend", g_model: "模型", g_profile: "憑證 profile", g_team: "Team(依目前設定)",
|
|
45
|
-
csv: "下載 CSV", basis: "依牌價換算的 API
|
|
54
|
+
csv: "下載 CSV", basis: "依牌價換算的 API 等值({0})——不是實際花費。", basisMore: "訂閱方案不按 token 計費。",
|
|
46
55
|
amount: "API 等值", input: "輸入", output: "輸出", reasoning: "推理", read: "快取讀取", write: "快取寫入", total: "token 總計", requests: "請求數", messages: "訊息數",
|
|
47
56
|
notPriced: "未定價", partial: "部分", noTeam: "(不屬於任何 team)", unknown: "未知",
|
|
48
|
-
|
|
49
|
-
|
|
57
|
+
t_not_priced: "未定價:{0}", t_partial: "這一列有部分模型沒有價格", t_write_unreported: "Codex/Muse 不回報快取寫入",
|
|
58
|
+
t_cost_reported: "金額為 CLI 自行回報", t_estimated: "依文字長度估算(Kiro 不記錄 token 數)", t_reasoning_none: "這個 CLI 不回報",
|
|
59
|
+
sourceNote: "部分時段在 AgEnD 記錄 backend 與 profile 之前就已讀取。", profileUnrecorded: "未記錄 profile",
|
|
60
|
+
l_partial: "◐ 部分定價", l_cost_reported: "† 金額由 CLI 回報", l_estimated: "≈ 估算值",
|
|
61
|
+
speed: "速度", speedUnit: "{0} token/秒", speedCoverage: "{1} 個請求中有 {0} 個可計時", speedSpread: "p10–p90:{0}–{1} token/秒",
|
|
62
|
+
speedNone: "transcript 沒有計時資訊", speedByModel: "各模型速度",
|
|
63
|
+
speedBasis: "輸出 token ÷ 模型本身的回應時間(不含工具執行時間);方法參考 tokdash。",
|
|
64
|
+
|
|
65
|
+
f_includes_estimates: "含估算值(Kiro)", estimatedPart: "其中估算:{0}",
|
|
50
66
|
scanning: "掃描中——總數可能還會增加。", updated: "更新於 {0} · 每 10 分鐘讀取一次", since: "自 {0} 起收集", notYet: "尚未收集",
|
|
51
67
|
refresh: "重新整理",
|
|
52
68
|
notMeasured: "未量測", nm_credit_billed: "Kiro 以 credit 計費,不記錄 token", nm_unsupported: "AgEnD 目前還讀不到這個 CLI 的用量", nm_no_data: "尚未讀到任何資料",
|
|
@@ -95,10 +111,6 @@ export function keyText(group, key) {
|
|
|
95
111
|
return key;
|
|
96
112
|
}
|
|
97
113
|
const writes = (r) => (r.cacheWrite5m || 0) + (r.cacheWrite1h || 0) + (r.cacheWrite || 0);
|
|
98
|
-
function flagText(f, r) {
|
|
99
|
-
if (f === "not_priced") return tu("f_not_priced", (r.unpriced || []).join(", "));
|
|
100
|
-
return ["cache_write_not_reported", "source_unknown", "estimated", "includes_estimates", "cost_reported"].includes(f) ? tu(`f_${f}`) : f;
|
|
101
|
-
}
|
|
102
114
|
|
|
103
115
|
// ── CSV (design §4): the daily rows of this same answer; messages on their own rows (they are per agent, not per model).
|
|
104
116
|
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"];
|
|
@@ -318,25 +330,73 @@ function Heatmap({ report, dates }) {
|
|
|
318
330
|
</section>`;
|
|
319
331
|
}
|
|
320
332
|
|
|
321
|
-
|
|
333
|
+
/**
|
|
334
|
+
* A mark with what it means: shown as its sign, said (title, and aria-label for readers) as words. role="img" makes it
|
|
335
|
+
* nameable (#3067 review, Prism P3: aria-label is not allowed on a generic span).
|
|
336
|
+
*/
|
|
337
|
+
const mark = (sign, words, cls = "us-mark") => html`<span class=${cls} role="img" title=${words} aria-label=${words}>${sign}</span>`;
|
|
338
|
+
/** "—" that says why there is no number (nameable the same way). */
|
|
339
|
+
const dash = (words) => html`<span class="us-none" role="img" title=${words} aria-label=${words}>—</span>`;
|
|
340
|
+
/** The marks a row's numbers carry (#3066 §3): ◐ partly priced, † the CLI's own amount, ≈ estimated. */
|
|
341
|
+
export function rowMarks(r) {
|
|
342
|
+
const flags = r.flags || [];
|
|
343
|
+
return { partial: r.priced === "partial", cost: flags.includes("cost_reported"), est: flags.includes("estimated") || r.estimated === true,
|
|
344
|
+
writeUnreported: flags.includes("cache_write_not_reported") && writes(r) === 0, unpriced: r.amount === null || r.amount === undefined };
|
|
345
|
+
}
|
|
346
|
+
/** A profile as shown: Codex's older hours were never tagged with one. */
|
|
347
|
+
const profileText = (p) => (p === "unrecorded" ? tu("profileUnrecorded") : p);
|
|
348
|
+
|
|
349
|
+
function Row({ r, group, max, measure, cols }) {
|
|
322
350
|
const share = max > 0 ? Math.max(0.01, measure(r) / max) : 0;
|
|
323
|
-
const meta = [r.backends.join(", "), r.models.join(", "), r.profiles.join(", ")].filter(Boolean).join(" · ");
|
|
351
|
+
const meta = [r.backends.join(", "), r.models.join(", "), r.profiles.map(profileText).join(", ")].filter(Boolean).join(" · ");
|
|
352
|
+
const m = rowMarks(r);
|
|
353
|
+
// Estimated rows (Kiro): every number is an estimate — "≈" before each, the reason in its tooltip.
|
|
354
|
+
const num = (text) => (m.est ? html`${mark("≈", tu("t_estimated"), "us-mark us-approx")}${text}` : text);
|
|
355
|
+
const key = group === "profile" ? profileText(keyText(group, r.key)) : keyText(group, r.key);
|
|
324
356
|
return html`<tr class="us-row">
|
|
325
|
-
<th scope="row" class="us-name"><span class="mono">${
|
|
357
|
+
<th scope="row" class="us-name"><span class="mono">${key}</span>
|
|
326
358
|
<svg class="us-bar" aria-hidden="true"><rect class="us-bar-bg" width="100%" height="6" rx="3" /><rect class="us-bar-fg" width=${`${Math.round(share * 100)}%`} height="6" rx="3" /></svg>
|
|
327
|
-
${group !== "instance" || meta ? html`<span class="us-meta">${meta}</span>` : null}
|
|
328
|
-
|
|
329
|
-
<td data-label=${tu("
|
|
330
|
-
<td data-label=${tu("
|
|
331
|
-
|
|
332
|
-
<td data-label=${tu("
|
|
333
|
-
<td data-label=${tu("
|
|
334
|
-
<td data-label=${tu("
|
|
335
|
-
<td data-label=${tu("total")} class="num">${tokens(r.total)}</td>
|
|
359
|
+
${group !== "instance" || meta ? html`<span class="us-meta">${meta}</span>` : null}</th>
|
|
360
|
+
<td data-label=${tu("amount")} class=${`num${m.unpriced ? " muted" : ""}`}>${m.unpriced ? dash(tu("t_not_priced", (r.unpriced || []).join(", "))) : html`${num(money(r.amount))}${m.partial ? mark("◐", tu("t_partial")) : null}${m.cost ? mark("†", tu("t_cost_reported")) : null}`}</td>
|
|
361
|
+
<td data-label=${tu("input")} class="num">${num(tokens(r.input))}</td>
|
|
362
|
+
<td data-label=${tu("output")} class="num">${num(tokens(r.output))}</td>
|
|
363
|
+
${cols.reasoning ? html`<td data-label=${tu("reasoning")} class="num">${r.reasoningReported === false ? dash(tu("t_reasoning_none")) : num(tokens(r.reasoning || 0))}</td>` : null}
|
|
364
|
+
<td data-label=${tu("read")} class="num">${num(tokens(r.cacheRead))}</td>
|
|
365
|
+
<td data-label=${tu("write")} class="num">${m.writeUnreported ? dash(tu("t_write_unreported")) : num(tokens(writes(r)))}</td>
|
|
366
|
+
<td data-label=${tu("total")} class="num">${num(tokens(r.total))}</td>
|
|
336
367
|
<td data-label=${tu("requests")} class="num">${n(r.requests)}</td>
|
|
337
|
-
|
|
368
|
+
${cols.messages ? html`<td data-label=${tu("messages")} class="num">${r.messages === null ? "—" : n(r.messages)}</td>` : null}
|
|
369
|
+
${cols.speed ? html`<td data-label=${tu("speed")} class="num">${r.speed ? speedText(r.speed) : dash(tu("speedNone"))}</td>` : null}
|
|
338
370
|
</tr>`;
|
|
339
371
|
}
|
|
372
|
+
/** #3066 §2: a rate as shown — whole tok/s, one decimal below 10. */
|
|
373
|
+
export const speedText = (s) => tu("speedUnit", s.tokPerSec >= 10 ? Math.round(s.tokPerSec).toLocaleString("en-US") : s.tokPerSec.toFixed(1));
|
|
374
|
+
/** Columns worth a place (#3066 §3): Reasoning only when some row reports it; Messages only when some row has them; Speed (§2) only when some response was timed. */
|
|
375
|
+
export function usageColumns(rows) {
|
|
376
|
+
return { reasoning: rows.some((r) => r.reasoningReported !== false), messages: rows.some((r) => r.messages !== null && r.messages !== undefined),
|
|
377
|
+
speed: rows.some((r) => !!r.speed) };
|
|
378
|
+
}
|
|
379
|
+
/** #3066 §2: each model's speed — rate · requests timed (coverage) · p10–p90 from 30 timed. */
|
|
380
|
+
function SpeedCard({ report }) {
|
|
381
|
+
const list = report.speedByModel || [];
|
|
382
|
+
if (!list.length) return null;
|
|
383
|
+
return html`<section class="us-speed card" aria-labelledby="us-speed-h">
|
|
384
|
+
<h3 id="us-speed-h">${tu("speedByModel")}</h3>
|
|
385
|
+
<ul class="rows">${list.map((m) => html`<li key=${m.model} class="row-item"><span class="grow strong mono">${m.model}</span>
|
|
386
|
+
<span class="num">${speedText(m.speed)}</span>
|
|
387
|
+
<span class="muted">${[m.requests > 0 ? tu("speedCoverage", n(m.speed.timedRequests), n(m.requests)) : null,
|
|
388
|
+
m.speed.p10 !== null && m.speed.p90 !== null ? tu("speedSpread", Math.round(m.speed.p10), Math.round(m.speed.p90)) : null].filter(Boolean).join(" · ")}</span></li>`)}</ul>
|
|
389
|
+
<p class="note">${tu("speedBasis")}</p>
|
|
390
|
+
</section>`;
|
|
391
|
+
}
|
|
392
|
+
/** The legend under the table: only the marks that appear, and the one footnote when an hour's source was not recorded. */
|
|
393
|
+
function Legend({ rows }) {
|
|
394
|
+
const marks = rows.map(rowMarks);
|
|
395
|
+
const parts = [marks.some((m) => m.partial) && tu("l_partial"), marks.some((m) => m.cost) && tu("l_cost_reported"), marks.some((m) => m.est) && tu("l_estimated")].filter(Boolean);
|
|
396
|
+
const source = rows.some((r) => (r.flags || []).includes("source_unknown"));
|
|
397
|
+
if (!parts.length && !source) return null;
|
|
398
|
+
return html`<p class="note us-key">${parts.join(" · ")}${parts.length && source ? html`<br />` : null}${source ? tu("sourceNote") : null}</p>`;
|
|
399
|
+
}
|
|
340
400
|
|
|
341
401
|
/** The tab's body for one answer of GET /ui/usage-report. */
|
|
342
402
|
export function UsageReport({ report, choice, setChoice, refresh, fetchedAt }) {
|
|
@@ -355,6 +415,7 @@ export function UsageReport({ report, choice, setChoice, refresh, fetchedAt }) {
|
|
|
355
415
|
const zones = zonesChanged(report);
|
|
356
416
|
const csvFrom = report.dailyTruncated ? report.dailyFrom : report.range.kind === "all" ? "all" : report.range.from;
|
|
357
417
|
const rows = report.rows.filter((r) => r.total > 0 || (r.messages || 0) > 0);
|
|
418
|
+
const cols = usageColumns(rows);
|
|
358
419
|
const anyAmount = rows.some((r) => r.amount !== null && r.amount > 0);
|
|
359
420
|
const measure = (r) => (anyAmount ? r.amount || 0 : r.total);
|
|
360
421
|
const max = Math.max(0, ...rows.map(measure));
|
|
@@ -375,7 +436,7 @@ export function UsageReport({ report, choice, setChoice, refresh, fetchedAt }) {
|
|
|
375
436
|
<label>${tu("from")} <input type="date" value=${draft.from} max=${draft.to} onInput=${(e) => setDraft({ ...draft, from: e.target.value })} /></label>
|
|
376
437
|
<label>${tu("to")} <input type="date" value=${draft.to} min=${draft.from} onInput=${(e) => setDraft({ ...draft, to: e.target.value })} /></label>
|
|
377
438
|
<button type="submit" class="btn btn-sm">${tu("apply")}</button></form>` : null}
|
|
378
|
-
<p class="us-basis" role="note">${tu("basis", report.pricesChecked)}</p>
|
|
439
|
+
<p class="us-basis" role="note" title=${tu("basisMore")}>${tu("basis", report.pricesChecked)}</p>
|
|
379
440
|
${noDaily ? html`<p class="us-partial" role="status">${tu("noDaily")}</p>` : report.dailyTruncated ? html`<p class="us-partial" role="status">${tu("partialDays", report.dailyFrom)}</p>` : null}
|
|
380
441
|
${zones ? html`<p class="us-partial" role="status">${tu("zoneChanged", zones.join(", "), report.zone)}</p>` : null}
|
|
381
442
|
<p class="note us-fresh">${tu("updated", new Date(fetchedAt).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" }))} · ${Number.isFinite(since) ? tu("since", new Date(since).toLocaleDateString()) : tu("notYet")} · ${tu("zoneNote", report.zone)}${group === "team" ? ` ${tu("teamsNote")}` : ""}
|
|
@@ -389,10 +450,12 @@ export function UsageReport({ report, choice, setChoice, refresh, fetchedAt }) {
|
|
|
389
450
|
<div class="ch-metric"><dt>${tu("messages")}</dt><dd>${report.totals.messages === null ? "—" : n(report.totals.messages)}</dd></div>
|
|
390
451
|
</dl>
|
|
391
452
|
${rows.length ? html`<table class="us-table"><thead><tr><th scope="col">${tu(`g_${group}`)}</th><th scope="col" class="num">${tu("amount")}</th>
|
|
392
|
-
<th scope="col" class="num">${tu("input")}</th><th scope="col" class="num">${tu("output")}</th
|
|
393
|
-
<th scope="col" class="num">${tu("total")}</th><th scope="col" class="num">${tu("requests")}</th
|
|
394
|
-
<tbody>${rows.map((r) => html`<${Row} key=${r.key} r=${r} group=${group} max=${max} measure=${measure} />`)}</tbody></table
|
|
453
|
+
<th scope="col" class="num">${tu("input")}</th><th scope="col" class="num">${tu("output")}</th>${cols.reasoning ? html`<th scope="col" class="num">${tu("reasoning")}</th>` : null}<th scope="col" class="num">${tu("read")}</th><th scope="col" class="num">${tu("write")}</th>
|
|
454
|
+
<th scope="col" class="num">${tu("total")}</th><th scope="col" class="num">${tu("requests")}</th>${cols.messages ? html`<th scope="col" class="num">${tu("messages")}</th>` : null}${cols.speed ? html`<th scope="col" class="num">${tu("speed")}</th>` : null}</tr></thead>
|
|
455
|
+
<tbody>${rows.map((r) => html`<${Row} key=${r.key} r=${r} group=${group} max=${max} measure=${measure} cols=${cols} />`)}</tbody></table>
|
|
456
|
+
<${Legend} rows=${rows} />`
|
|
395
457
|
: html`<p class="note">${tu("noRows")}</p>`}
|
|
458
|
+
<${SpeedCard} report=${report} />
|
|
396
459
|
<${Trend} report=${report} dates=${dates} />
|
|
397
460
|
<${Heatmap} report=${report} dates=${dates} />`}
|
|
398
461
|
${report.notMeasured.length || report.shared.length ? html`<section class="us-rest" aria-labelledby="us-rest-h"><h3 id="us-rest-h">${tu("notMeasured")}</h3>
|
package/dist/ui/panel-chat.js
CHANGED
|
@@ -797,6 +797,8 @@ function DeleteDialog({ name, onClose }) {
|
|
|
797
797
|
} catch (err) { r = { error: err && err.message ? err.message : t("chat.disconnected") }; }
|
|
798
798
|
if (r && r.error) { toast(r.error, false); if (!handedOver && lease.current()) setBusy(false); return; }
|
|
799
799
|
toast(t("chat.instanceDeleted", name));
|
|
800
|
+
// The agent's own topic went too, or stayed with the reason (the server's own words: no new string here).
|
|
801
|
+
if (r.topic_note) toast(r.topic_note, r.topic_deleted !== false);
|
|
800
802
|
if (handedOver || !lease.current()) return;
|
|
801
803
|
setBusy(false);
|
|
802
804
|
onClose();
|
package/dist/ui/panel-log.js
CHANGED
|
@@ -49,6 +49,7 @@ register("log", {
|
|
|
49
49
|
user: "Asked", assistant: "Replied", error: "Error", errorCode: "Error {0}", turnEnd: "Turn ended", turnEndIn: "Turn ended · {0}",
|
|
50
50
|
compacted: "Conversation compacted", turn: "Turn",
|
|
51
51
|
running: "running", done: "done", failed: "failed", interrupted: "interrupted", exit: "exit {0}",
|
|
52
|
+
showScreen: "Show what was on screen", hideScreen: "Hide what was on screen",
|
|
52
53
|
showOutput: "Show output", hideOutput: "Hide output", args: "Arguments", output: "Output", noOutput: "No output.",
|
|
53
54
|
showAll: "Show all", showLess: "Show less", cut: "… {0} more characters not shown.", tooLarge: "Output of {0}: only its start is shown.",
|
|
54
55
|
times: "×{0}", newer: "{0} new",
|
|
@@ -87,6 +88,7 @@ register("log", {
|
|
|
87
88
|
user: "收到要求", assistant: "回覆", error: "錯誤", errorCode: "錯誤 {0}", turnEnd: "回合結束", turnEndIn: "回合結束 · {0}",
|
|
88
89
|
compacted: "對話已壓縮", turn: "回合",
|
|
89
90
|
running: "執行中", done: "完成", failed: "失敗", interrupted: "中斷", exit: "結束碼 {0}",
|
|
91
|
+
showScreen: "顯示當時的畫面", hideScreen: "隱藏當時的畫面",
|
|
90
92
|
showOutput: "顯示輸出", hideOutput: "隱藏輸出", args: "參數", output: "輸出", noOutput: "沒有輸出。",
|
|
91
93
|
showAll: "顯示全部", showLess: "收合", cut: "… 還有 {0} 個字元沒有顯示。", tooLarge: "輸出共 {0},只顯示開頭。",
|
|
92
94
|
times: "×{0}", newer: "{0} 則新的",
|
|
@@ -402,7 +404,11 @@ function Row({ x, prev }) {
|
|
|
402
404
|
};
|
|
403
405
|
let row;
|
|
404
406
|
if (x.kind === "event") {
|
|
405
|
-
|
|
407
|
+
// M-2269: a dialog or prompt AgEnD saw (the CLI never writes it to its transcript): its text as it was on screen,
|
|
408
|
+
// folded until asked for. Text only (a text node), masked by the server.
|
|
409
|
+
row = html`${head(KIND_ICON.event, eventLabel(x.type))}${x.detail ? html`<div class="log-text muted">${x.detail}</div>` : null}
|
|
410
|
+
${x.screen ? html`<button type="button" class="link-btn log-toggle log-screen-toggle" aria-expanded=${open ? "true" : "false"} onClick=${() => setOpen(!open)}>${open ? tl("hideScreen") : tl("showScreen")}</button>` : null}
|
|
411
|
+
${x.screen && open ? html`<div class="log-detail"><div class="log-text mono log-screen">${x.screen}</div></div>` : null}`;
|
|
406
412
|
} else if (x.kind === "user" || x.kind === "assistant") {
|
|
407
413
|
row = html`${head(KIND_ICON[x.kind], tl(x.kind))}${text(x.body, x.bodyCut)}`;
|
|
408
414
|
} else if (x.kind === "error") {
|
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)", fleetSignIns: "Fleet sign-ins", signIn: "Sign in",
|
|
28
|
+
open: "Open chat", kiroOpen: "Open agent", kiroMigration: "Migration instructions", 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.",
|
|
@@ -34,11 +34,11 @@ register("needs", {
|
|
|
34
34
|
notifyMobile: "On a phone, rely on your chat app's notification: a new item is a new post in General.", notifyMobileWeb: "On a phone, open this page to see what needs you.",
|
|
35
35
|
notifyInsecure: "Notifications need a secure address (localhost or the HTTPS public link), not a plain-HTTP LAN address.",
|
|
36
36
|
notifyUnsupported: "This browser cannot show notifications.", turnOn: "Turn on", turnOff: "Turn off",
|
|
37
|
-
typePrompt: "Fleet prompt", typeAwaiting: "At its terminal", typeInstance: "Instance", typeDelivery: "Delivery",
|
|
37
|
+
typePrompt: "Fleet prompt", typeAwaiting: "At its terminal", typeInstance: "Instance", typeDelivery: "Delivery", typeMissed: "Missed while offline",
|
|
38
38
|
},
|
|
39
39
|
"zh-TW": {
|
|
40
40
|
title: "等你處理", empty: "目前沒有需要你處理的事", emptyHint: "agent 在等你時,會出現在這裡——也會出現在聊天 app 的 General。", emptyHintWeb: "agent 在等你時,會出現在這裡。",
|
|
41
|
-
open: "開啟聊天", openCard: "打開卡片", noAssignee: "任務看板(沒有負責人)", fleetSignIns: "Fleet 登入", signIn: "登入",
|
|
41
|
+
open: "開啟聊天", kiroOpen: "開啟 Agent", kiroMigration: "遷移說明", 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: "這個瀏覽器的通知已開啟(需要開著分頁)。",
|
|
@@ -47,10 +47,18 @@ register("needs", {
|
|
|
47
47
|
notifyMobile: "在手機上請以聊天 app 的通知為主:每個新項目都會在 General 發一則新訊息。", notifyMobileWeb: "在手機上請打開這個頁面查看等你處理的事。",
|
|
48
48
|
notifyInsecure: "通知需要安全的網址(localhost 或 HTTPS 公開連結),區網的一般 HTTP 網址不行。",
|
|
49
49
|
notifyUnsupported: "這個瀏覽器無法顯示通知。", turnOn: "開啟", turnOff: "關閉",
|
|
50
|
-
typePrompt: "Fleet 提示", typeAwaiting: "在終端機上", typeInstance: "Instance", typeDelivery: "傳送",
|
|
50
|
+
typePrompt: "Fleet 提示", typeAwaiting: "在終端機上", typeInstance: "Instance", typeDelivery: "傳送", typeMissed: "離線時錯過",
|
|
51
51
|
},
|
|
52
52
|
});
|
|
53
53
|
const tn = (k, ...v) => t(`needs.${k}`, ...v);
|
|
54
|
+
/** Stale shells keep the old app-i18n.js; a missing key would otherwise show as app.needs_reason_*. */
|
|
55
|
+
function itemReason(item) {
|
|
56
|
+
const text = reasonText(item);
|
|
57
|
+
if (typeof text === "string" && text.startsWith("app.needs_reason_") && (item.type === "missed" || item.reason === "missed_offline")) {
|
|
58
|
+
return tn("typeMissed");
|
|
59
|
+
}
|
|
60
|
+
return text;
|
|
61
|
+
}
|
|
54
62
|
|
|
55
63
|
/**
|
|
56
64
|
* The page's claims on what Needs you writes, kept for the life of the page — not of a panel or a render (#1463
|
|
@@ -86,7 +94,7 @@ const setClaim = (kind, key, value) => claims.set((c) => {
|
|
|
86
94
|
return { ...c, [kind]: next };
|
|
87
95
|
});
|
|
88
96
|
|
|
89
|
-
const ICON = { prompt: "chat", awaiting_input: "clock", instance: "alert", delivery: "send", task: "tasks" };
|
|
97
|
+
const ICON = { prompt: "chat", awaiting_input: "clock", instance: "alert", delivery: "send", task: "tasks", missed: "clock" };
|
|
90
98
|
const BAD = new Set(["crashed", "delivery_failed", "hang", "exited"]);
|
|
91
99
|
|
|
92
100
|
/**
|
|
@@ -195,16 +203,17 @@ function NeedsItem({ item, nowMs, owner }) {
|
|
|
195
203
|
return html`<article data-trust="permission" class=${`n-item${BAD.has(item.reason) ? " bad" : ""}`}>
|
|
196
204
|
<span class="n-icon"><${Icon} name=${ICON[item.type] || "alert"} size=${18} /></span>
|
|
197
205
|
<div class="n-body">
|
|
198
|
-
<div class="n-title"><strong>${
|
|
206
|
+
<div class="n-title"><strong>${itemReason(item)}</strong><span class="n-age">${age(item.since, nowMs)}</span></div>
|
|
199
207
|
${detailOf(item) ? html`<p class="n-detail">${detailOf(item)}</p>` : null}
|
|
200
208
|
<div class="n-actions">
|
|
201
209
|
${item.type === "prompt" && Array.isArray(item.actions) ? item.actions.filter((a) => !a.input).map((a) => html`<button key=${a.id} type="button" class="btn btn-sm"
|
|
202
210
|
disabled=${promptBusy} onClick=${() => answer(a.id)}>${(p ? p.busy : fallback === "busy") ? tn("answering") : a.label}</button>`) : null}
|
|
203
|
-
${item.type === "delivery" ? html`<button type="button" class="btn btn-sm" disabled=${!!ack} onClick=${acknowledge}>
|
|
211
|
+
${item.type === "delivery" || item.type === "missed" ? html`<button type="button" class="btn btn-sm" disabled=${!!ack} onClick=${acknowledge}>
|
|
204
212
|
<${Icon} name="check" size=${14} />${ack === "busy" ? tn("acknowledging") : tn("acknowledge")}</button>` : null}
|
|
205
213
|
${(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}
|
|
206
214
|
${item.type === "task" && item.card ? html`<a class="btn btn-sm" href=${`/ui/fleet?card=${encodeURIComponent(item.card.code)}`}>${tn("openCard")}</a>` : null}
|
|
207
|
-
${item.
|
|
215
|
+
${item.kiroChoice === true ? html`<a class="btn btn-sm" href="https://github.com/songsid/AgEnD/blob/main/src/general-knowledge/skills/kiro-engine-migration/SKILL.md" target="_blank" rel="noopener noreferrer">${tn("kiroMigration")}</a>` : null}
|
|
216
|
+
${item.instance ? html`<a class="btn btn-sm btn-ghost" href=${chatPath(item.instance)}>${tn(item.kiroChoice === true ? "kiroOpen" : "open")}</a>` : null}
|
|
208
217
|
</div>
|
|
209
218
|
</div>
|
|
210
219
|
</article>`;
|
|
@@ -166,7 +166,7 @@ register("settings", {
|
|
|
166
166
|
failed: "Failed",
|
|
167
167
|
actionFailed: "{0} failed",
|
|
168
168
|
noAgentMatch: "No agents match \"{0}\".",
|
|
169
|
-
deleteAgent: "Delete agent \"{0}\"? This will be applied only after you confirm the pending changes.",
|
|
169
|
+
deleteAgent: "Delete agent \"{0}\" and its chat topic (on Discord, its channel and history)? This will be applied only after you confirm the pending changes.",
|
|
170
170
|
nameRequired: "name required",
|
|
171
171
|
tokenEnvRequired: "token env required",
|
|
172
172
|
removeBot: "Remove bot \"{0}\"? (the token in .env is left untouched)",
|
|
@@ -823,7 +823,7 @@ register("settings", {
|
|
|
823
823
|
failed: "失敗",
|
|
824
824
|
actionFailed: "{0}失敗",
|
|
825
825
|
noAgentMatch: "沒有符合「{0}」的 Agent。",
|
|
826
|
-
deleteAgent: "確定刪除 Agent「{0}
|
|
826
|
+
deleteAgent: "確定刪除 Agent「{0}」及它的聊天 topic(在 Discord 上是它的頻道與訊息記錄)嗎?只有在確認套用待處理變更後才會生效。",
|
|
827
827
|
nameRequired: "必須填寫名稱",
|
|
828
828
|
tokenEnvRequired: "必須填寫 token 環境變數",
|
|
829
829
|
removeBot: "確定移除機器人「{0}」嗎?(.env 中的 token 會保留)",
|
|
@@ -78,7 +78,7 @@ register("app", {
|
|
|
78
78
|
statusQueued: "queued", statusStarting: "starting", fleetStarting: "Fleet starting {0}/{1}…", statusRunning: "running", statusStopped: "stopped", statusPaused: "paused", statusCrashed: "crashed", statusWorking: "working", statusStuck: "looks stuck", statusIdle: "idle",
|
|
79
79
|
connReconnecting: "Can't reach AgEnD — it may be restarting. Reconnecting…", connReconnectingIn: "Can't reach AgEnD — it may be restarting. Trying again in {0} s.",
|
|
80
80
|
hydrating: "Loading what is open now…", hydrateFailed: "Could not load what is open now (prompts, ticks).",
|
|
81
|
-
skip: "Skip to the conversation", loadFailed: "This could not be loaded.", retry: "Try again", loading: "Loading…",
|
|
81
|
+
skip: "Skip to the conversation", loadFailed: "This could not be loaded.", retry: "Try again", reloadPage: "Reload the page", loading: "Loading…",
|
|
82
82
|
noInstances: "No instances yet", noInstancesHint: "Create one to start chatting.",
|
|
83
83
|
guestChip: "Guest", guestAs: "Guest · {0}", guestAsOn: "Guest · {0} ({1})", guestHint: "You see only the agents you can already use in chat.",
|
|
84
84
|
session: "Session", signIn: "Sign in", signedIn: "Signed in", signedOut: "Not signed in", thisDevice: "This device", devicePrefs: "Theme and language",
|
|
@@ -111,7 +111,7 @@ register("app", {
|
|
|
111
111
|
confirmTitle: "Please confirm", confirmOk: "Continue", cancel: "Cancel",
|
|
112
112
|
sidePanelLeave: "Leave {0} without saving? Your changes there will be lost.", sidePanelDiscard: "Discard changes",
|
|
113
113
|
// The server's own wording (src/locale.ts needs.reason.*), so the web says what Discord says.
|
|
114
|
-
needs_reason_hang: "Not responding", needs_reason_exited: "Exited", needs_reason_assist: "Waiting at its terminal", needs_reason_question: "Asking you a question", 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_config_invalid: "Configuration file needs attention", needs_reason_config_fallback: "Running on stored configuration", config_history_edit: "{0}, line {1}, column {2}: {3}. AgEnD is still running on the previous settings. The next restart would use the stored valid copy from {4}. Correct the YAML error; the file has not been changed by AgEnD.", config_history_no_history: "{0}, line {1}, column {2}: {3}. AgEnD is still running on the previous settings. No stored valid copy is available, so the next restart cannot recover automatically. Correct the YAML error before restarting; the file has not been changed by AgEnD.", config_history_fallback: "{0}, line {1}, column {2}: {3}. AgEnD started using the stored valid copy from {4}. Correct the YAML error and reload the settings. The file on disk has not been changed by AgEnD.", needs_reason_crashed: "Crashed", needs_reason_usage_limit: "Usage limit reached · reset time unknown", 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",
|
|
114
|
+
needs_reason_hang: "Not responding", needs_reason_exited: "Exited", needs_reason_assist: "Waiting at its terminal", needs_reason_question: "Asking you a question", 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_kiro_choice: "Kiro needs your decision", 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_config_invalid: "Configuration file needs attention", needs_reason_config_fallback: "Running on stored configuration", config_history_edit: "{0}, line {1}, column {2}: {3}. AgEnD is still running on the previous settings. The next restart would use the stored valid copy from {4}. Correct the YAML error; the file has not been changed by AgEnD.", config_history_no_history: "{0}, line {1}, column {2}: {3}. AgEnD is still running on the previous settings. No stored valid copy is available, so the next restart cannot recover automatically. Correct the YAML error before restarting; the file has not been changed by AgEnD.", config_history_fallback: "{0}, line {1}, column {2}: {3}. AgEnD started using the stored valid copy from {4}. Correct the YAML error and reload the settings. The file on disk has not been changed by AgEnD.", needs_reason_crashed: "Crashed", needs_reason_usage_limit: "Usage limit reached · reset time unknown", needs_reason_delivery_uncertain: "Could not confirm delivery", needs_reason_delivery_failed: "Delivery failed", needs_reason_missed_offline: "Missed while AgEnD was offline", needs_reason_task_review: "Waiting for your confirmation", needs_reason_task_blocked: "Blocked: asks you",
|
|
115
115
|
},
|
|
116
116
|
"zh-TW": {
|
|
117
117
|
brand: "AgEnD", fleet: "Fleet", fleetOverview: "Fleet 概覽", view: "檢視", settings: "設定", instances: "Instances", newInstance: "新增 instance", newAgent: "新增 Agent",
|
|
@@ -126,7 +126,7 @@ register("app", {
|
|
|
126
126
|
statusQueued: "等待啟動", statusStarting: "啟動中", fleetStarting: "Fleet 啟動中 {0}/{1}…", statusRunning: "執行中", statusStopped: "已停止", statusPaused: "已暫停", statusCrashed: "已當掉", statusWorking: "工作中", statusStuck: "似乎卡住", statusIdle: "閒置",
|
|
127
127
|
connReconnecting: "連不上 AgEnD——可能正在重新啟動。正在重新連線…", connReconnectingIn: "連不上 AgEnD——可能正在重新啟動。{0} 秒後再試。",
|
|
128
128
|
hydrating: "正在載入目前的狀態…", hydrateFailed: "無法載入目前的狀態(提示、送達標記)。",
|
|
129
|
-
skip: "跳到對話", loadFailed: "無法載入。", retry: "再試一次", loading: "載入中…",
|
|
129
|
+
skip: "跳到對話", loadFailed: "無法載入。", retry: "再試一次", reloadPage: "重新載入頁面", loading: "載入中…",
|
|
130
130
|
noInstances: "還沒有 instance", noInstancesHint: "建立一個就能開始聊天。",
|
|
131
131
|
guestChip: "訪客", guestAs: "訪客 · {0}", guestAsOn: "訪客 · {0}({1})", guestHint: "你只會看到在聊天中本來就能用的 agent。",
|
|
132
132
|
session: "登入狀態", signIn: "登入", signedIn: "已登入", signedOut: "尚未登入", thisDevice: "這台裝置", devicePrefs: "主題與語言",
|
|
@@ -156,6 +156,6 @@ register("app", {
|
|
|
156
156
|
search: "搜尋", searchTitle: "搜尋聊天、agent 之間的訊息與任務({0})",
|
|
157
157
|
confirmTitle: "請確認", confirmOk: "繼續", cancel: "取消",
|
|
158
158
|
sidePanelLeave: "不儲存就離開「{0}」?你在那裡的修改會遺失。", sidePanelDiscard: "捨棄修改",
|
|
159
|
-
needs_reason_hang: "沒有回應", needs_reason_exited: "已結束", needs_reason_assist: "在終端機上等待", needs_reason_question: "正在問你問題", 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_config_invalid: "設定檔需要處理", needs_reason_config_fallback: "正在使用儲存的設定副本", config_history_edit: "{0} 第 {1} 行、第 {2} 欄:{3}。AgEnD 仍使用先前的設定執行。下次重新啟動會改用 {4} 儲存的有效副本。請修正 YAML 錯誤;AgEnD 未更動此檔案。", config_history_no_history: "{0} 第 {1} 行、第 {2} 欄:{3}。AgEnD 仍使用先前的設定執行。沒有可用的有效副本,下次重新啟動將無法自動恢復。請在重新啟動前修正 YAML 錯誤;AgEnD 未更動此檔案。", config_history_fallback: "{0} 第 {1} 行、第 {2} 欄:{3}。AgEnD 已使用 {4} 儲存的有效副本啟動。請修正 YAML 錯誤並重新載入設定。AgEnD 未更動磁碟上的檔案。", needs_reason_crashed: "已崩潰", needs_reason_usage_limit: "用量已達上限 · 恢復時間未知", needs_reason_delivery_uncertain: "無法確認是否送達", needs_reason_delivery_failed: "傳送失敗", needs_reason_task_review: "等你確認", needs_reason_task_blocked: "卡住,在問你",
|
|
159
|
+
needs_reason_hang: "沒有回應", needs_reason_exited: "已結束", needs_reason_assist: "在終端機上等待", needs_reason_question: "正在問你問題", needs_reason_permission: "需要權限", needs_reason_dangerous_command: "危險指令待確認", needs_reason_login: "需要登入", needs_reason_dialog: "停在對話框", needs_reason_kiro_choice: "Kiro 需要你決定", needs_reason_terminal_input: "可能在等輸入", needs_reason_auth_paused: "已暫停:需要登入", needs_reason_backend_signin: "後端需要登入", needs_reason_config_invalid: "設定檔需要處理", needs_reason_config_fallback: "正在使用儲存的設定副本", config_history_edit: "{0} 第 {1} 行、第 {2} 欄:{3}。AgEnD 仍使用先前的設定執行。下次重新啟動會改用 {4} 儲存的有效副本。請修正 YAML 錯誤;AgEnD 未更動此檔案。", config_history_no_history: "{0} 第 {1} 行、第 {2} 欄:{3}。AgEnD 仍使用先前的設定執行。沒有可用的有效副本,下次重新啟動將無法自動恢復。請在重新啟動前修正 YAML 錯誤;AgEnD 未更動此檔案。", config_history_fallback: "{0} 第 {1} 行、第 {2} 欄:{3}。AgEnD 已使用 {4} 儲存的有效副本啟動。請修正 YAML 錯誤並重新載入設定。AgEnD 未更動磁碟上的檔案。", needs_reason_crashed: "已崩潰", needs_reason_usage_limit: "用量已達上限 · 恢復時間未知", needs_reason_delivery_uncertain: "無法確認是否送達", needs_reason_delivery_failed: "傳送失敗", needs_reason_missed_offline: "AgEnD 離線時錯過", needs_reason_task_review: "等你確認", needs_reason_task_blocked: "卡住,在問你",
|
|
160
160
|
},
|
|
161
161
|
});
|
|
@@ -63,7 +63,7 @@ export const configDetail = (item) => {
|
|
|
63
63
|
const issue = item.configIssue;
|
|
64
64
|
return issue ? t(`app.config_history_${issue.mode === "fallback" ? "fallback" : issue.time ? "edit" : "no_history"}`, issue.file, issue.line, issue.column, issue.reason, issue.time || "") : item.detail;
|
|
65
65
|
};
|
|
66
|
-
export const reasonText = (item) => t(`app.needs_reason_${item.reason}`);
|
|
66
|
+
export const reasonText = (item) => t(`app.needs_reason_${item.kiroChoice ? "kiro_choice" : item.reason}`);
|
|
67
67
|
|
|
68
68
|
let stop = null;
|
|
69
69
|
|
|
@@ -508,12 +508,14 @@ function BottomTabs({ route, viewOnly }) {
|
|
|
508
508
|
</nav>`;
|
|
509
509
|
}
|
|
510
510
|
|
|
511
|
-
function ConnectionLine() {
|
|
511
|
+
export function ConnectionLine() {
|
|
512
512
|
const { connection, hydration, retryHydration } = useStore(appStore);
|
|
513
513
|
// A late catch-up that is not done: the chat may be missing what was open before it loaded (#1425 review).
|
|
514
|
+
// M-2260: never a dead end — beside Try again, a reload reads everything current, whatever kept the catch-up from it.
|
|
514
515
|
if (hydration === "retrying" || hydration === "failed") {
|
|
515
516
|
return html`<div data-trust="status" class="conn" role="status">${hydration === "failed" ? t("app.hydrateFailed") : t("app.hydrating")}
|
|
516
|
-
${hydration === "failed" && retryHydration ? html` <button type="button" class="btn btn-sm" onClick=${() => retryHydration()}>${t("app.retry")}</button>` : null}
|
|
517
|
+
${hydration === "failed" && retryHydration ? html` <button type="button" class="btn btn-sm" onClick=${() => retryHydration()}>${t("app.retry")}</button>` : null}
|
|
518
|
+
${hydration === "failed" ? html` <button type="button" class="btn btn-sm" onClick=${() => location.reload()}>${t("app.reloadPage")}</button>` : null}</div>`;
|
|
517
519
|
}
|
|
518
520
|
if (connection === "reconnecting") return html`<${Reconnecting} />`;
|
|
519
521
|
// #1603: polling is a working transport (the public link polls by design; a buffering proxy makes a page poll), not
|