@monster-orange/den 0.4.3 → 0.4.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/CHANGELOG.md +179 -0
- package/README.md +9 -9
- package/docs/distributions.md +215 -65
- package/package.json +1 -1
- package/src/shared/agents/catalog-runtime.ts +178 -0
- package/src/shared/agents/catalog.ts +343 -0
- package/src/shared/agents/den-claude.ts +14 -18
- package/src/shared/agents/runtime-search.ts +142 -15
- package/src/shared/agents/runtime.ts +18 -1
- package/src/shared/agents/runtimes.ts +23 -1
- package/src/shared/auth/sudo-vault.ts +16 -0
- package/src/shared/den-config.ts +57 -3
- package/src/shared/edge/status.ts +134 -0
- package/src/shared/environment-manager/health.ts +82 -8
- package/src/shared/environment-manager/workspaces.ts +54 -0
- package/src/shared/health/not-checked.ts +42 -0
- package/src/shared/health/rollup.ts +4 -0
- package/src/shared/process/spawn-streaming.ts +8 -3
- package/src/shared/sessions/client.ts +5 -1
- package/src/shared/sessions/host.ts +29 -1
- package/src/shared/sessions/protocol.ts +6 -1
- package/src/shared/sessions/types.ts +6 -0
- package/src/shared/stacks/status.ts +24 -0
- package/src/shared/strategies/registry.ts +5 -0
- package/src/shared/types/index.ts +6 -0
- package/src/ui/cli/agent-ops.ts +210 -19
- package/src/ui/cli/agents-command.ts +50 -21
- package/src/ui/cli/edge-command.ts +16 -3
- package/src/ui/cli/health-display.ts +4 -1
- package/src/ui/mcp/scope.ts +23 -3
- package/src/ui/mcp/server.ts +31 -7
- package/src/ui/mcp/tools.ts +327 -20
- package/src/ui/mcp/views.ts +450 -0
- package/src/ui/server/agent-routes.ts +118 -28
- package/src/ui/server/index.ts +77 -6
- package/src/ui/server/public/agent-start.js +46 -7
- package/src/ui/server/public/agents-page.js +232 -97
- package/src/ui/server/public/agents-section.js +3 -5
- package/src/ui/server/public/agents.html +12 -28
- package/src/ui/server/public/graph-model.js +2 -0
- package/src/ui/server/public/header.js +2 -3
- package/src/ui/server/public/health-rollup.js +20 -8
- package/src/ui/server/public/i18n/es.js +15 -13
- package/src/ui/server/public/i18n/ja.js +14 -13
- package/src/ui/server/public/index.html +17 -4
- package/src/ui/server/public/local-dev.html +28 -17
- package/src/ui/server/public/services.html +21 -5
- package/src/ui/server/public/settings-page.js +3 -2
- package/src/ui/server/public/settings-registry.js +225 -0
- package/src/ui/server/public/settings.html +90 -1
- package/src/ui/server/public/shell.js +28 -23
- package/src/ui/server/public/topbar.js +166 -206
- package/src/ui/server/readonly-routes.ts +29 -5
- package/src/ui/server/request-guard.ts +1 -1
- package/src/ui/server/route-classes.ts +14 -2
- package/src/ui/server/session-routes.ts +9 -1
- package/src/ui/server/sudo-store.ts +170 -6
- package/src/ui/server/workspace-routes.ts +10 -3
|
@@ -64,6 +64,13 @@ export const DEN_SETTING_CATEGORIES = [
|
|
|
64
64
|
description:
|
|
65
65
|
"Settings for one workspace. They follow the Workspace you view in the top bar.",
|
|
66
66
|
},
|
|
67
|
+
{
|
|
68
|
+
id: "agents",
|
|
69
|
+
label: "Agents",
|
|
70
|
+
order: 55,
|
|
71
|
+
description:
|
|
72
|
+
"The runtimes agents run on, installed first. Paths you set are this machine's only: everywhere (config/local/user.yml) or for one workspace (config/local/workspaces.yml), which wins.",
|
|
73
|
+
},
|
|
67
74
|
{
|
|
68
75
|
id: "cli",
|
|
69
76
|
label: "Command line",
|
|
@@ -416,6 +423,29 @@ export const DEN_SETTINGS = [
|
|
|
416
423
|
write: (v, ctx) => ctx.saveWorkspace({ editor: v || null }),
|
|
417
424
|
},
|
|
418
425
|
|
|
426
|
+
// ── Agents ─────────────────────────────────────────────────────────────
|
|
427
|
+
{
|
|
428
|
+
id: "agents.runtimes",
|
|
429
|
+
category: "agents",
|
|
430
|
+
label: "Runtimes",
|
|
431
|
+
description:
|
|
432
|
+
"Each runtime's status and version, the path in use and where it came from. Set path… runs its version command first and refuses a path that isn't that runtime.",
|
|
433
|
+
keywords: [
|
|
434
|
+
"runtime",
|
|
435
|
+
"claude",
|
|
436
|
+
"codex",
|
|
437
|
+
"gemini",
|
|
438
|
+
"grok",
|
|
439
|
+
"path",
|
|
440
|
+
"bin",
|
|
441
|
+
"cli",
|
|
442
|
+
"agent",
|
|
443
|
+
],
|
|
444
|
+
scope: "user",
|
|
445
|
+
control: { type: "custom", render: renderRuntimes },
|
|
446
|
+
read: () => null,
|
|
447
|
+
},
|
|
448
|
+
|
|
419
449
|
// ── Command line ───────────────────────────────────────────────────────
|
|
420
450
|
{
|
|
421
451
|
id: "cli.local_dev",
|
|
@@ -498,6 +528,53 @@ export const DEN_SETTINGS = [
|
|
|
498
528
|
},
|
|
499
529
|
read: () => null,
|
|
500
530
|
},
|
|
531
|
+
{
|
|
532
|
+
// R8, LK-0: the admin password is for sudo, and nothing else. Den asks
|
|
533
|
+
// for it only when a command it runs needs sudo; here is whether it is
|
|
534
|
+
// saved, and Forget. Reading never wakes the vault.
|
|
535
|
+
id: "cli.sudo",
|
|
536
|
+
category: "cli",
|
|
537
|
+
label: "Admin password",
|
|
538
|
+
description:
|
|
539
|
+
"Used only when a command Den runs needs sudo, and asked for only then. It is no sign-in: nothing else needs it.",
|
|
540
|
+
keywords: ["admin", "password", "sudo", "forget", "vault", "1password"],
|
|
541
|
+
scope: "user",
|
|
542
|
+
control: {
|
|
543
|
+
type: "custom",
|
|
544
|
+
render(host, ctx) {
|
|
545
|
+
const draw = (st) => {
|
|
546
|
+
const saved = st?.saved;
|
|
547
|
+
const where =
|
|
548
|
+
saved === "vault"
|
|
549
|
+
? `Saved in ${st.vault?.label || "the vault"}`
|
|
550
|
+
: saved === "session"
|
|
551
|
+
? "Saved for this session"
|
|
552
|
+
: "Not saved";
|
|
553
|
+
host.innerHTML =
|
|
554
|
+
'<output class="set-ro" id="set-sudo"></output>' +
|
|
555
|
+
(saved
|
|
556
|
+
? ' <button type="button" class="btn" id="set-sudo-forget">Forget</button>'
|
|
557
|
+
: "");
|
|
558
|
+
host.querySelector("output").textContent = where;
|
|
559
|
+
host
|
|
560
|
+
.querySelector("#set-sudo-forget")
|
|
561
|
+
?.addEventListener("click", () =>
|
|
562
|
+
ctx.shell
|
|
563
|
+
.api("POST", "/api/sudo-password/forget", {})
|
|
564
|
+
.then(load)
|
|
565
|
+
.catch(load),
|
|
566
|
+
);
|
|
567
|
+
};
|
|
568
|
+
const load = () =>
|
|
569
|
+
fetch("/api/sudo-password/status", { cache: "no-store" })
|
|
570
|
+
.then((r) => (r.ok ? r.json() : null))
|
|
571
|
+
.then(draw)
|
|
572
|
+
.catch(() => draw(null));
|
|
573
|
+
void load();
|
|
574
|
+
},
|
|
575
|
+
},
|
|
576
|
+
read: () => null,
|
|
577
|
+
},
|
|
501
578
|
|
|
502
579
|
// ── Distribution (read-only) ───────────────────────────────────────────
|
|
503
580
|
distRow(
|
|
@@ -547,6 +624,154 @@ export const DEN_SETTINGS = [
|
|
|
547
624
|
),
|
|
548
625
|
];
|
|
549
626
|
|
|
627
|
+
// ── Settings › Agents › Runtimes (AG-0.5) ────────────────────────────────
|
|
628
|
+
|
|
629
|
+
const escR = (s) =>
|
|
630
|
+
String(s ?? "").replace(
|
|
631
|
+
/[&<>"']/g,
|
|
632
|
+
(c) =>
|
|
633
|
+
({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[
|
|
634
|
+
c
|
|
635
|
+
],
|
|
636
|
+
);
|
|
637
|
+
|
|
638
|
+
/** Where a runtime's path came from, as the row says it. */
|
|
639
|
+
export const RUNTIME_SOURCE = {
|
|
640
|
+
workspace: "workspace",
|
|
641
|
+
setting: "global",
|
|
642
|
+
"login-shell": "detected · login shell",
|
|
643
|
+
PATH: "detected · PATH",
|
|
644
|
+
"well-known": "detected · install directory",
|
|
645
|
+
"interactive-shell": "detected · interactive shell",
|
|
646
|
+
};
|
|
647
|
+
|
|
648
|
+
/** One runtime's row (r: GET /api/agents/runtimes' entry). */
|
|
649
|
+
export function runtimeRowHtml(r, scopeWs) {
|
|
650
|
+
const id = escR(r.id);
|
|
651
|
+
const name =
|
|
652
|
+
`<b>${escR(r.label || r.id)}</b>` +
|
|
653
|
+
(r.vendor ? ` <span class="rt-v">${escR(r.vendor)}</span>` : "") +
|
|
654
|
+
(r.denTools === false
|
|
655
|
+
? ` <span class="set-tag" data-den-tools="coming">Den tools: coming</span>`
|
|
656
|
+
: "");
|
|
657
|
+
const set = r.source === "workspace" || r.source === "setting";
|
|
658
|
+
const status = r.available
|
|
659
|
+
? `<span class="rt-ok">✓ ${escR(r.version ? r.version : "installed")}</span>`
|
|
660
|
+
: `<span class="rt-bad">${escR(set ? r.why : "Not installed")}</span>`;
|
|
661
|
+
const where = r.path
|
|
662
|
+
? `<span class="den-mono rt-p">${escR(r.path)}</span> <span class="set-tag" data-src="${escR(r.source || "")}">${escR(RUNTIME_SOURCE[r.source] || r.source || "")}</span>`
|
|
663
|
+
: set
|
|
664
|
+
? `<span class="set-tag" data-src="${escR(r.source)}">${escR(RUNTIME_SOURCE[r.source])}</span>`
|
|
665
|
+
: "";
|
|
666
|
+
// A path set at the scope shown can be cleared from here.
|
|
667
|
+
const mine = scopeWs ? r.source === "workspace" : r.source === "setting";
|
|
668
|
+
return (
|
|
669
|
+
`<div class="rt" data-runtime="${id}" data-available="${r.available ? "true" : "false"}">` +
|
|
670
|
+
`<div class="rt-n">${name}</div>` +
|
|
671
|
+
`<div class="rt-s">${status}</div>` +
|
|
672
|
+
`<div class="rt-w">${where}</div>` +
|
|
673
|
+
`<div class="rt-a"><button type="button" class="btn sm" data-set-path="${id}">Set path…</button>` +
|
|
674
|
+
(mine
|
|
675
|
+
? ` <button type="button" class="btn sm" data-clear-path="${id}">Clear</button>`
|
|
676
|
+
: "") +
|
|
677
|
+
`</div>` +
|
|
678
|
+
`<form class="rt-f" data-path-form="${id}" hidden>` +
|
|
679
|
+
`<label class="rt-fl" for="rt-in-${id}">Path to ${escR(r.label || r.id)}${scopeWs ? ` for ${escR(scopeWs)}` : " (every workspace)"}</label>` +
|
|
680
|
+
`<input type="text" id="rt-in-${id}" class="den-mono" spellcheck="false" autocomplete="off" placeholder="/absolute/path/to/${escR(r.id === "den-claude" ? "claude" : r.id)}" value="${escR(mine ? r.path || "" : "")}">` +
|
|
681
|
+
`<button type="submit" class="btn sm primary">Save</button> <button type="button" class="btn sm" data-cancel-path>Cancel</button>` +
|
|
682
|
+
`<div class="rt-err" role="alert" hidden></div></form>` +
|
|
683
|
+
`</div>`
|
|
684
|
+
);
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
/** The Runtimes row: the list, a workspace selector, Set path… and Clear. */
|
|
688
|
+
function renderRuntimes(host, ctx) {
|
|
689
|
+
const wss = ctx.workspaces || [];
|
|
690
|
+
let ws = "";
|
|
691
|
+
const draw = (rows, note) => {
|
|
692
|
+
host.innerHTML =
|
|
693
|
+
`<div class="rt-scope"><label for="rt-ws">Paths for</label> <select id="rt-ws" data-focus-key="rt-ws">` +
|
|
694
|
+
`<option value="">every workspace (user.yml)</option>` +
|
|
695
|
+
wss
|
|
696
|
+
.map(
|
|
697
|
+
(w) =>
|
|
698
|
+
`<option value="${escR(w)}"${w === ws ? " selected" : ""}>${escR(w)} (workspaces.yml)</option>`,
|
|
699
|
+
)
|
|
700
|
+
.join("") +
|
|
701
|
+
`</select></div>` +
|
|
702
|
+
(note ? `<div class="set-note">${escR(note)}</div>` : "") +
|
|
703
|
+
`<div class="rt-list" role="list">${rows.map((r) => runtimeRowHtml(r, ws)).join("")}</div>`;
|
|
704
|
+
};
|
|
705
|
+
const load = () => {
|
|
706
|
+
// Under an invalid config the runtimes answer 422: say why, ask nothing.
|
|
707
|
+
if (ctx.shell?.configInvalid?.() === true)
|
|
708
|
+
return draw([], "Fix the config first: the runtimes are read from it.");
|
|
709
|
+
return ctx.shell
|
|
710
|
+
.api(
|
|
711
|
+
"GET",
|
|
712
|
+
`/api/agents/runtimes${ws ? `?workspace=${encodeURIComponent(ws)}` : ""}`,
|
|
713
|
+
)
|
|
714
|
+
.then((b) =>
|
|
715
|
+
// Only what has a CLI to find: generic is the persona's argv.
|
|
716
|
+
draw((b?.runtimes || []).filter((r) => r.setting)),
|
|
717
|
+
)
|
|
718
|
+
.catch((e) => draw([], e?.message || "The runtimes did not load."));
|
|
719
|
+
};
|
|
720
|
+
host.addEventListener("change", (e) => {
|
|
721
|
+
if (e.target.id !== "rt-ws") return;
|
|
722
|
+
ws = e.target.value;
|
|
723
|
+
void load();
|
|
724
|
+
});
|
|
725
|
+
host.addEventListener("click", async (e) => {
|
|
726
|
+
const b = e.target.closest("button");
|
|
727
|
+
if (!b) return;
|
|
728
|
+
const row = b.closest(".rt");
|
|
729
|
+
const form = row?.querySelector(".rt-f");
|
|
730
|
+
if (b.dataset.setPath && form) {
|
|
731
|
+
form.hidden = false;
|
|
732
|
+
form.querySelector("input").focus();
|
|
733
|
+
} else if (b.hasAttribute("data-cancel-path") && form) {
|
|
734
|
+
form.hidden = true;
|
|
735
|
+
} else if (b.dataset.clearPath) {
|
|
736
|
+
await savePath(b.dataset.clearPath, null, form);
|
|
737
|
+
}
|
|
738
|
+
});
|
|
739
|
+
host.addEventListener("submit", async (e) => {
|
|
740
|
+
e.preventDefault();
|
|
741
|
+
const form = e.target.closest(".rt-f");
|
|
742
|
+
if (!form) return;
|
|
743
|
+
const bin = form.querySelector("input").value.trim();
|
|
744
|
+
if (!bin) return;
|
|
745
|
+
await savePath(form.dataset.pathForm, bin, form);
|
|
746
|
+
});
|
|
747
|
+
async function savePath(id, bin, form) {
|
|
748
|
+
const err = form?.querySelector(".rt-err");
|
|
749
|
+
const btns = form ? [...form.querySelectorAll("button")] : [];
|
|
750
|
+
btns.forEach((x) => (x.disabled = true));
|
|
751
|
+
try {
|
|
752
|
+
await ctx.shell.api(
|
|
753
|
+
"POST",
|
|
754
|
+
`/api/agents/runtimes/${encodeURIComponent(id)}/path`,
|
|
755
|
+
{
|
|
756
|
+
scope: ws ? "workspace" : "global",
|
|
757
|
+
...(ws ? { workspace: ws } : {}),
|
|
758
|
+
bin,
|
|
759
|
+
},
|
|
760
|
+
);
|
|
761
|
+
await load();
|
|
762
|
+
} catch (x) {
|
|
763
|
+
// Its refusal is shown here, under the field, not as a toast.
|
|
764
|
+
if (err) {
|
|
765
|
+
err.textContent = x?.message || "Not saved";
|
|
766
|
+
err.hidden = false;
|
|
767
|
+
}
|
|
768
|
+
} finally {
|
|
769
|
+
btns.forEach((x) => (x.disabled = false));
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
void load();
|
|
773
|
+
}
|
|
774
|
+
|
|
550
775
|
/** Register Den's categories and rows with the shell's SETTINGS registry. */
|
|
551
776
|
export function registerDenSettings(shell) {
|
|
552
777
|
for (const c of DEN_SETTING_CATEGORIES) shell.registerSettingsCategory(c);
|
|
@@ -95,7 +95,9 @@
|
|
|
95
95
|
top: 0;
|
|
96
96
|
z-index: 4;
|
|
97
97
|
background: var(--bg);
|
|
98
|
-
box-shadow:
|
|
98
|
+
box-shadow:
|
|
99
|
+
0 -20px 0 0 var(--bg),
|
|
100
|
+
0 12px 0 0 var(--bg);
|
|
99
101
|
}
|
|
100
102
|
.ph .act {
|
|
101
103
|
margin-left: auto;
|
|
@@ -352,6 +354,93 @@
|
|
|
352
354
|
border-radius: 999px;
|
|
353
355
|
padding: 0 6px;
|
|
354
356
|
}
|
|
357
|
+
/* Settings › Agents › Runtimes (AG-0.5): one row per runtime. */
|
|
358
|
+
.set-custom {
|
|
359
|
+
flex: 1 1 100%;
|
|
360
|
+
min-width: 0;
|
|
361
|
+
}
|
|
362
|
+
.rt-scope {
|
|
363
|
+
display: flex;
|
|
364
|
+
align-items: center;
|
|
365
|
+
gap: 8px;
|
|
366
|
+
flex-wrap: wrap;
|
|
367
|
+
font-size: 13px;
|
|
368
|
+
color: var(--muted);
|
|
369
|
+
margin-bottom: 6px;
|
|
370
|
+
}
|
|
371
|
+
.rt-list {
|
|
372
|
+
display: grid;
|
|
373
|
+
border: 1px solid var(--border);
|
|
374
|
+
border-radius: var(--radius-button);
|
|
375
|
+
}
|
|
376
|
+
.rt {
|
|
377
|
+
display: grid;
|
|
378
|
+
grid-template-columns: minmax(0, 1.2fr) minmax(0, 0.8fr) minmax(
|
|
379
|
+
0,
|
|
380
|
+
2fr
|
|
381
|
+
) auto;
|
|
382
|
+
align-items: center;
|
|
383
|
+
gap: 4px 12px;
|
|
384
|
+
padding: 8px 10px;
|
|
385
|
+
font-size: 13px;
|
|
386
|
+
}
|
|
387
|
+
.rt + .rt {
|
|
388
|
+
border-top: 1px solid var(--border);
|
|
389
|
+
}
|
|
390
|
+
.rt-v {
|
|
391
|
+
color: var(--muted);
|
|
392
|
+
}
|
|
393
|
+
.rt-n .set-tag {
|
|
394
|
+
white-space: nowrap;
|
|
395
|
+
}
|
|
396
|
+
.rt-ok {
|
|
397
|
+
color: var(--ok);
|
|
398
|
+
}
|
|
399
|
+
.rt-bad {
|
|
400
|
+
color: var(--muted);
|
|
401
|
+
overflow-wrap: anywhere;
|
|
402
|
+
}
|
|
403
|
+
.rt-w {
|
|
404
|
+
min-width: 0;
|
|
405
|
+
overflow-wrap: anywhere;
|
|
406
|
+
}
|
|
407
|
+
.rt-p {
|
|
408
|
+
font-size: 12px;
|
|
409
|
+
}
|
|
410
|
+
.rt-f {
|
|
411
|
+
grid-column: 1 / -1;
|
|
412
|
+
display: flex;
|
|
413
|
+
flex-wrap: wrap;
|
|
414
|
+
align-items: center;
|
|
415
|
+
gap: 6px;
|
|
416
|
+
}
|
|
417
|
+
.rt-f[hidden],
|
|
418
|
+
.rt-err[hidden] {
|
|
419
|
+
display: none;
|
|
420
|
+
}
|
|
421
|
+
.rt-fl {
|
|
422
|
+
flex-basis: 100%;
|
|
423
|
+
color: var(--muted);
|
|
424
|
+
font-size: 12.5px;
|
|
425
|
+
}
|
|
426
|
+
.rt-f input {
|
|
427
|
+
flex: 1 1 260px;
|
|
428
|
+
min-width: 0;
|
|
429
|
+
}
|
|
430
|
+
.rt-err {
|
|
431
|
+
flex-basis: 100%;
|
|
432
|
+
color: var(--bad);
|
|
433
|
+
font-size: 12.5px;
|
|
434
|
+
overflow-wrap: anywhere;
|
|
435
|
+
}
|
|
436
|
+
@media (max-width: 640px) {
|
|
437
|
+
.rt {
|
|
438
|
+
grid-template-columns: minmax(0, 1fr) auto;
|
|
439
|
+
}
|
|
440
|
+
.rt-w {
|
|
441
|
+
grid-column: 1 / -1;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
355
444
|
.set-langs {
|
|
356
445
|
display: grid;
|
|
357
446
|
gap: 4px;
|
|
@@ -22,10 +22,10 @@
|
|
|
22
22
|
* each part an .ib button with a .pop menu (an ARIA menu: ↑/↓,
|
|
23
23
|
* Home, End, Enter; Escape and a click outside close it) ·
|
|
24
24
|
* the ⌘K search field (R5) · the status chip (R6) · the Runs
|
|
25
|
-
* chip (R7) · the
|
|
25
|
+
* chip (R7) · the sudo chip (R8, only while asked) · What's new · ◐ ▾ (R10).
|
|
26
26
|
* shell.js draws them; topbar.js (through header.js) drives the
|
|
27
27
|
* chips, the command palette (R17), the status drawer (R15) and
|
|
28
|
-
* the
|
|
28
|
+
* the admin-password prompt; appearance.js the user menu (dev.20).
|
|
29
29
|
* rail Pinned, then the NAV registry by GROUPS (Develop, Verify,
|
|
30
30
|
* Ship, a distribution's own), then Settings and the collapse
|
|
31
31
|
* toggle. One tab stop (the current page); ↑/↓, Home and End
|
|
@@ -251,24 +251,20 @@
|
|
|
251
251
|
"dock.err": "failed",
|
|
252
252
|
"dock.last": "Last run: {s} ↗",
|
|
253
253
|
"dock.resize": "Drag to resize",
|
|
254
|
-
// The
|
|
255
|
-
"lock.
|
|
256
|
-
"lock.
|
|
257
|
-
"lock.
|
|
258
|
-
"lock.nopw": "Passwordless sudo (NOPASSWD): no admin password needed",
|
|
259
|
-
"lock.session": "Unlocked for this session",
|
|
260
|
-
"lock.sessionDesc":
|
|
261
|
-
"Unlocked for this session: start, stop and restart work on every page.",
|
|
254
|
+
// The admin password, asked only when a command needs sudo (R8, LK-0).
|
|
255
|
+
"lock.waiting": "Admin password needed",
|
|
256
|
+
"lock.needs": "{cmd} needs your admin password",
|
|
257
|
+
"lock.cmd": "A command",
|
|
262
258
|
"lock.cfg":
|
|
263
259
|
"Saving the password is off: set secrets.provider and secrets.refs.sudo in {file}.",
|
|
264
260
|
"lock.update": "Update stored password",
|
|
265
261
|
"lock.saveTo": "Save to {s}",
|
|
266
262
|
"lock.pw": "Admin password",
|
|
267
|
-
"lock.go": "
|
|
263
|
+
"lock.go": "Continue",
|
|
268
264
|
"lock.checking": "Checking…",
|
|
269
|
-
"lock.note": "Den
|
|
270
|
-
"lock.
|
|
271
|
-
"lock.saveFailed": "
|
|
265
|
+
"lock.note": "Den uses it only for sudo. Agents can't enter it.",
|
|
266
|
+
"lock.saved": "Admin password kept for this session",
|
|
267
|
+
"lock.saveFailed": "Kept for this session, but saving to {s} failed: {err}",
|
|
272
268
|
"lock.wrong": "Incorrect password — try again",
|
|
273
269
|
"lock.reqFailed": "Request failed — is the server running?",
|
|
274
270
|
// What's new (R9) and the stale-server pill.
|
|
@@ -402,11 +398,13 @@
|
|
|
402
398
|
"set.graph.density": "Cards",
|
|
403
399
|
"set.graph.panelWidth": "Details panel",
|
|
404
400
|
"set.workspace.editor": "IDE for this workspace",
|
|
401
|
+
"set.agents.runtimes": "Runtimes",
|
|
405
402
|
"set.cli.local_dev": "Local environment",
|
|
406
403
|
"set.cli.cli_tabs": "Terminal tabs",
|
|
407
404
|
"set.cli.log_window_lines": "Log pane lines",
|
|
408
405
|
"set.cli.web_port": "Your web port",
|
|
409
406
|
"set.cli.signin": "Browser sign-in",
|
|
407
|
+
"set.cli.sudo": "Admin password",
|
|
410
408
|
"set.distribution.brand": "Product name",
|
|
411
409
|
"set.distribution.github_org": "GitHub org",
|
|
412
410
|
"set.distribution.orgs": "Org labels",
|
|
@@ -495,6 +493,11 @@
|
|
|
495
493
|
"ag.rt.fix":
|
|
496
494
|
"Install it, or set {key} to its path in {file}, or run {cmd}.",
|
|
497
495
|
"ag.rt.unknown": "No runtime {id} here.",
|
|
496
|
+
"ag.rt.denTools": "Den tools: coming",
|
|
497
|
+
"ag.rt.ownCli":
|
|
498
|
+
"It runs as its own CLI in the workspace: Den's tools and permission modes are coming for it.",
|
|
499
|
+
"ag.rt.notInstalled": "not installed",
|
|
500
|
+
"ag.rt.needsArgv": "the persona has no argv template",
|
|
498
501
|
};
|
|
499
502
|
// The languages the UI has a catalog for, each named in itself (a name is
|
|
500
503
|
// never translated). The server's list is ui-language.ts's UI_LANGUAGES.
|
|
@@ -1347,9 +1350,9 @@
|
|
|
1347
1350
|
|
|
1348
1351
|
// ── the frame ──────────────────────────────────────────────────────────
|
|
1349
1352
|
// The top bar after the scope, in the prototype's order (dev.20): the ⌘K
|
|
1350
|
-
// search field (R5), then .chips: status (R6), Runs (R7), the
|
|
1353
|
+
// search field (R5), then .chips: status (R6), Runs (R7), the sudo ask (R8),
|
|
1351
1354
|
// What's new (R9) and ◐ ▾ (R10, appearance.js fills #den-user). The
|
|
1352
|
-
// chips start neutral ("Checking…", "Runs"
|
|
1355
|
+
// chips start neutral ("Checking…", "Runs"; the sudo chip hidden) and topbar.js
|
|
1353
1356
|
// paints them: a cold load never shows a partial red.
|
|
1354
1357
|
var chips =
|
|
1355
1358
|
'<button type="button" class="den-search" id="den-search" aria-haspopup="dialog" aria-keyshortcuts="Meta+K Control+K" aria-label="' +
|
|
@@ -1366,10 +1369,10 @@
|
|
|
1366
1369
|
'<span class="den-dot off" aria-hidden="true"></span><span class="den-n den-lbl-l">' +
|
|
1367
1370
|
esc(t("runs.title")) +
|
|
1368
1371
|
"</span></button>" +
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
'
|
|
1372
|
-
esc(t("lock.
|
|
1372
|
+
// LK-0: shown only while a run waits for the admin password (topbar.js).
|
|
1373
|
+
'<button type="button" class="den-chip" id="den-lock" aria-haspopup="dialog" aria-expanded="false" hidden>' +
|
|
1374
|
+
'<span class="den-lock-ic" aria-hidden="true">🔑</span><span class="den-lbl-l">' +
|
|
1375
|
+
esc(t("lock.waiting")) +
|
|
1373
1376
|
"</span></button>" +
|
|
1374
1377
|
'<button class="den-ib v-pill" id="version-pill" onclick="openChangelog()" title="' +
|
|
1375
1378
|
esc(t("v.title")) +
|
|
@@ -3853,7 +3856,7 @@
|
|
|
3853
3856
|
" max-height: calc(100vh - 72px); overflow-y: auto; box-sizing: border-box;",
|
|
3854
3857
|
" font: 14px/1.45 var(--sans); color: var(--text); }",
|
|
3855
3858
|
".den-pop:focus { outline: none; }",
|
|
3856
|
-
// LK-1: the
|
|
3859
|
+
// LK-1: the admin-password prompt is a <dialog> in the top layer (a popover, or
|
|
3857
3860
|
// a modal over another modal): placed by its top/left, no UA box.
|
|
3858
3861
|
"dialog.den-pop { margin: 0; inset: auto; max-width: none; }",
|
|
3859
3862
|
"dialog.den-pop::backdrop { background: transparent; }",
|
|
@@ -3909,6 +3912,8 @@
|
|
|
3909
3912
|
".den-chip .den-n { font-variant-numeric: tabular-nums; }",
|
|
3910
3913
|
".den-chip .den-dot, .den-drawer .den-dot, .den-pal .den-dot { margin: 0; }",
|
|
3911
3914
|
".den-chip[aria-expanded='true'] { border-color: var(--border-strong); }",
|
|
3915
|
+
".den-chip[hidden] { display: none; }",
|
|
3916
|
+
"#den-lock { border-color: color-mix(in srgb, var(--warn) 55%, var(--border)); }",
|
|
3912
3917
|
".den-dot.run { background: var(--accent); animation: den-pulse 1.2s infinite; }",
|
|
3913
3918
|
".den-dot.pending { background: var(--faint); animation: den-pulse 1.2s infinite; }",
|
|
3914
3919
|
"@keyframes den-pulse { 50% { opacity: .35; } }",
|
|
@@ -3973,7 +3978,7 @@
|
|
|
3973
3978
|
".den-pal li.den-pal-empty { cursor: default; color: var(--muted); }",
|
|
3974
3979
|
".den-pal .den-foot { display: flex; gap: 14px; padding: 8px 14px; border-top: 1px solid var(--border);",
|
|
3975
3980
|
" color: var(--faint); font-size: 12px; flex-wrap: wrap; }",
|
|
3976
|
-
// The
|
|
3981
|
+
// The admin-password prompt (.pop form, .pop input, .note: R8, LK-0)
|
|
3977
3982
|
".den-pop form { display: grid; gap: 8px; padding: 6px 8px 8px; width: 260px; box-sizing: content-box; margin: 0; }",
|
|
3978
3983
|
".den-pop input:not([type='checkbox']) { border: 1px solid var(--border); background: var(--bg); color: var(--text);",
|
|
3979
3984
|
" border-radius: var(--radius-button); padding: 6px 8px; font: inherit; font-size: 13.3333px; line-height: normal; }",
|
|
@@ -3982,7 +3987,7 @@
|
|
|
3982
3987
|
".den-pop .den-lock-save { display: flex; gap: 6px; align-items: center; color: var(--muted); font-size: 12.5px; }",
|
|
3983
3988
|
".den-pop .den-lock-save[hidden], .den-pop .den-lock-err[hidden], .den-mslot[hidden] { display: none; }",
|
|
3984
3989
|
".den-pop .den-lock-err { color: var(--bad); font-size: 12.5px; }",
|
|
3985
|
-
".den-pop
|
|
3990
|
+
".den-pop #den-lock-t { overflow-wrap: anywhere; }",
|
|
3986
3991
|
// What's new (.ib.whatsnew + .badge-dot)
|
|
3987
3992
|
"#den-shell .v-pill { font: inherit; padding: 4px 8px; border: 1px solid transparent;",
|
|
3988
3993
|
" border-radius: var(--radius-button); color: var(--muted); flex-shrink: 0; }",
|