@songsid/agend 2.3.0 → 2.3.2-beta.1
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/README.md +1 -1
- package/README.zh-TW.md +1 -1
- package/dist/authority/authority-state.d.ts +4 -0
- package/dist/authority/authority-state.js +16 -10
- package/dist/authority/authority-state.js.map +1 -1
- package/dist/authority/session-authorizations.d.ts +7 -1
- package/dist/authority/session-authorizations.js +6 -4
- package/dist/authority/session-authorizations.js.map +1 -1
- package/dist/authority/web-authority.d.ts +19 -6
- package/dist/authority/web-authority.js +22 -8
- package/dist/authority/web-authority.js.map +1 -1
- package/dist/backend/muse.d.ts +20 -2
- package/dist/backend/muse.js +154 -16
- package/dist/backend/muse.js.map +1 -1
- package/dist/channel/adapters/discord.d.ts +2 -0
- package/dist/channel/adapters/discord.js +33 -3
- package/dist/channel/adapters/discord.js.map +1 -1
- package/dist/channel/adapters/telegram.d.ts +1 -1
- package/dist/channel/adapters/telegram.js +3 -35
- package/dist/channel/adapters/telegram.js.map +1 -1
- package/dist/channel/mcp-tools.js +5 -5
- package/dist/channel/mcp-tools.js.map +1 -1
- package/dist/channel/types.d.ts +11 -0
- package/dist/cli.js +6 -3
- package/dist/cli.js.map +1 -1
- package/dist/config-validator.js +42 -5
- package/dist/config-validator.js.map +1 -1
- package/dist/daemon.d.ts +47 -3
- package/dist/daemon.js +380 -60
- package/dist/daemon.js.map +1 -1
- package/dist/delivery-outbox.d.ts +23 -1
- package/dist/delivery-outbox.js +114 -17
- package/dist/delivery-outbox.js.map +1 -1
- package/dist/doctor.d.ts +3 -0
- package/dist/doctor.js +9 -0
- package/dist/doctor.js.map +1 -1
- package/dist/event-log.d.ts +5 -0
- package/dist/event-log.js +13 -0
- package/dist/event-log.js.map +1 -1
- package/dist/fleet-context.d.ts +1 -1
- package/dist/fleet-lock.d.ts +6 -0
- package/dist/fleet-lock.js +19 -0
- package/dist/fleet-lock.js.map +1 -1
- package/dist/fleet-manager.d.ts +174 -2
- package/dist/fleet-manager.js +678 -68
- package/dist/fleet-manager.js.map +1 -1
- package/dist/fleet-process-handlers.d.ts +1 -0
- package/dist/fleet-process-handlers.js +9 -1
- package/dist/fleet-process-handlers.js.map +1 -1
- package/dist/general-knowledge/skills/instance-lifecycle/SKILL.md +11 -0
- package/dist/general-knowledge/skills/web-appearance/SKILL.canvas-worker-off.md +4 -4
- package/dist/general-knowledge/skills/web-appearance/SKILL.md +7 -7
- package/dist/general-knowledge/skills/web-dashboard/SKILL.canvas-worker-off.md +109 -57
- package/dist/general-knowledge/skills/web-dashboard/SKILL.md +110 -58
- package/dist/guest-seen-people.d.ts +38 -0
- package/dist/guest-seen-people.js +78 -0
- package/dist/guest-seen-people.js.map +1 -0
- package/dist/instance-config-impact.js +4 -1
- package/dist/instance-config-impact.js.map +1 -1
- package/dist/instance-lifecycle.d.ts +2 -0
- package/dist/instance-lifecycle.js +27 -1
- package/dist/instance-lifecycle.js.map +1 -1
- package/dist/locale.js +62 -12
- package/dist/locale.js.map +1 -1
- package/dist/log-service.js +1 -0
- package/dist/log-service.js.map +1 -1
- package/dist/mac-auto-restore.d.ts +117 -0
- package/dist/mac-auto-restore.js +294 -0
- package/dist/mac-auto-restore.js.map +1 -0
- package/dist/needs-you.js +1 -0
- package/dist/needs-you.js.map +1 -1
- package/dist/outbound-handlers.d.ts +2 -2
- package/dist/outbound-handlers.js +5 -5
- package/dist/outbound-handlers.js.map +1 -1
- package/dist/outbound-schemas.d.ts +2 -0
- package/dist/outbound-schemas.js +2 -0
- package/dist/outbound-schemas.js.map +1 -1
- package/dist/public-web-gateway.js +9 -1
- package/dist/public-web-gateway.js.map +1 -1
- package/dist/search/search-index.d.ts +10 -2
- package/dist/search/search-index.js +17 -4
- package/dist/search/search-index.js.map +1 -1
- package/dist/service-installer.d.ts +23 -1
- package/dist/service-installer.js +40 -11
- package/dist/service-installer.js.map +1 -1
- package/dist/session-oom-stop.d.ts +45 -0
- package/dist/session-oom-stop.js +259 -0
- package/dist/session-oom-stop.js.map +1 -0
- package/dist/session-oom.d.ts +13 -0
- package/dist/session-oom.js +119 -7
- package/dist/session-oom.js.map +1 -1
- package/dist/settings-api.d.ts +27 -1
- package/dist/settings-api.js +108 -2
- package/dist/settings-api.js.map +1 -1
- package/dist/settings-change.js +37 -3
- package/dist/settings-change.js.map +1 -1
- package/dist/settings-effect.js +5 -2
- package/dist/settings-effect.js.map +1 -1
- package/dist/spawn-gate.d.ts +2 -0
- package/dist/spawn-gate.js +17 -4
- package/dist/spawn-gate.js.map +1 -1
- package/dist/start-attempt.d.ts +15 -1
- package/dist/start-attempt.js +35 -5
- package/dist/start-attempt.js.map +1 -1
- package/dist/start-failure-chat.d.ts +41 -0
- package/dist/start-failure-chat.js +159 -0
- package/dist/start-failure-chat.js.map +1 -0
- package/dist/start-failure-notice.d.ts +4 -0
- package/dist/start-failure-notice.js +8 -0
- package/dist/start-failure-notice.js.map +1 -1
- package/dist/start-failure.d.ts +49 -0
- package/dist/start-failure.js +141 -1
- package/dist/start-failure.js.map +1 -1
- package/dist/telegram-api-root.d.ts +1 -0
- package/dist/telegram-api-root.js +40 -0
- package/dist/telegram-api-root.js.map +1 -0
- package/dist/turn-reply-guard.d.ts +25 -0
- package/dist/turn-reply-guard.js +111 -12
- package/dist/turn-reply-guard.js.map +1 -1
- package/dist/types.d.ts +21 -3
- package/dist/ui/backend-signin.js +5 -2
- package/dist/ui/chat-ambient.js +1 -1
- package/dist/ui/chat-effects.js +4 -4
- package/dist/ui/chat-render.js +5 -2
- package/dist/ui/chat-strings.js +2 -2
- package/dist/ui/chat-thread.js +2 -2
- package/dist/ui/first-run.js +2 -2
- package/dist/ui/fleet-canvas-view.js +114 -0
- package/dist/ui/fleet-canvas.js +15 -77
- package/dist/ui/fleet-office-editor.js +80 -5
- package/dist/ui/fleet-office-layout.js +197 -0
- package/dist/ui/fleet-office-model.js +6 -3
- package/dist/ui/fleet-office-pack.d.ts +39 -0
- package/dist/ui/fleet-office-pack.js +240 -29
- package/dist/ui/fleet-office-skin.js +130 -21
- package/dist/ui/fleet-office-store.js +75 -4
- package/dist/ui/fleet-office-view.js +154 -0
- package/dist/ui/fleet-office-zones.js +95 -33
- package/dist/ui/fleet-office.js +530 -94
- package/dist/ui/fleet-usage.js +7 -6
- package/dist/ui/panel-chat.js +20 -7
- package/dist/ui/panel-details.js +2 -2
- package/dist/ui/panel-fleet.js +11 -77
- package/dist/ui/panel-log.js +5 -5
- package/dist/ui/panel-settings.js +586 -164
- package/dist/ui/search-dialog.js +26 -7
- package/dist/ui/settings-appearance.js +82 -29
- package/dist/ui/settings-apply.js +42 -7
- package/dist/ui/settings-dialogs.js +68 -22
- package/dist/ui/settings-draft.js +51 -0
- package/dist/ui/settings-guests.js +244 -78
- package/dist/ui/settings-learn.js +2 -2
- package/dist/ui/settings-model.js +2 -0
- package/dist/ui/settings-registry.js +142 -0
- package/dist/ui/settings-strings.js +108 -44
- package/dist/ui/settings-web-authority.js +34 -23
- package/dist/ui/shared/app-i18n.js +14 -0
- package/dist/ui/shared/app-nav.js +10 -5
- package/dist/ui/shared/app-prefs.js +80 -2
- package/dist/ui/shared/app-route.js +39 -5
- package/dist/ui/shared/app-shell.js +80 -8
- package/dist/ui/shared/app-stream.js +2 -1
- package/dist/ui/shared/app.css +251 -20
- package/dist/ui/shared/app.js +3 -0
- package/dist/ui/shared/effect-stock-trust.js +1 -1
- package/dist/ui/shared/identity-color.js +4 -4
- package/dist/ui/shared/signin.js +2 -2
- package/dist/ui/shared/ui-dialog.js +6 -1
- package/dist/ui/shared/ui-icons.js +2 -0
- package/dist/ui/shared/usage-dialog.js +21 -11
- package/dist/ui/shared/view-strings.js +2 -0
- package/dist/ui/shared/web-authorize.js +13 -12
- package/dist/web-api.d.ts +9 -3
- package/dist/web-api.js +161 -6
- package/dist/web-api.js.map +1 -1
- package/dist/web-auth.js +7 -1
- package/dist/web-auth.js.map +1 -1
- package/dist/web-experimental.d.ts +1 -1
- package/dist/web-experimental.js +1 -1
- package/dist/web-experimental.js.map +1 -1
- package/dist/web-mod-agent.js +2 -2
- package/dist/web-mod-agent.js.map +1 -1
- package/dist/web-office-skins.d.ts +108 -0
- package/dist/web-office-skins.js +298 -0
- package/dist/web-office-skins.js.map +1 -0
- package/dist/web-office-store.d.ts +8 -2
- package/dist/web-office-store.js +37 -7
- package/dist/web-office-store.js.map +1 -1
- package/dist/web-settings-patch.d.ts +6 -0
- package/dist/web-settings-patch.js +61 -4
- package/dist/web-settings-patch.js.map +1 -1
- package/dist/web-shell-routes.d.ts +4 -2
- package/dist/web-shell-routes.js +17 -7
- package/dist/web-shell-routes.js.map +1 -1
- package/dist/working-recovery.d.ts +104 -0
- package/dist/working-recovery.js +263 -0
- package/dist/working-recovery.js.map +1 -0
- package/dist/working-state-journal.d.ts +70 -0
- package/dist/working-state-journal.js +106 -0
- package/dist/working-state-journal.js.map +1 -0
- package/package.json +1 -1
package/dist/ui/fleet-usage.js
CHANGED
|
@@ -23,8 +23,8 @@ register("fusage", {
|
|
|
23
23
|
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
24
|
shared: "shares its working directory with {0}; their transcripts can't be told apart",
|
|
25
25
|
empty: "Nothing recorded yet", emptyHint: "Usage is read from Claude Code and Codex transcripts, from when the fleet started.",
|
|
26
|
-
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 — on the dashboard reached directly, on the computer running AgEnD.",
|
|
27
|
-
openSettings: "Open Settings → Web on that computer",
|
|
26
|
+
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
|
+
openSettings: "Open Settings → Web dashboard on that computer",
|
|
28
28
|
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}.",
|
|
29
29
|
csvFrom: "Download CSV (from {0})",
|
|
30
30
|
noDaily: "No daily detail for this range: even its latest day has more rows than one answer carries, and a part of a day is never shown as the day. The rows and totals above are complete; the trend, the heatmap and the CSV need the daily detail and are not shown.",
|
|
@@ -50,8 +50,8 @@ register("fusage", {
|
|
|
50
50
|
notMeasured: "未量測", nm_credit_billed: "Kiro 以 credit 計費,不記錄 token", nm_unsupported: "AgEnD 目前還讀不到這個 CLI 的用量", nm_no_data: "尚未讀到任何資料",
|
|
51
51
|
shared: "與 {0} 共用工作目錄,無法分辨各自的 transcript",
|
|
52
52
|
empty: "還沒有任何紀錄", emptyHint: "用量從 Claude Code 與 Codex 的 transcript 讀取,自 fleet 啟動起計。",
|
|
53
|
-
blocked: "公開連結上不提供", blockedHint: "只有在設定 →
|
|
54
|
-
openSettings: "在那台電腦上開啟設定 →
|
|
53
|
+
blocked: "公開連結上不提供", blockedHint: "只有在設定 → 網頁儀表板裡開啟「透過公開連結提供用量報告」時,公開連結才會提供用量;這個設定要在執行 AgEnD 的那台電腦上、直接開啟的儀表板裡變更。",
|
|
54
|
+
openSettings: "在那台電腦上開啟設定 → 網頁儀表板",
|
|
55
55
|
partialDays: "每日明細從 {0} 起:這段期間更早的日子資料列太多,無法一次送出。上方的各列與總計涵蓋整段期間;趨勢、熱度圖與 CSV 則從 {0} 開始。",
|
|
56
56
|
csvFrom: "下載 CSV(從 {0} 起)",
|
|
57
57
|
noDaily: "這段期間沒有每日明細:連最近的一天,資料列都超過一次回答能帶的數量,而不完整的一天絕不會被當成那一天顯示。上方的各列與總計是完整的;趨勢、熱度圖與 CSV 需要每日明細,所以不顯示。",
|
|
@@ -417,8 +417,9 @@ export function UsageTab({ lease }) {
|
|
|
417
417
|
if (r.status === 403 || r.status === 404) {
|
|
418
418
|
const body = await r.json().catch(() => null);
|
|
419
419
|
if (!lease.current() || mine !== seq.current) return; // a newer read (or another page) owns the view
|
|
420
|
-
// Over the public link: where it is turned on — Settings → Web on the dashboard reached directly
|
|
421
|
-
|
|
420
|
+
// Over the public link: where it is turned on — Settings → Web dashboard on the dashboard reached directly (#2347;
|
|
421
|
+
// an older AgEnD names /settings/web, which still leads there).
|
|
422
|
+
setState({ blocked: r.status === 403 ? "blocked" : "off", settings: body && typeof body.settings === "string" && /^http:\/\/localhost:\d+\/settings\/(web|web-dashboard)$/.test(body.settings) ? body.settings : null });
|
|
422
423
|
return;
|
|
423
424
|
}
|
|
424
425
|
if (!r.ok) throw new Error(`HTTP ${r.status}`);
|
package/dist/ui/panel-chat.js
CHANGED
|
@@ -426,7 +426,7 @@ function threadEntry(name, doc) {
|
|
|
426
426
|
else if (reason === "busy") getAppEffects()?.stopTrial();
|
|
427
427
|
else if (reason === "transport") location.reload();
|
|
428
428
|
else if (reason === "localAdmin") location.href = "/signin?next=" + encodeURIComponent(location.pathname + location.search);
|
|
429
|
-
else navigate("/settings/
|
|
429
|
+
else navigate("/settings/look");
|
|
430
430
|
},
|
|
431
431
|
canTryEffect: x => getAppEffects()?.canTry(x) === true,
|
|
432
432
|
startEffectTrial: x => { const seq = navStore.get().seq; void getAppEffects()?.startTrial(x).then(ok => { if (!ok && e.sink && navStore.get().seq === seq && document.hasFocus?.() === true && document.visibilityState === "visible") toast(t("chat.effectTrialUnavailable")); }); },
|
|
@@ -648,7 +648,13 @@ function Composer({ name, label = name, lease, busy }) {
|
|
|
648
648
|
const [, tick] = useState(0);
|
|
649
649
|
const [sel, setSel] = useState(0);
|
|
650
650
|
const [closedFor, setClosedFor] = useState(null); // the draft the palette was closed on (Esc); it opens again on change
|
|
651
|
+
// An IME composing (Zhuyin, Pinyin, kana…): between compositionstart and compositionend the box is the IME's. Nothing
|
|
652
|
+
// here touches it — no draft update, no re-render, no auto-grow (each one moved the box, and iOS redrew the candidate
|
|
653
|
+
// bar on every keystroke: the user's flicker). What it holds is taken once, at compositionend.
|
|
654
|
+
const composing = useRef(false);
|
|
651
655
|
const value = s.drafts[name] || "";
|
|
656
|
+
// A render while composing (another part of the chat changed) gives the box what it holds, so it never writes it.
|
|
657
|
+
const boxValue = composing.current && input.current ? input.current.value : value;
|
|
652
658
|
const files = s.pendingFiles[name] || [];
|
|
653
659
|
const reply = s.replies[name]; // #2272: the message this one will reply to
|
|
654
660
|
const content = !!value.trim() || files.length > 0;
|
|
@@ -660,7 +666,7 @@ function Composer({ name, label = name, lease, busy }) {
|
|
|
660
666
|
// Grow with the text, up to a limit: set through the CSSOM, never a style attribute (#1300). Empty, it is one line
|
|
661
667
|
// (#2478 — a long name's placeholder made the box two lines tall).
|
|
662
668
|
useLayoutEffect(() => {
|
|
663
|
-
const el = input.current; if (!el) return;
|
|
669
|
+
const el = input.current; if (!el || composing.current) return;
|
|
664
670
|
el.style.height = "auto";
|
|
665
671
|
if (value) el.style.height = `${Math.min(el.scrollHeight, 240)}px`;
|
|
666
672
|
}, [value]);
|
|
@@ -700,7 +706,11 @@ function Composer({ name, label = name, lease, busy }) {
|
|
|
700
706
|
if (reply && e.key === "Escape" && !e.isComposing) { e.preventDefault(); store.clearReply(name); return; } // #2272
|
|
701
707
|
if (R().composerKey(e, { touch: touchScreen() }) === "send") { e.preventDefault(); submit(); }
|
|
702
708
|
};
|
|
703
|
-
const onInput = (e) => { setValue(e.target.value); };
|
|
709
|
+
const onInput = (e) => { if (composing.current || e.isComposing) return; setValue(e.target.value); };
|
|
710
|
+
const onCompositionStart = () => { composing.current = true; };
|
|
711
|
+
// The composed text is the draft now (some engines send no input after it); a blur ends one that never ended.
|
|
712
|
+
// Lower-case props below: an element has no oncomposition… property, so Preact would listen for "CompositionStart".
|
|
713
|
+
const onCompositionEnd = (e) => { if (!composing.current) return; composing.current = false; setValue(e.target.value); };
|
|
704
714
|
// Files in a paste are attached; a very long text paste goes as a text file — only once it is really attached.
|
|
705
715
|
const onPaste = (e) => {
|
|
706
716
|
const list = e.clipboardData && e.clipboardData.files;
|
|
@@ -727,11 +737,14 @@ function Composer({ name, label = name, lease, busy }) {
|
|
|
727
737
|
<input ref=${fileIn} type="file" multiple hidden
|
|
728
738
|
onChange=${(e) => { store.addFiles(name, e.target.files); e.target.value = ""; }} />
|
|
729
739
|
${/* #2478: the placeholder is drawn beside the box, one line ending in "…" — a textarea's own placeholder is clipped,
|
|
730
|
-
never ellipsized, and a long name wrapped it to two lines. The box keeps the words as its accessible name.
|
|
731
|
-
|
|
740
|
+
never ellipsized, and a long name wrapped it to two lines. The box keeps the words as its accessible name. Its own
|
|
741
|
+
placeholder is one space: :placeholder-shown hides the drawn one (app.css) the moment the box holds text, an
|
|
742
|
+
IME's composing text included, with no change to the page. */ ""}
|
|
743
|
+
<span class="composer-field"><textarea id="msgIn" ref=${input} rows="1" value=${boxValue} aria-label=${t("chat.composerPlaceholder", label)}
|
|
732
744
|
enterkeyhint=${touchScreen() ? "enter" : undefined} autocomplete="off" aria-controls=${palette ? "cmdPalette" : undefined} aria-expanded=${palette ? "true" : "false"}
|
|
733
|
-
aria-activedescendant=${pick ? optId(pick) : undefined} onInput=${onInput} onKeyDown=${onKeyDown} onPaste=${onPaste}
|
|
734
|
-
|
|
745
|
+
aria-activedescendant=${pick ? optId(pick) : undefined} onInput=${onInput} onKeyDown=${onKeyDown} onPaste=${onPaste}
|
|
746
|
+
oncompositionstart=${onCompositionStart} oncompositionend=${onCompositionEnd} onBlur=${onCompositionEnd}
|
|
747
|
+
placeholder=" "></textarea><span class="composer-ph" aria-hidden="true">${t("chat.composerPlaceholder", label)}</span></span>
|
|
735
748
|
<button id="stopBtn" type="button" class="btn btn-stop" hidden=${!busy} title=${t("chat.stopReplyTitle")}
|
|
736
749
|
disabled=${!!s.cancelling[name]} onClick=${() => store.cancelReply(name)}><${Icon} name="stop" size=${14} /><span class="stop-label">${t("chat.stopReply")}</span></button>
|
|
737
750
|
<button id="sendBtn" type="button" class="btn btn-primary btn-send" hidden=${busy && !content} disabled=${!content}
|
package/dist/ui/panel-details.js
CHANGED
|
@@ -12,7 +12,7 @@ import { appStore, useStore } from "/assets/app-store.js";
|
|
|
12
12
|
import { useLease } from "/assets/app-ctx.js";
|
|
13
13
|
import { PanelHeader, setTitle, statusClass, statusLabel, openDrawer } from "/assets/app-shell.js";
|
|
14
14
|
import { navigate } from "/assets/app-nav.js";
|
|
15
|
-
import {
|
|
15
|
+
import { sectionPath } from "/assets/app-route.js";
|
|
16
16
|
import { InstanceSwitch } from "/assets/instance-switch.js";
|
|
17
17
|
import { modelText } from "/assets/instance-nav.js";
|
|
18
18
|
import { HeaderTools } from "/assets/header-tools.js";
|
|
@@ -94,7 +94,7 @@ function DetailsView({ name, inst, navKey, exec, awaiting }) {
|
|
|
94
94
|
// A ClassicBot room (classicBot.yaml) keeps Classic's split: its own Settings dialog, and only the actions Settings'
|
|
95
95
|
// Classic rows have (pause / wake) — never the fleet agent's (#1561 review).
|
|
96
96
|
const classic = !!(d && d.kind === "classic");
|
|
97
|
-
const editInSettings = () => { requestAgentSettings(name, classic ? "classic" : "agent"); navigate(
|
|
97
|
+
const editInSettings = () => { requestAgentSettings(name, classic ? "classic" : "agent"); navigate(sectionPath(classic ? "classic" : undefined)); };
|
|
98
98
|
const st = inst.status;
|
|
99
99
|
// Until its read is in, the page does not know which kind it is: no actions yet (only Edit is offered once known).
|
|
100
100
|
const items = !d ? [] : classic ? [
|
package/dist/ui/panel-fleet.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
// #1408 step 1: the Fleet panel (/ui/fleet[/<tab>]) — tasks (the task board: fleet-tasks.js), schedules, teams
|
|
2
|
-
//
|
|
1
|
+
// #1408 step 1: the Fleet panel (/ui/fleet[/<tab>]) — tasks (the task board: fleet-tasks.js), schedules, teams, the org
|
|
2
|
+
// chart, cache and usage (#2347 §10: its config tab moved to Settings) — and the "New instance" dialog. Behind the
|
|
3
|
+
// session gate (/ui/js/), loaded the first time it is opened.
|
|
3
4
|
//
|
|
4
5
|
// Opening a tab reads its list: a person's navigation, so it counts as use, as the old tab click did (#1374 — no timer
|
|
5
6
|
// here re-reads anything). Every read is under the navigation's lease: a list that arrives after the person moved on
|
|
@@ -38,7 +39,7 @@ register("fleet", {
|
|
|
38
39
|
hostMemory_elevated: "Host memory pressure: elevated — new agents start one at a time, at least 5 s apart",
|
|
39
40
|
hostMemory_critical: "Host memory pressure: critical — new agents wait for memory to recover",
|
|
40
41
|
hostMemory_top: "Largest: {0}", hostMemory_ownerFleet: "the fleet", hostMemory_ownerTmux: "tmux", hostMemory_ownerOther: "not an instance",
|
|
41
|
-
title: "Fleet", tasks: "Tasks", schedules: "Schedules", teams: "Teams", org: "Org chart", cache: "Cache", usage: "Usage",
|
|
42
|
+
title: "Fleet", tasks: "Tasks", schedules: "Schedules", teams: "Teams", org: "Org chart", cache: "Cache", usage: "Usage",
|
|
42
43
|
docs: "Docs", docsNewTab: "Docs (opens in a new tab)",
|
|
43
44
|
newSchedule: "New schedule", newTeam: "New team",
|
|
44
45
|
noSchedules: "No schedules yet", noSchedulesHint: "Automate recurring work with cron.",
|
|
@@ -55,10 +56,8 @@ register("fleet", {
|
|
|
55
56
|
scheduleFieldsRequired: "Cron, message, and target required", teamFieldsRequired: "Name and at least one member required",
|
|
56
57
|
deleteSchedule: "Delete this schedule?", deleteTeam: "Delete team “{0}”?", scheduleCreated: "Schedule created", scheduleDeleted: "Schedule deleted",
|
|
57
58
|
teamCreated: "Team created", teamDeleted: "Team deleted", teamUpdated: "Team updated", edit: "Edit", editTeam: "Edit team",
|
|
58
|
-
teamNoRename: "Renaming isn't supported — create a new team and delete this one.",
|
|
59
|
-
|
|
60
|
-
allowedUsers: "Allowed users", allowedUsersNote: "Comma-separated user IDs", defaults: "Defaults", backend: "Backend", roots: "Project roots", addRoot: "Add root", removeRoot: "Remove",
|
|
61
|
-
saveNote: "Saving rewrites fleet.yaml (its comments are lost).",
|
|
59
|
+
teamNoRename: "Renaming isn't supported — create a new team and delete this one.",
|
|
60
|
+
backend: "Backend",
|
|
62
61
|
newInstance: "New instance", directory: "Directory", directoryHint: "Optional — a workspace is created if empty", topic: "Name", topicHint: "From the directory name",
|
|
63
62
|
topicRequired: "Name is required when Directory is empty", description: "Description", descriptionHint: "What this instance does", model: "Model", modelHint: "e.g. sonnet, opus, gpt-5",
|
|
64
63
|
branch: "Branch (git worktree)", branchHint: "e.g. feature-x", tags: "Tags", tagsHint: "comma-separated, e.g. dev, review", systemPrompt: "System prompt", systemPromptHint: "Custom instructions for this instance",
|
|
@@ -68,7 +67,7 @@ register("fleet", {
|
|
|
68
67
|
hostMemory_elevated: "主機記憶體壓力偏高:新的 agent 一次啟動一個,至少間隔 5 秒",
|
|
69
68
|
hostMemory_critical: "主機記憶體壓力嚴重:新的 agent 會等記憶體恢復再啟動",
|
|
70
69
|
hostMemory_top: "最大:{0}", hostMemory_ownerFleet: "fleet 本身", hostMemory_ownerTmux: "tmux", hostMemory_ownerOther: "不屬於任何 instance",
|
|
71
|
-
title: "Fleet", tasks: "Tasks", schedules: "排程", teams: "Teams", org: "組織圖", cache: "快取", usage: "用量",
|
|
70
|
+
title: "Fleet", tasks: "Tasks", schedules: "排程", teams: "Teams", org: "組織圖", cache: "快取", usage: "用量",
|
|
72
71
|
docs: "文件", docsNewTab: "文件(在新分頁開啟)",
|
|
73
72
|
newSchedule: "新增排程", newTeam: "新增 team",
|
|
74
73
|
noSchedules: "還沒有排程", noSchedulesHint: "用 cron 自動執行例行工作。",
|
|
@@ -84,10 +83,8 @@ register("fleet", {
|
|
|
84
83
|
scheduleFieldsRequired: "必須填寫 Cron、訊息與目標 instance", teamFieldsRequired: "必須填寫名稱並選擇至少一名成員",
|
|
85
84
|
deleteSchedule: "確定刪除此排程嗎?", deleteTeam: "確定刪除 team「{0}」嗎?", scheduleCreated: "排程已建立", scheduleDeleted: "排程已刪除",
|
|
86
85
|
teamCreated: "Team 已建立", teamDeleted: "Team 已刪除", teamUpdated: "Team 已更新", edit: "編輯", editTeam: "編輯 team",
|
|
87
|
-
teamNoRename: "不支援重新命名:請建立新的 team,再刪除這個。",
|
|
88
|
-
|
|
89
|
-
allowedUsers: "允許的使用者", allowedUsersNote: "以逗號分隔的使用者 ID", defaults: "預設值", backend: "Backend", roots: "專案根目錄", addRoot: "新增根目錄", removeRoot: "移除",
|
|
90
|
-
saveNote: "儲存會改寫 fleet.yaml(其中的註解會遺失)。",
|
|
86
|
+
teamNoRename: "不支援重新命名:請建立新的 team,再刪除這個。",
|
|
87
|
+
backend: "Backend",
|
|
91
88
|
newInstance: "新增 instance", directory: "目錄", directoryHint: "可留空——留空會自動建立工作區", topic: "名稱", topicHint: "預設取自目錄名稱",
|
|
92
89
|
topicRequired: "目錄留空時必須填寫名稱", description: "說明", descriptionHint: "這個 instance 做什麼", model: "模型", modelHint: "例如 sonnet、opus、gpt-5",
|
|
93
90
|
branch: "分支(git worktree)", branchHint: "例如 feature-x", tags: "標籤", tagsHint: "以逗號分隔,例如 dev, review", systemPrompt: "System prompt", systemPromptHint: "這個 instance 的自訂指示",
|
|
@@ -100,7 +97,7 @@ const DOCS_SITE = "https://songsid.github.io/AgEnD";
|
|
|
100
97
|
export function docsUrl(language = lang()) {
|
|
101
98
|
return `${DOCS_SITE}${language === "zh-TW" ? "/zh-tw" : ""}/docs/web-guide/`;
|
|
102
99
|
}
|
|
103
|
-
const ICONS = { tasks: "tasks", schedules: "clock", teams: "team", org: "org", cache: "chart", usage: "chart"
|
|
100
|
+
const ICONS = { tasks: "tasks", schedules: "clock", teams: "team", org: "org", cache: "chart", usage: "chart" };
|
|
104
101
|
const BACKENDS = ["claude-code", "codex", "opencode", "kiro-cli", "antigravity", "grok", "muse"];
|
|
105
102
|
|
|
106
103
|
async function api(method, path, body, lease) {
|
|
@@ -140,7 +137,7 @@ export function FleetPanel({ route, navKey }) {
|
|
|
140
137
|
const tab = route.tab;
|
|
141
138
|
useEffect(() => { setTitle(`${t("fleet.title")} · ${t(`fleet.${tab}`)}`); }, [tab, navKey]);
|
|
142
139
|
useEffect(() => { rememberFleetTab(tab); }, [tab]); // #2183: the sidebar's and the phone's Fleet reopen it
|
|
143
|
-
const Body = { tasks: TaskBoardTab, schedules: Schedules, teams: Teams, org: Org, cache: Cache, usage: UsageTab
|
|
140
|
+
const Body = { tasks: TaskBoardTab, schedules: Schedules, teams: Teams, org: Org, cache: Cache, usage: UsageTab }[tab] || TaskBoardTab;
|
|
144
141
|
// #1685: host memory pressure slowing or holding new agents — shown here, where macOS's routine "elevated" is not a chat notice.
|
|
145
142
|
const { hostMemory, hostMemoryTop } = useStore(appStore);
|
|
146
143
|
// #2015: and which processes hold the most, and whose — text only (never chat, #1712).
|
|
@@ -262,69 +259,6 @@ function Cache({ lease }) {
|
|
|
262
259
|
: html`<${ErrorState} onRetry=${renavigate} />`)}</${Loaded}>`;
|
|
263
260
|
}
|
|
264
261
|
|
|
265
|
-
function Secret({ id, value, onInput, label }) {
|
|
266
|
-
const [shown, setShown] = useState(false);
|
|
267
|
-
return html`<div class="field-row"><input id=${id} type=${shown ? "text" : "password"} value=${value} onInput=${onInput} autocomplete="off" />
|
|
268
|
-
<button type="button" class="icon-btn" aria-label=${shown ? t("fleet.hide") : t("fleet.show")} aria-pressed=${shown ? "true" : "false"} title=${`${shown ? t("fleet.hide") : t("fleet.show")} ${label}`}
|
|
269
|
-
onClick=${() => setShown(!shown)}><${Icon} name="eye" size=${16} /></button></div>`;
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
function Config({ lease }) {
|
|
273
|
-
const state = useLoad(lease, "/ui/config", 0);
|
|
274
|
-
const [form, setForm] = useState(null);
|
|
275
|
-
const [saving, setSaving] = useState(false);
|
|
276
|
-
// Each save owns the form's busy state only while it is the latest: an older save that is decided later (it waited
|
|
277
|
-
// for an admin's confirmation) never unlocks the form under a newer one still on its way (#1453 review).
|
|
278
|
-
const saves = useRef(0);
|
|
279
|
-
// #2342: each project root's row keeps its own key — keyed by position, removing one shifted the texts below into
|
|
280
|
-
// the boxes above (each box's text rewritten, its undo history lost).
|
|
281
|
-
const rootKeys = useRef({ n: 0, list: [] });
|
|
282
|
-
const rootKey = (i) => { const k = rootKeys.current; while (k.list.length <= i) k.list.push(++k.n); return k.list[i]; };
|
|
283
|
-
useEffect(() => {
|
|
284
|
-
if (!state || !state.data) return;
|
|
285
|
-
const c = state.data, ch = c.channel || {}, acc = ch.access || {};
|
|
286
|
-
setForm({ type: ch.type || "", tokenEnv: ch.bot_token_env || "AGEND_BOT_TOKEN", groupId: ch.group_id || "", mode: acc.mode || "locked",
|
|
287
|
-
users: (acc.allowed_users || []).join(", "), backend: (c.defaults || {}).backend || "claude-code", roots: [...(c.project_roots || [])] });
|
|
288
|
-
}, [state]);
|
|
289
|
-
async function save() {
|
|
290
|
-
const mine = ++saves.current;
|
|
291
|
-
const done = () => { if (lease.current() && mine === saves.current) setSaving(false); };
|
|
292
|
-
setSaving(true);
|
|
293
|
-
const body = {
|
|
294
|
-
channel: { group_id: form.groupId.trim(), access: { mode: form.mode, allowed_users: form.users.split(",").map(s => s.trim()).filter(Boolean) } },
|
|
295
|
-
defaults: { backend: form.backend },
|
|
296
|
-
project_roots: form.roots.map(r => r.trim()).filter(Boolean),
|
|
297
|
-
};
|
|
298
|
-
let r;
|
|
299
|
-
// A change to access or the connection may need a fleet admin's confirmation (#1423): the shell follows it.
|
|
300
|
-
try {
|
|
301
|
-
const res = await confirmedWrite("/ui/config", { method: "POST", body, label: t("fleet.config"),
|
|
302
|
-
onPending: (_id, view) => { toast(t(selfConfirmed(view) ? "app.pendingSelfSent" : "app.pendingSent")); done(); } });
|
|
303
|
-
r = res.ok ? res.body || {} : { error: (res.body && res.body.error) || `HTTP ${res.status}` };
|
|
304
|
-
} catch (err) { r = { error: err.message }; }
|
|
305
|
-
done();
|
|
306
|
-
if (r.error) toast(r.error, false); else toast(t("fleet.configSaved") + (r.needs_restart ? t("fleet.configRestart") : ""));
|
|
307
|
-
}
|
|
308
|
-
const set = (k) => (e) => setForm({ ...form, [k]: e.target.value });
|
|
309
|
-
return html`<${Loaded} state=${state}>${() => !form ? html`<${Skeleton} lines=${4} />` : html`
|
|
310
|
-
<section class="card"><h3>${t("fleet.channel")}</h3>
|
|
311
|
-
<label class="field"><span>${t("fleet.type")}</span><input value=${form.type} disabled /></label>
|
|
312
|
-
<label class="field"><span>${t("fleet.tokenEnv")}</span><input value=${form.tokenEnv} disabled /></label>
|
|
313
|
-
<div class="field"><label for="cfg-gid">${t("fleet.groupId")}</label><${Secret} id="cfg-gid" value=${form.groupId} onInput=${set("groupId")} label=${t("fleet.groupId")} /></div></section>
|
|
314
|
-
<section class="card"><h3>${t("fleet.access")}</h3>
|
|
315
|
-
<label class="field"><span>${t("fleet.mode")}</span><select value=${form.mode} onChange=${set("mode")}><option value="locked">${t("fleet.locked")}</option><option value="open">${t("fleet.open")}</option></select></label>
|
|
316
|
-
<div class="field"><label for="cfg-users">${t("fleet.allowedUsers")}</label><${Secret} id="cfg-users" value=${form.users} onInput=${set("users")} label=${t("fleet.allowedUsers")} />
|
|
317
|
-
<p class="note">${t("fleet.allowedUsersNote")}</p></div></section>
|
|
318
|
-
<section class="card"><h3>${t("fleet.defaults")}</h3>
|
|
319
|
-
<div class="field"><label for="cfg-be">${t("fleet.backend")}</label><${BackendSelect} id="cfg-be" value=${form.backend} onChange=${(v) => setForm({ ...form, backend: v })} /></div></section>
|
|
320
|
-
<section class="card"><h3>${t("fleet.roots")}</h3>
|
|
321
|
-
${form.roots.map((r, i) => html`<div key=${rootKey(i)} class="field-row"><input value=${r} placeholder="/path/to/projects" aria-label=${t("fleet.roots")}
|
|
322
|
-
onInput=${(e) => { const roots = [...form.roots]; roots[i] = e.target.value; setForm({ ...form, roots }); }} />
|
|
323
|
-
<button type="button" class="icon-btn" aria-label=${t("fleet.removeRoot")} title=${t("fleet.removeRoot")} onClick=${() => { rootKeys.current.list.splice(i, 1); setForm({ ...form, roots: form.roots.filter((_, j) => j !== i) }); }}><${Icon} name="close" size=${16} /></button></div>`)}
|
|
324
|
-
<button type="button" class="btn btn-ghost" onClick=${() => setForm({ ...form, roots: [...form.roots, ""] })}><${Icon} name="plus" size=${16} />${t("fleet.addRoot")}</button></section>
|
|
325
|
-
<div class="save-row"><button type="button" class="btn btn-primary" disabled=${saving} onClick=${save}>${t("fleet.save")}</button><span class="note">${t("fleet.saveNote")}</span></div>`}</${Loaded}>`;
|
|
326
|
-
}
|
|
327
|
-
|
|
328
262
|
// ── Create dialogs ──
|
|
329
263
|
|
|
330
264
|
/**
|
package/dist/ui/panel-log.js
CHANGED
|
@@ -30,7 +30,7 @@ register("log", {
|
|
|
30
30
|
offTitle: "The Log is off",
|
|
31
31
|
offBody: "Turn it on to see each agent's work step by step: what it was asked, its replies, every tool call with its arguments and result, errors, and fleet events. It reads the agent's own transcript only while this tab is open, and masks secret values.",
|
|
32
32
|
enable: "Turn on the Log", enabling: "Waiting for a fleet admin to confirm it in chat (General topic) or on the host…", enabled: "The Log is on.",
|
|
33
|
-
enableFailed: "The Log was not turned on: {0}", offPublic: "A fleet admin can turn it on in Settings → Web.",
|
|
33
|
+
enableFailed: "The Log was not turned on: {0}", offPublic: "A fleet admin can turn it on in Settings → Web dashboard.",
|
|
34
34
|
unsupported: "{0} has no transcript AgEnD can read, so this Log shows fleet events only. View shows its screen.",
|
|
35
35
|
kiroWhy: "kiro's own steps are shown only when AgEnD can prove which conversation it is in now. {0} Fleet events are shown meanwhile.",
|
|
36
36
|
kiro_not_running: "It is not running.",
|
|
@@ -62,13 +62,13 @@ 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",
|
|
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",
|
|
66
66
|
},
|
|
67
67
|
"zh-TW": {
|
|
68
68
|
offTitle: "紀錄未開啟",
|
|
69
69
|
offBody: "開啟後可逐步看到每個 agent 的工作:收到的要求、回覆、每次工具呼叫的參數與結果、錯誤,以及 fleet 事件。只在這個分頁開著時讀取 agent 自己的對話紀錄,機密值會遮蔽。",
|
|
70
70
|
enable: "開啟紀錄", enabling: "等待 fleet admin 在聊天(General topic)或主機上確認…", enabled: "紀錄已開啟。",
|
|
71
|
-
enableFailed: "紀錄沒有開啟:{0}", offPublic: "fleet admin 可以在「設定 →
|
|
71
|
+
enableFailed: "紀錄沒有開啟:{0}", offPublic: "fleet admin 可以在「設定 → 網頁儀表板」開啟。",
|
|
72
72
|
unsupported: "{0} 沒有 AgEnD 讀得到的對話紀錄,所以這裡只顯示 fleet 事件。「檢視」可以看它的畫面。",
|
|
73
73
|
kiroWhy: "只有在 AgEnD 能證明 kiro 目前所在的對話時,才會顯示它自己的步驟。{0}目前先顯示 fleet 事件。",
|
|
74
74
|
kiro_not_running: "它沒有在執行。",
|
|
@@ -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: "健康檢查錯誤",
|
|
103
|
+
ev_supervision_ended: "監督結束", ev_tmux_server_crash: "tmux 當掉", ev_malformed_tool_call: "格式錯誤的工具呼叫", ev_health_check_error: "健康檢查錯誤", ev_working_state: "工作狀態紀錄",
|
|
104
104
|
},
|
|
105
105
|
});
|
|
106
106
|
const tl = (key, ...a) => t(`log.${key}`, ...a);
|
|
@@ -179,7 +179,7 @@ export function timeline(steps, events) {
|
|
|
179
179
|
return out;
|
|
180
180
|
}
|
|
181
181
|
|
|
182
|
-
const isError = (x) => x.kind === "error" || x.kind === "event" || x.status === "failed" || x.status === "interrupted";
|
|
182
|
+
const isError = (x) => x.kind === "error" || (x.kind === "event" && x.type !== "working_state") || x.status === "failed" || x.status === "interrupted";
|
|
183
183
|
/** Consecutive identical finished tool steps (same tool, subject and status) as one row with a count: a loop shows. */
|
|
184
184
|
export function collapse(items) {
|
|
185
185
|
const out = [];
|