localdeck 1.1.0 → 1.2.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/CHANGELOG.md +20 -0
- package/README.md +3 -0
- package/dashboard/assets/index-BzX_uJtU.js +20 -0
- package/dashboard/assets/index-DbQzubLF.css +1 -0
- package/dashboard/index.html +2 -2
- package/dist/{index-n4sq4z00.js → index-19n321tr.js} +188 -34
- package/dist/index.js +13 -3
- package/dist/{mcp-arq8ad4g.js → mcp-vkez9mq7.js} +1 -1
- package/dist/{update-gj01sqte.js → update-nx00r38m.js} +1 -1
- package/docs/dashboard.md +6 -0
- package/package.json +1 -1
- package/dashboard/assets/index-CmTkywPB.css +0 -1
- package/dashboard/assets/index-DqZDYOkh.js +0 -20
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@font-face{font-family:IBM Plex Sans;font-style:normal;font-display:swap;font-weight:400;src:url(/assets/ibm-plex-sans-latin-400-normal-CDDApCn2.woff2) format("woff2"),url(/assets/ibm-plex-sans-latin-400-normal-CYLoc0-x.woff) format("woff")}@font-face{font-family:IBM Plex Sans;font-style:normal;font-display:swap;font-weight:500;src:url(/assets/ibm-plex-sans-latin-500-normal-6ng42L7E.woff2) format("woff2"),url(/assets/ibm-plex-sans-latin-500-normal-BgVn5rGT.woff) format("woff")}@font-face{font-family:IBM Plex Sans;font-style:normal;font-display:swap;font-weight:600;src:url(/assets/ibm-plex-sans-latin-600-normal-CuJfVYMP.woff2) format("woff2"),url(/assets/ibm-plex-sans-latin-600-normal-Cu4Hd6ag.woff) format("woff")}@font-face{font-family:IBM Plex Mono;font-style:normal;font-display:swap;font-weight:400;src:url(/assets/ibm-plex-mono-latin-400-normal-DMJ8VG8y.woff2) format("woff2"),url(/assets/ibm-plex-mono-latin-400-normal-CvHOgSBP.woff) format("woff")}@font-face{font-family:IBM Plex Mono;font-style:normal;font-display:swap;font-weight:500;src:url(/assets/ibm-plex-mono-latin-500-normal-DSY6xOcd.woff2) format("woff2"),url(/assets/ibm-plex-mono-latin-500-normal-CB9ihrfo.woff) format("woff")}:root{color-scheme:light;--bg: #f2f0eb;--bg-2: #e9e7e1;--bg-3: #e1dfd8;--border: #d2d0c9;--text: #23231f;--muted: #62625b;--accent: #bd3c16;--orange: #f26538;--ok: #46633b;--warn: #8a5f19;--err: #bd3c16;--share: #815123;--chrome: #191917;--chrome-border: #3b3b36;--chrome-text: #eeede7;--chrome-muted: #a4a49a;--mono: "IBM Plex Mono", ui-monospace, monospace;--sans: "IBM Plex Sans", system-ui, sans-serif;--text-small: .8125rem;--text-body: .875rem;--text-label: 1rem;--text-section: 1.25rem;--text-title: 2rem;--control-height: 2.5rem}*{box-sizing:border-box}html{font-size:100%}html,body{margin:0;min-width:320px;height:100%;background:var(--chrome);color:var(--text);font-family:var(--sans);line-height:1.5}body{font-size:var(--text-body)}#app{height:100%}a{color:var(--accent);text-decoration:none}a:hover{text-decoration:underline}button{display:inline-flex;align-items:center;justify-content:center;text-align:center;gap:6px;font:500 var(--text-body)/1.4 var(--sans);color:var(--text);background:transparent;border:1px solid var(--border);border-radius:0;padding:7px 12px;min-height:var(--control-height);cursor:pointer;white-space:nowrap}button:hover{background:var(--bg-2);border-color:var(--muted)}button.primary{background:var(--text);border-color:var(--text);color:var(--bg)}button.primary:hover{background:#41413a;border-color:#41413a}button.danger:hover{color:var(--err);border-color:var(--err)}button:disabled{opacity:.45;cursor:default}input,select,textarea{font:inherit;color:var(--text);background:transparent;border:1px solid var(--border);border-radius:0;padding:8px 10px}input:not([type=checkbox]):not([type=radio]),select{min-height:var(--control-height)}input,select,textarea{font-size:var(--text-body);border-color:#8b8b81}input[type=checkbox]{accent-color:var(--accent)}button:focus-visible,a:focus-visible,summary:focus-visible{outline:2px solid var(--muted);outline-offset:3px}code,.mono{font-family:var(--mono);font-size:var(--text-small)}::-webkit-scrollbar{width:7px;height:7px}::-webkit-scrollbar-thumb{background:#8f8f8560}[hidden]{display:none!important}summary{cursor:pointer}pre{overflow:auto}@media(prefers-reduced-motion:reduce){*,*:before,*:after{scroll-behavior:auto!important;transition:none!important}}@media(pointer:coarse),(max-width:760px){:root{--control-height: 2.75rem}input:not([type=checkbox]):not([type=radio]),select,textarea{font-size:1rem}}label:has(input[type=checkbox]){min-height:var(--control-height)}input:focus,input:focus-visible,select:focus,select:focus-visible,textarea:focus,textarea:focus-visible{outline:none!important;box-shadow:none!important}dialog.svelte-vw7b2v{width:min(640px,calc(100vw - 32px));max-height:min(620px,80dvh);margin:12dvh auto auto;padding:0;border:1px solid var(--border);background:var(--bg);color:var(--text);box-shadow:0 24px 80px #0005;overflow:hidden}dialog[open].svelte-vw7b2v{display:flex;flex-direction:column}dialog.svelte-vw7b2v::backdrop{background:#1119}.search-row.svelte-vw7b2v{display:flex;align-items:center;gap:12px;padding:14px 18px;border-bottom:1px solid var(--border);flex-shrink:0}.search-row.svelte-vw7b2v svg{flex-shrink:0;color:var(--muted)}input.svelte-vw7b2v{flex:1;min-width:0;border:0;padding:8px 0}.close.svelte-vw7b2v{min-height:28px;padding:3px 6px;font:12px var(--mono);color:var(--muted)}.results.svelte-vw7b2v{overflow:auto;min-height:0;padding:6px}.results.svelte-vw7b2v button:where(.svelte-vw7b2v){width:100%;justify-content:space-between;gap:16px;border:0;padding:12px;text-align:left;white-space:normal}.results.svelte-vw7b2v button.chosen:where(.svelte-vw7b2v){background:var(--bg-3);box-shadow:inset 3px 0 var(--accent)}.results.svelte-vw7b2v button[aria-disabled=true]:where(.svelte-vw7b2v){color:var(--muted)}strong.svelte-vw7b2v,small.svelte-vw7b2v{display:block}strong.svelte-vw7b2v{font-weight:500}small.svelte-vw7b2v{font-size:var(--text-small);color:var(--muted);overflow-wrap:anywhere}footer.svelte-vw7b2v{display:flex;justify-content:space-between;gap:12px;padding:12px 18px;border-top:1px solid var(--border);font-size:var(--text-small);color:var(--muted);flex-shrink:0}.separator.svelte-vw7b2v{margin:0 6px}.empty.svelte-vw7b2v,.error.svelte-vw7b2v{padding:16px 18px;margin:0}.empty.svelte-vw7b2v{color:var(--muted)}.error.svelte-vw7b2v{color:var(--err)}.load-error.svelte-vw7b2v{display:flex;align-items:center;gap:12px;padding:12px 18px;color:var(--err);border-top:1px solid var(--border);font-size:var(--text-small)}@media(max-width:480px){dialog.svelte-vw7b2v{margin-top:6dvh;max-height:88dvh}.search-row.svelte-vw7b2v{gap:8px;padding:10px}footer.svelte-vw7b2v{flex-wrap:wrap}}section.svelte-1hauwfi{margin-top:32px}h3.svelte-1hauwfi{margin:0 0 12px;font:500 var(--text-section)/1.4 var(--sans)}p.svelte-1hauwfi,li.svelte-1hauwfi{line-height:1.7}p.svelte-1hauwfi{color:var(--muted)}ul.svelte-1hauwfi{padding-left:20px}li.svelte-1hauwfi+li:where(.svelte-1hauwfi){margin-top:8px}.about.svelte-1vwaeio{width:100%;max-width:880px;padding:48px 40px 64px}header.svelte-1vwaeio{max-width:65ch}header.svelte-1vwaeio img:where(.svelte-1vwaeio){display:block;margin:-12px 0 20px -12px}.eyebrow.svelte-1vwaeio{color:var(--muted);margin:0 0 8px}h1.svelte-1vwaeio{font-size:var(--text-title);line-height:1.2;margin:0 0 16px;font-weight:600}h2.svelte-1vwaeio{font-size:var(--text-section);line-height:1.4;margin:0 0 12px;font-weight:600}p.svelte-1vwaeio{line-height:1.6;margin:0 0 16px;max-width:65ch}.intro.svelte-1vwaeio{font-size:var(--text-label)}.about.svelte-1vwaeio>section:where(.svelte-1vwaeio){margin-top:40px;padding-top:28px;border-top:1px solid var(--border)}.steps.svelte-1vwaeio{padding-left:24px;margin:20px 0}.steps.svelte-1vwaeio li:where(.svelte-1vwaeio){padding-left:8px;margin-bottom:16px}.steps.svelte-1vwaeio span:where(.svelte-1vwaeio){display:block;margin-top:4px;color:var(--muted)}.note.svelte-1vwaeio{color:var(--muted);font-size:var(--text-small)}code.svelte-1vwaeio{overflow-wrap:anywhere}.command-groups.svelte-1vwaeio{margin:24px 0;border-top:1px solid var(--border)}details.svelte-1vwaeio{border-bottom:1px solid var(--border)}summary.svelte-1vwaeio{padding:16px 0;min-height:var(--control-height);font-weight:500}summary.svelte-1vwaeio span:where(.svelte-1vwaeio){color:var(--muted);font-size:var(--text-small);font-weight:400;margin-left:12px;white-space:nowrap}dl.svelte-1vwaeio{margin:0 0 16px}dl.svelte-1vwaeio>div:where(.svelte-1vwaeio){padding:16px 0}dl.svelte-1vwaeio>div:where(.svelte-1vwaeio)+div:where(.svelte-1vwaeio){border-top:1px solid var(--border)}dt.svelte-1vwaeio{margin-bottom:8px}dd.svelte-1vwaeio{margin:0;color:var(--muted);line-height:1.6;max-width:65ch}@media(max-width:760px){.about.svelte-1vwaeio{padding:24px 16px 40px}header.svelte-1vwaeio img:where(.svelte-1vwaeio){width:112px;height:112px;margin-left:-8px}summary.svelte-1vwaeio span:where(.svelte-1vwaeio){display:block;margin:4px 0 0 18px}}h3.svelte-1offp6a{margin-top:32px;font:500 var(--text-section)/1.4 var(--sans)}label.svelte-1offp6a{display:block;margin-bottom:8px}.controls.svelte-1offp6a{display:flex;align-items:center;gap:8px}input.svelte-1offp6a{width:160px}input.svelte-1offp6a:focus-visible{outline:none;border-color:var(--text)}p.svelte-1offp6a{color:var(--muted);line-height:1.6}.current.svelte-1offp6a{font-size:var(--text-small)}.changelog.svelte-1tl5wtp{padding:48px 40px}header.svelte-1tl5wtp{padding-bottom:24px;border-bottom:1px solid var(--border)}h1.svelte-1tl5wtp{margin:0 0 12px;font:600 var(--text-title)/1.2 var(--sans)}header.svelte-1tl5wtp p:where(.svelte-1tl5wtp){margin:0;color:var(--muted)}article.svelte-1tl5wtp{padding:28px 0;border-bottom:1px solid var(--border)}h2.svelte-1tl5wtp{margin:0 0 16px;font:500 var(--text-section)/1.4 var(--sans)}h2.svelte-1tl5wtp span:where(.svelte-1tl5wtp){color:var(--muted);margin-left:12px;font-size:var(--text-label)}h3.svelte-1tl5wtp{font-size:var(--text-label);font-weight:500;margin:0 0 10px}.release-section.svelte-1tl5wtp{max-width:100ch;margin-top:28px}li.svelte-1tl5wtp+li:where(.svelte-1tl5wtp){margin-top:8px}ul.svelte-1tl5wtp{margin:0;padding-left:20px;line-height:1.8}@media(max-width:760px){.changelog.svelte-1tl5wtp{padding:24px 16px}}.secrets.svelte-sh54s5{margin-top:28px}h2.svelte-sh54s5{font-size:18px;margin:0;font-weight:500}.section-heading.svelte-sh54s5{display:flex;align-items:center;justify-content:space-between;gap:16px}.count.svelte-sh54s5,.section-note.svelte-sh54s5{font-size:var(--text-small);color:var(--muted)}.section-note.svelte-sh54s5{margin:8px 0 22px;line-height:1.6}ul.svelte-sh54s5{padding:0;margin:0;list-style:none}.list-heading.svelte-sh54s5,li.svelte-sh54s5{display:grid;grid-template-columns:minmax(0,1fr) 130px minmax(124px,auto);gap:16px;align-items:center}.list-heading.svelte-sh54s5{padding:0 0 10px;border-bottom:1px solid var(--border);color:var(--muted);font-size:var(--text-small)}li.svelte-sh54s5{min-height:66px;padding:12px 0;border-bottom:1px solid var(--border)}code.svelte-sh54s5{overflow-wrap:anywhere;font-size:var(--text-small)}.secret-status.svelte-sh54s5{display:flex;gap:7px;align-items:center;font-size:var(--text-small);color:var(--muted)}.secret-status.svelte-sh54s5 i:where(.svelte-sh54s5){width:6px;height:6px;flex-shrink:0;background:currentColor}.secret-status.configured.svelte-sh54s5{color:var(--ok)}.actions.svelte-sh54s5{display:flex;justify-content:flex-end;gap:14px}.text-action.svelte-sh54s5{padding:4px 0;min-height:32px;border:0;background:transparent;font-size:var(--text-small);text-decoration:underline;text-underline-offset:4px}.text-action.svelte-sh54s5:hover{text-decoration-thickness:2px}.remove.svelte-sh54s5{color:var(--muted)}.count.svelte-sh54s5{display:block;margin-top:6px}.secret-editor.svelte-sh54s5{position:relative}summary.svelte-sh54s5{cursor:pointer;list-style:none;display:inline-flex;gap:7px;align-items:center;justify-content:center}summary.svelte-sh54s5::-webkit-details-marker{display:none}summary[aria-disabled=true].svelte-sh54s5{opacity:.5;cursor:default}.add-secret.svelte-sh54s5{padding:7px 12px;min-height:var(--control-height);border:1px solid var(--border);font-weight:500}.add-secret.svelte-sh54s5:hover{background:var(--bg-2)}.editor-popover.svelte-sh54s5{position:absolute;top:calc(100% + 8px);right:0;z-index:40;width:min(340px,calc(100vw - 110px));padding:20px;background:var(--bg);border:1px solid var(--border);box-shadow:0 8px 24px #0002;text-align:left}.editor-popover.svelte-sh54s5 h2:where(.svelte-sh54s5){margin-bottom:20px}.editor-popover.svelte-sh54s5 .section-note:where(.svelte-sh54s5){margin:14px 0}.editor-popover.svelte-sh54s5 .primary:where(.svelte-sh54s5){width:100%}.fields.svelte-sh54s5{display:grid;grid-template-columns:1fr;gap:16px}label.svelte-sh54s5{display:grid;gap:8px;font-size:var(--text-small);font-weight:500;min-width:0}input.svelte-sh54s5{width:100%;min-width:0;background:var(--bg)}.storage-note.svelte-sh54s5{margin-top:28px;padding-left:14px;border-left:2px solid var(--border);max-width:680px;font-size:var(--text-small);color:var(--muted)}.storage-note.svelte-sh54s5 strong:where(.svelte-sh54s5){font-weight:500;color:var(--text)}.storage-note.svelte-sh54s5 p:where(.svelte-sh54s5){margin:6px 0 0;line-height:1.6}.error.svelte-sh54s5{color:var(--err)}.saved.svelte-sh54s5{color:var(--ok)}.empty.svelte-sh54s5{padding:22px 0;border-block:1px solid var(--border);color:var(--muted)}@media(max-width:1000px){.list-heading.svelte-sh54s5{display:none}li.svelte-sh54s5{grid-template-columns:minmax(0,1fr) auto;gap:8px 16px}.secret-status.svelte-sh54s5{grid-column:1;grid-row:2}.actions.svelte-sh54s5{grid-column:2;grid-row:1 / 3}}@media(max-width:650px){.fields.svelte-sh54s5{grid-template-columns:1fr;gap:16px}form.svelte-sh54s5{padding:18px}}.share-line.svelte-iodvty{display:flex;align-items:center;flex-wrap:wrap;gap:8px 16px;min-width:0}.slow-hint.svelte-iodvty{flex-basis:100%;color:var(--muted);font-size:var(--text-small)}.slow-hint.svelte-iodvty a:where(.svelte-iodvty){text-decoration:underline}.password.svelte-iodvty{display:inline-flex;flex-wrap:wrap;align-items:center;gap:7px;color:var(--muted);font-size:var(--text-small);overflow-wrap:anywhere}.password.svelte-iodvty button:where(.svelte-iodvty){padding:0;min-height:0;border:0;background:transparent;text-decoration:underline;color:inherit}a.svelte-iodvty{width:fit-content;max-width:100%;overflow-wrap:anywhere;color:var(--share);font-size:var(--text-small)}.connecting.svelte-iodvty,.error.svelte-iodvty{display:flex;align-items:center;gap:7px;font-size:var(--text-small)}.connecting.svelte-iodvty{flex-wrap:wrap;color:var(--muted)}.error.svelte-iodvty{color:var(--err);align-items:flex-start;overflow-wrap:anywhere}.error.svelte-iodvty svg{flex-shrink:0;margin-top:3px}.spinner.svelte-iodvty{display:inline-flex;animation:svelte-iodvty-spin 1s linear infinite}@keyframes svelte-iodvty-spin{to{transform:rotate(360deg)}}@media(prefers-reduced-motion:reduce){.spinner.svelte-iodvty{animation:none}}.menu-item.svelte-1u7hpyn>summary:where(.svelte-1u7hpyn){justify-content:flex-start;gap:10px;border:0;font-weight:400;padding:10px 12px}.menu-item.svelte-1u7hpyn .share-popover:where(.svelte-1u7hpyn){position:static;width:100%;box-shadow:none;border:0;padding:12px}.share-control.svelte-1u7hpyn{position:relative}summary.svelte-1u7hpyn{display:flex;align-items:center;justify-content:center;gap:7px;padding:7px 12px;min-height:var(--control-height);border:1px solid var(--border);list-style:none;font-weight:500}summary.svelte-1u7hpyn::-webkit-details-marker{display:none}summary.svelte-1u7hpyn:hover{background:var(--bg-2);border-color:var(--muted)}.share-popover.svelte-1u7hpyn{position:absolute;right:0;top:calc(100% + 8px);z-index:30;width:min(340px,calc(100vw - 96px));padding:18px;border:1px solid var(--border);background:var(--bg);box-shadow:0 8px 24px #0002;text-align:left}.share-url.svelte-1u7hpyn{display:block;margin-top:12px;overflow-wrap:anywhere}p.svelte-1u7hpyn{font-size:var(--text-small);color:var(--muted);line-height:1.6;overflow-wrap:anywhere}label.svelte-1u7hpyn{display:grid;gap:6px;font-size:var(--text-small)}input.svelte-1u7hpyn{width:100%;min-width:0}.actions.svelte-1u7hpyn{display:flex;flex-wrap:wrap;gap:8px}.error.svelte-1u7hpyn{color:var(--err)}.service-options.svelte-m918bk{position:relative}summary.svelte-m918bk{display:flex;align-items:center;justify-content:center;gap:8px;padding:7px 12px;min-height:var(--control-height);border:1px solid var(--border);list-style:none;font-weight:500;cursor:pointer}summary.svelte-m918bk::-webkit-details-marker{display:none}summary.svelte-m918bk:hover,.service-options[open].svelte-m918bk>summary:where(.svelte-m918bk){background:var(--bg-2);border-color:var(--muted)}.options-popover.svelte-m918bk{position:absolute;z-index:40;right:0;top:calc(100% + 6px);width:min(300px,calc(100vw - 100px));padding:6px;background:var(--bg);border:1px solid var(--border);box-shadow:0 8px 24px #0002}.options-popover.svelte-m918bk>button:where(.svelte-m918bk){width:100%;border:0;background:transparent;display:flex;gap:10px;justify-content:flex-start;padding:10px 12px;text-align:left;font-weight:400}.options-popover.svelte-m918bk>button:where(.svelte-m918bk):hover{background:var(--bg-2)}.share-action.svelte-m918bk{border-top:1px solid var(--border);margin-top:4px;padding-top:4px}.service-error.svelte-13pnhk8{padding:12px 0;font-size:var(--text-small);overflow-wrap:anywhere}strong.svelte-13pnhk8,p.svelte-13pnhk8{color:var(--err)}p.svelte-13pnhk8{margin:0;white-space:pre-wrap}ul.svelte-13pnhk8{margin:8px 0 12px;padding-left:20px;color:var(--text);line-height:1.7}li.svelte-13pnhk8+li:where(.svelte-13pnhk8){margin-top:6px}summary.svelte-13pnhk8{width:fit-content;color:var(--muted)}pre.svelte-13pnhk8{margin:8px 0 0;white-space:pre-wrap;font:inherit;font-family:var(--mono);color:var(--muted)}.diagnostics.svelte-1xk5qw3{margin:16px 0;padding:12px;border:1px solid var(--border);border-radius:0}summary.svelte-1xk5qw3{cursor:pointer}p.svelte-1xk5qw3{color:var(--muted);font-size:var(--text-small)}textarea.svelte-1xk5qw3{display:block;width:100%;box-sizing:border-box;margin:8px 0;background:var(--bg-2);color:var(--text);border:1px solid var(--border);font:var(--text-small)/1.5 var(--mono)}form.svelte-1gn57ev{width:100%;min-width:0;padding:20px 0 8px}fieldset.svelte-1gn57ev{border:0;padding:0;margin:0;min-width:0}.fields.svelte-1gn57ev{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px}label.svelte-1gn57ev{display:flex;flex-direction:column;gap:6px;font-size:var(--text-body);color:var(--text)}input.svelte-1gn57ev,select.svelte-1gn57ev{width:100%;min-width:0;background:var(--bg)}.dependencies.svelte-1gn57ev{margin:20px 0;font-size:var(--text-small)}.dependencies.svelte-1gn57ev>div:where(.svelte-1gn57ev){display:flex;flex-wrap:wrap;gap:16px;margin-top:8px}.dependencies.svelte-1gn57ev label:where(.svelte-1gn57ev){flex-direction:row;align-items:center}.dependencies.svelte-1gn57ev input:where(.svelte-1gn57ev){width:auto}p.svelte-1gn57ev{color:var(--muted);font-size:var(--text-small)}.error.svelte-1gn57ev{color:var(--err)}@media(max-width:600px){.fields.svelte-1gn57ev{grid-template-columns:1fr}}form.svelte-ruqv4s{margin:24px 0 40px;max-width:480px}label.svelte-ruqv4s{font-weight:600}p.svelte-ruqv4s{font-size:var(--text-small);color:var(--muted);line-height:1.6}.controls.svelte-ruqv4s{display:flex;gap:8px;margin-top:8px}input.svelte-ruqv4s{flex:1;width:180px;min-width:0}.error.svelte-ruqv4s{color:var(--err);margin-bottom:0}.notice.svelte-ruqv4s{color:var(--ok);margin-bottom:0}.hint.svelte-ruqv4s{font-size:var(--text-small)}.service-port.svelte-1poq4pf{display:flex;flex-wrap:wrap;gap:4px 16px;color:var(--muted);font-size:var(--text-small);line-height:1.5}strong.svelte-1poq4pf{color:var(--text);font-weight:500}.project-overview.svelte-l7un4l{min-height:100%;padding:48px 40px 40px;width:100%;max-width:1500px;margin:0 auto;display:flex;flex-direction:column}header.svelte-l7un4l{display:flex;flex-wrap:wrap;align-items:flex-start;justify-content:space-between;gap:20px}.heading.svelte-l7un4l{min-width:0}.eyebrow.svelte-l7un4l{margin:0 0 3px;color:var(--muted);font-size:var(--text-small);font-weight:600;letter-spacing:.1em;text-transform:none}h1.svelte-l7un4l,h2.svelte-l7un4l,p.svelte-l7un4l{margin-top:0}h1.svelte-l7un4l{margin:0 0 18px;font:600 var(--text-title)/1.4 var(--sans);letter-spacing:0;line-height:1.2;overflow-wrap:anywhere}h2.svelte-l7un4l{margin-bottom:8px;font-size:var(--text-section)}.project-actions.svelte-l7un4l,.service-actions.svelte-l7un4l,.recovery-actions.svelte-l7un4l{display:flex;align-items:center;gap:8px}.summary-row.svelte-l7un4l{display:flex;flex-wrap:wrap;gap:14px;padding:4px 0;color:var(--muted);font-size:var(--text-small)}.summary-row.svelte-l7un4l strong:where(.svelte-l7un4l){color:var(--text);font-variant-numeric:tabular-nums}.bulk-actions.svelte-l7un4l{margin-bottom:24px}.bulk-summary.svelte-l7un4l{margin:0 0 10px;color:var(--muted)}.service-grid.svelte-l7un4l{display:grid;grid-template-columns:1fr;gap:0}.service-card.svelte-l7un4l{min-width:0;display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;column-gap:16px;padding:22px 0;border-bottom:1px solid var(--border)}.service-card.failed.svelte-l7un4l{border-color:#f87171a6}.service-main.svelte-l7un4l{display:grid;grid-template-columns:minmax(0,1fr);justify-content:stretch;width:100%;padding:0;border:0;background:transparent;text-align:left;white-space:normal}.service-main.svelte-l7un4l:hover{background:transparent}.service-heading.svelte-l7un4l{display:flex;align-items:center;gap:8px}.status-dot.svelte-l7un4l{width:7px;height:7px;border-radius:0;background:var(--muted)}.status-dot.running.svelte-l7un4l{background:var(--ok)}.status-dot.waiting.svelte-l7un4l{background:var(--warn)}.status-text.svelte-l7un4l{margin-left:8px;color:var(--muted);font-size:var(--text-small);background:var(--bg-3);border-radius:0;padding:2px 7px}.ownership.svelte-l7un4l{margin:4px 0 8px 15px;color:var(--muted);font-size:var(--text-small)}.service-url.svelte-l7un4l{color:var(--accent);overflow:hidden;text-overflow:ellipsis}.command.svelte-l7un4l{margin-top:7px;color:var(--text);overflow:hidden;text-overflow:ellipsis}.dependency-summary.svelte-l7un4l{margin-top:7px;color:var(--accent);font-size:var(--text-small)}.dependency-summary.svelte-l7un4l span:where(.svelte-l7un4l){color:var(--muted)}.dependency-editor.svelte-l7un4l{margin-top:10px;padding-top:9px;border-top:1px solid var(--border)}.dependency-editor.svelte-l7un4l summary:where(.svelte-l7un4l){color:var(--muted);cursor:pointer;font-size:var(--text-small)}.dependency-editor.svelte-l7un4l form:where(.svelte-l7un4l){margin-top:9px}.dependency-editor.svelte-l7un4l fieldset:where(.svelte-l7un4l){display:flex;flex-wrap:wrap;gap:7px 12px;margin:0;padding:0;border:0}.dependency-editor.svelte-l7un4l legend:where(.svelte-l7un4l){width:100%;margin-bottom:6px;color:var(--muted);font-size:var(--text-small)}.dependency-editor.svelte-l7un4l label:where(.svelte-l7un4l){display:inline-flex;align-items:center;gap:5px;font-size:var(--text-small)}.dependency-actions.svelte-l7un4l{display:flex;gap:7px;margin-top:10px}.no-dependencies.svelte-l7un4l{color:var(--muted);font-size:var(--text-small)}.inline-error.svelte-l7un4l{margin:9px 0 0;color:var(--err);font-size:var(--text-small);overflow-wrap:anywhere}.unavailable.svelte-l7un4l{display:flex;justify-content:space-between;align-items:center;gap:20px;margin-top:16px;padding:16px;border:1px solid rgba(248,113,113,.55);border-radius:0;background:var(--bg-2)}.unavailable.svelte-l7un4l p:where(.svelte-l7un4l),.empty-services.svelte-l7un4l p:where(.svelte-l7un4l){margin-bottom:0;color:var(--muted)}.active-services.svelte-l7un4l{margin-top:18px}.active-services.svelte-l7un4l>h2:where(.svelte-l7un4l){margin-bottom:3px}.active-services.svelte-l7un4l>p:where(.svelte-l7un4l){margin-bottom:10px;color:var(--muted)}.empty-services.svelte-l7un4l{grid-column:1 / -1;padding:24px;border:1px dashed var(--border);border-radius:0;text-align:center}.launch-panel.svelte-l7un4l{padding:20px;background:var(--bg-2);border:1px solid var(--err);border-radius:0;margin-bottom:32px}.launch-panel.svelte-l7un4l h2:where(.svelte-l7un4l){font-size:var(--text-section);letter-spacing:-.025em;margin:7px 0}.launch-panel.svelte-l7un4l p:where(.svelte-l7un4l):last-child{color:var(--muted);margin-bottom:0;font-size:var(--text-small)}.open-app.svelte-l7un4l{display:inline-flex;align-items:center;gap:10px;padding:7px 12px;min-height:var(--control-height);font-family:var(--sans);line-height:1.4;border-radius:0;background:var(--text);color:var(--bg);font-weight:600;white-space:nowrap;font-size:var(--text-body)}.open-app.svelte-l7un4l:hover{background:#41413a;text-decoration:none}.list-heading.svelte-l7un4l{display:flex;align-items:center;justify-content:space-between;gap:16px;margin-bottom:18px}.list-heading.svelte-l7un4l h2:where(.svelte-l7un4l){font-size:var(--text-section);margin:0;font-weight:600}.service-search.svelte-l7un4l span:where(.svelte-l7un4l){display:block;color:var(--muted);font-size:var(--text-small);margin-bottom:4px}.service-search.svelte-l7un4l input:where(.svelte-l7un4l){background:var(--bg-2);width:220px}.service-heading.svelte-l7un4l strong:where(.svelte-l7un4l){font-size:var(--text-body)}.service-settings.svelte-l7un4l{grid-column:1 / -1;margin-top:14px;border-top:1px solid var(--border);padding-top:9px;color:var(--muted);font-size:var(--text-small)}.service-settings[open].svelte-l7un4l{padding-bottom:12px}.service-open.svelte-l7un4l{font-weight:600;padding:8px;white-space:nowrap}.service-actions.svelte-l7un4l{flex-wrap:wrap;justify-content:flex-end}.copy.svelte-l7un4l{background:transparent}.service-links.svelte-l7un4l{display:grid;gap:5px;margin-top:8px;min-width:0}.service-links.svelte-l7un4l a:where(.svelte-l7un4l){width:fit-content;max-width:100%;overflow-wrap:anywhere;font-size:var(--text-small)}.inline-error.svelte-l7un4l{grid-column:1 / -1}.settings-panel.svelte-l7un4l{width:100%;min-width:0}.settings-title.svelte-l7un4l{margin:28px 0 8px}.settings-project.svelte-l7un4l,.settings-note.svelte-l7un4l{color:var(--muted);font-size:var(--text-small)}.config-list.svelte-l7un4l{width:100%;min-width:0;margin:20px 0 32px;border-top:1px solid var(--border)}.config-list.svelte-l7un4l>details:where(.svelte-l7un4l){min-width:0;border-bottom:1px solid var(--border);padding:16px 0}.config-list.svelte-l7un4l summary:where(.svelte-l7un4l){min-height:var(--control-height);display:flex;gap:20px;align-items:center;list-style:none}.config-list.svelte-l7un4l summary:where(.svelte-l7un4l)::-webkit-details-marker{display:none}.config-list.svelte-l7un4l summary:where(.svelte-l7un4l) strong:where(.svelte-l7un4l){min-width:80px;font:500 var(--text-label)/1.4 var(--sans)}.config-list.svelte-l7un4l summary:where(.svelte-l7un4l) span:where(.svelte-l7un4l){color:var(--muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--text-small)}.config-list.svelte-l7un4l summary:where(.svelte-l7un4l) .edit-label:where(.svelte-l7un4l){margin-left:auto;flex-shrink:0;color:var(--text)}.settings-tools.svelte-l7un4l{padding:12px 0;color:var(--muted)}.settings-panel.svelte-l7un4l h2:where(.svelte-l7un4l){margin-top:24px}.project-health.svelte-l7un4l{display:flex;align-items:center;gap:12px;color:var(--muted);font-size:var(--text-label);margin-bottom:0}.project-health.svelte-l7un4l:has(.running:where(.svelte-l7un4l)){color:var(--ok)}.project-address.svelte-l7un4l{display:flex;align-items:center;gap:12px;min-width:0;color:var(--muted);padding:24px 0;border-bottom:1px solid var(--border);margin-bottom:28px}.project-address.svelte-l7un4l a:where(.svelte-l7un4l){color:var(--muted);overflow-wrap:anywhere;font-size:var(--text-body)}.project-address.svelte-l7un4l button:where(.svelte-l7un4l),.manage-button.svelte-l7un4l{display:inline-flex;align-items:center;border:0;background:transparent;color:var(--muted);padding:10px}.manage-button.svelte-l7un4l{text-decoration:none;border:1px solid var(--border);min-height:var(--control-height);gap:8px;padding:7px 12px;justify-content:center}.overview-row.svelte-l7un4l{display:grid;grid-template-columns:36px minmax(90px,1fr) minmax(60px,.8fr) minmax(90px,1fr);gap:16px;align-items:center;width:100%;font-size:var(--text-body)}.overview-row.svelte-l7un4l strong:where(.svelte-l7un4l){font-size:var(--text-label);font-weight:500;overflow-wrap:anywhere}.service-icon.svelte-l7un4l{width:36px;height:36px;display:grid;place-items:center;border:1px solid var(--border);border-radius:0;background:var(--bg-2);color:var(--muted)}.technical-name.svelte-l7un4l{color:var(--muted);font-weight:400;overflow-wrap:anywhere}.row-health.svelte-l7un4l{display:flex;align-items:center;gap:9px;color:var(--muted);font-weight:400}.row-health.svelte-l7un4l .status-dot:where(.svelte-l7un4l){background:currentColor;flex-shrink:0}.row-health.ready.svelte-l7un4l{color:var(--ok)}.row-health.errored.svelte-l7un4l{color:var(--err)}.row-health.svelte-l7un4l{text-transform:capitalize}.readiness-summary.svelte-l7un4l{color:var(--muted);font-size:var(--text-body);margin:24px 0 48px}.managing.svelte-l7un4l{margin-top:32px}.muted.svelte-l7un4l{color:var(--muted)}.profiles.svelte-l7un4l{padding:18px;border:1px solid var(--border);border-radius:0;background:var(--bg-2)}.profiles[open].svelte-l7un4l summary:where(.svelte-l7un4l){margin-bottom:16px}@media(min-width:801px)and (max-width:1100px){.project-overview.svelte-l7un4l{padding:48px 28px}.overview-row.svelte-l7un4l{grid-template-columns:48px minmax(0,1fr) auto;gap:16px}.technical-name.svelte-l7un4l{white-space:nowrap;display:none}.managing.svelte-l7un4l .service-card:where(.svelte-l7un4l){grid-template-columns:1fr}.managing.svelte-l7un4l .service-actions:where(.svelte-l7un4l){justify-content:flex-start;margin-top:16px}}@media(max-width:800px){.project-overview.svelte-l7un4l{padding:16px}header.svelte-l7un4l,.unavailable.svelte-l7un4l{align-items:stretch;flex-direction:column}.project-actions.svelte-l7un4l button:where(.svelte-l7un4l),.recovery-actions.svelte-l7un4l button:where(.svelte-l7un4l){flex:1}.service-grid.svelte-l7un4l{grid-template-columns:1fr}.service-card.svelte-l7un4l{grid-template-columns:1fr;padding:18px}.service-actions.svelte-l7un4l{justify-content:flex-start;margin-top:16px;gap:6px}.service-actions.svelte-l7un4l button:where(.svelte-l7un4l){padding:8px 10px}.launch-panel.svelte-l7un4l{align-items:flex-start;flex-direction:column;padding:20px}.list-heading.svelte-l7un4l{align-items:stretch;flex-direction:column}.service-search.svelte-l7un4l input:where(.svelte-l7un4l){width:100%}.project-actions.svelte-l7un4l{flex-wrap:wrap}header.svelte-l7un4l{flex-direction:row;align-items:flex-start;gap:12px}h1.svelte-l7un4l{font-size:1.5rem}.open-app.svelte-l7un4l{padding:7px 12px;font-size:var(--text-small)}.project-actions.svelte-l7un4l{gap:8px;flex-shrink:0}.manage-button.svelte-l7un4l{min-height:var(--control-height)}.project-address.svelte-l7un4l{padding:24px 0;margin-bottom:28px}.overview-row.svelte-l7un4l{grid-template-columns:40px minmax(0,1fr) auto;gap:12px}.service-icon.svelte-l7un4l{width:40px;height:40px}.technical-name.svelte-l7un4l{white-space:nowrap;display:none}.overview-row.svelte-l7un4l strong:where(.svelte-l7un4l){font-size:var(--text-label)}.row-health.svelte-l7un4l{font-size:var(--text-small)}.service-card.svelte-l7un4l{padding:18px 0}}.service-row.svelte-1h3c7zm{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:12px 24px;padding:20px 0;border-bottom:1px solid var(--border)}.service-info.svelte-1h3c7zm{display:grid;gap:5px;min-width:0}.service-heading.svelte-1h3c7zm{display:flex;align-items:center;gap:9px}strong.svelte-1h3c7zm{font-size:var(--text-label);font-weight:500}.status-dot.svelte-1h3c7zm{width:7px;height:7px;background:var(--muted);flex-shrink:0}.status-dot.running.svelte-1h3c7zm{background:var(--ok)}.service-status.svelte-1h3c7zm,.project-name.svelte-1h3c7zm{color:var(--muted);font-size:var(--text-small)}.service-status.svelte-1h3c7zm{margin-left:6px}.service-address.svelte-1h3c7zm{width:fit-content;max-width:100%;overflow-wrap:anywhere;color:var(--text)}.service-controls.svelte-1h3c7zm{display:flex;align-items:center;gap:8px;flex-wrap:wrap}button.svelte-1h3c7zm{display:inline-flex;justify-content:center;align-items:center;gap:7px}.action-error.svelte-1h3c7zm{grid-column:1 / -1;margin:0;color:var(--err);font-size:var(--text-small)}@media(max-width:900px){.service-row.svelte-1h3c7zm{grid-template-columns:minmax(0,1fr)}.service-controls.svelte-1h3c7zm{justify-content:flex-start}}.metadata.svelte-s74nzf{display:flex;flex-direction:column;margin:16px 0}details.svelte-s74nzf{min-width:0;border-bottom:1px solid var(--chrome-border)}summary.svelte-s74nzf{display:flex;align-items:center;justify-content:space-between;padding:10px 0;list-style:none;cursor:pointer;font-weight:600;color:var(--chrome-text)}summary.svelte-s74nzf::-webkit-details-marker{display:none}summary.svelte-s74nzf:after{content:"›";font-size:1rem}details[open].svelte-s74nzf>summary:where(.svelte-s74nzf):after{transform:rotate(90deg)}summary.svelte-s74nzf:hover{color:#fff}pre.svelte-s74nzf{white-space:pre-wrap;overflow-wrap:anywhere;font:.75rem/1.6 var(--mono)}dl.svelte-s74nzf{margin:8px 0;font-family:var(--mono)}dl.svelte-s74nzf>div:where(.svelte-s74nzf){display:grid;grid-template-columns:minmax(90px,1fr) minmax(0,2fr);gap:12px;padding:5px 0;border-bottom:1px solid var(--chrome-border)}dt.svelte-s74nzf,dd.svelte-s74nzf{overflow-wrap:anywhere;white-space:pre-wrap}dd.svelte-s74nzf{margin:0;color:var(--chrome-muted)}h4.svelte-s74nzf{font-size:inherit;margin:12px 0 6px}p.svelte-s74nzf{color:var(--chrome-muted)}.requests-panel.svelte-tqqrb7{flex:1;min-height:0;overflow:auto;font-size:.75rem}.request-list.svelte-tqqrb7{min-height:80px}table.svelte-tqqrb7{width:100%;border-collapse:collapse;text-align:left}th.svelte-tqqrb7,td.svelte-tqqrb7{padding:6px 14px;border-bottom:1px solid var(--chrome-border)}th.svelte-tqqrb7{position:sticky;top:0;background:var(--chrome);color:var(--chrome-muted)}.request-row.svelte-tqqrb7{cursor:pointer;transition:background-color .12s ease}.request-row.selected.svelte-tqqrb7{background:#ffffff0b}.request-row.svelte-tqqrb7:hover,.request-row.svelte-tqqrb7:focus-within{background:#ffffff18}@media(prefers-reduced-motion:reduce){.request-row.svelte-tqqrb7{transition:none}}button.svelte-tqqrb7{font:inherit;color:var(--chrome-text);background:transparent;min-height:0}td.svelte-tqqrb7 button:where(.svelte-tqqrb7){padding:0;border:0;text-decoration:underline;text-align:left;white-space:normal;overflow-wrap:anywhere}.inspector.svelte-tqqrb7{padding:12px 14px;overflow-wrap:anywhere}p.svelte-tqqrb7,span.svelte-tqqrb7{color:var(--chrome-muted)}.replay.svelte-tqqrb7{border:1px solid var(--chrome-border);padding:6px 10px}.error.svelte-tqqrb7{color:#ff9c92}.empty.svelte-tqqrb7{padding:14px}.request-filter-bar.svelte-147la1m{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:8px;padding:8px 14px;color:var(--chrome-muted);font-size:.75rem;border-bottom:1px solid var(--chrome-border)}.request-filter-bar.svelte-147la1m label:where(.svelte-147la1m){display:flex;align-items:center;gap:6px;cursor:pointer}.logs-dock.svelte-147la1m{position:relative;display:flex;flex-direction:column;min-height:0;min-width:0;color:var(--chrome-text);background:var(--chrome);border-top:1px solid var(--chrome-border)}.resize-handle.svelte-147la1m{position:absolute;top:-4px;left:0;right:0;height:8px;cursor:ns-resize;touch-action:none;z-index:31}.resize-handle.svelte-147la1m:hover,.resize-handle.svelte-147la1m:focus-visible{background:var(--chrome-muted);outline:none}.logs-toolbar.svelte-147la1m{display:flex;align-items:center;gap:8px;padding:8px 14px;flex:0 0 auto}h2.svelte-147la1m{display:flex;align-items:center;gap:8px;margin:0 10px 0 0;font-size:.875rem;font-weight:500}button.svelte-147la1m,summary.svelte-147la1m{display:inline-flex;align-items:center;justify-content:center;gap:6px;min-height:32px;color:var(--chrome-text);border-color:var(--chrome-border);font-size:.75rem;padding:5px 9px}button.svelte-147la1m:hover,summary.svelte-147la1m:hover{background:#ffffff0b;border-color:var(--chrome-muted)}button.svelte-147la1m:focus-visible,summary.svelte-147la1m:focus-visible,input.svelte-147la1m:focus-visible,.log-output.svelte-147la1m:focus-visible{outline:2px solid var(--chrome-muted);outline-offset:-2px}.source-picker.svelte-147la1m{position:relative;flex-shrink:0}summary.svelte-147la1m{list-style:none;border:1px solid var(--chrome-border)}summary.svelte-147la1m::-webkit-details-marker{display:none}.count.svelte-147la1m{color:var(--chrome-muted)}.source-options.svelte-147la1m{position:absolute;top:calc(100% + 8px);left:0;z-index:30;width:min(300px,calc(100vw - 40px));max-height:min(260px,calc(var(--logs-height) - 100px));overflow:auto;border:1px solid var(--chrome-border);padding:8px;background:var(--chrome);box-shadow:0 8px 24px #0005}.picker-label.svelte-147la1m{color:var(--chrome-muted);padding:5px 8px 8px;font-size:.75rem}.source-options.svelte-147la1m label:where(.svelte-147la1m){display:flex;align-items:center;gap:9px;padding:6px 8px;cursor:pointer;font-size:.8125rem}.source-options.svelte-147la1m label:where(.svelte-147la1m):hover{background:#ffffff0b}.source-options.svelte-147la1m small:where(.svelte-147la1m){display:block;color:var(--chrome-muted)}.source-options.svelte-147la1m input:where(.svelte-147la1m){accent-color:var(--chrome-muted)}.filter.svelte-147la1m{display:flex;align-items:center;gap:7px;flex:1;min-width:110px;max-width:360px;color:var(--chrome-muted);border:1px solid var(--chrome-border);padding-left:9px}.filter.svelte-147la1m input:where(.svelte-147la1m){min-width:0;width:100%;min-height:30px;border:0;padding:4px 8px 4px 0;font-size:.75rem;color:var(--chrome-text)}.filter.svelte-147la1m input:where(.svelte-147la1m)::placeholder{color:var(--chrome-muted)}.close.svelte-147la1m{margin-left:auto;width:32px;padding:0;flex-shrink:0;border:0;background:transparent;color:var(--chrome-muted)}.close.svelte-147la1m:hover{background:transparent;color:var(--chrome-text)}.source-tabs.svelte-147la1m{display:flex;gap:0;flex-shrink:0;overflow-x:auto;border-bottom:1px solid var(--chrome-border);padding:0 14px}.source-tabs.svelte-147la1m button:where(.svelte-147la1m){border:0;border-bottom:2px solid transparent;color:var(--chrome-muted);padding:5px 12px}.source-tabs.svelte-147la1m button.active:where(.svelte-147la1m){border-bottom-color:var(--chrome-text);color:var(--chrome-text)}.source-tab.svelte-147la1m{display:flex;flex-shrink:0;align-items:center}.source-tabs.svelte-147la1m .clear-source:where(.svelte-147la1m){padding:5px}.clear-source.svelte-147la1m:disabled{opacity:.4;cursor:wait}.project-name.svelte-147la1m{opacity:.7}.log-output.svelte-147la1m{flex:1;overflow:auto;min-height:0;padding:8px 14px;font:.75rem/1.7 var(--mono)}.log-row.svelte-147la1m{display:flex;gap:14px;width:max-content;min-width:100%}time.svelte-147la1m{color:var(--chrome-muted);flex:0 0 8ch}.source.svelte-147la1m{color:#bcbcb1;width:24ch;flex-shrink:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.stream.svelte-147la1m{width:6ch;flex-shrink:0;color:var(--chrome-muted)}.line.svelte-147la1m{white-space:pre}.shared.svelte-147la1m{color:#91c7c4}.shared.svelte-147la1m .stream:where(.svelte-147la1m){color:#91c7c4;font-weight:500}.stderr.svelte-147la1m .stream:where(.svelte-147la1m){color:#d1b78d}.empty.svelte-147la1m{display:flex;flex-direction:column;align-items:center;justify-content:center;min-height:100%;gap:4px;text-align:center;font-family:var(--sans)}.empty.svelte-147la1m strong:where(.svelte-147la1m){font-weight:500;font-size:.8125rem}.empty.svelte-147la1m span:where(.svelte-147la1m){color:var(--chrome-muted)}.history-error.svelte-147la1m{padding:8px 14px;color:var(--chrome-text);display:flex;align-items:center;gap:12px}.logs-status.svelte-147la1m{display:flex;align-items:center;justify-content:space-between;gap:10px;flex-shrink:0;min-height:30px;padding:0 14px;border-top:1px solid var(--chrome-border);color:var(--chrome-muted);font-size:.6875rem}.logs-status.svelte-147la1m button:where(.svelte-147la1m){border:0;min-height:28px;font-size:.6875rem;padding:2px 5px}@media(max-width:680px){.logs-toolbar.svelte-147la1m{flex-wrap:wrap;gap:6px;padding:6px 10px}h2.svelte-147la1m{margin-right:0}.filter.svelte-147la1m{order:5;flex-basis:100%;max-width:none}.record-count.svelte-147la1m{display:none}.source.svelte-147la1m{width:18ch}}.secrets-page.svelte-1n46o8q{padding:36px 40px 56px;width:100%;max-width:1080px}.secrets-page-heading.svelte-1n46o8q{margin-top:28px;padding-bottom:24px;border-bottom:1px solid var(--border)}.secrets-page-heading.svelte-1n46o8q h1:where(.svelte-1n46o8q){margin:6px 0 0}.secrets-page-heading.svelte-1n46o8q p:where(.svelte-1n46o8q){margin:0;font:var(--text-small)/1.5 var(--mono)}@media(max-width:700px){.secrets-page.svelte-1n46o8q{padding:24px 20px}}.secrets-page-heading.svelte-1n46o8q p:where(.svelte-1n46o8q){color:var(--muted)}.layout.svelte-1n46o8q{position:relative;display:grid;grid-template-columns:var(--sidebar-width) minmax(0,1fr);grid-template-rows:minmax(0,1fr) auto auto;height:100dvh;min-height:0;background:var(--chrome)}.app-rail.svelte-1n46o8q{position:relative;grid-row:1 / 3;min-height:0;border-right:1px solid var(--chrome-border);display:flex;flex-direction:column;color:var(--chrome-text)}.brand.svelte-1n46o8q{letter-spacing:-.03em;display:flex;align-items:center;justify-content:space-between;padding:20px 16px;font:500 var(--text-section)/1.2 var(--sans);text-transform:none}.brand-identity.svelte-1n46o8q{display:flex;align-items:center;gap:10px;min-width:0}.brand-identity.svelte-1n46o8q img:where(.svelte-1n46o8q){display:block;flex-shrink:0}.brand-name.svelte-1n46o8q{font-size:var(--text-label)}.collapsed.svelte-1n46o8q .brand-name:where(.svelte-1n46o8q){display:none}.app-rail.svelte-1n46o8q nav:where(.svelte-1n46o8q){display:grid;gap:4px;padding:0 8px}.app-rail.svelte-1n46o8q :is(button:where(.svelte-1n46o8q),a:where(.svelte-1n46o8q)){display:flex;align-items:center;gap:10px;width:100%;min-height:44px;padding:12px 16px;font:500 var(--text-body)/1.4 var(--sans);text-transform:none;color:var(--chrome-muted);background:transparent;border:0;border-left:3px solid transparent;text-align:left}.app-rail.svelte-1n46o8q :where(.svelte-1n46o8q):is(button:where(.svelte-1n46o8q),a:where(.svelte-1n46o8q)):hover{color:var(--chrome-text);background:#ffffff0c}.app-rail.svelte-1n46o8q a:where(.svelte-1n46o8q){text-decoration:none}.app-rail.svelte-1n46o8q a.active:where(.svelte-1n46o8q){color:var(--chrome-text);border-left-color:var(--orange)}.app-rail.svelte-1n46o8q :is(button:where(.svelte-1n46o8q),a:where(.svelte-1n46o8q)) svg{flex-shrink:0}main.svelte-1n46o8q{grid-column:2;grid-row:1;min-width:0;min-height:0;overflow:auto;display:flex;flex-direction:column;background:var(--bg);color:var(--text)}.logs-slot.svelte-1n46o8q{grid-column:2;grid-row:2;min-width:0}.statusbar.svelte-1n46o8q{grid-column:1 / -1;grid-row:3;min-height:40px;display:flex;align-items:center;gap:24px;border-top:1px solid var(--chrome-border);color:var(--chrome-muted);font-size:var(--text-small)}.runtime-label.svelte-1n46o8q{width:var(--sidebar-width);align-self:stretch;display:flex;align-items:center;flex-shrink:0;padding:0 20px;border-right:1px solid var(--chrome-border)}.collapsed.svelte-1n46o8q .runtime-label:where(.svelte-1n46o8q){width:64px;padding:0 8px;font-size:11px}.panel-controls.svelte-1n46o8q{display:flex;align-items:center;gap:8px;margin-left:auto;margin-right:16px}.statusbar.svelte-1n46o8q .logs-toggle:where(.svelte-1n46o8q){min-height:30px;color:var(--chrome-muted);border:0;background:transparent;text-decoration:underline;text-underline-offset:4px}.statusbar.svelte-1n46o8q .logs-toggle:where(.svelte-1n46o8q):hover,.statusbar.svelte-1n46o8q .logs-toggle[aria-expanded=true]:where(.svelte-1n46o8q){background:transparent;color:var(--chrome-text);text-decoration-thickness:2px}.connection.svelte-1n46o8q{display:flex;align-items:center;gap:14px}.connection.svelte-1n46o8q i:where(.svelte-1n46o8q){display:block;width:11px;height:11px;background:#76766e}.connection.connected.svelte-1n46o8q i:where(.svelte-1n46o8q){background:var(--orange)}.port-status.svelte-1n46o8q{padding-left:30px;border-left:1px solid var(--chrome-border)}.catalog-error.svelte-1n46o8q{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:12px 24px;color:var(--err);background:var(--bg-2)}.all-services.svelte-1n46o8q{padding:48px 40px}.all-services.svelte-1n46o8q header:where(.svelte-1n46o8q){display:flex;flex-wrap:wrap;gap:12px;align-items:center;justify-content:space-between;padding-bottom:24px;border-bottom:1px solid var(--border)}.eyebrow.svelte-1n46o8q{color:var(--muted);font:var(--text-small)/1.4 var(--sans);text-transform:none;letter-spacing:.06em}h1.svelte-1n46o8q{margin:0 0 12px;font:600 var(--text-title)/1.2 var(--sans)}h2.svelte-1n46o8q{font:500 var(--text-section)/1.4 var(--sans)}.runtime-count.svelte-1n46o8q{color:var(--muted);font-size:var(--text-body)}.all-service-grid.svelte-1n46o8q{display:grid;margin-top:14px}.all-service-card.svelte-1n46o8q{display:grid;justify-content:stretch;min-width:0;padding:14px 0;gap:4px;text-align:left;white-space:normal;background:transparent;border:0;border-bottom:1px solid var(--border)}.service-heading.svelte-1n46o8q strong:where(.svelte-1n46o8q){font:500 var(--text-label)/1.4 var(--sans)}.service-heading.svelte-1n46o8q{display:flex;flex-wrap:wrap;align-items:center;gap:8px}.service-status.svelte-1n46o8q{margin-left:auto;color:var(--muted);font:var(--text-small)/1.4 var(--sans);text-transform:none}.project-name.svelte-1n46o8q{color:var(--muted);font-size:var(--text-small)}.empty-state.svelte-1n46o8q,.load-state.svelte-1n46o8q{width:100%;padding:48px 32px;text-align:center;color:var(--muted)}.empty-state.svelte-1n46o8q h2:where(.svelte-1n46o8q),.load-state.svelte-1n46o8q h1:where(.svelte-1n46o8q){color:var(--text)}.global-settings.svelte-1n46o8q{padding:50px 40px;max-width:800px;font-size:var(--text-body);line-height:1.8}.global-settings.svelte-1n46o8q h3:where(.svelte-1n46o8q){margin-top:40px;font:500 var(--text-section)/1.4 var(--sans)}.global-settings.svelte-1n46o8q label:where(.svelte-1n46o8q){display:flex;gap:12px;align-items:center}.forwarder-error.svelte-1n46o8q{color:var(--err)}.collapsed.svelte-1n46o8q{grid-template-columns:64px minmax(0,1fr)}.app-rail.svelte-1n46o8q .collapse-toggle:where(.svelte-1n46o8q){width:36px;min-height:44px;flex-shrink:0;padding:4px;border:0;justify-content:center}.collapsed.svelte-1n46o8q .brand:where(.svelte-1n46o8q){flex-direction:column;gap:12px;padding:16px 4px}.collapsed.svelte-1n46o8q nav:where(.svelte-1n46o8q) a:where(.svelte-1n46o8q){justify-content:center;padding:12px 0}.collapsed.svelte-1n46o8q nav:where(.svelte-1n46o8q) a:where(.svelte-1n46o8q) span:where(.svelte-1n46o8q){display:none}.palette-trigger.svelte-1n46o8q kbd:where(.svelte-1n46o8q){margin-left:auto;font:11px var(--mono)}.collapsed.svelte-1n46o8q .palette-trigger:where(.svelte-1n46o8q){justify-content:center;padding:12px 0}.collapsed.svelte-1n46o8q .palette-trigger:where(.svelte-1n46o8q) span:where(.svelte-1n46o8q),.collapsed.svelte-1n46o8q .palette-trigger:where(.svelte-1n46o8q) kbd:where(.svelte-1n46o8q){display:none}.app-rail.svelte-1n46o8q .clean-urls-warning:where(.svelte-1n46o8q){margin-top:auto;border:0;border-top:1px solid var(--chrome-border);padding:16px 20px;color:#d1b78d;flex-shrink:0;justify-content:flex-start;white-space:normal}.app-rail.svelte-1n46o8q .clean-urls-warning:where(.svelte-1n46o8q):hover{color:#ead5ac;background:#ffffff0c;text-decoration:none}.clean-urls-warning.svelte-1n46o8q strong:where(.svelte-1n46o8q),.clean-urls-warning.svelte-1n46o8q small:where(.svelte-1n46o8q){display:block}.clean-urls-warning.svelte-1n46o8q strong:where(.svelte-1n46o8q){font-size:var(--text-small);font-weight:500}.clean-urls-warning.svelte-1n46o8q small:where(.svelte-1n46o8q){color:var(--chrome-muted);font-size:var(--text-small)}.collapsed.svelte-1n46o8q .clean-urls-warning:where(.svelte-1n46o8q){justify-content:center;padding:16px 0}.collapsed.svelte-1n46o8q .clean-urls-warning:where(.svelte-1n46o8q) span:where(.svelte-1n46o8q){display:none}.project-shortcuts.svelte-1n46o8q{overflow:auto;padding:24px 8px}.project-shortcuts.svelte-1n46o8q p:where(.svelte-1n46o8q){padding:0 12px;color:var(--chrome-muted);font:var(--text-small)/1.4 var(--sans);text-transform:none}.project-shortcuts.svelte-1n46o8q button:where(.svelte-1n46o8q){text-transform:none;overflow:hidden;text-overflow:ellipsis;display:block;min-height:36px;padding:8px 12px}.project-shortcuts.svelte-1n46o8q button.current:where(.svelte-1n46o8q){color:var(--chrome-text);background:#ffffff0c}.sidebar-resizer.svelte-1n46o8q{position:absolute;right:-3px;top:0;bottom:0;width:7px;cursor:col-resize;touch-action:none;z-index:10}.sidebar-resizer.svelte-1n46o8q:hover,.sidebar-resizer.svelte-1n46o8q:focus-visible{background:var(--orange)}.all-search.svelte-1n46o8q{display:flex;align-items:center;gap:16px;margin-top:24px;color:var(--muted)}.all-search.svelte-1n46o8q input:where(.svelte-1n46o8q){width:min(360px,100%)}@media(max-width:760px){.layout.svelte-1n46o8q,.layout.collapsed.svelte-1n46o8q{grid-template-columns:64px minmax(0,1fr)}.layout.svelte-1n46o8q:not(.collapsed) .app-rail:where(.svelte-1n46o8q){position:absolute;inset:0 auto 0 0;width:min(var(--sidebar-width),calc(100vw - 64px));z-index:20;background:var(--chrome)}.sidebar-resizer.svelte-1n46o8q{display:none}.statusbar.svelte-1n46o8q{gap:10px;font-size:11px}.runtime-label.svelte-1n46o8q{width:64px;padding:0 8px;font-size:11px}.panel-controls.svelte-1n46o8q{gap:0;margin-right:8px}.statusbar.svelte-1n46o8q .logs-toggle:where(.svelte-1n46o8q){padding:4px 8px}.port-status.svelte-1n46o8q{padding-left:10px}.connection.svelte-1n46o8q{gap:6px}.connection.svelte-1n46o8q i:where(.svelte-1n46o8q){width:6px;height:6px}.global-settings.svelte-1n46o8q,.all-services.svelte-1n46o8q{padding:24px 16px}.all-search.svelte-1n46o8q{align-items:stretch;flex-direction:column;gap:6px}}
|
package/dashboard/index.html
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<title>LocalDeck</title>
|
|
7
7
|
<link rel="icon" type="image/png" href="/localdeck-icon.png" />
|
|
8
|
-
<script type="module" crossorigin src="/assets/index-
|
|
9
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
8
|
+
<script type="module" crossorigin src="/assets/index-BzX_uJtU.js"></script>
|
|
9
|
+
<link rel="stylesheet" crossorigin href="/assets/index-DbQzubLF.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
|
12
12
|
<div id="app"></div>
|
|
@@ -3409,9 +3409,9 @@ function stopOrder(commands) {
|
|
|
3409
3409
|
}
|
|
3410
3410
|
|
|
3411
3411
|
// ../daemon/src/index.ts
|
|
3412
|
-
import
|
|
3412
|
+
import fs10 from "node:fs";
|
|
3413
3413
|
import crypto2 from "node:crypto";
|
|
3414
|
-
import
|
|
3414
|
+
import path11 from "node:path";
|
|
3415
3415
|
|
|
3416
3416
|
// ../daemon/src/api.ts
|
|
3417
3417
|
import http5 from "node:http";
|
|
@@ -6986,8 +6986,8 @@ function settlesWithin2(promise, timeoutMs) {
|
|
|
6986
6986
|
|
|
6987
6987
|
// ../daemon/src/supervisor.ts
|
|
6988
6988
|
import { spawn as spawn3 } from "node:child_process";
|
|
6989
|
-
import
|
|
6990
|
-
import
|
|
6989
|
+
import path10 from "node:path";
|
|
6990
|
+
import fs9 from "node:fs";
|
|
6991
6991
|
|
|
6992
6992
|
// ../daemon/src/startup-guidance.ts
|
|
6993
6993
|
function startupGuidance(message) {
|
|
@@ -7011,6 +7011,154 @@ function startupGuidance(message) {
|
|
|
7011
7011
|
};
|
|
7012
7012
|
}
|
|
7013
7013
|
|
|
7014
|
+
// ../daemon/src/port-environment.ts
|
|
7015
|
+
import fs8 from "node:fs";
|
|
7016
|
+
import path9 from "node:path";
|
|
7017
|
+
function inferPortEnvironment(command, cwd, port) {
|
|
7018
|
+
const visited = new Set;
|
|
7019
|
+
const inspect = (input, directory) => {
|
|
7020
|
+
if (visited.size >= 16)
|
|
7021
|
+
return;
|
|
7022
|
+
const words = typeof input === "string" ? shellWords(input) : input;
|
|
7023
|
+
if (!words?.length)
|
|
7024
|
+
return;
|
|
7025
|
+
const executable = path9.basename(words[0]).replace(/\.cmd$/, "");
|
|
7026
|
+
if (words[0].includes("=") || ["echo", "printf"].includes(executable))
|
|
7027
|
+
return;
|
|
7028
|
+
if (["npm", "pnpm", "yarn", "bun"].includes(executable)) {
|
|
7029
|
+
let target = directory;
|
|
7030
|
+
let workspace;
|
|
7031
|
+
let script;
|
|
7032
|
+
for (let i = 1;i < words.length; i++) {
|
|
7033
|
+
const word = words[i];
|
|
7034
|
+
if (word === "--")
|
|
7035
|
+
break;
|
|
7036
|
+
if (word === "run" || word === "run-script")
|
|
7037
|
+
continue;
|
|
7038
|
+
const option = /^(--prefix|--cwd|--dir|-C|--workspace|-w)(?:=(.*))?$/.exec(word);
|
|
7039
|
+
if (option) {
|
|
7040
|
+
const value = option[2] ?? words[++i];
|
|
7041
|
+
if (!value || /[$`]/.test(value))
|
|
7042
|
+
return;
|
|
7043
|
+
if (option[1] === "--workspace" || option[1] === "-w") {
|
|
7044
|
+
if (workspace)
|
|
7045
|
+
return;
|
|
7046
|
+
workspace = value;
|
|
7047
|
+
} else
|
|
7048
|
+
target = path9.resolve(directory, value);
|
|
7049
|
+
} else if (word.startsWith("-") || script)
|
|
7050
|
+
return;
|
|
7051
|
+
else
|
|
7052
|
+
script = word;
|
|
7053
|
+
}
|
|
7054
|
+
if (!script || /[$`]/.test(script))
|
|
7055
|
+
return;
|
|
7056
|
+
if (workspace) {
|
|
7057
|
+
const resolved = workspaceDirectory(target, workspace);
|
|
7058
|
+
if (!resolved)
|
|
7059
|
+
return;
|
|
7060
|
+
target = resolved;
|
|
7061
|
+
}
|
|
7062
|
+
const key = `${target}\x00${script}`;
|
|
7063
|
+
if (visited.has(key))
|
|
7064
|
+
return;
|
|
7065
|
+
visited.add(key);
|
|
7066
|
+
const pkg = manifest(target);
|
|
7067
|
+
const run = pkg?.scripts?.[script];
|
|
7068
|
+
return typeof run === "string" ? inspect(run, target) : undefined;
|
|
7069
|
+
}
|
|
7070
|
+
const arguments_ = words.slice(1).flatMap((word, i) => word === "--port" ? [words[i + 2] ?? ""] : word.startsWith("--port=") ? [word.slice(7)] : []);
|
|
7071
|
+
if (arguments_.length !== 1)
|
|
7072
|
+
return;
|
|
7073
|
+
const match = /^(?:\$([A-Za-z_][A-Za-z0-9_]*)|\$\{([A-Za-z_][A-Za-z0-9_]*)(?::?-\d+)?\})$/.exec(arguments_[0]);
|
|
7074
|
+
const name2 = match?.[1] ?? match?.[2];
|
|
7075
|
+
if (name2 && name2 !== "PORT" && !name2.startsWith("LOCALDECK_"))
|
|
7076
|
+
return name2;
|
|
7077
|
+
};
|
|
7078
|
+
const name = inspect(command, path9.resolve(cwd));
|
|
7079
|
+
return name ? { [name]: String(port) } : {};
|
|
7080
|
+
}
|
|
7081
|
+
function shellWords(command) {
|
|
7082
|
+
const words = [];
|
|
7083
|
+
let word = "";
|
|
7084
|
+
let quote = "";
|
|
7085
|
+
let started = false;
|
|
7086
|
+
for (let i = 0;i < command.length; i++) {
|
|
7087
|
+
const char = command[i];
|
|
7088
|
+
if (char === "`" || char === "\\" || char === `
|
|
7089
|
+
` || command.slice(i, i + 2) === "$(")
|
|
7090
|
+
return;
|
|
7091
|
+
if (quote) {
|
|
7092
|
+
if (char === quote)
|
|
7093
|
+
quote = "";
|
|
7094
|
+
else
|
|
7095
|
+
word += quote === "'" && char === "$" ? "\x00" : char;
|
|
7096
|
+
} else if (char === '"' || char === "'") {
|
|
7097
|
+
quote = char;
|
|
7098
|
+
started = true;
|
|
7099
|
+
} else if (/\s/.test(char)) {
|
|
7100
|
+
if (started)
|
|
7101
|
+
words.push(word);
|
|
7102
|
+
word = "";
|
|
7103
|
+
started = false;
|
|
7104
|
+
} else {
|
|
7105
|
+
if (/[;&|<>()#]/.test(char))
|
|
7106
|
+
return;
|
|
7107
|
+
word += char;
|
|
7108
|
+
started = true;
|
|
7109
|
+
}
|
|
7110
|
+
}
|
|
7111
|
+
if (quote)
|
|
7112
|
+
return;
|
|
7113
|
+
if (started)
|
|
7114
|
+
words.push(word);
|
|
7115
|
+
return words;
|
|
7116
|
+
}
|
|
7117
|
+
function manifest(directory) {
|
|
7118
|
+
try {
|
|
7119
|
+
const value = JSON.parse(fs8.readFileSync(path9.join(directory, "package.json"), "utf8"));
|
|
7120
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : undefined;
|
|
7121
|
+
} catch {
|
|
7122
|
+
return;
|
|
7123
|
+
}
|
|
7124
|
+
}
|
|
7125
|
+
function workspaceDirectory(root, selector) {
|
|
7126
|
+
const workspaces = manifest(root)?.workspaces;
|
|
7127
|
+
const patterns = Array.isArray(workspaces) ? workspaces : workspaces?.packages;
|
|
7128
|
+
if (!Array.isArray(patterns))
|
|
7129
|
+
return;
|
|
7130
|
+
const directories = new Set;
|
|
7131
|
+
for (const pattern of patterns.slice(0, 100)) {
|
|
7132
|
+
if (typeof pattern !== "string" || path9.isAbsolute(pattern))
|
|
7133
|
+
continue;
|
|
7134
|
+
const parts = pattern.replace(/^\.\//, "").replace(/\/$/, "").split("/");
|
|
7135
|
+
if (parts.some((part) => !part || part === ".." || /[^\w@.*-]/.test(part) || part.includes("**")))
|
|
7136
|
+
continue;
|
|
7137
|
+
let candidates = [root];
|
|
7138
|
+
for (const part of parts) {
|
|
7139
|
+
const matcher = new RegExp(`^${part.replace(/\./g, "\\.").replace(/\*/g, ".*")}$`);
|
|
7140
|
+
const next = [];
|
|
7141
|
+
for (const candidate of candidates) {
|
|
7142
|
+
try {
|
|
7143
|
+
for (const entry of fs8.readdirSync(candidate, { withFileTypes: true })) {
|
|
7144
|
+
if (entry.isDirectory() && !["node_modules", ".git"].includes(entry.name) && matcher.test(entry.name))
|
|
7145
|
+
next.push(path9.join(candidate, entry.name));
|
|
7146
|
+
if (next.length > 100)
|
|
7147
|
+
return;
|
|
7148
|
+
}
|
|
7149
|
+
} catch {}
|
|
7150
|
+
}
|
|
7151
|
+
candidates = next;
|
|
7152
|
+
}
|
|
7153
|
+
for (const candidate of candidates) {
|
|
7154
|
+
const pkg = manifest(candidate);
|
|
7155
|
+
if (pkg && (candidate === path9.resolve(root, selector) || pkg.name === selector))
|
|
7156
|
+
directories.add(candidate);
|
|
7157
|
+
}
|
|
7158
|
+
}
|
|
7159
|
+
return directories.size === 1 ? [...directories][0] : undefined;
|
|
7160
|
+
}
|
|
7161
|
+
|
|
7014
7162
|
// ../daemon/src/readiness.ts
|
|
7015
7163
|
import http7 from "node:http";
|
|
7016
7164
|
import { spawn as spawn2 } from "node:child_process";
|
|
@@ -7041,7 +7189,7 @@ async function waitForReadiness(command, getService, options = {}) {
|
|
|
7041
7189
|
await delay2(Math.min(command.ready.intervalMs, afterProbe), command.name, options.signal);
|
|
7042
7190
|
}
|
|
7043
7191
|
}
|
|
7044
|
-
function probeHttp(service,
|
|
7192
|
+
function probeHttp(service, path10, expectedStatus, remainingMs, signal) {
|
|
7045
7193
|
return new Promise((resolve, reject) => {
|
|
7046
7194
|
if (signal?.aborted)
|
|
7047
7195
|
return reject(new Error(`${service.name} readiness cancelled`));
|
|
@@ -7059,7 +7207,7 @@ function probeHttp(service, path9, expectedStatus, remainingMs, signal) {
|
|
|
7059
7207
|
const request = http7.request({
|
|
7060
7208
|
host: service.upstreamHost,
|
|
7061
7209
|
port: service.upstreamPort,
|
|
7062
|
-
path:
|
|
7210
|
+
path: path10,
|
|
7063
7211
|
method: "GET",
|
|
7064
7212
|
timeout: Math.max(1, Math.min(remainingMs, 2000))
|
|
7065
7213
|
}, (response) => {
|
|
@@ -7334,11 +7482,11 @@ class ProcessSupervisor {
|
|
|
7334
7482
|
return started;
|
|
7335
7483
|
const hasDependents = project.commands.some((candidate) => candidate.after.includes(command.name));
|
|
7336
7484
|
if (command.ready.type === "tcp" && !hasDependents) {
|
|
7337
|
-
const cwd2 = command.cwd ?
|
|
7485
|
+
const cwd2 = command.cwd ? path10.resolve(project.directory, command.cwd) : project.directory;
|
|
7338
7486
|
this.verifyReadiness(command, key, cwd2);
|
|
7339
7487
|
return started;
|
|
7340
7488
|
}
|
|
7341
|
-
const cwd = command.cwd ?
|
|
7489
|
+
const cwd = command.cwd ? path10.resolve(project.directory, command.cwd) : project.directory;
|
|
7342
7490
|
return this.verifyReadiness(command, key, cwd, started);
|
|
7343
7491
|
})();
|
|
7344
7492
|
attempts.set(command.name, attempt);
|
|
@@ -7484,9 +7632,9 @@ class ProcessSupervisor {
|
|
|
7484
7632
|
const project = this.projects.details(projectId2);
|
|
7485
7633
|
if (!project.available)
|
|
7486
7634
|
throw new ProjectError("invalid", project.error);
|
|
7487
|
-
const cwd = command.cwd ?
|
|
7635
|
+
const cwd = command.cwd ? path10.resolve(project.directory, command.cwd) : project.directory;
|
|
7488
7636
|
try {
|
|
7489
|
-
if (!
|
|
7637
|
+
if (!fs9.statSync(cwd).isDirectory())
|
|
7490
7638
|
throw new Error("not a directory");
|
|
7491
7639
|
} catch {
|
|
7492
7640
|
throw new ProjectError("invalid", `configured working directory does not exist or is not a directory: ${cwd}`);
|
|
@@ -7535,6 +7683,12 @@ class ProcessSupervisor {
|
|
|
7535
7683
|
}
|
|
7536
7684
|
const argv = shellCommand(command.run.replaceAll("{port}", String(upstreamPort)));
|
|
7537
7685
|
const database = service.serviceType !== undefined && service.serviceType !== "http";
|
|
7686
|
+
const portEnv = database ? {} : inferPortEnvironment(command.run, cwd, upstreamPort);
|
|
7687
|
+
commandEnv = { ...portEnv, ...commandEnv };
|
|
7688
|
+
for (const name2 of Object.keys(portEnv)) {
|
|
7689
|
+
if (commandEnv[name2] === portEnv[name2])
|
|
7690
|
+
this.store.log({ ts: Date.now(), service: key, stream: "system", line: `LocalDeck: supplying assigned port ${upstreamPort} through ${name2}` });
|
|
7691
|
+
}
|
|
7538
7692
|
const env = {
|
|
7539
7693
|
...process.env,
|
|
7540
7694
|
...commandEnv,
|
|
@@ -7713,7 +7867,7 @@ class ProcessSupervisor {
|
|
|
7713
7867
|
else {
|
|
7714
7868
|
const command = this.projects.resolve(projectId2, name);
|
|
7715
7869
|
const project = this.projects.details(projectId2);
|
|
7716
|
-
const cwd = command.cwd ?
|
|
7870
|
+
const cwd = command.cwd ? path10.resolve(project.directory, command.cwd) : project.directory;
|
|
7717
7871
|
this.verifyReadiness(command, key, cwd);
|
|
7718
7872
|
}
|
|
7719
7873
|
return result;
|
|
@@ -7989,7 +8143,7 @@ async function waitForProcessGroupExit(groupId, timeoutMs) {
|
|
|
7989
8143
|
return true;
|
|
7990
8144
|
}
|
|
7991
8145
|
// ../daemon/package.json
|
|
7992
|
-
var version = "1.1
|
|
8146
|
+
var version = "1.2.1";
|
|
7993
8147
|
|
|
7994
8148
|
// ../daemon/src/index.ts
|
|
7995
8149
|
var VERSION = version;
|
|
@@ -8005,8 +8159,8 @@ async function startDaemon(opts = {}) {
|
|
|
8005
8159
|
writePrivateState: writePrivateJson,
|
|
8006
8160
|
...opts.dependencies
|
|
8007
8161
|
};
|
|
8008
|
-
const stateFile = opts.homeDir ?
|
|
8009
|
-
const projectsFile = opts.homeDir ?
|
|
8162
|
+
const stateFile = opts.homeDir ? path11.join(opts.homeDir, "daemon.json") : STATE_FILE;
|
|
8163
|
+
const projectsFile = opts.homeDir ? path11.join(opts.homeDir, "projects.json") : PROJECTS_FILE;
|
|
8010
8164
|
const apiPort = opts.apiPort ?? DEFAULT_API_PORT;
|
|
8011
8165
|
const store = dependencies.createStore();
|
|
8012
8166
|
const registry = dependencies.createRegistry(store, apiPort);
|
|
@@ -8066,16 +8220,16 @@ async function startDaemon(opts = {}) {
|
|
|
8066
8220
|
if (stateCleanup === "failed-write") {
|
|
8067
8221
|
if (!stateWriteAttempted)
|
|
8068
8222
|
return;
|
|
8069
|
-
|
|
8223
|
+
fs10.rmSync(`${stateFile}.${process.pid}.tmp`, { force: true });
|
|
8070
8224
|
if (priorState)
|
|
8071
8225
|
restorePrivateState(stateFile, priorState.contents, priorState.mode);
|
|
8072
8226
|
else
|
|
8073
|
-
|
|
8227
|
+
fs10.rmSync(stateFile, { force: true });
|
|
8074
8228
|
return;
|
|
8075
8229
|
}
|
|
8076
8230
|
const state = readJson(stateFile, null);
|
|
8077
8231
|
if (state?.pid === process.pid)
|
|
8078
|
-
|
|
8232
|
+
fs10.unlinkSync(stateFile);
|
|
8079
8233
|
}));
|
|
8080
8234
|
return errors;
|
|
8081
8235
|
})();
|
|
@@ -8097,9 +8251,9 @@ async function startDaemon(opts = {}) {
|
|
|
8097
8251
|
server.once("error", reject);
|
|
8098
8252
|
server.listen(apiPort, "127.0.0.1", resolve);
|
|
8099
8253
|
});
|
|
8100
|
-
if (
|
|
8101
|
-
const stat =
|
|
8102
|
-
priorState = { contents:
|
|
8254
|
+
if (fs10.existsSync(stateFile)) {
|
|
8255
|
+
const stat = fs10.statSync(stateFile);
|
|
8256
|
+
priorState = { contents: fs10.readFileSync(stateFile), mode: stat.mode & 511 };
|
|
8103
8257
|
}
|
|
8104
8258
|
stateWriteAttempted = true;
|
|
8105
8259
|
dependencies.writePrivateState(stateFile, {
|
|
@@ -8120,9 +8274,9 @@ async function startDaemon(opts = {}) {
|
|
|
8120
8274
|
}
|
|
8121
8275
|
function restorePrivateState(file, contents, mode) {
|
|
8122
8276
|
const temporary = `${file}.${process.pid}.restore.tmp`;
|
|
8123
|
-
|
|
8124
|
-
|
|
8125
|
-
|
|
8277
|
+
fs10.writeFileSync(temporary, contents, { mode });
|
|
8278
|
+
fs10.chmodSync(temporary, mode);
|
|
8279
|
+
fs10.renameSync(temporary, file);
|
|
8126
8280
|
}
|
|
8127
8281
|
function toError3(error) {
|
|
8128
8282
|
return error instanceof Error ? error : new Error(String(error));
|
|
@@ -8157,24 +8311,24 @@ async function findDaemon() {
|
|
|
8157
8311
|
|
|
8158
8312
|
// src/client.ts
|
|
8159
8313
|
import { spawn as spawn4, spawnSync } from "node:child_process";
|
|
8160
|
-
import
|
|
8161
|
-
import
|
|
8314
|
+
import fs11 from "node:fs";
|
|
8315
|
+
import path12 from "node:path";
|
|
8162
8316
|
import { fileURLToPath } from "node:url";
|
|
8163
8317
|
function dashboardDir() {
|
|
8164
|
-
const here =
|
|
8318
|
+
const here = path12.dirname(fileURLToPath(import.meta.url));
|
|
8165
8319
|
const candidates = [
|
|
8166
|
-
|
|
8167
|
-
|
|
8320
|
+
path12.resolve(here, "../dashboard"),
|
|
8321
|
+
path12.resolve(here, "../../dashboard/dist")
|
|
8168
8322
|
];
|
|
8169
|
-
return candidates.find((d) =>
|
|
8323
|
+
return candidates.find((d) => fs11.existsSync(path12.join(d, "index.html")));
|
|
8170
8324
|
}
|
|
8171
8325
|
function daemonCommand() {
|
|
8172
8326
|
const entry = process.argv[1];
|
|
8173
8327
|
const runningUnderBun = Boolean(process.versions.bun);
|
|
8174
8328
|
if (runningUnderBun) {
|
|
8175
|
-
const dist =
|
|
8329
|
+
const dist = path12.resolve(path12.dirname(fileURLToPath(import.meta.url)), "../dist/index.js");
|
|
8176
8330
|
const hasNode = spawnSync("node", ["--version"], { stdio: "ignore" }).status === 0;
|
|
8177
|
-
if (
|
|
8331
|
+
if (fs11.existsSync(dist) && hasNode)
|
|
8178
8332
|
return ["node", [dist, "daemon", "run"]];
|
|
8179
8333
|
console.warn("LocalDeck: starting daemon under Bun — WebSocket proxying (HMR) will not work. Run `bun run build` and make sure `node` is on PATH.");
|
|
8180
8334
|
}
|
|
@@ -8186,8 +8340,8 @@ async function ensureDaemon() {
|
|
|
8186
8340
|
const running = await findDaemon();
|
|
8187
8341
|
if (running)
|
|
8188
8342
|
return running;
|
|
8189
|
-
|
|
8190
|
-
const out =
|
|
8343
|
+
fs11.mkdirSync(path12.dirname(DAEMON_LOG), { recursive: true });
|
|
8344
|
+
const out = fs11.openSync(DAEMON_LOG, "a");
|
|
8191
8345
|
const [cmd, args] = daemonCommand();
|
|
8192
8346
|
const child = spawn4(cmd, args, { detached: true, stdio: ["ignore", out, out], env: process.env });
|
|
8193
8347
|
child.unref();
|
|
@@ -8256,4 +8410,4 @@ class Api {
|
|
|
8256
8410
|
shutdown = () => this.call("POST", "/api/shutdown");
|
|
8257
8411
|
}
|
|
8258
8412
|
|
|
8259
|
-
export { __toESM, __commonJS, __export, __require, wrapper_default, startForwarder, HOME_DIR, STATE_FILE, DEFAULT_API_PORT, findProjectFile, loadProject, loadProjectFile, shellCommand, isPortFree, getFreePort, serviceKey, processTree, listeningPorts, chooseUpstream, connectHost, streamLines, killProcessTree, stripAnsi, redactDiagnostic, environmentValues, listProjectSecrets, resolveProjectSecrets, startupGuidance, startupLayers, waitForReadiness, secretOutput, VERSION, startDaemon, findDaemon, dashboardDir, ensureDaemon, Api };
|
|
8413
|
+
export { __toESM, __commonJS, __export, __require, wrapper_default, startForwarder, HOME_DIR, STATE_FILE, DEFAULT_API_PORT, findProjectFile, loadProject, loadProjectFile, shellCommand, isPortFree, getFreePort, serviceKey, processTree, listeningPorts, chooseUpstream, connectHost, streamLines, killProcessTree, stripAnsi, redactDiagnostic, environmentValues, listProjectSecrets, resolveProjectSecrets, startupGuidance, inferPortEnvironment, startupLayers, waitForReadiness, secretOutput, VERSION, startDaemon, findDaemon, dashboardDir, ensureDaemon, Api };
|
package/dist/index.js
CHANGED
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
findDaemon,
|
|
12
12
|
findProjectFile,
|
|
13
13
|
getFreePort,
|
|
14
|
+
inferPortEnvironment,
|
|
14
15
|
isPortFree,
|
|
15
16
|
killProcessTree,
|
|
16
17
|
listeningPorts,
|
|
@@ -29,7 +30,7 @@ import {
|
|
|
29
30
|
stripAnsi,
|
|
30
31
|
waitForReadiness,
|
|
31
32
|
wrapper_default
|
|
32
|
-
} from "./index-
|
|
33
|
+
} from "./index-19n321tr.js";
|
|
33
34
|
|
|
34
35
|
// src/index.ts
|
|
35
36
|
import { spawn as spawn2 } from "node:child_process";
|
|
@@ -167,6 +168,15 @@ async function startService(opts, overrides = {}) {
|
|
|
167
168
|
});
|
|
168
169
|
const argv = opts.command.map((a) => a.replaceAll("{port}", String(upstreamPort)));
|
|
169
170
|
const database = service.serviceType !== undefined && service.serviceType !== "http";
|
|
171
|
+
const portEnv = database ? {} : inferPortEnvironment(opts.displayCommand ?? opts.command, cwd, upstreamPort);
|
|
172
|
+
commandEnv = { ...portEnv, ...commandEnv };
|
|
173
|
+
for (const name of Object.keys(portEnv)) {
|
|
174
|
+
if (commandEnv[name] === portEnv[name]) {
|
|
175
|
+
const line = `LocalDeck: supplying assigned port ${upstreamPort} through ${name}`;
|
|
176
|
+
console.log(`${tag}${c.dim(line)}`);
|
|
177
|
+
send({ type: "log", stream: "stdout", line });
|
|
178
|
+
}
|
|
179
|
+
}
|
|
170
180
|
let env = {
|
|
171
181
|
...process.env,
|
|
172
182
|
...commandEnv,
|
|
@@ -897,13 +907,13 @@ async function main(argv, overrides = {}) {
|
|
|
897
907
|
case "--update":
|
|
898
908
|
if (rest.length)
|
|
899
909
|
throw new Error("Usage: localdeck --update");
|
|
900
|
-
return (await import("./update-
|
|
910
|
+
return (await import("./update-nx00r38m.js")).updateLocalDeck();
|
|
901
911
|
case "up":
|
|
902
912
|
return cmdUp(rest, dependencies);
|
|
903
913
|
case "init":
|
|
904
914
|
return cmdInit(rest, dependencies);
|
|
905
915
|
case "mcp":
|
|
906
|
-
return (await import("./mcp-
|
|
916
|
+
return (await import("./mcp-vkez9mq7.js")).runMcp(rest);
|
|
907
917
|
case "doctor":
|
|
908
918
|
return cmdDoctor(rest);
|
|
909
919
|
case "forward":
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
listProjectSecrets,
|
|
10
10
|
redactDiagnostic,
|
|
11
11
|
resolveProjectSecrets
|
|
12
|
-
} from "./index-
|
|
12
|
+
} from "./index-19n321tr.js";
|
|
13
13
|
|
|
14
14
|
// ../../node_modules/.bun/ajv@8.20.0/node_modules/ajv/dist/compile/codegen/code.js
|
|
15
15
|
var require_code = __commonJS((exports) => {
|
package/docs/dashboard.md
CHANGED
|
@@ -4,6 +4,12 @@
|
|
|
4
4
|
|
|
5
5
|
Open the dashboard with `localdeck open`. It runs on `http://localhost:7777` by default and updates service status and logs live.
|
|
6
6
|
|
|
7
|
+
## Command palette
|
|
8
|
+
|
|
9
|
+
Press **⌘K** on macOS or **Ctrl+K** on Windows/Linux, or click **Search commands** in the sidebar. Search by action, project, or service name; words can appear in any order, such as `logs web my-app`. Use **↑/↓** to select, **Enter** to run, and **Escape** to close. Closing returns focus to the previous control.
|
|
10
|
+
|
|
11
|
+
Commands open projects, Settings, running app URLs, logs, and requests, and start, stop, or restart individual services through the existing dashboard controls. Start is available for configured stopped services; restart is available for configured daemon-owned services. Controls are unavailable while disconnected or while that service is starting, stopping, or restarting. Failed actions stay visible in the palette. Project loading failures show a Retry control.
|
|
12
|
+
|
|
7
13
|
## Pages and projects
|
|
8
14
|
|
|
9
15
|
- **Projects** (`/projects`) lists projects remembered through the CLI. Selecting one opens `/projects/<id>`.
|