@songsid/agend 2.3.2-beta.9 → 2.3.3-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 +6 -0
- package/README.zh-TW.md +6 -0
- package/dist/agent-cli-instructions.md +2 -2
- package/dist/agent-cli.js +48 -0
- package/dist/agent-cli.js.map +1 -1
- package/dist/agent-endpoint.js +6 -0
- package/dist/agent-endpoint.js.map +1 -1
- package/dist/agent-whats-new.d.ts +21 -0
- package/dist/agent-whats-new.js +53 -21
- package/dist/agent-whats-new.js.map +1 -1
- package/dist/auth-api.js +2 -0
- package/dist/auth-api.js.map +1 -1
- package/dist/backend/claude-code.d.ts +13 -1
- package/dist/backend/claude-code.js +43 -2
- package/dist/backend/claude-code.js.map +1 -1
- package/dist/backend/codex-session-lookup.d.ts +15 -0
- package/dist/backend/codex-session-lookup.js +58 -0
- package/dist/backend/codex-session-lookup.js.map +1 -1
- package/dist/backend/codex.js +15 -4
- package/dist/backend/codex.js.map +1 -1
- package/dist/backend/kiro-classic-archive.d.ts +57 -0
- package/dist/backend/kiro-classic-archive.js +622 -0
- package/dist/backend/kiro-classic-archive.js.map +1 -0
- package/dist/backend/kiro-classic-links.d.ts +24 -0
- package/dist/backend/kiro-classic-links.js +135 -0
- package/dist/backend/kiro-classic-links.js.map +1 -0
- package/dist/backend/kiro-identity.d.ts +100 -1
- package/dist/backend/kiro-identity.js +262 -31
- package/dist/backend/kiro-identity.js.map +1 -1
- package/dist/backend/kiro-migration-verify.d.ts +10 -0
- package/dist/backend/kiro-migration-verify.js +52 -0
- package/dist/backend/kiro-migration-verify.js.map +1 -0
- package/dist/backend/kiro-reconcile-store.d.ts +27 -0
- package/dist/backend/kiro-reconcile-store.js +351 -0
- package/dist/backend/kiro-reconcile-store.js.map +1 -0
- package/dist/backend/kiro-v2-store-worker.js +35 -1
- package/dist/backend/kiro-v2-store-worker.js.map +1 -1
- package/dist/backend/kiro-v2-store.d.ts +31 -1
- package/dist/backend/kiro-v2-store.js +22 -12
- package/dist/backend/kiro-v2-store.js.map +1 -1
- package/dist/backend/kiro.d.ts +124 -6
- package/dist/backend/kiro.js +553 -39
- package/dist/backend/kiro.js.map +1 -1
- package/dist/backend/types.d.ts +109 -4
- package/dist/backend/types.js +9 -0
- package/dist/backend/types.js.map +1 -1
- package/dist/cache-service.d.ts +13 -1
- package/dist/cache-service.js +45 -2
- package/dist/cache-service.js.map +1 -1
- package/dist/channel/ipc-timeouts.js +3 -0
- package/dist/channel/ipc-timeouts.js.map +1 -1
- package/dist/channel/mcp-tools.js +40 -5
- package/dist/channel/mcp-tools.js.map +1 -1
- package/dist/channel/tool-router.js +2 -1
- package/dist/channel/tool-router.js.map +1 -1
- package/dist/classic-channel-manager.d.ts +6 -0
- package/dist/classic-channel-manager.js +25 -0
- package/dist/classic-channel-manager.js.map +1 -1
- package/dist/cli.js +52 -6
- package/dist/cli.js.map +1 -1
- package/dist/config-validator.d.ts +7 -1
- package/dist/config-validator.js +20 -9
- package/dist/config-validator.js.map +1 -1
- package/dist/config.js +2 -0
- package/dist/config.js.map +1 -1
- package/dist/cross-instance-envelope.d.ts +10 -5
- package/dist/cross-instance-envelope.js +20 -17
- package/dist/cross-instance-envelope.js.map +1 -1
- package/dist/daemon.d.ts +125 -63
- package/dist/daemon.js +694 -330
- package/dist/daemon.js.map +1 -1
- package/dist/dashboard-permissions.d.ts +15 -4
- package/dist/dashboard-permissions.js +49 -23
- package/dist/dashboard-permissions.js.map +1 -1
- package/dist/delivery-outbox.d.ts +27 -22
- package/dist/delivery-outbox.js +109 -161
- package/dist/delivery-outbox.js.map +1 -1
- package/dist/delivery-outbox.test.js +10 -25
- package/dist/delivery-outbox.test.js.map +1 -1
- package/dist/doctor.js +2 -1
- package/dist/doctor.js.map +1 -1
- package/dist/fleet-control-audit.d.ts +1 -1
- package/dist/fleet-control-audit.js +3 -0
- package/dist/fleet-control-audit.js.map +1 -1
- package/dist/fleet-manager.d.ts +94 -15
- package/dist/fleet-manager.js +597 -133
- package/dist/fleet-manager.js.map +1 -1
- package/dist/forged-envelope-scan.d.ts +9 -0
- package/dist/forged-envelope-scan.js +30 -5
- package/dist/forged-envelope-scan.js.map +1 -1
- package/dist/general-instance.d.ts +24 -0
- package/dist/general-instance.js +53 -0
- package/dist/general-instance.js.map +1 -1
- package/dist/general-knowledge/skills/delegation-playbook/SKILL.md +1 -1
- package/dist/general-knowledge/skills/docker-install/SKILL.md +25 -0
- package/dist/general-knowledge/skills/fleet-config/SKILL.md +5 -3
- package/dist/general-knowledge/skills/fleet-restart/SKILL.md +1 -1
- package/dist/general-knowledge/skills/kiro-engine-migration/SKILL.md +34 -0
- package/dist/general-knowledge/skills/session-management/SKILL.md +2 -2
- package/dist/general-knowledge/skills/tui-effort/SKILL.md +1 -1
- package/dist/general-knowledge/skills/web-appearance/SKILL.canvas-worker-off.md +32 -0
- package/dist/general-knowledge/skills/web-appearance/SKILL.md +32 -0
- package/dist/general-knowledge/skills/web-dashboard/SKILL.canvas-worker-off.md +57 -17
- package/dist/general-knowledge/skills/web-dashboard/SKILL.md +57 -17
- package/dist/instance-config-impact.js +3 -2
- package/dist/instance-config-impact.js.map +1 -1
- package/dist/instance-lifecycle.d.ts +4 -0
- package/dist/instance-lifecycle.js +28 -5
- package/dist/instance-lifecycle.js.map +1 -1
- package/dist/instructions.js +6 -7
- package/dist/instructions.js.map +1 -1
- package/dist/kiro-migrate.d.ts +19 -2
- package/dist/kiro-migrate.js +133 -35
- package/dist/kiro-migrate.js.map +1 -1
- package/dist/kiro-reconcile.d.ts +21 -0
- package/dist/kiro-reconcile.js +88 -0
- package/dist/kiro-reconcile.js.map +1 -0
- package/dist/kiro-session-proof.d.ts +41 -0
- package/dist/kiro-session-proof.js +89 -0
- package/dist/kiro-session-proof.js.map +1 -0
- package/dist/kiro-tui-forensic.d.ts +19 -0
- package/dist/kiro-tui-forensic.js +124 -0
- package/dist/kiro-tui-forensic.js.map +1 -0
- package/dist/locale.js +202 -16
- package/dist/locale.js.map +1 -1
- package/dist/log-service.js +3 -3
- package/dist/log-service.js.map +1 -1
- package/dist/needs-you.d.ts +3 -1
- package/dist/needs-you.js +4 -2
- package/dist/needs-you.js.map +1 -1
- package/dist/office-levels.d.ts +64 -0
- package/dist/office-levels.js +66 -0
- package/dist/office-levels.js.map +1 -0
- package/dist/office-share-page.d.ts +3 -1
- package/dist/office-share-page.js +8 -3
- package/dist/office-share-page.js.map +1 -1
- package/dist/office-share-service.d.ts +6 -3
- package/dist/office-share-service.js +12 -8
- package/dist/office-share-service.js.map +1 -1
- package/dist/office-share.d.ts +45 -8
- package/dist/office-share.js +75 -15
- package/dist/office-share.js.map +1 -1
- package/dist/outbound-handlers.js +21 -2
- package/dist/outbound-handlers.js.map +1 -1
- package/dist/outbound-schemas.d.ts +47 -2
- package/dist/outbound-schemas.js +42 -3
- package/dist/outbound-schemas.js.map +1 -1
- package/dist/public-web-gateway.js +1 -1
- package/dist/public-web-gateway.js.map +1 -1
- package/dist/quickstart-api.d.ts +39 -1
- package/dist/quickstart-api.js +115 -17
- package/dist/quickstart-api.js.map +1 -1
- package/dist/remote-card-answer.d.ts +83 -0
- package/dist/remote-card-answer.js +208 -0
- package/dist/remote-card-answer.js.map +1 -0
- package/dist/remote-card-prompt.d.ts +38 -0
- package/dist/remote-card-prompt.js +86 -0
- package/dist/remote-card-prompt.js.map +1 -0
- package/dist/scheduler/task-board.d.ts +44 -17
- package/dist/scheduler/task-board.js +95 -36
- package/dist/scheduler/task-board.js.map +1 -1
- package/dist/sd-notify.d.ts +13 -14
- package/dist/sd-notify.js +62 -28
- package/dist/sd-notify.js.map +1 -1
- package/dist/service-installer.d.ts +13 -0
- package/dist/service-installer.js +15 -0
- package/dist/service-installer.js.map +1 -1
- package/dist/service-owner.d.ts +25 -0
- package/dist/service-owner.js +43 -2
- package/dist/service-owner.js.map +1 -1
- package/dist/settings-api.d.ts +2 -1
- package/dist/settings-api.js +19 -26
- package/dist/settings-api.js.map +1 -1
- package/dist/settings-change.js +10 -5
- package/dist/settings-change.js.map +1 -1
- package/dist/settings-effect.js +7 -6
- package/dist/settings-effect.js.map +1 -1
- package/dist/settings-instance-patch.js +1 -1
- package/dist/settings-instance-patch.js.map +1 -1
- package/dist/setup-form.d.ts +2 -2
- package/dist/setup-form.js +139 -93
- package/dist/setup-form.js.map +1 -1
- package/dist/setup-i18n.d.ts +25 -0
- package/dist/setup-i18n.js +226 -0
- package/dist/setup-i18n.js.map +1 -0
- package/dist/task-board-waker.d.ts +40 -1
- package/dist/task-board-waker.js +115 -9
- package/dist/task-board-waker.js.map +1 -1
- package/dist/tmux-control.d.ts +1 -1
- package/dist/tmux-control.js +3 -2
- package/dist/tmux-control.js.map +1 -1
- package/dist/tmux-manager.js +18 -16
- package/dist/tmux-manager.js.map +1 -1
- package/dist/tmux-read.d.ts +2 -0
- package/dist/tmux-read.js +7 -1
- package/dist/tmux-read.js.map +1 -1
- package/dist/tool-permissions.js +18 -0
- package/dist/tool-permissions.js.map +1 -1
- package/dist/topic-commands.d.ts +2 -0
- package/dist/topic-commands.js +2 -1
- package/dist/topic-commands.js.map +1 -1
- package/dist/transcript-sources.d.ts +1 -0
- package/dist/transcript-sources.js +20 -3
- package/dist/transcript-sources.js.map +1 -1
- package/dist/types.d.ts +11 -5
- package/dist/ui/backend-signin.js +4 -3
- package/dist/ui/chat-store.js +3 -2
- package/dist/ui/chat-strings.js +2 -2
- package/dist/ui/fleet-office-card.js +114 -0
- package/dist/ui/fleet-office-editor.js +81 -9
- package/dist/ui/fleet-office-layout.js +56 -11
- package/dist/ui/fleet-office-levels.js +105 -0
- package/dist/ui/fleet-office-model.js +9 -1
- package/dist/ui/fleet-office-pack.d.ts +15 -3
- package/dist/ui/fleet-office-pack.js +177 -23
- package/dist/ui/fleet-office-skin.js +39 -3
- package/dist/ui/fleet-office-store.js +74 -3
- package/dist/ui/fleet-office-view.js +8 -0
- package/dist/ui/fleet-office-zones.js +102 -19
- package/dist/ui/fleet-office.js +308 -44
- package/dist/ui/fleet-org.js +2 -0
- package/dist/ui/fleet-task-card.js +2 -2
- package/dist/ui/fleet-task-common.js +30 -7
- package/dist/ui/fleet-task-work.js +2 -2
- package/dist/ui/fleet-tasks.js +10 -11
- package/dist/ui/office-share-dialog.js +31 -7
- package/dist/ui/office-share-page.js +1 -0
- package/dist/ui/panel-chat.js +14 -2
- package/dist/ui/panel-log.js +6 -6
- package/dist/ui/panel-needs.js +1 -1
- package/dist/ui/panel-settings.js +16 -8
- package/dist/ui/settings-appearance.js +3 -35
- package/dist/ui/settings-discord.js +3 -2
- package/dist/ui/settings-guests.js +17 -7
- package/dist/ui/settings-model.js +17 -9
- package/dist/ui/settings-registry.js +1 -1
- package/dist/ui/settings-strings.js +18 -6
- package/dist/ui/settings-token.js +3 -2
- package/dist/ui/settings-wizard.js +25 -9
- package/dist/ui/shared/app-i18n.js +2 -2
- package/dist/ui/shared/app-stream.js +1 -1
- package/dist/ui/shared/app.css +70 -2
- package/dist/ui/shared/setup-host-text.js +107 -0
- package/dist/ui/structured-signin.js +89 -38
- package/dist/update-check.d.ts +13 -4
- package/dist/update-check.js +17 -4
- package/dist/update-check.js.map +1 -1
- package/dist/usage-rollup.d.ts +34 -3
- package/dist/usage-rollup.js +56 -3
- package/dist/usage-rollup.js.map +1 -1
- package/dist/web-api.d.ts +10 -1
- package/dist/web-api.js +207 -17
- package/dist/web-api.js.map +1 -1
- package/dist/web-auth.js +1 -1
- package/dist/web-auth.js.map +1 -1
- package/dist/web-experimental.d.ts +6 -2
- package/dist/web-experimental.js +8 -4
- package/dist/web-experimental.js.map +1 -1
- package/dist/web-office-acts.d.ts +5 -2
- package/dist/web-office-acts.js +9 -4
- package/dist/web-office-acts.js.map +1 -1
- package/dist/web-office-pack-read.d.ts +35 -0
- package/dist/web-office-pack-read.js +252 -0
- package/dist/web-office-pack-read.js.map +1 -0
- package/dist/web-office-pack-tools.d.ts +241 -0
- package/dist/web-office-pack-tools.js +785 -0
- package/dist/web-office-pack-tools.js.map +1 -0
- package/dist/web-office-skins.d.ts +68 -4
- package/dist/web-office-skins.js +324 -33
- package/dist/web-office-skins.js.map +1 -1
- package/dist/web-office-store.d.ts +47 -4
- package/dist/web-office-store.js +124 -23
- package/dist/web-office-store.js.map +1 -1
- package/dist/web-settings-patch.d.ts +3 -2
- package/dist/web-settings-patch.js +7 -5
- package/dist/web-settings-patch.js.map +1 -1
- package/dist/workflow-templates/default.md +3 -3
- package/dist/working-recovery.d.ts +0 -2
- package/dist/working-recovery.js +2 -23
- package/dist/working-recovery.js.map +1 -1
- package/package.json +2 -2
- package/templates/windows-shortcuts.ps1 +18 -17
- package/dist/upgrade-notices.d.ts +0 -17
- package/dist/upgrade-notices.js +0 -93
- package/dist/upgrade-notices.js.map +0 -1
|
@@ -60,11 +60,19 @@ function wroteTo(names) {
|
|
|
60
60
|
return html`${before}${names.map((n, i) => html`${i ? ", " : ""}<span key=${n} class="g-wrote">${n}</span>`)}${after}`;
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
|
|
63
|
+
/** #2667: a granted name as a person reads it — a ClassicBot room by its display name, when it has one. */
|
|
64
|
+
const shownName = (rooms, n) => { const r = (rooms || []).find((x) => x.name === n); return (r && r.display_name) || n; };
|
|
65
|
+
|
|
66
|
+
/** The agents to choose from: fleet.yaml's instances, then (#2667) the ClassicBot rooms, under their own heading. */
|
|
67
|
+
function Names({ id, all, rooms = [], value, wrote = [], onChange }) {
|
|
64
68
|
const chosen = new Set(value || []);
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
<
|
|
69
|
+
const order = [...all, ...rooms.map((r) => r.name)];
|
|
70
|
+
const box = (n, label, note) => html`<label key=${n} class="check guest-name" title=${note ? n : undefined}>
|
|
71
|
+
<input type="checkbox" checked=${chosen.has(n)} onChange=${(e) => { const s = new Set(chosen); if (e.target.checked) s.add(n); else s.delete(n); onChange(order.filter((x) => s.has(x))); }} />
|
|
72
|
+
<span>${label}${note ? html` <span class="note">${n}</span>` : null}${wrote.includes(n) ? html` <span class="note">${tn("grantsWroteHere")}</span>` : null}</span></label>`;
|
|
73
|
+
return html`<div class="guest-names" id=${id} role="group">${all.map((n) => box(n, n, false))}
|
|
74
|
+
${rooms.length ? html`<span class="guest-names-group note" key="--rooms">${tn("grantsClassicRooms")}</span>` : null}
|
|
75
|
+
${rooms.map((r) => box(r.name, r.display_name || r.name, !!r.display_name))}</div>`;
|
|
68
76
|
}
|
|
69
77
|
|
|
70
78
|
const clock = (ms) => new Date(ms).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
|
|
@@ -147,6 +155,8 @@ export function GuestsSection({ ctx, staged }) {
|
|
|
147
155
|
const setGrant = (k, grant) => { setStatus(null); setF((x) => { const g = { ...(x.grants || {}) }; if (grant) g[k] = grant; else delete g[k]; return { ...x, grants: g }; }); };
|
|
148
156
|
const guests = (overview && overview.guests) || [];
|
|
149
157
|
const instances = (overview && overview.instances) || [];
|
|
158
|
+
const rooms = (overview && Array.isArray(overview.rooms) && overview.rooms) || [];
|
|
159
|
+
const choosable = [...instances, ...rooms.map((r) => r.name)];
|
|
150
160
|
const who = (k) => {
|
|
151
161
|
const g = guests.find((x) => accountKey(x) === k), p = (people || []).find((x) => accountKey(x) === k);
|
|
152
162
|
const grant = (f.grants && f.grants[k]) || (original.grants && original.grants[k]);
|
|
@@ -223,10 +233,10 @@ export function GuestsSection({ ctx, staged }) {
|
|
|
223
233
|
<div class="g-head"><span class="g-av" aria-hidden="true">${(person.name || "?").slice(0, 1).toUpperCase()}</span>
|
|
224
234
|
<div class="g-id"><strong>${person.name}</strong> <span class="note">${PLATFORMS[person.platform] || person.platform}${person.username ? ` · @${person.username}` : ""}</span></div>
|
|
225
235
|
${removed ? html`<span class="g-state">${tn("grantsWillBeRemoved")}</span>` : added ? html`<span class="g-state">${tn("grantsNew")}</span>` : pill(person)}</div>
|
|
226
|
-
<div class="g-chips">${((draft || saved).instances || []).map((n) => html`<span key=${n} class="g-chip">${n}</span>`)}</div>
|
|
236
|
+
<div class="g-chips">${((draft || saved).instances || []).map((n) => html`<span key=${n} class="g-chip" title=${shownName(rooms, n) !== n ? n : undefined}>${shownName(rooms, n)}</span>`)}</div>
|
|
227
237
|
${draft && !draft.instances.length ? html`<p class="note g-error" role="alert">${tn("grantsNoAgents")}</p>` : null}
|
|
228
238
|
${editing === k && draft ? html`<div class="g-edit"><p class="note">${tn("grantsMaySee", person.name)}</p>
|
|
229
|
-
<${Names} id=${`grant-${k}`} all=${instances} value=${draft.instances} wrote=${person.wrote} onChange=${(list) => setGrant(k, { ...draft, instances: list })} /></div>` : null}
|
|
239
|
+
<${Names} id=${`grant-${k}`} all=${instances} rooms=${rooms} value=${draft.instances} wrote=${person.wrote} onChange=${(list) => setGrant(k, { ...draft, instances: list })} /></div>` : null}
|
|
230
240
|
${readOnly ? null : html`<div class="guest-actions">
|
|
231
241
|
${draft ? html`<button type="button" class="btn btn-sm" aria-expanded=${editing === k ? "true" : "false"} onClick=${() => setEditing(editing === k ? null : k)}>${tn("grantsEditAgents")}</button>` : null}
|
|
232
242
|
${draft ? html`<button type="button" class="btn btn-sm g-send" disabled=${!applied || ss.sending || cooling || !f.enabled || !original.enabled}
|
|
@@ -245,7 +255,7 @@ export function GuestsSection({ ctx, staged }) {
|
|
|
245
255
|
<span class="g-av" aria-hidden="true">${(p.name || "?").slice(0, 1).toUpperCase()}</span>
|
|
246
256
|
<div class="g-id"><strong>${p.name}</strong> <span class="note">${PLATFORMS[p.platform] || p.platform}${p.username ? ` · @${p.username}` : ""} · <span class="g-when">${tn("grantsLastSeen", new Date(p.lastSeen).toLocaleString())}</span></span>
|
|
247
257
|
${p.instances && p.instances.length ? html`<div class="note">${wroteTo(p.instances)}</div>` : null}</div>
|
|
248
|
-
<button type="button" class="btn btn-sm" onClick=${() => { const k = accountKey(p); setGrant(k, { ...(p.name ? { name: p.name } : {}), instances:
|
|
258
|
+
<button type="button" class="btn btn-sm" onClick=${() => { const k = accountKey(p); setGrant(k, { ...(p.name ? { name: p.name } : {}), instances: choosable.filter((n) => (p.instances || []).includes(n)) }); setEditing(k); }}>${tn("grantsChoose")}</button></li>`)}</ul>`}`}
|
|
249
259
|
</fieldset>
|
|
250
260
|
${overview && overview.audit ? html`<h4>${tn("grantsRecent")}</h4>${!overview.audit.length ? html`<p class="note" id="grantsRecentNone">${tn("grantsRecentNone")}</p>`
|
|
251
261
|
: html`<ul class="g-audit" id="grantsRecentList">${overview.audit.map((e, i) => html`<li key=${`${e.at}-${i}`} class="g-audit-row" data-kind=${e.kind}>
|
|
@@ -40,26 +40,32 @@ export function changedFields(next, baseline) {
|
|
|
40
40
|
|
|
41
41
|
/**
|
|
42
42
|
* The dashboard features an agent may use (dashboard-permissions.ts): each "inherit" (the fleet default: `defaults.dashboard`,
|
|
43
|
-
* else allowed — off for OFF_UNLESS_ON, `office`), "on" or "off". The patch names only the features that changed: null
|
|
43
|
+
* else allowed — off for OFF_UNLESS_ON, `office` and `office_packs`), "on" or "off". The patch names only the features that changed: null
|
|
44
44
|
* follows the default again.
|
|
45
45
|
*/
|
|
46
|
-
export const DASHBOARD_FEATURES = ["appearance", "task_board", "web_settings", "office"];
|
|
47
|
-
/** #2578: the features a person switches on — unset is off (dashboard-permissions.ts OFF_UNLESS_ON). */
|
|
48
|
-
export const OFF_UNLESS_ON = ["office"];
|
|
46
|
+
export const DASHBOARD_FEATURES = ["appearance", "task_board", "web_settings", "office", "office_packs"];
|
|
47
|
+
/** #2578, #2692: the features a person switches on — unset is off (dashboard-permissions.ts OFF_UNLESS_ON). */
|
|
48
|
+
export const OFF_UNLESS_ON = ["office", "office_packs"];
|
|
49
|
+
/** #2601, #2692: the features kept beside `dashboard` under their own key (dashboard-permissions.ts SEPARATE_FEATURE_KEYS). */
|
|
50
|
+
export const SEPARATE_FEATURE_KEYS = { office: "office_access", office_packs: "office_pack_access" };
|
|
49
51
|
export const DASHBOARD_CHOICES = ["inherit", "on", "off"];
|
|
50
52
|
const dashboardOf = (v) => (v && typeof v === "object" && !Array.isArray(v) ? v : {});
|
|
51
53
|
/** What a feature is for an agent with no setting of its own: the default's, else allowed (off for OFF_UNLESS_ON). */
|
|
52
54
|
export const dashboardDefault = (defaults, feature) => {
|
|
53
|
-
const
|
|
55
|
+
const key = Object.hasOwn(SEPARATE_FEATURE_KEYS, feature) ? SEPARATE_FEATURE_KEYS[feature] : null;
|
|
56
|
+
const v = key && defaults && Object.hasOwn(defaults, key) ? defaults[key] : dashboardOf(defaults && defaults.dashboard)[feature];
|
|
54
57
|
return OFF_UNLESS_ON.includes(feature) ? v === true : v !== false;
|
|
55
58
|
};
|
|
56
59
|
export function dashboardForm(inst) {
|
|
57
|
-
const own = { ...dashboardOf(inst.dashboard)
|
|
60
|
+
const own = { ...dashboardOf(inst.dashboard) };
|
|
61
|
+
for (const [feature, key] of Object.entries(SEPARATE_FEATURE_KEYS)) if (Object.hasOwn(inst, key)) own[feature] = inst[key];
|
|
58
62
|
return Object.fromEntries(DASHBOARD_FEATURES.map((f) => [f, own[f] === true ? "on" : own[f] === false ? "off" : "inherit"]));
|
|
59
63
|
}
|
|
60
64
|
export function dashboardPatchValue(choices) {
|
|
61
|
-
return Object.fromEntries(DASHBOARD_FEATURES.filter((f) => f
|
|
65
|
+
return Object.fromEntries(DASHBOARD_FEATURES.filter((f) => !Object.hasOwn(SEPARATE_FEATURE_KEYS, f)).map((f) => [f, choices[f] === "on" ? true : choices[f] === "off" ? false : null]));
|
|
62
66
|
}
|
|
67
|
+
/** A separately kept feature's own key in a patch (office_access, office_pack_access): true, false or null (inherit). */
|
|
68
|
+
export const separateChoice = (choice) => (choice === "on" ? true : choice === "off" ? false : null);
|
|
63
69
|
|
|
64
70
|
/** #1302: cross-instance notices. Unset, or a value the fleet does not know, means full. */
|
|
65
71
|
export const visibilityDefault = (defaults) => (VISIBILITY_MODES.includes(defaults && defaults.cross_instance_visibility) ? defaults.cross_instance_visibility : "full");
|
|
@@ -181,7 +187,8 @@ export function agentPatch(form, inst, defaults, visibilityBaseline, statusEmoji
|
|
|
181
187
|
display_name: form.inherit.display_name ? null : form.display_name.trim(),
|
|
182
188
|
status_emojis: form.status_emojis,
|
|
183
189
|
dashboard: dashboardPatchValue(form.dashboard),
|
|
184
|
-
office_access: form.dashboard.office
|
|
190
|
+
office_access: separateChoice(form.dashboard.office),
|
|
191
|
+
office_pack_access: separateChoice(form.dashboard.office_packs),
|
|
185
192
|
};
|
|
186
193
|
return changedFields(next, {
|
|
187
194
|
backend: inst.backend || defaults.backend || "claude-code",
|
|
@@ -205,7 +212,8 @@ export function agentPatch(form, inst, defaults, visibilityBaseline, statusEmoji
|
|
|
205
212
|
display_name: hasOwn(inst, "display_name") ? inst.display_name : null,
|
|
206
213
|
status_emojis: statusEmojisBaseline,
|
|
207
214
|
dashboard: dashboardPatchValue(dashboardForm(inst)),
|
|
208
|
-
office_access: dashboardForm(inst).office
|
|
215
|
+
office_access: separateChoice(dashboardForm(inst).office),
|
|
216
|
+
office_pack_access: separateChoice(dashboardForm(inst).office_packs),
|
|
209
217
|
});
|
|
210
218
|
}
|
|
211
219
|
|
|
@@ -66,9 +66,9 @@ const ROWS = [
|
|
|
66
66
|
// Fleet · Web dashboard
|
|
67
67
|
["dash.log-tab", "web-dashboard", "#webLogTab", "settings.webLogTab", "web.log_tab", ["log tab", "steps", "log"], ["Log 分頁", "紀錄", "步驟"]],
|
|
68
68
|
["dash.usage-public", "web-dashboard", "#webUsagePublic", "settings.webUsagePublic", "web.usage_report_on_public_link", ["usage", "public link", "cost", "tokens"], ["用量", "公開連結", "費用"]],
|
|
69
|
+
["dash.office-levels", "web-dashboard", "#webOfficeLevels", "settings.webOfficeLevels", "web.office_levels", ["office", "level", "badge", "profile card"], ["辦公室", "等級", "徽章", "名片"]],
|
|
69
70
|
["dash.app-icon", "web-dashboard", ".s-app-icon", "settings.appIconTitle", null, ["app icon", "favicon", "home screen", "icon"], ["App 圖示", "圖示", "主畫面"]],
|
|
70
71
|
["dash.card-limits", "web-dashboard", ".s-card-limits", "settings.cardLimitsTitle", "web.appearance", ["upload limits", "portrait", "banner", "card limits"], ["上傳限制", "身分卡上傳限制"]],
|
|
71
|
-
["dash.canvas-worker", "web-dashboard", ".s-experimental-effects", "experimentalEffects.title", "web.experimental.canvas_worker", ["canvas worker", "experimental", "effects"], ["Canvas Worker", "實驗功能", "特效"]],
|
|
72
72
|
// Fleet · Access & security
|
|
73
73
|
["access.session-absolute", "access", "#webSessionAbsolute", "settings.sessionAbsolute", "web.session.local.absolute_hours", ["session", "sign in", "hours", "expire", "logout"], ["session", "登入", "時數", "到期"]],
|
|
74
74
|
["access.session-idle", "access", "#webSessionIdle", "settings.sessionIdle", "web.session.local.idle_hours", ["session", "idle", "unused", "hours"], ["session", "閒置", "時數"]],
|
|
@@ -39,6 +39,7 @@ register("settings", {
|
|
|
39
39
|
namedTokenSaved: "Token change saved. Reopen the public link.",
|
|
40
40
|
webEcho: "Web echo",
|
|
41
41
|
webEchoHint: "Copies web messages to the bound Telegram or Discord topic. ClassicBot rooms follow it unless a room sets its own.",
|
|
42
|
+
webOfficeLevels: "Office levels", webOfficeLevelsHint: "Each agent's level from its lifetime work, on its name tag in the Office and on its profile card. Off removes the badges and the card's level rows. The token counts behind a level follow the usage report's rules. Applies at once.",
|
|
42
43
|
webUsagePublic: "Usage report over the public link", webUsagePublicHint: "Fleet → Usage (up to 400 days of each agent's tokens, requests, messages and API-equivalent amounts) is offered over the temporary public link too. Off by default; guests never see it. Applies at once.",
|
|
43
44
|
webLogTab: "Log tab: each agent's steps", webLogTabHint: "Shows each instance's prompts, replies, tool calls and results, and fleet events in its Log tab, read from its own transcript only while the tab is open. Secret values are masked. Also over the public link. Turning it on waits for a fleet admin's confirmation.",
|
|
44
45
|
general: "General Settings",
|
|
@@ -113,6 +114,7 @@ register("settings", {
|
|
|
113
114
|
dashboard_task_board: "The task board",
|
|
114
115
|
dashboard_web_settings: "Your web appearance settings",
|
|
115
116
|
dashboard_office: "Office: walk, speak and act in the Office view",
|
|
117
|
+
dashboard_office_packs: "Office skin packs: check, upload, replace and restore them (everyone sees them)",
|
|
116
118
|
dashboardInherit: "Fleet default ({0})",
|
|
117
119
|
dashboardOn: "allowed",
|
|
118
120
|
dashboardOff: "off",
|
|
@@ -184,6 +186,7 @@ register("settings", {
|
|
|
184
186
|
wizardBackendFound: "Found on this host: {0}",
|
|
185
187
|
wizardBackendNone: "No backend CLI found on this host — install one first.",
|
|
186
188
|
wizardAgentName: "First agent name",
|
|
189
|
+
wizardGeneralNote: "This agent is the General: it answers in the chat's own General topic and hands work to the agents you add later.",
|
|
187
190
|
wizardAgentWhich: "Which agent answers on this bot",
|
|
188
191
|
wizardAgentNew: "A new agent",
|
|
189
192
|
wizardAgentExisting: "An agent you already have",
|
|
@@ -192,7 +195,10 @@ register("settings", {
|
|
|
192
195
|
wizardAgentNewName: "New agent name",
|
|
193
196
|
wizardTopicNotCarried: "Its topic ({0}) is in the chat of its old connection, so it is not carried over: in the new chat it has no topic until one is bound.",
|
|
194
197
|
wizardTopicGeneral: "It is the General agent: in the new chat it takes that chat's General topic.",
|
|
195
|
-
wizardNeedDir: "
|
|
198
|
+
wizardNeedDir: "A working directory must be an absolute path, or leave it empty.",
|
|
199
|
+
wizardDir: "Working directory (optional)",
|
|
200
|
+
wizardDirDefault: "Leave it empty and the agent gets its own folder, {0}, which AgEnD creates. A path you enter must be absolute.",
|
|
201
|
+
wizardDirDefaultName: "Leave it empty and the agent gets its own folder in AgEnD's workspaces, which AgEnD creates. A path you enter must be absolute.",
|
|
196
202
|
wizardTelegramHint: "Create a bot with @BotFather, then add it to a group.",
|
|
197
203
|
wizardDiscordHint: "Create an application in the Discord developer portal and invite the bot to your server.",
|
|
198
204
|
wizardToken: "Bot token",
|
|
@@ -406,7 +412,7 @@ register("settings", {
|
|
|
406
412
|
modInstalled: "Installed {0}.",
|
|
407
413
|
modFailed: "Not done: {0}",
|
|
408
414
|
idLine: "ID: {0}",
|
|
409
|
-
modCanvasWorkerOff: "Not done: this mod has Canvas Worker effects,
|
|
415
|
+
modCanvasWorkerOff: "Not done: this mod has Canvas Worker effects, which AgEnD no longer runs.",
|
|
410
416
|
modDownload: "Download",
|
|
411
417
|
modUninstall: "Uninstall",
|
|
412
418
|
modUninstallConfirm: "Uninstall {0}? Its effects leave your library unless something still uses them. What it applied stays.",
|
|
@@ -532,7 +538,7 @@ register("settings", {
|
|
|
532
538
|
grantsLegacy: "Guests now reach what their chat access gives them. Saving grants switches to explicit access: only the people below, only their ticked agents.",
|
|
533
539
|
grantsConvert: "Start from today's guests", grantsWithAccess: "People with access", grantsNoneYet: "No one has guest access yet.",
|
|
534
540
|
grantsAdd: "Add a person", grantsSearch: "Search people who have written to your agents", grantsNoPeople: "No one matches. A person must have written to an agent first.",
|
|
535
|
-
grantsChoose: "Choose", grantsChosen: "Chosen", grantsMaySee: "{0} may see:", grantsWroteHere: "wrote here", grantsWroteTo: "Wrote to: {0}",
|
|
541
|
+
grantsChoose: "Choose", grantsChosen: "Chosen", grantsMaySee: "{0} may see:", grantsClassicRooms: "ClassicBot rooms", grantsWroteHere: "wrote here", grantsWroteTo: "Wrote to: {0}",
|
|
536
542
|
grantsLastSeen: "last seen {0}", grantsRecent: "Recent changes", grantsRecentNone: "No change to anyone's access yet.", grantsAuditDirect: "applied at once", grantsAuditConfirmed: "confirmed in General", grantsAuditEnded: "{0} session(s) ended", grantsAuditCodeSent: "sign-in code sent", grantsAuditCodeNot: "sign-in code not sent ({0})", grantsAuditDmFailed: "the DM did not go through", grantsAuditWait: "asked again within a minute", grantsAuditAdminLimit: "the admin's limit of codes was reached",
|
|
537
543
|
grantsEditAgents: "Edit agents", grantsRemove: "Remove access", grantsUndoRemove: "Keep access",
|
|
538
544
|
grantsWillBeRemoved: "Access ends when you save.", grantsNew: "New — granted when you save", grantsNoAgents: "Tick at least one agent, or remove this person.",
|
|
@@ -714,6 +720,7 @@ register("settings", {
|
|
|
714
720
|
namedTokenSaved: "Token 變更已儲存,請重新開啟公開連結。",
|
|
715
721
|
webEcho: "Web 同步",
|
|
716
722
|
webEchoHint: "將網頁訊息複製到綁定的 Telegram 或 Discord 主題。ClassicBot 聊天室也照這個設定,除非該聊天室另外設定。",
|
|
723
|
+
webOfficeLevels: "辦公室等級", webOfficeLevelsHint: "每個 agent 依終身工作量得到的等級,顯示在辦公室的名牌與名片上。關閉會移除徽章與名片上的等級列。等級背後的 token 數字依用量報告的規則顯示。變更立即生效。",
|
|
717
724
|
webUsagePublic: "透過公開連結提供用量報告", webUsagePublicHint: "Fleet → 用量(最多 400 天、每個 agent 的 token、請求、訊息與依牌價換算的 API 等值)也會透過臨時公開連結提供。預設關閉;訪客一律看不到。變更立即生效。",
|
|
718
725
|
webLogTab: "紀錄分頁:每個 agent 的步驟", webLogTabHint: "在每個 instance 的「紀錄」分頁顯示提示、回覆、工具呼叫與結果,以及 fleet 事件;只在分頁開著時從它自己的對話紀錄讀取。機密值會遮蔽。公開連結也看得到。開啟需 fleet admin 確認。",
|
|
719
726
|
general: "一般設定",
|
|
@@ -762,6 +769,7 @@ register("settings", {
|
|
|
762
769
|
dashboard_task_board: "任務看板",
|
|
763
770
|
dashboard_web_settings: "你的網頁外觀設定",
|
|
764
771
|
dashboard_office: "辦公室:在辦公室畫面走動、說話、做動作",
|
|
772
|
+
dashboard_office_packs: "辦公室外觀包:檢查、上傳、取代與還原(全 fleet 都看得到)",
|
|
765
773
|
dashboardInherit: "跟 fleet 預設({0})",
|
|
766
774
|
dashboardOn: "允許",
|
|
767
775
|
dashboardOff: "關閉",
|
|
@@ -833,6 +841,7 @@ register("settings", {
|
|
|
833
841
|
wizardBackendFound: "在這台主機上找到:{0}",
|
|
834
842
|
wizardBackendNone: "這台主機上找不到任何後端 CLI —— 請先安裝一個。",
|
|
835
843
|
wizardAgentName: "第一個 agent 名稱",
|
|
844
|
+
wizardGeneralNote: "這個 agent 就是 General:它在聊天本身的 General 主題回覆,並把工作分給你之後加入的 agent。",
|
|
836
845
|
wizardAgentWhich: "由哪個 agent 在這個機器人上回覆",
|
|
837
846
|
wizardAgentNew: "新的 agent",
|
|
838
847
|
wizardAgentExisting: "既有的 agent",
|
|
@@ -841,7 +850,10 @@ register("settings", {
|
|
|
841
850
|
wizardAgentNewName: "新 agent 名稱",
|
|
842
851
|
wizardTopicNotCarried: "它的 topic({0})屬於舊連線的聊天室,不會帶過去:在新的聊天室裡,綁定新的 topic 之前它沒有 topic。",
|
|
843
852
|
wizardTopicGeneral: "它是 General agent:在新的聊天室裡會改用那裡的 General topic。",
|
|
844
|
-
wizardNeedDir: "
|
|
853
|
+
wizardNeedDir: "工作目錄必須是絕對路徑,或留空。",
|
|
854
|
+
wizardDir: "工作目錄(選填)",
|
|
855
|
+
wizardDirDefault: "留空的話,agent 會有自己的資料夾 {0},由 AgEnD 建立。若要填寫,必須是絕對路徑。",
|
|
856
|
+
wizardDirDefaultName: "留空的話,agent 會在 AgEnD 的 workspaces 裡有自己的資料夾,由 AgEnD 建立。若要填寫,必須是絕對路徑。",
|
|
845
857
|
wizardTelegramHint: "用 @BotFather 建立 bot,然後把它加進一個群組。",
|
|
846
858
|
wizardDiscordHint: "在 Discord 開發者後台建立應用程式,並把 bot 邀請到你的伺服器。",
|
|
847
859
|
wizardToken: "Bot token",
|
|
@@ -1054,7 +1066,7 @@ register("settings", {
|
|
|
1054
1066
|
modInstalled: "已安裝 {0}。",
|
|
1055
1067
|
modFailed: "未完成:{0}",
|
|
1056
1068
|
idLine: "ID:{0}",
|
|
1057
|
-
modCanvasWorkerOff: "未完成:這個 mod 含有 Canvas Worker
|
|
1069
|
+
modCanvasWorkerOff: "未完成:這個 mod 含有 Canvas Worker 效果,AgEnD 已不再執行這類效果。",
|
|
1058
1070
|
modDownload: "下載",
|
|
1059
1071
|
modUninstall: "解除安裝",
|
|
1060
1072
|
modUninstallConfirm: "要解除安裝 {0} 嗎?它的效果會離開你的效果庫,除非還有東西在使用。它已套用的外觀會保留。",
|
|
@@ -1179,7 +1191,7 @@ register("settings", {
|
|
|
1179
1191
|
grantsLegacy: "目前訪客能看到的,取決於他們在聊天中的權限。儲存授權後改為明確授權:只有下列的人,只看得到勾選的 agent。",
|
|
1180
1192
|
grantsConvert: "以目前的訪客為起點", grantsWithAccess: "有存取權的人", grantsNoneYet: "還沒有人有訪客存取權。",
|
|
1181
1193
|
grantsAdd: "新增人員", grantsSearch: "搜尋曾傳訊息給你的 agent 的人", grantsNoPeople: "沒有符合的人。對方必須先傳過訊息給某個 agent。",
|
|
1182
|
-
grantsChoose: "選擇", grantsChosen: "已選擇", grantsMaySee: "{0} 可以看到:", grantsWroteHere: "傳過訊息", grantsWroteTo: "傳過訊息給:{0}",
|
|
1194
|
+
grantsChoose: "選擇", grantsChosen: "已選擇", grantsMaySee: "{0} 可以看到:", grantsClassicRooms: "ClassicBot 聊天室", grantsWroteHere: "傳過訊息", grantsWroteTo: "傳過訊息給:{0}",
|
|
1183
1195
|
grantsLastSeen: "最後出現 {0}", grantsRecent: "最近的變更", grantsRecentNone: "還沒有人的存取權變更過。", grantsAuditDirect: "立即生效", grantsAuditConfirmed: "在 General 確認後生效", grantsAuditEnded: "結束了 {0} 個登入", grantsAuditCodeSent: "已寄出登入碼", grantsAuditCodeNot: "登入碼未寄出({0})", grantsAuditDmFailed: "私訊沒有送達", grantsAuditWait: "一分鐘內重複要求", grantsAuditAdminLimit: "已達管理員的登入碼上限",
|
|
1184
1196
|
grantsEditAgents: "編輯 agent", grantsRemove: "移除存取權", grantsUndoRemove: "保留存取權",
|
|
1185
1197
|
grantsWillBeRemoved: "儲存後存取權就會結束。", grantsNew: "新增 —— 儲存後授權", grantsNoAgents: "至少勾選一個 agent,或移除這個人。",
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
// lives in this field's state only: never in storage, a URL, a label or the page's other state, and the server never
|
|
5
5
|
// hands it back — afterwards a connection shows "Token set · @bot".
|
|
6
6
|
import { html, useState } from "/assets/app-html.js";
|
|
7
|
-
import { t } from "/assets/app-i18n.js";
|
|
7
|
+
import { t, lang } from "/assets/app-i18n.js";
|
|
8
|
+
import { hostText } from "/assets/setup-host-text.js";
|
|
8
9
|
import { useTypedText } from "/assets/text-undo.js";
|
|
9
10
|
import { Icon } from "/assets/ui-icons.js";
|
|
10
11
|
import { api } from "./settings-confirm.js";
|
|
@@ -24,7 +25,7 @@ export async function verifyBotToken(platform, token) {
|
|
|
24
25
|
.catch(() => ({ ok: false, body: {} }));
|
|
25
26
|
// A Discord bot's invite and portal page come with it (#1519 P3).
|
|
26
27
|
if (res.ok && res.body && res.body.identity) return { ...res.body.identity, invite: res.body.invite_url || null, portal: res.body.portal_url || null };
|
|
27
|
-
return { valid: false, reason: (res.body && res.body.error) || tn("verifyFailed") };
|
|
28
|
+
return { valid: false, reason: hostText(res.body && res.body.error, lang()) || tn("verifyFailed") };
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
/** A bot's name as it is addressed: @name, once. */
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
// to the ordinary Apply: the app's runner (settings-apply.js) posts the apply and watches its job, with the same
|
|
4
4
|
// progress, deadline and restart recovery as every other change.
|
|
5
5
|
import { html, useEffect, useRef, useState } from "/assets/app-html.js";
|
|
6
|
-
import { t } from "/assets/app-i18n.js";
|
|
6
|
+
import { t, lang } from "/assets/app-i18n.js";
|
|
7
|
+
import { hostText } from "/assets/setup-host-text.js";
|
|
7
8
|
import { useTypedText } from "/assets/text-undo.js";
|
|
8
9
|
import { useLease } from "/assets/app-ctx.js";
|
|
9
10
|
import { Dialog } from "/assets/ui-dialog.js";
|
|
@@ -16,6 +17,8 @@ import { DiscordServerPicker } from "./settings-discord.js";
|
|
|
16
17
|
|
|
17
18
|
const tn = (k, ...v) => t(`settings.${k}`, ...v);
|
|
18
19
|
const STEPS = 4;
|
|
20
|
+
// #2726: the host's words (English) or code, in the page's language.
|
|
21
|
+
const said = (text) => hostText(text, lang());
|
|
19
22
|
const post = (path, body) => api(path, { method: "POST", body: JSON.stringify(body) }).catch(() => ({ ok: false, status: 0, body: { error: tn("failed") } }));
|
|
20
23
|
|
|
21
24
|
export function SetupWizard({ ctx, onClose }) {
|
|
@@ -41,7 +44,11 @@ export function SetupWizard({ ctx, onClose }) {
|
|
|
41
44
|
const agents = Array.isArray(e.agents) ? e.agents : [];
|
|
42
45
|
const names = new Set(agents.map((a) => a.name));
|
|
43
46
|
let n = 1; while (names.has(`agent-${n}`)) n++;
|
|
44
|
-
|
|
47
|
+
// M-2069: on a fleet with no chat connection and no General, the new agent is the General — named "general" (unless
|
|
48
|
+
// an agent has that name already: #2744 review).
|
|
49
|
+
const general = !!e.first_general && !names.has("general");
|
|
50
|
+
setW({ step: 1, env: e, backend: (e.backends || [])[0] || "claude-code", working_directory: "", instance_name: general ? "general" : `agent-${n}`,
|
|
51
|
+
general, defaultName: `agent-${n}`, nameTyped: false,
|
|
45
52
|
agent: agents.length ? "existing" : "new", existing_name: agents.length ? agents[0].name : "",
|
|
46
53
|
platform: "telegram", token: "", group_id: "", guild_id: "", general_channel_id: "", admin_user_id: "",
|
|
47
54
|
identity: null, guilds: [], plan: null, offset: 0 });
|
|
@@ -51,6 +58,11 @@ export function SetupWizard({ ctx, onClose }) {
|
|
|
51
58
|
// Every field the plan or a probe is about moves the revision (#1529 review r2): a plan or Detect that began before an
|
|
52
59
|
// edit — target, admin, backend, directory, name — is dropped when it lands, never committed or written over the edit.
|
|
53
60
|
const set = (k) => (v) => { bump(); setW((x) => ({ ...x, [k]: v })); };
|
|
61
|
+
// #2744 review: the General works in its own folder — a typed directory makes the new agent a worker, so a name not
|
|
62
|
+
// typed by hand goes back to agent-N (and "general" again once the directory is cleared).
|
|
63
|
+
const asGeneral = (x) => x.general && !x.working_directory;
|
|
64
|
+
const setDir = (v) => { bump(); setW((x) => { const next = { ...x, working_directory: v };
|
|
65
|
+
return x.nameTyped ? next : { ...next, instance_name: asGeneral(next) ? "general" : x.defaultName }; }); };
|
|
54
66
|
// No token env: the plan generates one (#1519 P1: AGEND_<PLATFORM>_<ID>_TOKEN, unique) and the commit carries the plan's.
|
|
55
67
|
// An existing agent (#1519 P7) is named and nothing else: the server keeps its directory and backend.
|
|
56
68
|
const input = () => ({
|
|
@@ -83,14 +95,15 @@ export function SetupWizard({ ctx, onClose }) {
|
|
|
83
95
|
if (!lease.current()) return;
|
|
84
96
|
if (rev.current !== at) { setBusy(""); return; }
|
|
85
97
|
setBusy("");
|
|
86
|
-
if (!res.ok) { setErr((res.body && res.body.error) || tn("applyFailed")); return; }
|
|
98
|
+
if (!res.ok) { setErr(said(res.body && res.body.error) || tn("applyFailed")); return; }
|
|
87
99
|
if (res.body.found) setW((x) => ({ ...x, offset: res.body.offset, group_id: String(res.body.found.groupId), admin_user_id: String(res.body.found.userId) }));
|
|
88
100
|
else { setW((x) => ({ ...x, offset: res.body.offset })); setErr(tn("wizardNoStartYet")); }
|
|
89
101
|
};
|
|
90
102
|
const next = async () => {
|
|
91
103
|
setErr("");
|
|
92
104
|
if (w.step === 1) {
|
|
93
|
-
|
|
105
|
+
// #2726: none is the agent's own workspace (the server fills it in); one that is given is absolute.
|
|
106
|
+
if (w.agent !== "existing" && w.working_directory && !w.working_directory.startsWith("/")) { setErr(tn("wizardNeedDir")); return; }
|
|
94
107
|
setW({ ...w, step: 2 }); return;
|
|
95
108
|
}
|
|
96
109
|
if (w.step === 2) { setW({ ...w, step: 3 }); return; }
|
|
@@ -104,7 +117,7 @@ export function SetupWizard({ ctx, onClose }) {
|
|
|
104
117
|
if (!lease.current()) return;
|
|
105
118
|
setBusy("");
|
|
106
119
|
if (rev.current !== at) return;
|
|
107
|
-
if (!res.ok) { setErr((res.body && res.body.error) || tn("applyFailed")); return; }
|
|
120
|
+
if (!res.ok) { setErr(said(res.body && res.body.error) || tn("applyFailed")); return; }
|
|
108
121
|
setW((x) => ({ ...x, plan: res.body, step: 4 }));
|
|
109
122
|
return;
|
|
110
123
|
}
|
|
@@ -140,8 +153,10 @@ export function SetupWizard({ ctx, onClose }) {
|
|
|
140
153
|
<p class="note">${tn("wizardAgentExistingNote")}</p></div>` : html`${which}<div class="field"><label for="wz-be">${tn("wizardBackend")}</label>
|
|
141
154
|
<${Select} id="wz-be" value=${w.backend} onChange=${set("backend")} options=${w.env.backends && w.env.backends.length ? w.env.backends : BACKENDS} />
|
|
142
155
|
<p class="note">${w.env.backends && w.env.backends.length ? tn("wizardBackendFound", w.env.backends.join(", ")) : tn("wizardBackendNone")}</p></div>
|
|
143
|
-
<div class="field"><label for="wz-wd">${tn("
|
|
144
|
-
|
|
156
|
+
<div class="field"><label for="wz-wd">${tn("wizardDir")}</label><input id="wz-wd" type="text" placeholder="/home/you/projects/app" aria-describedby="wz-wd-note" value=${dirText} onInput=${(e) => setDir(onDirText(e.target.value))} />
|
|
157
|
+
<p class="note" id="wz-wd-note">${w.env.workspaces_dir && w.instance_name ? tn("wizardDirDefault", `${w.env.workspaces_dir}/${w.instance_name}`) : tn("wizardDirDefaultName")}</p></div>
|
|
158
|
+
<div class="field"><label for="wz-name">${agents.length ? tn("wizardAgentNewName") : tn("wizardAgentName")}</label><input id="wz-name" type="text" value=${nameText} onInput=${(e) => { const v = onNameText(e.target.value); bump(); setW((x) => ({ ...x, instance_name: v, nameTyped: true })); }} />
|
|
159
|
+
${asGeneral(w) ? html`<p class="note">${tn("wizardGeneralNote")}</p>` : null}</div>`;
|
|
145
160
|
} else if (w.step === 2) {
|
|
146
161
|
body = html`<div class="seg-inline" role="group" aria-label=${tn("wizardPlatform")}>
|
|
147
162
|
${["telegram", "discord"].map((p) => html`<button key=${p} type="button" class=${`btn${w.platform === p ? " btn-primary" : ""}`} aria-pressed=${w.platform === p ? "true" : "false"}
|
|
@@ -164,12 +179,13 @@ export function SetupWizard({ ctx, onClose }) {
|
|
|
164
179
|
body = !w.plan ? html`<p class="note">${tn("wizardPlanLoading")}</p>` : html`
|
|
165
180
|
<p><strong>${tn("wizardWillWrite")}</strong></p>
|
|
166
181
|
<pre class="s-yaml">${toYaml({ channels: [w.plan.channel], instances: { [w.plan.instance.name]: { working_directory: w.plan.instance.working_directory, backend: w.plan.instance.backend, channel_id: w.plan.instance.channel_id,
|
|
167
|
-
...(w.plan.instance.topic && w.plan.instance.topic.to != null ? { topic_id: w.plan.instance.topic.to } : {})
|
|
182
|
+
...(w.plan.instance.topic && w.plan.instance.topic.to != null ? { topic_id: w.plan.instance.topic.to } : {}),
|
|
183
|
+
...(w.plan.instance.general ? { general_topic: true, ...(w.plan.instance.general.topic_id != null ? { topic_id: w.plan.instance.general.topic_id } : {}) } : {}) } } })}</pre>
|
|
168
184
|
${w.plan.instance && w.plan.instance.existing ? html`<p class="note">${tn("wizardAgentExistingNote")}</p>` : null}
|
|
169
185
|
${w.plan.instance && w.plan.instance.topic ? html`<p class="feedback warning">${w.plan.instance.topic.to == null
|
|
170
186
|
? tn("wizardTopicNotCarried", w.plan.instance.topic.from) : tn("wizardTopicGeneral")}</p>` : null}
|
|
171
187
|
<${Drawer} title=${tn("advancedSection")}><${TokenEnvNote} name=${w.plan.token_env} /></${Drawer}>
|
|
172
|
-
${(w.plan.warnings || []).map((x, i) => html`<p key=${i} class="feedback warning">${x}</p>`)}`;
|
|
188
|
+
${(w.plan.warnings || []).map((x, i) => html`<p key=${i} class="feedback warning">${said(x)}</p>`)}`;
|
|
173
189
|
}
|
|
174
190
|
return html`<${Dialog} title=${tn("wizardTitle")} onClose=${onClose} wide=${true} busy=${busy === tn("wizardCommitting")}
|
|
175
191
|
actions=${html`<button type="button" class="btn" disabled=${w.step === 1 || !!busy} onClick=${() => setW({ ...w, step: w.step - 1 })}>${tn("wizardBack")}</button>
|
|
@@ -105,7 +105,7 @@ register("app", {
|
|
|
105
105
|
confirmTitle: "Please confirm", confirmOk: "Continue", cancel: "Cancel",
|
|
106
106
|
sidePanelLeave: "Leave {0} without saving? Your changes there will be lost.", sidePanelDiscard: "Discard changes",
|
|
107
107
|
// The server's own wording (src/locale.ts needs.reason.*), so the web says what Discord says.
|
|
108
|
-
needs_reason_hang: "Not responding", needs_reason_exited: "Exited", needs_reason_assist: "Waiting at its terminal", needs_reason_permission: "Permission needed", needs_reason_dangerous_command: "Dangerous command waiting", needs_reason_login: "Sign-in needed", needs_reason_dialog: "Waiting at a dialog", needs_reason_terminal_input: "May be waiting for input", needs_reason_auth_paused: "Paused: sign-in needed", needs_reason_backend_signin: "Backend sign-in needed", needs_reason_crashed: "Crashed", needs_reason_delivery_uncertain: "Could not confirm delivery", needs_reason_delivery_failed: "Delivery failed", needs_reason_task_review: "Waiting for your confirmation", needs_reason_task_blocked: "Blocked: asks you",
|
|
108
|
+
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_crashed: "Crashed", needs_reason_delivery_uncertain: "Could not confirm delivery", needs_reason_delivery_failed: "Delivery failed", needs_reason_task_review: "Waiting for your confirmation", needs_reason_task_blocked: "Blocked: asks you",
|
|
109
109
|
},
|
|
110
110
|
"zh-TW": {
|
|
111
111
|
brand: "AgEnD", fleet: "Fleet", fleetOverview: "Fleet 概覽", view: "檢視", settings: "設定", instances: "Instances", newInstance: "新增 instance", newAgent: "新增 Agent",
|
|
@@ -145,6 +145,6 @@ register("app", {
|
|
|
145
145
|
search: "搜尋", searchTitle: "搜尋聊天、agent 之間的訊息與任務({0})",
|
|
146
146
|
confirmTitle: "請確認", confirmOk: "繼續", cancel: "取消",
|
|
147
147
|
sidePanelLeave: "不儲存就離開「{0}」?你在那裡的修改會遺失。", sidePanelDiscard: "捨棄修改",
|
|
148
|
-
needs_reason_hang: "沒有回應", needs_reason_exited: "已結束", needs_reason_assist: "在終端機上等待", needs_reason_permission: "需要權限", needs_reason_dangerous_command: "危險指令待確認", needs_reason_login: "需要登入", needs_reason_dialog: "停在對話框", needs_reason_terminal_input: "可能在等輸入", needs_reason_auth_paused: "已暫停:需要登入", needs_reason_backend_signin: "後端需要登入", needs_reason_crashed: "已崩潰", needs_reason_delivery_uncertain: "無法確認是否送達", needs_reason_delivery_failed: "傳送失敗", needs_reason_task_review: "等你確認", needs_reason_task_blocked: "卡住,在問你",
|
|
148
|
+
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_crashed: "已崩潰", needs_reason_delivery_uncertain: "無法確認是否送達", needs_reason_delivery_failed: "傳送失敗", needs_reason_task_review: "等你確認", needs_reason_task_blocked: "卡住,在問你",
|
|
149
149
|
},
|
|
150
150
|
});
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
// offices — the stored offices changed ({ rev }; SSE only: the Office view reads /ui/offices again).
|
|
38
38
|
// office_skins — a skin pack was uploaded or deleted ({ rev }; SSE only: the Office view reads /ui/office-skins again).
|
|
39
39
|
// office_acts — the agents' live acts in the Office view changed ({ acts }, #2578; a poll page reads /ui/office-acts).
|
|
40
|
-
const EVENTS = ["status", "message", "agent_reply_live", "delivery", "deliveries", "prompt", "prompts", "prompt_resolved", "activity", "needs", "reply_buttons", "reactions", "steps_tick", "clock", "traffic", "delegation", "backend_login", "tasks", "offices", "office_skins", "office_acts"];
|
|
40
|
+
const EVENTS = ["status", "message", "agent_reply_live", "delivery", "deliveries", "prompt", "prompts", "prompt_resolved", "activity", "needs", "reply_buttons", "reactions", "steps_tick", "clock", "traffic", "delegation", "backend_login", "tasks", "offices", "office_skins", "office_acts", "office_pack_changes"];
|
|
41
41
|
const MAX_HELD = 1000; // live events held during one catch-up read; more → read again afterwards
|
|
42
42
|
const RETRY_DELAYS = [1000, 2000, 4000]; // after the first failed catch-up read; then it waits for Retry
|
|
43
43
|
const POLL_LIMIT_MS = 10000; // a poll that has not answered by then counts as failed
|
package/dist/ui/shared/app.css
CHANGED
|
@@ -873,6 +873,9 @@ img.amb-p { object-fit: contain; }
|
|
|
873
873
|
.st-link:hover { text-decoration-thickness: 2px; }
|
|
874
874
|
.prompt .acts { display: flex; gap: var(--s-2); margin-top: var(--s-2); align-items: center; flex-wrap: wrap; }
|
|
875
875
|
.prompt .wait { font-size: var(--fs-xs); color: var(--text-3); }
|
|
876
|
+
/* #2675: a prompt's typed answer. 16px keeps iOS from zooming in on focus (#1612). */
|
|
877
|
+
.prompt .prompt-text { display: flex; gap: var(--s-2); margin-top: var(--s-2); }
|
|
878
|
+
.prompt .prompt-text input { flex: 1; min-width: 0; font-size: 16px; }
|
|
876
879
|
.work-bar { display: flex; gap: var(--s-2); align-items: center; padding: 0 var(--s-2); font-size: var(--fs-sm); color: var(--text-2); }
|
|
877
880
|
.work-bar .lbl { flex: 1; min-width: 0; }
|
|
878
881
|
.work-bar .pulse { width: 8px; height: 8px; border-radius: 50%; background: var(--ok); animation: pulse 1.2s ease-in-out infinite; flex-shrink: 0; }
|
|
@@ -931,6 +934,8 @@ img.amb-p { object-fit: contain; }
|
|
|
931
934
|
.s-guests .guest-names { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 2px var(--s-3); max-height: 220px; overflow: auto;
|
|
932
935
|
padding: var(--s-1) 0; border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); }
|
|
933
936
|
.s-guests .guest-name span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
937
|
+
/* #2667: the ClassicBot rooms follow the fleet's instances under their own heading, across the grid. */
|
|
938
|
+
.s-guests .guest-names-group { grid-column: 1 / -1; margin-top: var(--s-2); }
|
|
934
939
|
.s-guests .guest-list, .s-guests .g-pick { list-style: none; margin: 0 0 var(--s-3); padding: 0; display: flex; flex-direction: column; border-top: 1px solid var(--border); }
|
|
935
940
|
.s-guests .guest-row, .s-guests .g-cand { padding: var(--s-3) 0; border-bottom: 1px solid var(--border); min-width: 0; }
|
|
936
941
|
.s-guests .guest-row.s-dirty { border-radius: 0; margin-left: 0; align-self: stretch; padding-left: calc(var(--s-2) + 3px); padding-right: var(--s-2); }
|
|
@@ -1793,6 +1798,8 @@ strong.org-name { font-size: var(--fs-sm); color: var(--text); }
|
|
|
1793
1798
|
.oo-zoom .oo-fill { font-size: 11px; font-weight: var(--fw-semibold); }
|
|
1794
1799
|
.oo-zoom .oo-fill.on { background: var(--accent-dim); color: var(--text); }
|
|
1795
1800
|
.oo-stage.editing .oo-mini { display: none; }
|
|
1801
|
+
/* #2737: a single office all in view (the page sets data-whole): the overview would repeat the panel. */
|
|
1802
|
+
.oo-mini[data-whole] { display: none; }
|
|
1796
1803
|
.oo-mini-scene { fill: var(--bg); }
|
|
1797
1804
|
.oo-mini-room { fill: var(--surface); stroke: var(--border-strong); stroke-width: 6; }
|
|
1798
1805
|
.oo-mini-dot { fill: var(--text-3); }
|
|
@@ -1802,6 +1809,47 @@ strong.org-name { font-size: var(--fs-sm); color: var(--text); }
|
|
|
1802
1809
|
.oo-mini-dot.match { fill: var(--focus); }
|
|
1803
1810
|
.oo-tip { position: absolute; left: 0; top: 0; z-index: 5; max-width: 240px; pointer-events: none; padding: 6px 10px; font-size: var(--fs-xs); line-height: 1.4;
|
|
1804
1811
|
color: var(--text); background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-md); box-shadow: var(--shadow-2); overflow-wrap: anywhere; }
|
|
1812
|
+
/* #2661: a person's profile card — a popover beside them (placed by the page: transform through the CSSOM), 320 px fixed;
|
|
1813
|
+
on a phone a bottom sheet. Tone over borders; the status tokens for the level's tier. */
|
|
1814
|
+
.oo-card { position: absolute; left: 0; top: 0; z-index: 8; width: 320px; box-sizing: border-box; padding: var(--s-3); font-size: var(--fs-sm); line-height: var(--lh-sm);
|
|
1815
|
+
color: var(--text); background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-lg); box-shadow: var(--shadow-2); }
|
|
1816
|
+
.oo-card.sheet { position: fixed; left: 0; right: 0; top: auto; bottom: 0; width: auto; transform: none; z-index: 40; border-radius: var(--r-lg) var(--r-lg) 0 0;
|
|
1817
|
+
padding-bottom: calc(var(--s-3) + env(safe-area-inset-bottom, 0px)); touch-action: none; }
|
|
1818
|
+
/* On a phone the tab bar is fixed at the window's foot (z 35): the sheet sits above it. */
|
|
1819
|
+
@media (max-width: 899px) {
|
|
1820
|
+
.oo-card.sheet { bottom: calc(56px + env(safe-area-inset-bottom, 0px)); padding-bottom: var(--s-3); }
|
|
1821
|
+
.kb-open .oo-card.sheet { bottom: 0; }
|
|
1822
|
+
}
|
|
1823
|
+
.oo-card-grip { width: 36px; height: 4px; margin: 0 auto var(--s-2); border-radius: var(--r-full); background: var(--surface-2); }
|
|
1824
|
+
.oo-card-head { display: flex; gap: var(--s-3); align-items: flex-start; }
|
|
1825
|
+
.oo-card-avatar { position: relative; flex: none; width: 56px; height: 56px; border-radius: var(--r-md); background: var(--surface-2); }
|
|
1826
|
+
.oo-card-avatar canvas { width: 56px; height: 56px; image-rendering: pixelated; }
|
|
1827
|
+
.oo-card-avatar .oo-badge { position: absolute; left: -6px; top: -6px; }
|
|
1828
|
+
.oo-card-names { flex: 1; min-width: 0; }
|
|
1829
|
+
.oo-card-name { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
1830
|
+
/* One line, cut; a fixed line height so a CJK fallback in the mono stack doesn't make it taller. */
|
|
1831
|
+
.oo-card-instance { height: 18px; line-height: 18px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--fs-xs); color: var(--text-2); }
|
|
1832
|
+
.oo-card-state { color: var(--text-2); }
|
|
1833
|
+
.oo-card-close { flex: none; margin: -4px -4px 0 0; }
|
|
1834
|
+
.oo-card-xp { margin-top: var(--s-3); }
|
|
1835
|
+
.oo-card-bar { display: block; width: 100%; height: 6px; margin-top: var(--s-1); appearance: none; border: 0; border-radius: var(--r-full); background: var(--surface-2); overflow: hidden; }
|
|
1836
|
+
.oo-card-bar::-webkit-progress-bar { background: var(--surface-2); border-radius: var(--r-full); }
|
|
1837
|
+
.oo-card-bar::-webkit-progress-value { background: var(--accent); border-radius: var(--r-full); }
|
|
1838
|
+
.oo-card-bar::-moz-progress-bar { background: var(--accent); border-radius: var(--r-full); }
|
|
1839
|
+
.oo-card-rows { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s-2) var(--s-3); margin: var(--s-3) 0 0; }
|
|
1840
|
+
.oo-card-rows > div { min-width: 0; }
|
|
1841
|
+
.oo-card-rows dt { font-size: var(--fs-xs); color: var(--text-3); }
|
|
1842
|
+
.oo-card-rows dd { margin: 0; overflow-wrap: anywhere; }
|
|
1843
|
+
.oo-card-now { margin-top: var(--s-3); overflow-wrap: anywhere; }
|
|
1844
|
+
.oo-card-actions { display: flex; justify-content: flex-end; gap: var(--s-2); margin-top: var(--s-3); }
|
|
1845
|
+
.oo-badge { display: inline-block; min-width: 18px; padding: 0 4px; box-sizing: border-box; font-size: 10px; font-weight: var(--fw-semibold); line-height: 16px; text-align: center;
|
|
1846
|
+
border-radius: var(--r-sm); border: 1px solid var(--border); background: var(--surface-2); color: var(--text-2); }
|
|
1847
|
+
.oo-badge.mark { min-width: 10px; width: 10px; height: 10px; padding: 0; transform: rotate(45deg); border-radius: 2px; }
|
|
1848
|
+
.oo-badge.tier-1 { background: var(--ok-bg); color: var(--ok); border-color: var(--ok); }
|
|
1849
|
+
.oo-badge.tier-2 { background: var(--accent-dim); color: var(--accent); border-color: var(--accent); }
|
|
1850
|
+
.oo-badge.tier-3 { background: var(--accent); color: var(--surface); border-color: var(--accent); }
|
|
1851
|
+
.oo-badge.tier-4 { background: var(--warn-bg); color: var(--warn); border-color: var(--warn); }
|
|
1852
|
+
.oo-badge.tier-5 { background: var(--danger-bg); color: var(--danger); border-color: var(--danger); }
|
|
1805
1853
|
/* #2554: All offices — each tile's label (office name and head count) just above the tile, placed by the page (left, top,
|
|
1806
1854
|
max-width through the CSSOM); a button that opens the office, the lobby's a plain chip. */
|
|
1807
1855
|
.oo-tile-label { position: absolute; left: 0; top: 0; z-index: 3; transform: translateY(calc(-100% - 4px)); max-width: 240px; overflow: hidden; text-overflow: ellipsis;
|
|
@@ -1846,10 +1894,18 @@ html.oo-immersive .p-fleet > .panel-body { z-index: 50; }
|
|
|
1846
1894
|
.ol-seat > circle { fill: var(--ok); }
|
|
1847
1895
|
.ol-furniture > rect { fill: var(--warn); }
|
|
1848
1896
|
.ol-door > rect { fill: var(--danger); }
|
|
1897
|
+
/* #2736: the mail drop — an envelope; dashed while it is the automatic spot (the pack names none). */
|
|
1898
|
+
.ol-mail > rect { fill: var(--accent-dim); }
|
|
1899
|
+
.ol-mail > .ol-flap { fill: none; stroke: var(--text); stroke-width: 1.5; pointer-events: none; }
|
|
1900
|
+
.ol-mail.auto > rect { stroke-dasharray: 3 2; fill-opacity: 0.6; }
|
|
1849
1901
|
/* #2665: an item's night place — a moon on a faint disc, a thin dashed line to its day place. */
|
|
1850
1902
|
.ol-night > circle { fill: var(--surface); fill-opacity: 0.85; }
|
|
1851
1903
|
.ol-night > .ol-moon { fill: var(--warn); stroke: none; pointer-events: none; }
|
|
1852
1904
|
.ol-night-line { stroke: var(--warn); stroke-width: 1.5; stroke-dasharray: 4 3; stroke-opacity: 0.8; pointer-events: none; }
|
|
1905
|
+
/* #2691: a reserved seat — a dashed ring round its dot; the selected seat's "Reserved for" picks. */
|
|
1906
|
+
.ol-seat > .ol-for-ring { fill: none; stroke: var(--warn); stroke-width: 2; stroke-dasharray: 3 3; pointer-events: none; }
|
|
1907
|
+
.ol-for { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 4px var(--s-2); }
|
|
1908
|
+
.ol-for > legend { float: left; margin-right: var(--s-2); }
|
|
1853
1909
|
.ol-waypoint > circle { fill: var(--focus); }
|
|
1854
1910
|
.ol-handle.on > circle, .ol-handle.on > rect, .ol-handle:focus-visible > circle, .ol-handle:focus-visible > rect { stroke: var(--focus); stroke-width: 4; }
|
|
1855
1911
|
.ol-bar { position: absolute; left: 0; right: 0; bottom: 0; z-index: 8; display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2); padding: var(--s-2);
|
|
@@ -1861,14 +1917,23 @@ html.oo-immersive .p-fleet > .panel-body { z-index: 50; }
|
|
|
1861
1917
|
.ol-corridors { display: inline-flex; flex-wrap: wrap; gap: 4px; }
|
|
1862
1918
|
.ol-msg { flex-basis: 100%; margin: 0; }
|
|
1863
1919
|
@media (max-width: 640px) {
|
|
1864
|
-
/* A phone: the bars at the column's narrower padding;
|
|
1920
|
+
/* A phone: the bars at the column's narrower padding; no overview (as the canvas). #2689: the stage takes the panel's
|
|
1921
|
+
height that is left under the bars (the column, .oc-office and .oo grow into it) and no more, so zoomed in the
|
|
1922
|
+
scene's bottom is on screen: a floor fixed to the window (100dvh less a guess at the bars) put it under the tab bar
|
|
1923
|
+
once the bars wrapped. Its own floor is low enough for a 375 × 667 phone with the Office bar on five rows (215 px
|
|
1924
|
+
left); only a shorter screen scrolls the panel (on the bars: the stage's touches are its own). */
|
|
1865
1925
|
.oc-office > .oc-bar { padding: var(--s-2) var(--s-3); }
|
|
1866
1926
|
.oc-office > .oc-legend { margin: 0 var(--s-3) var(--s-2); }
|
|
1867
1927
|
.oo > :not(.oo-stage):not(dialog) { margin-left: var(--s-3); margin-right: var(--s-3); }
|
|
1868
|
-
.oo-stage { min-height:
|
|
1928
|
+
.oo-stage { min-height: 200px; }
|
|
1869
1929
|
.oo-pick .tb-select { max-width: 150px; }
|
|
1870
1930
|
.oo-mini { display: none; }
|
|
1871
1931
|
.oo-zoom .icon-btn { width: 40px; height: 40px; }
|
|
1932
|
+
/* #2689: a column of the label and five 40 px buttons (~240 px) is taller than that stage: a row along its top
|
|
1933
|
+
instead, out of fullscreen (there the stage is the screen, and the office switcher is on the left of its top). */
|
|
1934
|
+
.oo:not(.fs) .oo-zoom { flex-direction: row; }
|
|
1935
|
+
.oo:not(.fs) .oo-zoom-pct { display: flex; align-items: center; padding: 0 6px; border-bottom: 0; border-right: 1px solid var(--border); }
|
|
1936
|
+
.oo:not(.fs) .oo-zoom .icon-btn + .icon-btn { border-top: 0; border-left: 1px solid var(--border); }
|
|
1872
1937
|
}
|
|
1873
1938
|
/* A phone: Fleet's five tabs fit when only the open one shows its label (the others keep theirs for screen readers). */
|
|
1874
1939
|
@media (max-width: 479px) {
|
|
@@ -2368,6 +2433,9 @@ html.oo-immersive .p-fleet > .panel-body { z-index: 50; }
|
|
|
2368
2433
|
.tb-tile-note { display: flex; gap: var(--s-1); align-items: flex-start; font-size: var(--fs-xs); color: var(--text-2); overflow-wrap: anywhere; }
|
|
2369
2434
|
/* A main task's sub task at work now (its worker in the foot), and what a card waiting for you still lacks. */
|
|
2370
2435
|
.tb-tile-now { display: flex; align-items: baseline; gap: var(--s-1); min-width: 0; font-size: var(--fs-xs); color: var(--text-2); }
|
|
2436
|
+
/* #2080: whom a card in review waits for — the person (accented), or the agent that confirms it. */
|
|
2437
|
+
.tb-tile-waits { font-size: var(--fs-xs); color: var(--text-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
2438
|
+
.tb-tile-waits.you { color: var(--text); font-weight: var(--fw-semibold); }
|
|
2371
2439
|
.tb-now-title { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
2372
2440
|
.tb-now-label { flex-shrink: 0; font-size: 11px; font-weight: var(--fw-semibold); color: var(--text-2); }
|
|
2373
2441
|
.tb-now-label.st-claimed { color: var(--accent); }
|