@monster-orange/den 0.4.17 → 0.4.19
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/CHANGELOG.md +177 -0
- package/README.md +14 -13
- package/docs/distributions.md +138 -25
- package/docs/reference.md +1 -1
- package/package.json +2 -1
- package/skills/install-den/SKILL.md +35 -75
- package/src/shared/agents/den-claude.ts +40 -6
- package/src/shared/agents/guardrails/stop-hook.ts +30 -4
- package/src/shared/agents/guardrails.ts +40 -4
- package/src/shared/agents/handback.ts +22 -4
- package/src/shared/agents/personas.ts +32 -5
- package/src/shared/agents/runtime.ts +8 -0
- package/src/shared/agents/server-agent.ts +57 -0
- package/src/shared/agents/server-pack/server.md +45 -0
- package/src/shared/environment-manager/workspaces.ts +4 -0
- package/src/ui/cli/agent-ops.ts +84 -6
- package/src/ui/cli/create.ts +2 -2
- package/src/ui/cli/index.ts +1 -1
- package/src/ui/cli/repo-command.ts +8 -1
- package/src/ui/cli/repo-detect.ts +58 -0
- package/src/ui/cli/server-agent-ops.ts +411 -0
- package/src/ui/mcp/server.ts +29 -12
- package/src/ui/mcp/tools.ts +4 -2
- package/src/ui/server/agent-routes.ts +10 -1
- package/src/ui/server/held-actions.ts +35 -7
- package/src/ui/server/index.ts +20 -5
- package/src/ui/server/public/agents-page.js +33 -1
- package/src/ui/server/public/agents.html +13 -0
- package/src/ui/server/public/error-page.js +39 -1
- package/src/ui/server/public/graph.css +43 -0
- package/src/ui/server/public/graph.js +68 -1
- package/src/ui/server/public/header.js +36 -7
- package/src/ui/server/public/i18n/es.js +72 -0
- package/src/ui/server/public/i18n/ja.js +74 -0
- package/src/ui/server/public/local-dev.html +33 -3
- package/src/ui/server/public/log-source.js +26 -0
- package/src/ui/server/public/logs.html +7 -20
- package/src/ui/server/public/persona-ui.css +6 -0
- package/src/ui/server/public/server-agent-page.js +415 -0
- package/src/ui/server/public/server-agent.html +222 -0
- package/src/ui/server/public/services.html +18 -3
- package/src/ui/server/public/shell.js +274 -31
- package/src/ui/server/public/svc-panel.js +685 -0
- package/src/ui/server/public/topbar.js +13 -1
- package/src/ui/server/route-classes.ts +21 -0
- package/src/ui/server/server-agent-routes.ts +176 -0
- package/src/ui/server/session-routes.ts +12 -1
- package/src/ui/server/ui-assets.ts +6 -0
- package/src/ui/server/workspace-routes.ts +3 -0
|
@@ -169,6 +169,43 @@
|
|
|
169
169
|
"act.unpinX": "Unpin {s}",
|
|
170
170
|
"toast.pinned": "Pinned {s}",
|
|
171
171
|
"toast.unpinned": "Unpinned {s}",
|
|
172
|
+
// 0.4.18: the service panel (svc-panel.js) and Start's Folder.
|
|
173
|
+
"svp.label": "{s}: quick panel",
|
|
174
|
+
"svp.more": "Quick panel for {s}",
|
|
175
|
+
"svp.notRunning": "Not running",
|
|
176
|
+
"svp.up": "up {d}",
|
|
177
|
+
"svp.upNow": "up",
|
|
178
|
+
"svp.down": "down: {c}",
|
|
179
|
+
"svp.downNone": "down",
|
|
180
|
+
"svp.starting": "starting…",
|
|
181
|
+
"svp.stopped": "stopped",
|
|
182
|
+
"svp.noUrl": "No URL",
|
|
183
|
+
"svp.start": "Start",
|
|
184
|
+
"svp.stop": "Stop",
|
|
185
|
+
"svp.restart": "Restart",
|
|
186
|
+
"svp.logs": "Logs",
|
|
187
|
+
"svp.stopping": "Stopping {s}",
|
|
188
|
+
"svp.tests": "Last test run",
|
|
189
|
+
"svp.testsOk": "✓ {t}",
|
|
190
|
+
"svp.testsBad": "✗ failed {t}",
|
|
191
|
+
"svp.testsRun": "running…",
|
|
192
|
+
"svp.testsNone": "—",
|
|
193
|
+
"svp.runTests": "Run tests",
|
|
194
|
+
"svp.testsDone": "Tests passed: {s}",
|
|
195
|
+
"svp.testsFailed": "Tests failed: {s}",
|
|
196
|
+
"svp.agents": "Agents",
|
|
197
|
+
"svp.noAgents": "No agents in this repo.",
|
|
198
|
+
"svp.open": "Open",
|
|
199
|
+
"svp.openAg": "Open {s}",
|
|
200
|
+
"svp.startHere": "Start agent here",
|
|
201
|
+
"svp.openSvc": "Open in Services",
|
|
202
|
+
"svp.openGraph": "Open in Graph",
|
|
203
|
+
"graph.outside": "{s} is in {ws}, outside this View.",
|
|
204
|
+
"graph.showWs": "Show {ws}",
|
|
205
|
+
"svp.close": "Close",
|
|
206
|
+
"ag.new.folder": "Folder (optional)",
|
|
207
|
+
"ag.new.folderHelp":
|
|
208
|
+
"Inside the workspace's folder. Empty: the workspace's own.",
|
|
172
209
|
collapse: "Collapse",
|
|
173
210
|
expand: "Expand",
|
|
174
211
|
menu: "Menu",
|
|
@@ -393,6 +430,10 @@
|
|
|
393
430
|
"err.signin.step2":
|
|
394
431
|
"This page signs you in by itself once approved. The code expires in 10 minutes.",
|
|
395
432
|
"err.signin.waiting": "Waiting for approval…",
|
|
433
|
+
"err.signin.windowsSteps":
|
|
434
|
+
"Open Windows Terminal or PowerShell, paste this, and press Enter.",
|
|
435
|
+
"err.signin.nothingOpened":
|
|
436
|
+
"Nothing opened? Copy the command below and paste it into your terminal app.",
|
|
396
437
|
"err.signin.noTerminal":
|
|
397
438
|
"Don't have a terminal on {host}? From this computer, run:",
|
|
398
439
|
"err.signin.openTerminal": "Open Terminal",
|
|
@@ -656,6 +697,8 @@
|
|
|
656
697
|
"ap.do.repo_add.new":
|
|
657
698
|
'Add the repo at {path} to a new workspace "{workspace}"',
|
|
658
699
|
"ap.do.service_try": "Start {service}",
|
|
700
|
+
"ap.do.service_try.activates":
|
|
701
|
+
"Start {service} (this activates {workspace})",
|
|
659
702
|
"ap.says": "Agent says:",
|
|
660
703
|
"ap.review": "Review",
|
|
661
704
|
"ap.hide": "Hide details",
|
|
@@ -798,6 +841,34 @@
|
|
|
798
841
|
"ag.ws": "Workspace",
|
|
799
842
|
"ag.pal": "Agents › {ws} / {name}",
|
|
800
843
|
"ag.palStart": "Start agent…",
|
|
844
|
+
// ON-6: the server agent (server-agent-page.js, the rail, ⌘K).
|
|
845
|
+
"n.serverAgent": "__DEN_TITLE__ agent",
|
|
846
|
+
"ag.server": "Server",
|
|
847
|
+
"pal.askServer": "Ask __DEN_TITLE__",
|
|
848
|
+
"sa.sub.fresh":
|
|
849
|
+
"Let's set up __DEN_TITLE__. It reads only until you allow a write.",
|
|
850
|
+
"sa.sub":
|
|
851
|
+
"For anything about this server: add a repo, fix a failing service, change a setting, or explain what's running.",
|
|
852
|
+
"sa.login":
|
|
853
|
+
"If Claude asks you to log in, log in here. Then {name} starts.",
|
|
854
|
+
"sa.trust": "Claude asks whether to trust this folder. Choose Yes.",
|
|
855
|
+
"sa.model": "Model",
|
|
856
|
+
"sa.readsOnly":
|
|
857
|
+
"It acts only through __DEN_TITLE__'s own tools. Each change asks you first, in this browser.",
|
|
858
|
+
"sa.starting": "Starting the agent…",
|
|
859
|
+
"sa.idle": "{name} isn't running.",
|
|
860
|
+
"sa.start": "Start",
|
|
861
|
+
"sa.failed": "It didn't start: {why}. {cli} agents doctor says more.",
|
|
862
|
+
"sa.unread": "Couldn't read the agent's status. Is the web server running?",
|
|
863
|
+
"sa.none.h": "No runtime can run the agent yet",
|
|
864
|
+
"sa.none":
|
|
865
|
+
"The agent runs on an agent CLI from the runtime catalog. Install one, log in to it once, then reload this page.",
|
|
866
|
+
"sa.noTools": "can't use __DEN_TITLE__'s tools yet",
|
|
867
|
+
"sa.manual.h": "Or set it up yourself",
|
|
868
|
+
"sa.manual": "Every step the agent takes is also a command. In a terminal:",
|
|
869
|
+
"sa.runsOn": "Runs on",
|
|
870
|
+
"sa.openAgents": "Open in Agents",
|
|
871
|
+
"sa.saved": "Saved. The agent uses it from its next start.",
|
|
801
872
|
"ag.cap": "Up to 4 panes: {id}'s closed to make room (it keeps running)",
|
|
802
873
|
// AG-4b: the Agents tab's layouts and named tabs.
|
|
803
874
|
"ag.layout": "Layout",
|
|
@@ -918,6 +989,9 @@
|
|
|
918
989
|
agents:
|
|
919
990
|
'<rect x="3" y="5" width="18" height="14" rx="2"/><path d="M7 10l3 2-3 2M12 15h5"/>',
|
|
920
991
|
edge: '<path d="M12 3l8 4v5c0 4.5-3.4 8.3-8 9-4.6-.7-8-4.5-8-9V7z"/><path d="M8 12h8M12 8v8"/>',
|
|
992
|
+
// ON-6: the server agent, a speech bubble with a spark.
|
|
993
|
+
assistant:
|
|
994
|
+
'<path d="M5 5h14a1 1 0 0 1 1 1v9a1 1 0 0 1-1 1h-8l-4 3v-3H5a1 1 0 0 1-1-1V6a1 1 0 0 1 1-1z"/><path d="M12 8v4M10 10h4"/>',
|
|
921
995
|
// SEC-2a: who this browser is (the rail footer's identity chip).
|
|
922
996
|
person:
|
|
923
997
|
'<circle cx="12" cy="8" r="3.5"/><path d="M5 20c.8-3.6 3.6-5.5 7-5.5s6.2 1.9 7 5.5"/>',
|
|
@@ -1214,6 +1288,12 @@
|
|
|
1214
1288
|
// SEC-2a: who this browser is (GET /api/session `identity`): local,
|
|
1215
1289
|
// a signed-in device, or a GitHub login. Null until known.
|
|
1216
1290
|
identity: null,
|
|
1291
|
+
// 0.4.18: each pin's URL (svc-panel.js, from the health feed) for its
|
|
1292
|
+
// Visit ↗, whether that Visit is off (down or starting: the panel's own
|
|
1293
|
+
// live state), and the pin whose service panel is open.
|
|
1294
|
+
pinUrls: {},
|
|
1295
|
+
pinOff: {},
|
|
1296
|
+
svpOpen: null,
|
|
1217
1297
|
};
|
|
1218
1298
|
try {
|
|
1219
1299
|
var cached = JSON.parse(localStorage.getItem(LS) || "{}");
|
|
@@ -1441,6 +1521,31 @@
|
|
|
1441
1521
|
var r = anchor.getBoundingClientRect();
|
|
1442
1522
|
var gap = opts.gap != null ? opts.gap : 4;
|
|
1443
1523
|
el.style.maxHeight = "";
|
|
1524
|
+
// 0.4.18: a bottom sheet is placed by its CSS (bottom: 0), not here.
|
|
1525
|
+
if (opts.sheet) {
|
|
1526
|
+
el.style.removeProperty("top");
|
|
1527
|
+
el.style.removeProperty("left");
|
|
1528
|
+
return;
|
|
1529
|
+
}
|
|
1530
|
+
// 0.4.18: beside the anchor (the rail), level with a row in it.
|
|
1531
|
+
if (opts.side === "right") {
|
|
1532
|
+
var row = typeof opts.row === "function" ? opts.row() : null;
|
|
1533
|
+
var rr = row ? row.getBoundingClientRect() : r;
|
|
1534
|
+
var bw = el.offsetWidth;
|
|
1535
|
+
var bh = el.offsetHeight;
|
|
1536
|
+
var bl = Math.min(r.right + gap, window.innerWidth - bw - TOP_MARGIN);
|
|
1537
|
+
var bt = Math.min(
|
|
1538
|
+
rr.top + (opts.dy || 0),
|
|
1539
|
+
window.innerHeight - bh - TOP_MARGIN,
|
|
1540
|
+
);
|
|
1541
|
+
el.style.setProperty("top", Math.max(TOP_MARGIN, bt) + "px", "important");
|
|
1542
|
+
el.style.setProperty(
|
|
1543
|
+
"left",
|
|
1544
|
+
Math.max(TOP_MARGIN, bl) + "px",
|
|
1545
|
+
"important",
|
|
1546
|
+
);
|
|
1547
|
+
return;
|
|
1548
|
+
}
|
|
1444
1549
|
var w = el.offsetWidth;
|
|
1445
1550
|
var h = el.offsetHeight;
|
|
1446
1551
|
var vw = window.innerWidth;
|
|
@@ -1747,6 +1852,16 @@
|
|
|
1747
1852
|
href: "/agents",
|
|
1748
1853
|
keywords: ["sessions", "terminal"],
|
|
1749
1854
|
},
|
|
1855
|
+
// ON-6: the server agent, this Den's own: one click away, after Agents.
|
|
1856
|
+
{
|
|
1857
|
+
id: "server-agent",
|
|
1858
|
+
label: "n.serverAgent",
|
|
1859
|
+
icon: "assistant",
|
|
1860
|
+
group: "develop",
|
|
1861
|
+
order: 18,
|
|
1862
|
+
href: "/server-agent",
|
|
1863
|
+
keywords: ["server agent", "ask", "setup", "onboarding"],
|
|
1864
|
+
},
|
|
1750
1865
|
{
|
|
1751
1866
|
id: "services",
|
|
1752
1867
|
label: "n.services",
|
|
@@ -1900,11 +2015,16 @@
|
|
|
1900
2015
|
"</div>" +
|
|
1901
2016
|
chips +
|
|
1902
2017
|
"</header>" +
|
|
2018
|
+
// The rail's box: no box of its own (display: contents). As ☰'s
|
|
2019
|
+
// drawer it is the modal dialog the rail sits in, so the rail stays a
|
|
2020
|
+
// nav (a <nav> may not be a dialog).
|
|
2021
|
+
'<div class="den-rail-box" id="den-rail-box">' +
|
|
1903
2022
|
'<nav class="den-rail" id="den-rail" aria-label="' +
|
|
1904
2023
|
esc(t("pages")) +
|
|
1905
|
-
'"></nav>';
|
|
2024
|
+
'"></nav></div>';
|
|
1906
2025
|
|
|
1907
2026
|
var nav = host.querySelector(".den-rail");
|
|
2027
|
+
var railBox = host.querySelector(".den-rail-box");
|
|
1908
2028
|
|
|
1909
2029
|
// ── the scope parts (R4) ───────────────────────────────────────────────
|
|
1910
2030
|
// Each part's menu comes from its model, set by header.js: setOrgs (the
|
|
@@ -2123,6 +2243,47 @@
|
|
|
2123
2243
|
: " off";
|
|
2124
2244
|
return '<span class="den-dot' + cls + '" aria-hidden="true"></span>';
|
|
2125
2245
|
}
|
|
2246
|
+
/**
|
|
2247
|
+
* 0.4.18: a pin's Visit ↗: none without a URL, greyed out while it is
|
|
2248
|
+
* down. Down is the service panel's live state (pinOff), the same as its
|
|
2249
|
+
* dot, so it holds for a pin outside the View too; the rail's rollup
|
|
2250
|
+
* only without it.
|
|
2251
|
+
*/
|
|
2252
|
+
function pinVisit(id) {
|
|
2253
|
+
var url = state.pinUrls && state.pinUrls[id];
|
|
2254
|
+
if (!url) return "";
|
|
2255
|
+
var off = state.pinOff || {};
|
|
2256
|
+
var down = Object.prototype.hasOwnProperty.call(off, id)
|
|
2257
|
+
? !!off[id]
|
|
2258
|
+
: state.health[id] === "down";
|
|
2259
|
+
return (
|
|
2260
|
+
'<button type="button" class="den-pvisit" tabindex="-1" data-visit="' +
|
|
2261
|
+
esc(id) +
|
|
2262
|
+
'" data-url="' +
|
|
2263
|
+
esc(url) +
|
|
2264
|
+
'" aria-label="' +
|
|
2265
|
+
esc(t("act.visitX", { s: id })) +
|
|
2266
|
+
'" title="' +
|
|
2267
|
+
esc(down ? t("svp.notRunning") : url) +
|
|
2268
|
+
'"' +
|
|
2269
|
+
(down ? ' aria-disabled="true"' : "") +
|
|
2270
|
+
'><span aria-hidden="true">↗</span></button>'
|
|
2271
|
+
);
|
|
2272
|
+
}
|
|
2273
|
+
function visitPin(b) {
|
|
2274
|
+
if (b.getAttribute("aria-disabled") === "true") {
|
|
2275
|
+
toast(t("svp.notRunning"));
|
|
2276
|
+
return;
|
|
2277
|
+
}
|
|
2278
|
+
var url = b.getAttribute("data-url");
|
|
2279
|
+
if (url && /^https?:\/\//i.test(url))
|
|
2280
|
+
window.open(url, "_blank", "noopener");
|
|
2281
|
+
}
|
|
2282
|
+
// 0.4.18: the service panel (svc-panel.js registers it).
|
|
2283
|
+
var servicePanel = null;
|
|
2284
|
+
function setServicePanel(p) {
|
|
2285
|
+
servicePanel = p && typeof p.open === "function" ? p : null;
|
|
2286
|
+
}
|
|
2126
2287
|
function pinHref(id) {
|
|
2127
2288
|
var repo = id.split("/")[0];
|
|
2128
2289
|
return "/services#repo-" + encodeURIComponent(repo);
|
|
@@ -2191,9 +2352,12 @@
|
|
|
2191
2352
|
null,
|
|
2192
2353
|
state.pins
|
|
2193
2354
|
.map(function (p) {
|
|
2194
|
-
//
|
|
2195
|
-
//
|
|
2196
|
-
//
|
|
2355
|
+
// 0.4.18: the row (named by the id alone) opens the service's
|
|
2356
|
+
// panel in place (svc-panel.js); it is still the link to
|
|
2357
|
+
// Services, so ⌘-click and middle-click open that in a new
|
|
2358
|
+
// tab. Delete unpins it. Visit ↗ beside it opens the service's
|
|
2359
|
+
// URL, out of the tab order: the panel's first button is the
|
|
2360
|
+
// keyboard's Visit. Unpin is in the panel's footer.
|
|
2197
2361
|
return (
|
|
2198
2362
|
'<div class="den-pin-row">' +
|
|
2199
2363
|
item(
|
|
@@ -2205,17 +2369,17 @@
|
|
|
2205
2369
|
mono: true,
|
|
2206
2370
|
},
|
|
2207
2371
|
false,
|
|
2208
|
-
|
|
2209
|
-
'
|
|
2210
|
-
|
|
2372
|
+
"",
|
|
2373
|
+
' data-pin="' +
|
|
2374
|
+
esc(p) +
|
|
2375
|
+
'" data-svpanel="' +
|
|
2376
|
+
esc(p) +
|
|
2377
|
+
'" aria-haspopup="dialog" aria-expanded="' +
|
|
2378
|
+
(state.svpOpen === p ? "true" : "false") +
|
|
2379
|
+
'" aria-keyshortcuts="Delete"',
|
|
2211
2380
|
) +
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
'" aria-label="' +
|
|
2215
|
-
esc(t("act.unpinX", { s: p })) +
|
|
2216
|
-
'" title="' +
|
|
2217
|
-
esc(t("act.unpin")) +
|
|
2218
|
-
'"><span aria-hidden="true">×</span></button></div>'
|
|
2381
|
+
pinVisit(p) +
|
|
2382
|
+
"</div>"
|
|
2219
2383
|
);
|
|
2220
2384
|
})
|
|
2221
2385
|
.join(""),
|
|
@@ -2423,10 +2587,28 @@
|
|
|
2423
2587
|
});
|
|
2424
2588
|
nav.addEventListener("click", function (e) {
|
|
2425
2589
|
var tgt = e.target;
|
|
2426
|
-
var
|
|
2427
|
-
if (
|
|
2590
|
+
var v = tgt && tgt.closest ? tgt.closest("[data-visit]") : null;
|
|
2591
|
+
if (v) {
|
|
2428
2592
|
e.preventDefault();
|
|
2429
|
-
|
|
2593
|
+
visitPin(v);
|
|
2594
|
+
return;
|
|
2595
|
+
}
|
|
2596
|
+
// 0.4.18: a plain click (or Enter) on a pinned row opens its panel;
|
|
2597
|
+
// ⌘/Ctrl-, Shift- and middle-click keep the link (Services).
|
|
2598
|
+
var sp = tgt && tgt.closest ? tgt.closest("[data-svpanel]") : null;
|
|
2599
|
+
if (
|
|
2600
|
+
sp &&
|
|
2601
|
+
servicePanel &&
|
|
2602
|
+
e.button === 0 &&
|
|
2603
|
+
!e.metaKey &&
|
|
2604
|
+
!e.ctrlKey &&
|
|
2605
|
+
!e.shiftKey &&
|
|
2606
|
+
!e.altKey
|
|
2607
|
+
) {
|
|
2608
|
+
e.preventDefault();
|
|
2609
|
+
servicePanel.open(sp.getAttribute("data-svpanel"), sp, {
|
|
2610
|
+
fromRail: true,
|
|
2611
|
+
});
|
|
2430
2612
|
return;
|
|
2431
2613
|
}
|
|
2432
2614
|
var c = tgt && tgt.closest ? tgt.closest('[data-act="collapse"]') : null;
|
|
@@ -2465,8 +2647,9 @@
|
|
|
2465
2647
|
function openDrawer() {
|
|
2466
2648
|
document.body.classList.add("den-rail-open");
|
|
2467
2649
|
if (menu) menu.setAttribute("aria-expanded", "true");
|
|
2468
|
-
|
|
2469
|
-
|
|
2650
|
+
railBox.setAttribute("role", "dialog");
|
|
2651
|
+
railBox.setAttribute("aria-modal", "true");
|
|
2652
|
+
railBox.setAttribute("aria-label", t("pages"));
|
|
2470
2653
|
if (!scrim) {
|
|
2471
2654
|
scrim = document.createElement("div");
|
|
2472
2655
|
scrim.className = "den-scrim";
|
|
@@ -2486,8 +2669,9 @@
|
|
|
2486
2669
|
if (!drawerOpen()) return;
|
|
2487
2670
|
document.body.classList.remove("den-rail-open");
|
|
2488
2671
|
if (menu) menu.setAttribute("aria-expanded", "false");
|
|
2489
|
-
|
|
2490
|
-
|
|
2672
|
+
railBox.removeAttribute("role");
|
|
2673
|
+
railBox.removeAttribute("aria-modal");
|
|
2674
|
+
railBox.removeAttribute("aria-label");
|
|
2491
2675
|
if (scrim && scrim.remove) scrim.remove();
|
|
2492
2676
|
setInert(false);
|
|
2493
2677
|
if (refocus && menu) menu.focus();
|
|
@@ -4206,7 +4390,10 @@
|
|
|
4206
4390
|
}
|
|
4207
4391
|
function apWhat(a) {
|
|
4208
4392
|
var p = a.params || {};
|
|
4209
|
-
var key =
|
|
4393
|
+
var key =
|
|
4394
|
+
"ap.do." +
|
|
4395
|
+
a.action +
|
|
4396
|
+
(p.isNew ? ".new" : p.activates ? ".activates" : "");
|
|
4210
4397
|
var s = t(key, p);
|
|
4211
4398
|
if (s !== key) return s;
|
|
4212
4399
|
s = String(a.summary || a.action);
|
|
@@ -4523,6 +4710,14 @@
|
|
|
4523
4710
|
* anchor; hide(el). The page hiding it (display: none) closes it too.
|
|
4524
4711
|
*/
|
|
4525
4712
|
topLayer: { show: topShow, hide: topHide },
|
|
4713
|
+
/**
|
|
4714
|
+
* 0.4.18: the service panel. svc-panel.js registers { open, close,
|
|
4715
|
+
* visit }; openServicePanel(id, opener) opens it beside opener.
|
|
4716
|
+
*/
|
|
4717
|
+
setServicePanel: setServicePanel,
|
|
4718
|
+
openServicePanel: function (id, opener) {
|
|
4719
|
+
if (servicePanel) servicePanel.open(id, opener);
|
|
4720
|
+
},
|
|
4526
4721
|
closeMenu: function () {
|
|
4527
4722
|
closeMenu(false);
|
|
4528
4723
|
},
|
|
@@ -4830,6 +5025,7 @@
|
|
|
4830
5025
|
// ◐ ▾ (the prototype's user menu, an .ib: appearance.js)
|
|
4831
5026
|
".den-top .den-ib[aria-expanded='true'] { background: var(--sunken); color: var(--text); }",
|
|
4832
5027
|
// Rail (.rail)
|
|
5028
|
+
".den-rail-box { display: contents; }",
|
|
4833
5029
|
".den-rail { position: fixed; left: 0; top: var(--den-top-h); bottom: 0; width: var(--den-rail-cw);",
|
|
4834
5030
|
" box-sizing: content-box; display: flex; flex-direction: column; padding: 10px 8px;",
|
|
4835
5031
|
" background: var(--surface); border-right: 1px solid var(--border); overflow-y: auto; z-index: 15;",
|
|
@@ -4865,18 +5061,65 @@
|
|
|
4865
5061
|
" display: inline-block; margin: 0 5px; }",
|
|
4866
5062
|
".den-dot.bad { background: var(--bad); } .den-dot.warn { background: var(--warn); }",
|
|
4867
5063
|
".den-dot.off { background: var(--faint); }",
|
|
4868
|
-
|
|
4869
|
-
".den-pin-
|
|
4870
|
-
".den-pin-
|
|
4871
|
-
"
|
|
4872
|
-
"
|
|
4873
|
-
"
|
|
4874
|
-
"
|
|
5064
|
+
// 0.4.18: a pinned row is its name (opens the service panel) and Visit ↗.
|
|
5065
|
+
".den-pin-row { display: flex; align-items: center; gap: 2px; min-width: 0; }",
|
|
5066
|
+
".den-pin-row .den-ni { flex: 1; min-width: 0; }",
|
|
5067
|
+
".den-pin-row .den-ni[aria-expanded='true'] { background: var(--sunken); color: var(--text); }",
|
|
5068
|
+
".den-pvisit { flex: none; width: 26px; height: 26px; padding: 0; display: grid; place-items: center;",
|
|
5069
|
+
" background: none; border: 1px solid transparent; border-radius: var(--radius-button);",
|
|
5070
|
+
" color: var(--muted); cursor: pointer; font: 13px/1 var(--sans); }",
|
|
5071
|
+
".den-pvisit:hover { background: var(--sunken); color: var(--accent-text); border-color: var(--border); }",
|
|
5072
|
+
".den-pvisit[aria-disabled='true'], .den-svp .den-btn[aria-disabled='true'] { opacity: .45; cursor: not-allowed; }",
|
|
5073
|
+
".den-pvisit[aria-disabled='true']:hover { background: none; color: var(--muted); border-color: transparent; }",
|
|
5074
|
+
"body.den-rail-collapsed .den-rail .den-pvisit { display: none; }",
|
|
5075
|
+
"@media (max-width: 720px) { .den-pvisit { width: 32px; height: 32px; }",
|
|
5076
|
+
" body.den-rail-collapsed .den-rail .den-pvisit { display: grid; } }",
|
|
5077
|
+
// The service panel (svc-panel.js): beside its row, a bottom sheet at phone width.
|
|
5078
|
+
".den-pop.den-svp { width: 340px; max-width: calc(100vw - 16px); box-sizing: border-box; padding: 0;",
|
|
5079
|
+
" max-height: calc(100dvh - 16px); overflow-y: auto; min-width: 0; }",
|
|
5080
|
+
".den-svp-h { display: grid; gap: 4px; padding: 12px 12px 10px; border-bottom: 1px solid var(--border); }",
|
|
5081
|
+
".den-svp-t { display: flex; align-items: center; gap: 8px; min-width: 0; }",
|
|
5082
|
+
".den-svp-t .den-dot, .den-svp-ag .den-dot, .den-svp-line .den-dot { margin: 0; }",
|
|
5083
|
+
// Line heights pinned to the mock's (its mono font's normal), whatever the theme's font.
|
|
5084
|
+
".den-svp-t b { flex: 1; min-width: 0; font: 600 14px/21px var(--mono); overflow: hidden;",
|
|
5085
|
+
" text-overflow: ellipsis; white-space: nowrap; }",
|
|
5086
|
+
".den-svp-x { padding: 2px 6px; margin: -4px -6px -4px 0; }",
|
|
5087
|
+
".den-svp-meta { display: flex; align-items: center; gap: 4px 8px; flex-wrap: wrap; font-size: 12.5px; color: var(--muted); }",
|
|
5088
|
+
".den-wsp { font: 11px/16px var(--mono); border-radius: 999px; padding: 0 7px; white-space: nowrap;",
|
|
5089
|
+
" border: 1px solid var(--border); color: var(--muted); }",
|
|
5090
|
+
".den-svp-st { color: var(--ok); } .den-svp-st.bad { color: var(--bad); }",
|
|
5091
|
+
".den-svp-st.off { color: var(--faint); } .den-svp-st.run { color: var(--accent-text); }",
|
|
5092
|
+
".den-svp-ms { font: 11.5px var(--mono); color: var(--faint); }",
|
|
5093
|
+
".den-svp-url { font: 12px/17px var(--mono); color: var(--faint); overflow-wrap: anywhere; }",
|
|
5094
|
+
".den-svp-acts { display: flex; gap: 6px; flex-wrap: wrap; padding: 10px 12px; }",
|
|
5095
|
+
".den-svp-sec { display: grid; gap: 6px; padding: 8px 12px 10px; border-top: 1px solid var(--border); }",
|
|
5096
|
+
".den-svp-k { font: 11px/16px var(--mono); color: var(--faint); text-transform: uppercase; letter-spacing: .07em; }",
|
|
5097
|
+
".den-svp-line { display: flex; align-items: center; gap: 8px; font-size: 13px; }",
|
|
5098
|
+
".den-svp-line .den-svp-sp { margin-left: auto; }",
|
|
5099
|
+
".den-svp-ok { color: var(--ok); } .den-svp-bad { color: var(--bad); } .den-svp-none { color: var(--faint); }",
|
|
5100
|
+
".den-svp-ag { display: grid; grid-template-columns: auto minmax(0, 1fr) auto auto; gap: 0 8px;",
|
|
5101
|
+
" align-items: center; font-size: 13px; }",
|
|
5102
|
+
".den-svp-nm { font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }",
|
|
5103
|
+
".den-svp-as { font: 11px var(--mono); color: var(--faint); white-space: nowrap; }",
|
|
5104
|
+
".den-wbdg { font: 10.5px var(--mono); color: var(--warn); border: 1px solid color-mix(in srgb, var(--warn) 45%, transparent);",
|
|
5105
|
+
" border-radius: 999px; padding: 0 6px; }",
|
|
5106
|
+
".den-svp-help { font-size: 12px; color: var(--faint); line-height: 1.4; }",
|
|
5107
|
+
".den-svp-foot { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; padding: 8px 12px 10px;",
|
|
5108
|
+
" border-top: 1px solid var(--border); }",
|
|
5109
|
+
".den-svp-grow { margin-left: auto; }",
|
|
5110
|
+
".den-lnk { color: var(--accent-text); cursor: pointer; font: inherit; font-size: 12.5px; text-decoration: underline;",
|
|
5111
|
+
" background: none; border: 0; padding: 0; }",
|
|
5112
|
+
".den-scrim.den-svp-scrim { z-index: 43; }",
|
|
5113
|
+
".den-pop.den-svp.den-sheet.den-toplayer { top: auto !important; left: 0 !important; right: 0 !important;",
|
|
5114
|
+
" bottom: 0 !important; width: auto; max-width: none; border-bottom: 0; border-radius: 14px 14px 0 0;",
|
|
5115
|
+
" max-height: 85dvh; padding-bottom: env(safe-area-inset-bottom, 0px); }",
|
|
5116
|
+
".den-pop.den-svp.den-sheet::before { content: ''; display: block; width: 36px; height: 4px; border-radius: 2px;",
|
|
5117
|
+
" background: var(--border-strong); margin: 8px auto 0; }",
|
|
5118
|
+
".den-pop.den-svp.den-sheet .den-svp-acts .den-btn { flex: 1 1 auto; padding: 9px 12px; }",
|
|
4875
5119
|
// Collapsed: icons only. The prototype hides headings and labels; they
|
|
4876
5120
|
// stay here for screen readers (visually hidden, no space taken).
|
|
4877
5121
|
"body.den-rail-collapsed .den-rail .den-lbl, body.den-rail-collapsed .den-rail .den-gh,",
|
|
4878
|
-
"body.den-rail-collapsed .den-rail .den-bdg
|
|
4879
|
-
"body.den-rail-collapsed .den-rail .den-pin-sp {",
|
|
5122
|
+
"body.den-rail-collapsed .den-rail .den-bdg {",
|
|
4880
5123
|
" position: absolute; width: 1px; height: 1px; padding: 0; overflow: hidden;",
|
|
4881
5124
|
" clip: rect(0 0 0 0); white-space: nowrap; border: 0; }",
|
|
4882
5125
|
// Toast (.toast)
|