@songsid/agend 2.3.5-alpha.3 → 2.3.5-alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent-runtime-api.d.ts +4 -0
- package/dist/agent-runtime-api.js +59 -0
- package/dist/agent-runtime-api.js.map +1 -0
- package/dist/agent-runtime-change.d.ts +74 -0
- package/dist/agent-runtime-change.js +102 -0
- package/dist/agent-runtime-change.js.map +1 -0
- package/dist/auth-api.js +4 -0
- package/dist/auth-api.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.js +8 -10
- package/dist/backend/codex.js.map +1 -1
- package/dist/fleet-manager.d.ts +3 -0
- package/dist/fleet-manager.js +157 -1
- package/dist/fleet-manager.js.map +1 -1
- package/dist/fleet-windows-runtime.d.ts +6 -1
- package/dist/fleet-windows-runtime.js +70 -1
- package/dist/fleet-windows-runtime.js.map +1 -1
- package/dist/office-share-page.js +1 -1
- package/dist/office-share-page.js.map +1 -1
- package/dist/public-web-link.d.ts +6 -0
- package/dist/public-web-link.js +9 -0
- package/dist/public-web-link.js.map +1 -1
- package/dist/runtime-api.js +84 -9
- package/dist/runtime-api.js.map +1 -1
- package/dist/runtime-build-info.d.ts +9 -0
- package/dist/runtime-build-info.js +57 -0
- package/dist/runtime-build-info.js.map +1 -0
- package/dist/runtime-bundle.d.ts +3 -1
- package/dist/runtime-bundle.js +14 -8
- package/dist/runtime-bundle.js.map +1 -1
- package/dist/runtime-cli.d.ts +6 -1
- package/dist/runtime-cli.js +46 -11
- package/dist/runtime-cli.js.map +1 -1
- package/dist/runtime-client-store.d.ts +20 -1
- package/dist/runtime-client-store.js +56 -4
- package/dist/runtime-client-store.js.map +1 -1
- package/dist/runtime-client.d.ts +12 -0
- package/dist/runtime-client.js +43 -7
- package/dist/runtime-client.js.map +1 -1
- package/dist/runtime-connection.d.ts +22 -0
- package/dist/runtime-connection.js +93 -0
- package/dist/runtime-connection.js.map +1 -0
- package/dist/runtime-coordinator.d.ts +9 -0
- package/dist/runtime-coordinator.js +81 -34
- package/dist/runtime-coordinator.js.map +1 -1
- package/dist/runtime-pane-boot.d.ts +7 -0
- package/dist/runtime-pane-boot.js +23 -0
- package/dist/runtime-pane-boot.js.map +1 -1
- package/dist/runtime-protocol.d.ts +13 -0
- package/dist/runtime-protocol.js +18 -0
- package/dist/runtime-protocol.js.map +1 -1
- package/dist/settings-effect.js +1 -1
- package/dist/settings-effect.js.map +1 -1
- package/dist/settings-http-confirmation.d.ts +3 -0
- package/dist/settings-http-confirmation.js +16 -1
- package/dist/settings-http-confirmation.js.map +1 -1
- package/dist/ui/agent-runtime-settings.js +67 -0
- package/dist/ui/agent-runtime.js +20 -2
- package/dist/ui/backend-signin.js +36 -21
- package/dist/ui/native-instance-settings.js +5 -8
- package/dist/ui/panel-chat.js +3 -2
- package/dist/ui/panel-fleet.js +4 -2
- package/dist/ui/panel-runtimes.js +136 -33
- package/dist/ui/panel-settings.js +224 -139
- package/dist/ui/panel-windows-cli.js +77 -41
- package/dist/ui/settings-agent-filters.js +94 -0
- package/dist/ui/settings-appearance.js +122 -23
- package/dist/ui/settings-dialogs.js +5 -5
- package/dist/ui/settings-guests.js +25 -11
- package/dist/ui/settings-layout.js +245 -0
- package/dist/ui/settings-model.js +8 -0
- package/dist/ui/settings-registry.js +5 -3
- package/dist/ui/settings-shortcuts.js +65 -0
- package/dist/ui/settings-strings.js +93 -0
- package/dist/ui/settings-web-authority.js +14 -11
- package/dist/ui/shared/app-shell.js +17 -7
- package/dist/ui/shared/app.css +1022 -12
- package/dist/ui/shared/instance-nav.js +3 -2
- package/dist/ui/shared/machine-name.js +13 -0
- package/dist/ui/shared/settings-width.js +31 -0
- package/dist/ui/shared/tokens.css +1 -0
- package/dist/ui/shared/ui-dialog.js +2 -2
- package/dist/ui/shared/ui-menu.js +3 -3
- package/dist/ui/windows-cli-catalog.js +41 -12
- package/dist/web-api.d.ts +1 -0
- package/dist/web-api.js +3 -0
- package/dist/web-api.js.map +1 -1
- package/dist/windows-agents.d.ts +3 -1
- package/dist/windows-agents.js +13 -10
- package/dist/windows-agents.js.map +1 -1
- package/dist/windows-cli-api.js +2 -1
- package/dist/windows-cli-api.js.map +1 -1
- package/dist/windows-cli-worker.d.ts +1 -0
- package/dist/windows-cli-worker.js +2 -2
- package/dist/windows-cli-worker.js.map +1 -1
- package/dist/windows-cli.d.ts +1 -0
- package/dist/windows-cli.js +7 -2
- package/dist/windows-cli.js.map +1 -1
- package/package.json +1 -1
|
@@ -18,6 +18,7 @@ import { viewStore } from "./view-roster-store.js";
|
|
|
18
18
|
import { onPrefsChanged, prefInForce, prefsWritable, savePref } from "./app-prefs.js";
|
|
19
19
|
import "./view-strings.js";
|
|
20
20
|
import { themesShown, themesStore } from "./app-themes.js";
|
|
21
|
+
import { machineName } from "./machine-name.js";
|
|
21
22
|
import { identityClasses, identityOf, paintIdentity, useIdentityColors } from "./identity-color.js";
|
|
22
23
|
|
|
23
24
|
/** view.* text with named values. */
|
|
@@ -145,7 +146,7 @@ export function instanceTooltip(it) {
|
|
|
145
146
|
else lines.push(name);
|
|
146
147
|
lines.push(line("tooltipBackend", backendLabel(it.backend)));
|
|
147
148
|
if (it.runtime) lines.push(`Runtime: ${runtimeLabel(it.runtime)}`);
|
|
148
|
-
if (it.machine_id) lines.push(line("tooltipMachine",it.
|
|
149
|
+
if (it.machine_id) lines.push(line("tooltipMachine",machineName(it.machine_id,it.machine_name)));
|
|
149
150
|
if (it.machine_id && it.machine_status !== "online") lines.push(tn(it.machine_status === "revoked" ? "machineRevoked" : "machineOffline"));
|
|
150
151
|
const src = (s) => (s === "instance" || s === "classic" ? tn("srcConfigured") : s === "fleet-default" ? tn("srcFleetDefault") : "");
|
|
151
152
|
lines.push(line("tooltipModel", (modelText(it) || tn("tooltipUnavailable")) + src(it.model_source)));
|
|
@@ -630,7 +631,7 @@ export function InstanceNav({ route, items, loaded = true, exec = {}, awaiting =
|
|
|
630
631
|
<span class="v-meta">${it.runtime === "windows" ? "Windows" : it.context_pct != null ? `${Math.round(it.context_pct)}%` : ""}</span></span>
|
|
631
632
|
${two ? html`<span class="inst-line inst-line2"><span class="inst-alt" title=${secondary || undefined}>${secondary || ""}</span>
|
|
632
633
|
${mins != null ? html`<span class=${`inst-when${fade > 0 ? " fresh" : ""}`} title=${tn("replyTitle", { time: new Date(Date.parse(it.last_reply)).toLocaleString() })}>${replyText(mins)}</span>` : null}</span>` : null}
|
|
633
|
-
${it.machine_id ? html`<span class=${`inst-machine${it.machine_status !== "online" ? " offline" : ""}`} title=${tn("tooltipMachine",{value:it.
|
|
634
|
+
${it.machine_id ? html`<span class=${`inst-machine${it.machine_status !== "online" ? " offline" : ""}`} title=${tn("tooltipMachine",{value:machineName(it.machine_id,it.machine_name)})}><span class="inst-machine-name">${machineName(it.machine_id,it.machine_name)}</span>${it.machine_status !== "online" ? html`<span class="inst-machine-status">${tn(it.machine_status === "revoked" ? "machineRevoked" : "machineOffline")}</span>` : null}</span>` : null}
|
|
634
635
|
${facet === "needs" ? html`<span class="inst-sub"><span class="badge-await" title=${waiting || t("app.approxNote")}>${t("app.needsYou")}</span></span>` : null}
|
|
635
636
|
<span class="sr-only">${tn("tooltipBackend", { value: backendLabel(it.backend) })}</span></span>
|
|
636
637
|
</a>${fav && editing && canStar ? html`<button type="button" class="icon-btn inst-move" aria-label=${tn("favUp", { name: label })}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// A paired computer's display name. A module of its own, imported by the sidebar (instance-nav.js) and by the lazy
|
|
2
|
+
// chat panel. A tab opened before an upgrade keeps the old shell, whose instance-nav.js has no `machineName`; the new
|
|
3
|
+
// chat panel imports it from here instead, a module that tab loads fresh, so Chat still opens (as #2978 did for
|
|
4
|
+
// settings-width.js). It registers its own words so it does not depend on the shell's older string tables.
|
|
5
|
+
import { register, t } from "./app-i18n.js";
|
|
6
|
+
|
|
7
|
+
register("machine", {
|
|
8
|
+
"en": { "short": "Computer {value}" },
|
|
9
|
+
"zh-TW": { "short": "電腦 {value}" },
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
/** A remote computer by its name; with no name yet, by the start of its id, never the whole id. The 8-character cut matches `shortId` in src/ui/settings-agent-filters.js; keep the two in step. */
|
|
13
|
+
export const machineName = (id, name) => name || t("machine.short").split("{value}").join(String(id).slice(0, 8));
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// #2936 (Settings content width, from app-shell.js) — #2978 merge: a module of its own, imported by the shell (which
|
|
2
|
+
// restores the choice at load) and by Settings' Look section. A tab opened before an upgrade has the old shell, without
|
|
3
|
+
// these names; the new Settings panel imports them from here instead, a module that tab loads fresh, so Settings still
|
|
4
|
+
// opens (the width then applies from the first change on, and at the next load).
|
|
5
|
+
import { createStore } from "./app-store.js";
|
|
6
|
+
|
|
7
|
+
/** Settings' reading space is this device's layout choice, never a host-kept or staged preference. */
|
|
8
|
+
export const SETTINGS_CONTENT_WIDTH_KEY = "agend_settings_content_width";
|
|
9
|
+
export const SETTINGS_CONTENT_WIDTHS = Object.freeze([1000, 1200, 1440]);
|
|
10
|
+
export const DEFAULT_SETTINGS_CONTENT_WIDTH = 1200;
|
|
11
|
+
export const settingsContentWidthStore = createStore({ width: DEFAULT_SETTINGS_CONTENT_WIDTH });
|
|
12
|
+
function storedSettingsContentWidth() {
|
|
13
|
+
try {
|
|
14
|
+
const value = globalThis.localStorage.getItem(SETTINGS_CONTENT_WIDTH_KEY);
|
|
15
|
+
return SETTINGS_CONTENT_WIDTHS.find((width) => String(width) === value) ?? DEFAULT_SETTINGS_CONTENT_WIDTH;
|
|
16
|
+
} catch { return DEFAULT_SETTINGS_CONTENT_WIDTH; }
|
|
17
|
+
}
|
|
18
|
+
function showSettingsContentWidth(width) {
|
|
19
|
+
// The property is consumed only by Settings' content maximum; CSS still fits a narrower window or form.
|
|
20
|
+
if (typeof document !== "undefined") document.documentElement.style.setProperty("--settings-width", `${width}px`);
|
|
21
|
+
settingsContentWidthStore.set({ width });
|
|
22
|
+
}
|
|
23
|
+
/** A page load restores this device's choice. Unreadable or invalid storage keeps the normal 1200 px maximum. */
|
|
24
|
+
export function initSettingsContentWidth() { showSettingsContentWidth(storedSettingsContentWidth()); }
|
|
25
|
+
/** Apply immediately even when storage is unavailable; then the choice lasts for this page only. */
|
|
26
|
+
export function setSettingsContentWidth(width) {
|
|
27
|
+
if (!SETTINGS_CONTENT_WIDTHS.includes(width)) return;
|
|
28
|
+
try { globalThis.localStorage.setItem(SETTINGS_CONTENT_WIDTH_KEY, String(width)); } catch { /* this page only */ }
|
|
29
|
+
showSettingsContentWidth(width);
|
|
30
|
+
}
|
|
31
|
+
|
|
@@ -46,6 +46,7 @@
|
|
|
46
46
|
|
|
47
47
|
/* ── Layout ── */
|
|
48
48
|
--col: 768px; /* the conversation column */
|
|
49
|
+
--settings-width: 1200px; /* settings workspace, including its horizontal padding */
|
|
49
50
|
--sidebar-w: 260px;
|
|
50
51
|
--header-h: 52px;
|
|
51
52
|
--tap: 44px; /* the smallest touch target on a phone */
|
|
@@ -10,7 +10,7 @@ import { t } from "./app-i18n.js";
|
|
|
10
10
|
* <${Dialog} title="Create task" onClose=${…} actions=${html`…`}>…body…</${Dialog}>
|
|
11
11
|
* Rendered = open; the parent unmounts it to close. `busy` keeps Esc and the backdrop from closing it mid-request.
|
|
12
12
|
*/
|
|
13
|
-
export function Dialog({ title, onClose, actions, children, busy = false, wide = false, drawer = false, label, tools = null }) {
|
|
13
|
+
export function Dialog({ title, onClose, actions, children, busy = false, wide = false, drawer = false, label, tools = null, cls = "" }) {
|
|
14
14
|
const ref = useRef(null);
|
|
15
15
|
const opener = useRef(null);
|
|
16
16
|
const busyRef = useRef(busy);
|
|
@@ -41,7 +41,7 @@ export function Dialog({ title, onClose, actions, children, busy = false, wide =
|
|
|
41
41
|
d.addEventListener("click", onClick);
|
|
42
42
|
return () => { d.removeEventListener("cancel", onCancel); d.removeEventListener("click", onClick); };
|
|
43
43
|
}, [onClose]);
|
|
44
|
-
return html`<dialog data-trust="dialog" ref=${ref} class=${`dlg${wide ? " dlg-wide" : ""}${drawer ? " dlg-drawer" : ""}`} aria-label=${label || title}>
|
|
44
|
+
return html`<dialog data-trust="dialog" ref=${ref} class=${`dlg${wide ? " dlg-wide" : ""}${drawer ? " dlg-drawer" : ""}${cls ? ` ${cls}` : ""}`} aria-label=${label || title}>
|
|
45
45
|
<div class="dlg-box" tabindex="-1">
|
|
46
46
|
<div class="dlg-head"><h2 class="dlg-title">${title}</h2>${tools ? html`<span class="dlg-tools">${tools}</span>` : null}
|
|
47
47
|
<button type="button" class="icon-btn dlg-x" aria-label=${t("app.close")} title=${t("app.close")} onClick=${() => { if (!busyRef.current) onClose(); }}><${Icon} name="close" /></button></div>
|
|
@@ -34,7 +34,7 @@ export function Menu({ items, label, icon = "more", cls = "", active = false, tr
|
|
|
34
34
|
useEffect(() => {
|
|
35
35
|
if (!open || disabled) { if (open && disabled) setOpen(false); return undefined; }
|
|
36
36
|
const first = list.current && list.current.querySelector("[role=menuitem]:not([disabled]), [role=menuitemradio]:not([disabled]), [role=menuitemcheckbox]:not([disabled])");
|
|
37
|
-
if (first) first.focus();
|
|
37
|
+
if (first) first.focus({ preventScroll: true });
|
|
38
38
|
const outside = (e) => { if (list.current && !list.current.contains(e.target) && btn.current && !btn.current.contains(e.target)) setOpen(false); };
|
|
39
39
|
document.addEventListener("pointerdown", outside, true);
|
|
40
40
|
return () => document.removeEventListener("pointerdown", outside, true);
|
|
@@ -42,7 +42,7 @@ export function Menu({ items, label, icon = "more", cls = "", active = false, tr
|
|
|
42
42
|
function onKey(e) {
|
|
43
43
|
const all = [...list.current.querySelectorAll("[role=menuitem]:not([disabled]), [role=menuitemradio]:not([disabled]), [role=menuitemcheckbox]:not([disabled])")];
|
|
44
44
|
const i = all.indexOf(document.activeElement);
|
|
45
|
-
if (e.key === "Escape") { e.preventDefault(); e.stopPropagation(); setOpen(false); btn.current && btn.current.focus(); }
|
|
45
|
+
if (e.key === "Escape") { e.preventDefault(); e.stopPropagation(); setOpen(false); btn.current && btn.current.focus({ preventScroll: true }); }
|
|
46
46
|
else if (e.key === "Enter" || e.key === " ") { e.preventDefault(); document.activeElement?.click(); }
|
|
47
47
|
else if (e.key === "ArrowDown") { e.preventDefault(); (all[(i + 1) % all.length] || all[0])?.focus(); }
|
|
48
48
|
else if (e.key === "ArrowUp") { e.preventDefault(); (all[(i - 1 + all.length) % all.length] || all[0])?.focus(); }
|
|
@@ -50,7 +50,7 @@ export function Menu({ items, label, icon = "more", cls = "", active = false, tr
|
|
|
50
50
|
else if (e.key === "End") { e.preventDefault(); all[all.length - 1]?.focus(); }
|
|
51
51
|
else if (e.key === "Tab") setOpen(false);
|
|
52
52
|
}
|
|
53
|
-
function choose(item) { if (disabled || item.disabled) return; setOpen(false); btn.current && btn.current.focus(); item.onSelect(); }
|
|
53
|
+
function choose(item) { if (disabled || item.disabled) return; setOpen(false); btn.current && btn.current.focus({ preventScroll: true }); item.onSelect(); }
|
|
54
54
|
return html`<div class=${`menu ${cls}`}>
|
|
55
55
|
<button ref=${btn} type="button" class=${`${triggerClass}${active ? " active" : ""}`} aria-haspopup="menu" aria-expanded=${open ? "true" : "false"} disabled=${disabled}
|
|
56
56
|
aria-label=${label || t("app.more")} title=${label || t("app.more")} onClick=${() => { if (!disabled) setOpen(!open); }}
|
|
@@ -11,7 +11,7 @@ const initial = () => ({ data:null, loading:false, error:"", checkedAt:0, starte
|
|
|
11
11
|
|
|
12
12
|
/** Successful inventory only, in memory. No polling, localStorage, credential data or model tasks. A plain load reads the
|
|
13
13
|
* server's last detection (which starts nothing, M-2239 P1-2); only `force` (Detect again) runs detection. */
|
|
14
|
-
export function createWindowsCliCatalog({ fetcher = (...args) => fetch(...args), now = () => Date.now(), ttlMs = WINDOWS_CLI_CATALOG_TTL_MS, timeoutMs =
|
|
14
|
+
export function createWindowsCliCatalog({ fetcher = (...args) => fetch(...args), now = () => Date.now(), ttlMs = WINDOWS_CLI_CATALOG_TTL_MS, timeoutMs = 100_000, machineId = "" } = {}) {
|
|
15
15
|
const store = createStore(initial());
|
|
16
16
|
let pending = null, controller = null, generation = 0;
|
|
17
17
|
const load = ({ force = false } = {}) => {
|
|
@@ -26,12 +26,14 @@ export function createWindowsCliCatalog({ fetcher = (...args) => fetch(...args),
|
|
|
26
26
|
pending = Promise.resolve().then(async () => {
|
|
27
27
|
try {
|
|
28
28
|
if (mine !== generation) return null;
|
|
29
|
-
const
|
|
30
|
-
const
|
|
29
|
+
const base = machineId ? `/ui/runtimes/machines/${encodeURIComponent(machineId)}` : "/ui/windows-cli";
|
|
30
|
+
const response = await fetcher(`${base}/${machineId && !force ? "inventory" : "probe"}`,{credentials:"same-origin",...(machineId && !force ? {} : {method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(machineId ? {} : force ? {force:true} : {})}),signal:abort.signal});
|
|
31
|
+
const body = await response.json();
|
|
31
32
|
if (!response.ok) {
|
|
32
33
|
if (mine === generation && [401,403].includes(response.status)) store.set({data:null,checkedAt:0});
|
|
33
|
-
throw new Error(
|
|
34
|
+
throw new Error(body?.error || `HTTP ${response.status}`);
|
|
34
35
|
}
|
|
36
|
+
const value = machineId ? body.inventory || { home:"", clis:[], probedAt:null } : body;
|
|
35
37
|
if (!value || !Array.isArray(value.clis) || typeof value.home !== "string") throw new Error("Invalid Windows CLI inventory response");
|
|
36
38
|
if (mine === generation) store.set({data:value,checkedAt:now(),error:""});
|
|
37
39
|
return value;
|
|
@@ -49,20 +51,47 @@ export function createWindowsCliCatalog({ fetcher = (...args) => fetch(...args),
|
|
|
49
51
|
}
|
|
50
52
|
|
|
51
53
|
const catalog = createWindowsCliCatalog();
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
return
|
|
54
|
+
const remoteCatalogs = new Map();
|
|
55
|
+
function catalogFor(machineId) {
|
|
56
|
+
if (!machineId) return catalog;
|
|
57
|
+
if (!remoteCatalogs.has(machineId)) remoteCatalogs.set(machineId,createWindowsCliCatalog({machineId}));
|
|
58
|
+
return remoteCatalogs.get(machineId);
|
|
59
|
+
}
|
|
60
|
+
export const refreshWindowsCliCatalog = (machineId = "") => catalogFor(machineId).load({force:true});
|
|
61
|
+
/** Subscribe to progress without starting a read; cards observe detection started in a dialog. */
|
|
62
|
+
export const useWindowsCliCatalogSnapshot = (machineId = "") => useStore(catalogFor(machineId));
|
|
63
|
+
export function forgetWindowsCliCatalog() { catalog.clear(); for (const remote of remoteCatalogs.values()) remote.clear(); remoteCatalogs.clear(); }
|
|
64
|
+
export function useWindowsCliCatalog(enabled = true, machineId = "") {
|
|
65
|
+
const current = catalogFor(machineId);
|
|
66
|
+
const state = useStore(current);
|
|
67
|
+
useEffect(() => { if (enabled) void current.load(); },[enabled,current]);
|
|
68
|
+
return { ...(enabled ? state : initial()), refresh:() => current.load({force:true}) };
|
|
57
69
|
}
|
|
58
70
|
|
|
71
|
+
register("windetect", {
|
|
72
|
+
en: { remoteWindows:"Paired Windows Runtime" },
|
|
73
|
+
"zh-TW": { remoteWindows:"已配對的 Windows Runtime" },
|
|
74
|
+
});
|
|
59
75
|
register("windetect", {
|
|
60
76
|
"zh-TW": { loading:"正在偵測 Windows CLI…", refreshing:"正在更新 Windows CLI…", hint:"正在確認已安裝的 CLI、版本與登入狀態。完成後會重用結果,不必每次重新等待。", elapsed:"已等待 {0} 秒,仍在檢查中。", failed:"無法完成 Windows CLI 偵測", previous:"更新未完成,目前顯示上次成功偵測的結果。", retry:"重試偵測", refresh:"重新偵測", cached:"已載入最近的偵測結果", never:"尚未偵測 Windows CLI。偵測會逐一啟動已安裝的 CLI 一次,讀取版本與登入狀態;之後只在你按下「重新偵測」時再做。", detect:"偵測 Windows CLI" },
|
|
61
77
|
en: { loading:"Detecting Windows CLIs…", refreshing:"Updating Windows CLIs…", hint:"Checking installed CLIs, versions and sign-ins. Results are reused so reopening does not repeat the wait.", elapsed:"Still checking after {0} seconds.", failed:"Windows CLI detection failed", previous:"Refresh failed. Showing the last successful inventory.", retry:"Retry detection", refresh:"Detect again", cached:"Loaded the recent inventory", never:"Windows CLIs have not been detected yet. Detection starts each installed CLI once to read its version and sign-in; after that, only when you press Detect again.", detect:"Detect Windows CLIs" },
|
|
62
78
|
});
|
|
79
|
+
register("windetect", {
|
|
80
|
+
en: { computer:"Diagnostic computer", hostWindows:"Windows on the AgEnD host", hostHint:"Diagnostics and test tasks use this computer's CLIs and sign-ins.", hostUnknown:"Computer name not reported", hostRefresh:"Detect again to read the Windows computer name." },
|
|
81
|
+
"zh-TW": { computer:"診斷電腦", hostWindows:"AgEnD 主機的 Windows", hostHint:"診斷與測試任務使用這台電腦的 CLI 與登入。", hostUnknown:"電腦名稱尚未回報", hostRefresh:"重新偵測後可取得 Windows 電腦名稱。" },
|
|
82
|
+
});
|
|
63
83
|
export const detectionText = key => t(`windetect.${key}`);
|
|
64
84
|
|
|
65
|
-
|
|
85
|
+
/** Show the execution computer's identity, independently of the computer opening the dashboard. */
|
|
86
|
+
export function WindowsCliHostIdentity({ inventory, compact = false, machineId = "", machine }) {
|
|
87
|
+
const hostname = (inventory?.hostname || machine?.hostname || "").trim();
|
|
88
|
+
return html`<div class=${`windows-cli-target${compact ? " is-compact" : ""}`} aria-label=${detectionText("computer")}>
|
|
89
|
+
<${Icon} name="fleet" size=${compact ? 16 : 21} /><div><span class="windows-cli-target-label">${machineId ? t("windetect.remoteWindows") : detectionText("hostWindows")}</span><strong class="windows-cli-target-name">${machineId ? `${machine?.name || machineId}${hostname && hostname !== machine?.name ? ` · ${hostname}` : ""}` : hostname || detectionText("hostUnknown")}</strong>
|
|
90
|
+
${!compact ? html`<p>${detectionText(hostname ? "hostHint" : "hostRefresh")}</p>` : null}</div>
|
|
91
|
+
</div>`;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function WindowsCliDiscoveryStatus({ state, disabled = false }) {
|
|
66
95
|
const lease = useLease("windows-cli-discovery-status");
|
|
67
96
|
const [seconds,setSeconds] = useState(0);
|
|
68
97
|
useEffect(() => {
|
|
@@ -71,9 +100,9 @@ export function WindowsCliDiscoveryStatus({ state }) {
|
|
|
71
100
|
tick(); const timer = lease.interval(tick,1000);
|
|
72
101
|
return () => lease.clear(timer);
|
|
73
102
|
},[lease,state.loading,state.startedAt]);
|
|
74
|
-
if (state.error) return html`<div class="cli-discovery-status is-error" role="alert"><${Icon} name="alert" size=${18} /><div><strong>${detectionText("failed")}</strong><p>${state.data ? detectionText("previous") : state.error}</p>${state.data ? html`<small>${state.error}</small>` : null}<button type="button" class="btn btn-sm" onClick=${state.refresh}>${detectionText("retry")}</button></div></div>`;
|
|
103
|
+
if (state.error) return html`<div class="cli-discovery-status is-error" role="alert"><${Icon} name="alert" size=${18} /><div><strong>${detectionText("failed")}</strong><p>${state.data ? detectionText("previous") : state.error}</p>${state.data ? html`<small>${state.error}</small>` : null}<button type="button" class="btn btn-sm" disabled=${disabled} onClick=${state.refresh}>${detectionText("retry")}</button></div></div>`;
|
|
75
104
|
// M-2239 P1-2: nothing is detected on its own — the first detection is the administrator's press too.
|
|
76
|
-
if (!state.loading && state.data && state.data.probedAt === null) return html`<div class="cli-discovery-status" role="status"><${Icon} name="info" size=${18} /><div><p>${detectionText("never")}</p><button type="button" class="btn btn-sm" onClick=${state.refresh}>${detectionText("detect")}</button></div></div>`;
|
|
105
|
+
if (!state.loading && state.data && state.data.probedAt === null) return html`<div class="cli-discovery-status" role="status"><${Icon} name="info" size=${18} /><div><p>${detectionText("never")}</p><button type="button" class="btn btn-sm" disabled=${disabled} onClick=${state.refresh}>${detectionText("detect")}</button></div></div>`;
|
|
77
106
|
if (!state.loading && state.data) return null;
|
|
78
107
|
return html`<div class="cli-discovery-status" role="status" aria-live="polite" aria-busy="true"><span class="out-spin" aria-hidden="true"></span><div><strong>${detectionText(state.data ? "refreshing" : "loading")}</strong><p>${detectionText("hint")}</p>${seconds >= 8 ? html`<small>${t("windetect.elapsed",seconds)}</small>` : null}</div></div>`;
|
|
79
108
|
}
|
package/dist/web-api.d.ts
CHANGED
|
@@ -40,6 +40,7 @@ export interface WebApiContext {
|
|
|
40
40
|
recoverNativePane?(name: string, launchId: string, authorized: () => boolean): Promise<void>;
|
|
41
41
|
startFreshNativePane?(name: string, launchId: string, sessionId: string | null, authorized: () => boolean): Promise<void>;
|
|
42
42
|
nativeInstanceRuntime?(): import("./fleet-windows-runtime.js").FleetWindowsRuntime;
|
|
43
|
+
agentRuntimeChanges?(): import("./agent-runtime-change.js").AgentRuntimeChanges;
|
|
43
44
|
createNativePaneInstance?(profile: Record<string, unknown>, channelId: string | undefined, authorized: () => boolean, execution: import("./settings-transaction.js").SettingsExecution): Promise<unknown>;
|
|
44
45
|
updateNativePaneConfig?(name: string, patch: Partial<import("./fleet-windows-runtime.js").NativeRuntimePatch>, authorized: () => boolean, execution?: import("./settings-transaction.js").SettingsExecution): Promise<unknown>;
|
|
45
46
|
runtimeCoordinator?(): RuntimeCoordinator;
|
package/dist/web-api.js
CHANGED
|
@@ -58,6 +58,7 @@ import { xmsgShown } from "./search/search-docs.js";
|
|
|
58
58
|
import { WebSendDedupe } from "./web-send-dedupe.js";
|
|
59
59
|
import { handleWindowsCliRequest, nativeCliAuthorization } from "./windows-cli-api.js";
|
|
60
60
|
import { createNativeInstance, handleNativeInstanceRequest } from "./native-instance-api.js";
|
|
61
|
+
import { handleAgentRuntimeChange } from "./agent-runtime-api.js";
|
|
61
62
|
import { isWindowsInstance, isNativePaneInstance, isNativeExecInstance } from "./native-instance-registry.js";
|
|
62
63
|
import { handleNativeModelCatalog } from "./native-model-catalog.js";
|
|
63
64
|
import { claudeDocumentedModels } from "./model-catalog-defaults.js";
|
|
@@ -1894,6 +1895,8 @@ export function handleWebRequest(req, res, url, ctx) {
|
|
|
1894
1895
|
json(res, 403, { error: "Windows runtime requires an administrator on the local dashboard" });
|
|
1895
1896
|
return true;
|
|
1896
1897
|
}
|
|
1898
|
+
if (handleAgentRuntimeChange(req, res, url, ctx))
|
|
1899
|
+
return true;
|
|
1897
1900
|
if (handleNativeInstanceRequest(req, res, url, ctx))
|
|
1898
1901
|
return true;
|
|
1899
1902
|
if (handleWindowsCliRequest(req, res, url, ctx))
|