@monster-orange/den 0.4.2 → 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.
Files changed (64) hide show
  1. package/CHANGELOG.md +273 -0
  2. package/README.md +9 -9
  3. package/docs/distributions.md +313 -50
  4. package/package.json +1 -1
  5. package/src/shared/agents/catalog-runtime.ts +178 -0
  6. package/src/shared/agents/catalog.ts +343 -0
  7. package/src/shared/agents/den-claude.ts +53 -12
  8. package/src/shared/agents/generic.ts +1 -0
  9. package/src/shared/agents/runtime-search.ts +543 -0
  10. package/src/shared/agents/runtime.ts +43 -1
  11. package/src/shared/agents/runtimes.ts +53 -4
  12. package/src/shared/auth/sudo-vault.ts +16 -0
  13. package/src/shared/den-config.ts +92 -2
  14. package/src/shared/edge/render.ts +31 -0
  15. package/src/shared/edge/status.ts +134 -0
  16. package/src/shared/environment-manager/health.ts +82 -8
  17. package/src/shared/environment-manager/workspaces.ts +54 -0
  18. package/src/shared/health/not-checked.ts +42 -0
  19. package/src/shared/health/rollup.ts +4 -0
  20. package/src/shared/process/spawn-streaming.ts +8 -3
  21. package/src/shared/sessions/client.ts +5 -1
  22. package/src/shared/sessions/host.ts +29 -1
  23. package/src/shared/sessions/protocol.ts +6 -1
  24. package/src/shared/sessions/types.ts +6 -0
  25. package/src/shared/stacks/status.ts +24 -0
  26. package/src/shared/strategies/registry.ts +5 -0
  27. package/src/shared/types/index.ts +6 -0
  28. package/src/ui/cli/agent-ops.ts +298 -19
  29. package/src/ui/cli/agents-command.ts +129 -4
  30. package/src/ui/cli/edge-command.ts +16 -3
  31. package/src/ui/cli/health-display.ts +4 -1
  32. package/src/ui/cli/sessions-command.ts +9 -4
  33. package/src/ui/cli/web-command.ts +53 -8
  34. package/src/ui/mcp/scope.ts +23 -3
  35. package/src/ui/mcp/server.ts +31 -7
  36. package/src/ui/mcp/tools.ts +327 -20
  37. package/src/ui/mcp/views.ts +450 -0
  38. package/src/ui/server/agent-routes.ts +123 -26
  39. package/src/ui/server/edge-exposure.ts +143 -0
  40. package/src/ui/server/index.ts +171 -25
  41. package/src/ui/server/public/agent-start.js +241 -0
  42. package/src/ui/server/public/agents-page.js +246 -45
  43. package/src/ui/server/public/agents-section.js +7 -21
  44. package/src/ui/server/public/agents.html +55 -1
  45. package/src/ui/server/public/graph-model.js +2 -0
  46. package/src/ui/server/public/header.js +2 -3
  47. package/src/ui/server/public/health-rollup.js +20 -8
  48. package/src/ui/server/public/i18n/es.js +26 -13
  49. package/src/ui/server/public/i18n/ja.js +25 -13
  50. package/src/ui/server/public/index.html +17 -4
  51. package/src/ui/server/public/local-dev.html +62 -22
  52. package/src/ui/server/public/services.html +21 -5
  53. package/src/ui/server/public/settings-page.js +3 -2
  54. package/src/ui/server/public/settings-registry.js +226 -1
  55. package/src/ui/server/public/settings.html +90 -1
  56. package/src/ui/server/public/shell.js +67 -22
  57. package/src/ui/server/public/topbar.js +217 -158
  58. package/src/ui/server/readonly-routes.ts +29 -5
  59. package/src/ui/server/request-guard.ts +123 -8
  60. package/src/ui/server/route-classes.ts +14 -2
  61. package/src/ui/server/session-routes.ts +9 -1
  62. package/src/ui/server/sudo-store.ts +170 -6
  63. package/src/ui/server/ui-assets.ts +2 -0
  64. package/src/ui/server/workspace-routes.ts +10 -3
@@ -95,7 +95,9 @@
95
95
  top: 0;
96
96
  z-index: 4;
97
97
  background: var(--bg);
98
- box-shadow: 0 -20px 0 0 var(--bg), 0 12px 0 0 var(--bg);
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 lock chip (R8) · What's new · ◐ ▾ (R10).
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 lock popover; appearance.js the user menu (dev.20).
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 lock chip and its popover (R8).
255
- "lock.locked": "Locked",
256
- "lock.unlocked": "Unlocked",
257
- "lock.title": "Unlock to start, stop and restart services and agents",
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": "Unlock",
263
+ "lock.go": "Continue",
268
264
  "lock.checking": "Checking…",
269
- "lock.note": "Den asks once per session. Agents can't unlock.",
270
- "lock.again": "Enter the password again…",
271
- "lock.saveFailed": "Unlocked, but saving to {s} failed: {err}",
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",
@@ -444,6 +442,7 @@
444
442
  "ag.persona": "Persona",
445
443
  "ag.runtime": "Runtime",
446
444
  "ag.runtime.auto": "The persona's",
445
+ "ag.runtime.default": "{name} (persona default)",
447
446
  "ag.unavailable": "unavailable",
448
447
  "ag.go": "Start",
449
448
  "ag.starting": "Starting…",
@@ -484,6 +483,21 @@
484
483
  "ag.pal": "Agents › {ws} / {name}",
485
484
  "ag.palStart": "Start agent…",
486
485
  "ag.cap": "Up to 4 panes: {id}'s closed to make room (it keeps running)",
486
+ "ag.rt.ready": "Starts {name} {version} from",
487
+ "ag.rt.readyNoVer": "Starts {name} from",
488
+ "ag.rt.notFound": "{name} not found.",
489
+ "ag.rt.searched": "Searched:",
490
+ "ag.rt.more": "and {n} more",
491
+ "ag.rt.nowhere": "no directories",
492
+ "ag.rt.refused": "{name} can't start: {why}.",
493
+ "ag.rt.fix":
494
+ "Install it, or set {key} to its path in {file}, or run {cmd}.",
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",
487
501
  };
488
502
  // The languages the UI has a catalog for, each named in itself (a name is
489
503
  // never translated). The server's list is ui-language.ts's UI_LANGUAGES.
@@ -1336,9 +1350,9 @@
1336
1350
 
1337
1351
  // ── the frame ──────────────────────────────────────────────────────────
1338
1352
  // The top bar after the scope, in the prototype's order (dev.20): the ⌘K
1339
- // search field (R5), then .chips: status (R6), Runs (R7), the lock (R8),
1353
+ // search field (R5), then .chips: status (R6), Runs (R7), the sudo ask (R8),
1340
1354
  // What's new (R9) and ◐ ▾ (R10, appearance.js fills #den-user). The
1341
- // chips start neutral ("Checking…", "Runs", "Locked") and topbar.js
1355
+ // chips start neutral ("Checking…", "Runs"; the sudo chip hidden) and topbar.js
1342
1356
  // paints them: a cold load never shows a partial red.
1343
1357
  var chips =
1344
1358
  '<button type="button" class="den-search" id="den-search" aria-haspopup="dialog" aria-keyshortcuts="Meta+K Control+K" aria-label="' +
@@ -1355,10 +1369,10 @@
1355
1369
  '<span class="den-dot off" aria-hidden="true"></span><span class="den-n den-lbl-l">' +
1356
1370
  esc(t("runs.title")) +
1357
1371
  "</span></button>" +
1358
- '<button type="button" class="den-chip" id="den-lock" aria-haspopup="dialog" aria-expanded="false" title="' +
1359
- esc(t("lock.title")) +
1360
- '"><span class="den-lock-ic" aria-hidden="true">🔒</span><span class="den-lbl-l">' +
1361
- esc(t("lock.locked")) +
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")) +
1362
1376
  "</span></button>" +
1363
1377
  '<button class="den-ib v-pill" id="version-pill" onclick="openChangelog()" title="' +
1364
1378
  esc(t("v.title")) +
@@ -3361,6 +3375,31 @@
3361
3375
  }
3362
3376
  }
3363
3377
 
3378
+ // 0.4.3: the edge is reachable from other machines (the server fills
3379
+ // data-edge-exposed on #den-shell). One line; dismissed per browser.
3380
+ var EDGE_LS = "den.edgeExposed.dismissed";
3381
+ var edgeDismissed = false;
3382
+ try {
3383
+ edgeDismissed = localStorage.getItem(EDGE_LS) === "1";
3384
+ } catch (e) {
3385
+ edgeDismissed = false;
3386
+ }
3387
+ if (host.dataset.edgeExposed && !edgeDismissed)
3388
+ showBanner("edge-exposed", {
3389
+ text: host.dataset.edgeExposed,
3390
+ action: {
3391
+ label: t("api.close"),
3392
+ run: function () {
3393
+ try {
3394
+ localStorage.setItem(EDGE_LS, "1");
3395
+ } catch (e) {
3396
+ /* no storage: dismissed for this page only */
3397
+ }
3398
+ hideBanner("edge-exposed");
3399
+ },
3400
+ },
3401
+ });
3402
+
3364
3403
  // The config fails validation (0.4.1): the server marks every page it
3365
3404
  // serves while it does (data-config-invalid on #den-shell), and the first
3366
3405
  // /api answer of 422 config_invalid marks it too. From then on the shell
@@ -3817,6 +3856,10 @@
3817
3856
  " max-height: calc(100vh - 72px); overflow-y: auto; box-sizing: border-box;",
3818
3857
  " font: 14px/1.45 var(--sans); color: var(--text); }",
3819
3858
  ".den-pop:focus { outline: none; }",
3859
+ // LK-1: the admin-password prompt is a <dialog> in the top layer (a popover, or
3860
+ // a modal over another modal): placed by its top/left, no UA box.
3861
+ "dialog.den-pop { margin: 0; inset: auto; max-width: none; }",
3862
+ "dialog.den-pop::backdrop { background: transparent; }",
3820
3863
  ".den-pop :focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }",
3821
3864
  ".den-pop .den-ml { font: 11px var(--mono); color: var(--faint); text-transform: uppercase;",
3822
3865
  " letter-spacing: .07em; padding: 6px 8px 2px; }",
@@ -3869,6 +3912,8 @@
3869
3912
  ".den-chip .den-n { font-variant-numeric: tabular-nums; }",
3870
3913
  ".den-chip .den-dot, .den-drawer .den-dot, .den-pal .den-dot { margin: 0; }",
3871
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)); }",
3872
3917
  ".den-dot.run { background: var(--accent); animation: den-pulse 1.2s infinite; }",
3873
3918
  ".den-dot.pending { background: var(--faint); animation: den-pulse 1.2s infinite; }",
3874
3919
  "@keyframes den-pulse { 50% { opacity: .35; } }",
@@ -3933,7 +3978,7 @@
3933
3978
  ".den-pal li.den-pal-empty { cursor: default; color: var(--muted); }",
3934
3979
  ".den-pal .den-foot { display: flex; gap: 14px; padding: 8px 14px; border-top: 1px solid var(--border);",
3935
3980
  " color: var(--faint); font-size: 12px; flex-wrap: wrap; }",
3936
- // The lock popover (.pop form, .pop input, .note: R8)
3981
+ // The admin-password prompt (.pop form, .pop input, .note: R8, LK-0)
3937
3982
  ".den-pop form { display: grid; gap: 8px; padding: 6px 8px 8px; width: 260px; box-sizing: content-box; margin: 0; }",
3938
3983
  ".den-pop input:not([type='checkbox']) { border: 1px solid var(--border); background: var(--bg); color: var(--text);",
3939
3984
  " border-radius: var(--radius-button); padding: 6px 8px; font: inherit; font-size: 13.3333px; line-height: normal; }",
@@ -3942,7 +3987,7 @@
3942
3987
  ".den-pop .den-lock-save { display: flex; gap: 6px; align-items: center; color: var(--muted); font-size: 12.5px; }",
3943
3988
  ".den-pop .den-lock-save[hidden], .den-pop .den-lock-err[hidden], .den-mslot[hidden] { display: none; }",
3944
3989
  ".den-pop .den-lock-err { color: var(--bad); font-size: 12.5px; }",
3945
- ".den-pop .den-lock-desc { padding: 2px 8px 6px; color: var(--muted); font-size: 12.5px; max-width: 260px; }",
3990
+ ".den-pop #den-lock-t { overflow-wrap: anywhere; }",
3946
3991
  // What's new (.ib.whatsnew + .badge-dot)
3947
3992
  "#den-shell .v-pill { font: inherit; padding: 4px 8px; border: 1px solid transparent;",
3948
3993
  " border-radius: var(--radius-button); color: var(--muted); flex-shrink: 0; }",