dsh-home-hosted 0.1.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/docs/DESIGN.md +19 -0
- package/lib/client.js +6 -5
- package/lib/index.js +79 -23
- package/lib/index.js.map +2 -2
- package/lib/types/boot/common.d.ts +2 -0
- package/lib/types/boot/launchd.d.ts +5 -1
- package/lib/types/shared/contracts.d.ts +12 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -39,7 +39,7 @@ Everything a person toggles lives in `<stateDir>/settings.json`, including **Opt
|
|
|
39
39
|
|
|
40
40
|
- A plugin cannot act at boot: it installs and re-syncs the OS entry while dsh runs, and the OS starts home-hosted from then on.
|
|
41
41
|
- The plugin ships its own `home-hosted` (pinned range) and runs that copy by default; Options in the page can switch to a global install instead. Boot entries run a small stable launcher it writes, so a `node_modules` path that moves never breaks boot.
|
|
42
|
-
- Boot (pre-login)
|
|
42
|
+
- Boot (pre-login) needs privilege somewhere, and the page shows the exact commands when it cannot elevate: on macOS pick the boot-scope **launchd-daemon** (a one-time `sudo` install), on Linux **systemd-system** or `loginctl enable-linger`. A `LaunchAgent` and an XDG entry start at login only.
|
|
43
43
|
- The panel API token this plugin uses is minted on first write and kept 0600 under the plugin state directory; it is never rendered or logged.
|
|
44
44
|
- `onPortConflict: kill` needs home-hosted 0.6.0 or newer; against an older panel the plugin refuses that write and says so, because that panel cannot parse the config it would produce.
|
|
45
45
|
|
package/docs/DESIGN.md
CHANGED
|
@@ -41,6 +41,25 @@ CLI that will parse it next. Below 0.6.0 the write is refused with
|
|
|
41
41
|
`KILL_UNSUPPORTED` and the page offers the fix it already has — replace the panel
|
|
42
42
|
with the preferred copy, or choose another policy.
|
|
43
43
|
|
|
44
|
+
## macOS: agent or daemon
|
|
45
|
+
|
|
46
|
+
A `LaunchAgent` starts at login; starting before login means a `LaunchDaemon` in
|
|
47
|
+
`/Library/LaunchDaemons`, which is root-owned and needs a one-time `sudo`
|
|
48
|
+
install. The daemon is therefore offered even when this process cannot elevate:
|
|
49
|
+
install stages the plist and returns the three commands to run. The daemon plist
|
|
50
|
+
names the invoking user in `UserName`, Apple's sanctioned way to avoid running
|
|
51
|
+
the panel as root, and the recommendation still prefers a mechanism this process
|
|
52
|
+
can install on its own so "Automatic" stays a single click.
|
|
53
|
+
|
|
54
|
+
## macOS: reachable launchd is not a requirement
|
|
55
|
+
|
|
56
|
+
A plist in `~/Library/LaunchAgents` is loaded by launchd at the next login whether
|
|
57
|
+
or not the process that wrote it can reach `gui/$UID` (SSH sessions often cannot).
|
|
58
|
+
So the agent stays `available` and its install writes the plist and reports "loads
|
|
59
|
+
at the next login" instead of refusing; only the `bootstrap`/`enable`/`print`
|
|
60
|
+
steps need the domain, and they are skipped when it is unreachable. The daemon
|
|
61
|
+
scope still needs root for `/Library/LaunchDaemons`.
|
|
62
|
+
|
|
44
63
|
## Starting and replacing the panel
|
|
45
64
|
|
|
46
65
|
`panel.start` runs the preferred CLI's `up`, which detaches itself and returns
|
package/lib/client.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
window.__ModuleLoader__.load({ id: "dsh-home-hosted", factory: (require) => {
|
|
2
2
|
var module = { exports: {} }; var exports = module.exports;
|
|
3
|
-
"use strict";var G=Object.defineProperty;var Be=Object.getOwnPropertyDescriptor;var Ie=Object.getOwnPropertyNames;var Me=Object.prototype.hasOwnProperty;var De=(e,t)=>{for(var n in t)G(e,n,{get:t[n],enumerable:!0})},Ue=(e,t,n,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of Ie(t))!Me.call(e,r)&&r!==n&&G(e,r,{get:()=>t[r],enumerable:!(s=Be(t,r))||s.enumerable});return e};var $e=e=>Ue(G({},"__esModule",{value:!0}),e);var it={};De(it,{apply:()=>st,inject:()=>rt});module.exports=$e(it);var $="homeHosted",K={tab:"Home Hosted",pageDesc:"Boot autostart and home-hosted server management.",loading:"Loading\u2026",refresh:"Refresh",retry:"Retry",errorTitle:"Error",statusUnavailable:"The panel did not answer.",yes:"Yes",no:"No",copy:"Copy",copied:"Copied",panelTitle:"Panel",panelDesc:"Reachability and identity of the home-hosted panel.",panelReachable:"Reachable",panelHome:"$HHOSTED_HOME",panelUrl:"URL",panelVersion:"Version",panelPid:"PID",panelWriteVia:"Writes via",panelToken:"API token",panelCliSource:"CLI",panelCliPath:"CLI path",panelCliConfig:"configured command",panelCliDependency:"pinned dependency",panelCliPathSource:"global install (PATH)",panelCliMissing:"not found",panelCliNotPinned:"This host uses a global home-hosted instead of the plugin's pinned copy ({range}); reinstall the plugin with its dependencies to use the pinned one.",panelCliLauncherFailed:"The boot launcher did not answer; a boot entry may fail to start the panel.",panelStart:"Start the panel",panelReplace:"Replace with {version}",panelAlreadyPreferred:"The running panel is already the preferred copy.",panelTakeoverTitle:"Replace the running panel?",panelTakeoverBody:"This stops the running panel and every server it supervises \u2014 including this dsh, so this page disconnects. It only works when the dsh entry is adopted with autostart enabled.",confirmCancel:"Cancel",confirmReplace:"Replace",writeViaApi:"authenticated API",writeViaFile:"config file",writeViaNone:"unavailable",tokenEnrolled:"enrolled",tokenPresent:"present",tokenAbsent:"absent",tokenUnknown:"unknown",optionsTitle:"Options",optionsDesc:"Which home-hosted to run, and how to get a global copy.",optionsCliUnavailable:"The host did not report any CLI information.",optionsCurrent:"CLI in use",optionsVersion:"Version",optionsPath:"Path",optionsPreferPinned:"Pinned dependency (recommended)",optionsPreferGlobal:"Global install (PATH)",optionsNotResolved:"not resolved",optionsPreferHint:"This choice decides which copy boot autostart and the panel actions run.",optionsInstallHint:"No global home-hosted was found. Install the pinned range, then pick the global copy above:",optionsInstall:"Install globally",optionsOutput:"Command output",optionsConfigOverride:"The plugin row's homeHostedCommand overrides this choice.",bootTitle:"Boot autostart",bootDesc:"Start the panel automatically when the machine boots.",bootEnabled:"Enable autostart",bootMechanism:"Mechanism",bootMechanismAuto:"Automatic (recommended)",bootState:"State",bootStateNotInstalled:"not installed",bootStateInstalledDisabled:"installed, disabled",bootStateEnabledRunning:"enabled, running",bootStateEnabledFailing:"enabled, failing",bootStateUnsupported:"unsupported",bootBootCapable:"Starts before login",bootPrivileged:"This process can install it",bootUnitPath:"Unit path",bootCommands:"Manual commands",bootCommandsExplain:"This process could not elevate. Run these commands yourself to install autostart:",bootRecheck:"Re-check",entriesTitle:"Managed entries",entriesDesc:"What this plugin wants each entry to be, and what the panel reports.",entriesEmpty:"No managed entries are configured yet.",entriesExists:"exists",entriesMissing:"missing",entriesManaged:"managed",entriesUnmanaged:"unmanaged",entriesDrift:"Drift",entriesLive:"Live",entriesNotRunning:"not running",entriesAutostart:"Autostart",entriesOnPortConflict:"On port conflict",entriesStopKillPortHolders:"Stop port holders",entriesAdopt:"Adopt",entriesPause:"Pause",entriesRestore:"Restore",agentTitle:"Agent tools",agentDesc:"Which of this plugin\u2019s tools the agent may call.",agentMaster:"Enable agent tools",agentApproval:"Mutating tools ask for approval before they run.",agentToolMutating:"{name} \xB7 asks approval",serversTitle:"Servers",serversDesc:"Servers supervised by the panel.",serversHintPanel:"Add, edit and remove entries in the home-hosted panel: {url}",serversHintNoPanel:"Add, edit and remove entries in the home-hosted panel (it is not running right now).",serversEmpty:"The panel reports no servers.",serversPid:"PID",serversUrl:"URL",serversStart:"Start",serversStop:"Stop",serversRestart:"Restart"},te={tab:"Home Hosted",pageDesc:"\u5F00\u673A\u81EA\u542F\u4E0E home-hosted \u670D\u52A1\u5668\u7BA1\u7406\u3002",loading:"\u52A0\u8F7D\u4E2D\u2026",refresh:"\u5237\u65B0",retry:"\u91CD\u8BD5",errorTitle:"\u9519\u8BEF",statusUnavailable:"\u9762\u677F\u6CA1\u6709\u54CD\u5E94\u3002",yes:"\u662F",no:"\u5426",copy:"\u590D\u5236",copied:"\u5DF2\u590D\u5236",panelTitle:"\u9762\u677F",panelDesc:"home-hosted \u9762\u677F\u7684\u53EF\u8FBE\u6027\u4E0E\u8EAB\u4EFD\u3002",panelReachable:"\u53EF\u8FBE",panelHome:"$HHOSTED_HOME",panelUrl:"URL",panelVersion:"\u7248\u672C",panelPid:"PID",panelWriteVia:"\u5199\u5165\u65B9\u5F0F",panelToken:"API \u4EE4\u724C",panelCliSource:"CLI",panelCliPath:"CLI \u8DEF\u5F84",panelCliConfig:"\u914D\u7F6E\u7684\u547D\u4EE4",panelCliDependency:"\u56FA\u5B9A\u7684\u4F9D\u8D56\u7248\u672C",panelCliPathSource:"\u5168\u5C40\u5B89\u88C5\uFF08PATH\uFF09",panelCliMissing:"\u672A\u627E\u5230",panelCliNotPinned:"\u6B64\u5BBF\u4E3B\u4F7F\u7528\u5168\u5C40 home-hosted\uFF0C\u800C\u4E0D\u662F\u63D2\u4EF6\u56FA\u5B9A\u7684\u526F\u672C\uFF08{range}\uFF09\uFF1B\u91CD\u65B0\u5B89\u88C5\u63D2\u4EF6\u53CA\u5176\u4F9D\u8D56\u5373\u53EF\u4F7F\u7528\u56FA\u5B9A\u7248\u672C\u3002",panelCliLauncherFailed:"\u542F\u52A8\u5668\u6CA1\u6709\u5E94\u7B54\uFF1B\u5F00\u673A\u9879\u53EF\u80FD\u65E0\u6CD5\u542F\u52A8\u9762\u677F\u3002",panelStart:"\u542F\u52A8\u9762\u677F",panelReplace:"\u66FF\u6362\u4E3A {version}",panelAlreadyPreferred:"\u6B63\u5728\u8FD0\u884C\u7684\u9762\u677F\u5DF2\u7ECF\u662F\u9996\u9009\u526F\u672C\u3002",panelTakeoverTitle:"\u66FF\u6362\u6B63\u5728\u8FD0\u884C\u7684\u9762\u677F\uFF1F",panelTakeoverBody:"\u8FD9\u4F1A\u505C\u6B62\u6B63\u5728\u8FD0\u884C\u7684\u9762\u677F\u4EE5\u53CA\u5B83\u76D1\u7BA1\u7684\u6240\u6709\u670D\u52A1\u5668\u2014\u2014\u5305\u62EC\u672C dsh\uFF0C\u56E0\u6B64\u672C\u9875\u9762\u4F1A\u65AD\u5F00\u8FDE\u63A5\u3002\u4EC5\u5F53 dsh \u6761\u76EE\u5DF2\u63A5\u7BA1\u5E76\u542F\u7528\u81EA\u542F\u65F6\u624D\u53EF\u7528\u3002",confirmCancel:"\u53D6\u6D88",confirmReplace:"\u66FF\u6362",writeViaApi:"\u5DF2\u8BA4\u8BC1 API",writeViaFile:"\u914D\u7F6E\u6587\u4EF6",writeViaNone:"\u4E0D\u53EF\u7528",tokenEnrolled:"\u5DF2\u767B\u8BB0",tokenPresent:"\u5DF2\u5B58\u5728",tokenAbsent:"\u4E0D\u5B58\u5728",tokenUnknown:"\u672A\u77E5",optionsTitle:"\u9009\u9879",optionsDesc:"\u8FD0\u884C\u54EA\u4E2A home-hosted\uFF0C\u4EE5\u53CA\u5982\u4F55\u83B7\u5F97\u5168\u5C40\u526F\u672C\u3002",optionsCliUnavailable:"\u5BBF\u4E3B\u6CA1\u6709\u62A5\u544A\u4EFB\u4F55 CLI \u4FE1\u606F\u3002",optionsCurrent:"\u5F53\u524D CLI",optionsVersion:"\u7248\u672C",optionsPath:"\u8DEF\u5F84",optionsPreferPinned:"\u56FA\u5B9A\u4F9D\u8D56\uFF08\u63A8\u8350\uFF09",optionsPreferGlobal:"\u5168\u5C40\u5B89\u88C5\uFF08PATH\uFF09",optionsNotResolved:"\u672A\u89E3\u6790",optionsPreferHint:"\u8BE5\u9009\u62E9\u51B3\u5B9A\u5F00\u673A\u81EA\u542F\u4E0E\u9762\u677F\u64CD\u4F5C\u8FD0\u884C\u54EA\u4E2A\u526F\u672C\u3002",optionsInstallHint:"\u672A\u627E\u5230\u5168\u5C40 home-hosted\u3002\u5B89\u88C5\u56FA\u5B9A\u7248\u672C\u8303\u56F4\u540E\uFF0C\u5728\u4E0A\u65B9\u9009\u62E9\u5168\u5C40\u526F\u672C\uFF1A",optionsInstall:"\u5168\u5C40\u5B89\u88C5",optionsOutput:"\u547D\u4EE4\u8F93\u51FA",optionsConfigOverride:"\u63D2\u4EF6\u884C\u7684 homeHostedCommand \u4F1A\u8986\u76D6\u6B64\u9009\u62E9\u3002",bootTitle:"\u5F00\u673A\u81EA\u542F",bootDesc:"\u968F\u673A\u5668\u542F\u52A8\u81EA\u52A8\u62C9\u8D77\u9762\u677F\u3002",bootEnabled:"\u542F\u7528\u81EA\u542F",bootMechanism:"\u673A\u5236",bootMechanismAuto:"\u81EA\u52A8\uFF08\u63A8\u8350\uFF09",bootState:"\u72B6\u6001",bootStateNotInstalled:"\u672A\u5B89\u88C5",bootStateInstalledDisabled:"\u5DF2\u5B89\u88C5\uFF0C\u672A\u542F\u7528",bootStateEnabledRunning:"\u5DF2\u542F\u7528\uFF0C\u8FD0\u884C\u4E2D",bootStateEnabledFailing:"\u5DF2\u542F\u7528\uFF0C\u542F\u52A8\u5931\u8D25",bootStateUnsupported:"\u4E0D\u652F\u6301",bootBootCapable:"\u767B\u5F55\u524D\u542F\u52A8",bootPrivileged:"\u672C\u8FDB\u7A0B\u53EF\u5B89\u88C5",bootUnitPath:"\u5355\u5143\u6587\u4EF6\u8DEF\u5F84",bootCommands:"\u624B\u52A8\u547D\u4EE4",bootCommandsExplain:"\u672C\u8FDB\u7A0B\u65E0\u6CD5\u63D0\u6743\u3002\u8BF7\u81EA\u884C\u6267\u884C\u4EE5\u4E0B\u547D\u4EE4\u6765\u5B89\u88C5\u81EA\u542F\uFF1A",bootRecheck:"\u91CD\u65B0\u68C0\u67E5",entriesTitle:"\u53D7\u7BA1\u6761\u76EE",entriesDesc:"\u672C\u63D2\u4EF6\u5E0C\u671B\u6BCF\u6761\u76EE\u6210\u4E3A\u7684\u6837\u5B50\uFF0C\u4EE5\u53CA\u9762\u677F\u5B9E\u9645\u62A5\u544A\u7684\u72B6\u6001\u3002",entriesEmpty:"\u5C1A\u672A\u914D\u7F6E\u4EFB\u4F55\u53D7\u7BA1\u6761\u76EE\u3002",entriesExists:"\u5B58\u5728",entriesMissing:"\u7F3A\u5931",entriesManaged:"\u5DF2\u63A5\u7BA1",entriesUnmanaged:"\u672A\u63A5\u7BA1",entriesDrift:"\u6F02\u79FB",entriesLive:"\u5B9E\u65F6",entriesNotRunning:"\u672A\u8FD0\u884C",entriesAutostart:"\u81EA\u542F",entriesOnPortConflict:"\u7AEF\u53E3\u51B2\u7A81\u65F6",entriesStopKillPortHolders:"\u505C\u6B62\u7AEF\u53E3\u5360\u7528\u8005",entriesAdopt:"\u63A5\u7BA1",entriesPause:"\u6682\u505C",entriesRestore:"\u8FD8\u539F",agentTitle:"Agent \u5DE5\u5177",agentDesc:"Agent \u53EF\u4EE5\u8C03\u7528\u672C\u63D2\u4EF6\u7684\u54EA\u4E9B\u5DE5\u5177\u3002",agentMaster:"\u542F\u7528 Agent \u5DE5\u5177",agentApproval:"\u4F1A\u6539\u53D8\u72B6\u6001\u7684\u5DE5\u5177\u5728\u8FD0\u884C\u524D\u4F1A\u8BF7\u6C42\u6279\u51C6\u3002",agentToolMutating:"{name} \xB7 \u9700\u6279\u51C6",serversTitle:"\u670D\u52A1\u5668",serversDesc:"\u9762\u677F\u76D1\u7BA1\u7684\u670D\u52A1\u5668\u3002",serversHintPanel:"\u5728 home-hosted \u9762\u677F\u4E2D\u6DFB\u52A0\u3001\u7F16\u8F91\u548C\u5220\u9664\u6761\u76EE\uFF1A{url}",serversHintNoPanel:"\u5728 home-hosted \u9762\u677F\u4E2D\u6DFB\u52A0\u3001\u7F16\u8F91\u548C\u5220\u9664\u6761\u76EE\uFF08\u5F53\u524D\u672A\u8FD0\u884C\uFF09\u3002",serversEmpty:"\u9762\u677F\u672A\u62A5\u544A\u4EFB\u4F55\u670D\u52A1\u5668\u3002",serversPid:"PID",serversUrl:"URL",serversStart:"\u542F\u52A8",serversStop:"\u505C\u6B62",serversRestart:"\u91CD\u542F"};function Le(e,t){return t===void 0?e:e.replace(/\{(\w+)\}/g,(n,s)=>Object.prototype.hasOwnProperty.call(t,s)?String(t[s]):n)}var ne=(e,t)=>Le(K[e]??e,t);function oe(e){if(e!==void 0)try{let t=e.bind($);if(typeof t=="function")return t}catch{}return ne}function re(e,t=ne){return e===void 0?t:(n,s)=>{let r;try{r=e(n,s)}catch{r=void 0}return r===void 0||r.length===0||r===n?t(n,s):r}}var B=require("react");var A=require("react");var se="/home-hosted";var L=["status","servers_list","servers_start","servers_stop","servers_restart","servers_create","servers_update","servers_delete","autostart_install","autostart_uninstall"],ie=["servers_start","servers_stop","servers_restart","servers_create","servers_update","servers_delete","autostart_install","autostart_uninstall"];var Ve="/api";function k(e,t,n){return{ok:!1,error:n===void 0?{code:e,message:t}:{code:e,message:t,detail:n}}}function W(e){return typeof e=="object"&&e!==null}function je(e){return e instanceof Error?e.message:String(e)}function Fe(e){if(!W(e))return k("bad-response","The panel returned a non-object response");if(typeof e.v=="number"&&e.v!==1)return k("version-mismatch",`Response protocol v${e.v} does not match the expected v${1}`);let t=e.result;if(!W(t))return k("bad-response","The panel returned no result");if(t.ok===!0)return"value"in t?{ok:!0,value:t.value}:k("bad-response","A successful response carried no value");if(t.ok===!1){let n=t.error;return W(n)&&typeof n.message=="string"?k(typeof n.code=="string"?n.code:"error",n.message,n.detail):k("error","The panel reported a failure without a message")}return k("bad-response","The panel returned an unrecognised result")}async function h(e,t,n={}){let s=n.fetch??globalThis.fetch;if(typeof s!="function")return k("no-fetch","No fetch implementation is available");let r={v:1,endpoint:e,payload:t},o;try{o=await s(`${Ve}${se}`,{method:"POST",credentials:"same-origin",headers:{"content-type":"application/json"},body:JSON.stringify(r)})}catch(p){return k("network",je(p))}if(!o.ok){let p=o.statusText.length>0?` ${o.statusText}`:"";return k("http",`HTTP ${o.status}${p}`)}let i;try{i=await o.json()}catch{return k("bad-json","The panel returned invalid JSON")}return Fe(i)}function ae(e,t={}){return h("settings.update",{patch:e},t)}var ze=5e3;function le(e=ze){let[t,n]=(0,A.useState)(null),[s,r]=(0,A.useState)(null),[o,i]=(0,A.useState)(!0),p=(0,A.useRef)(!0),v=(0,A.useCallback)(async()=>{let S=await h("status",{});p.current&&(S.ok?(n(S.value),r(null)):r(S.error),i(!1))},[]);return(0,A.useEffect)(()=>{p.current=!0,v();let S=setInterval(()=>{v()},e);return()=>{p.current=!1,clearInterval(S)}},[v,e]),{data:t,error:s,loading:o,refresh:v}}var V="\u2014";function b(e){if(e==null)return V;let t=String(e);return t.length>0?t:V}function pe(e){return e.length>0?e.join(", "):V}function de(e){return ie.includes(e)}var ce={api:"writeViaApi",file:"writeViaFile",none:"writeViaNone"},ue={enrolled:"tokenEnrolled",present:"tokenPresent",absent:"tokenAbsent",unknown:"tokenUnknown"},ge={"not-installed":"bootStateNotInstalled","installed-disabled":"bootStateInstalledDisabled","enabled-running":"bootStateEnabledRunning","enabled-failing":"bootStateEnabledFailing",unsupported:"bootStateUnsupported"},j={config:"panelCliConfig",dependency:"panelCliDependency",path:"panelCliPathSource",none:"panelCliMissing"};function q(e){return e==null?V:`${b(e.version)} \xB7 ${b(e.path)}`}function fe(e){let t=n=>e.source===n&&e.path!==null?{source:n,path:e.path,version:e.version}:null;return{dependency:e.dependency??t("dependency"),global:e.global??t("path")}}function me(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function Ge(e,t){if(Object.is(e,t))return!0;try{return JSON.stringify(e)===JSON.stringify(t)}catch{return!1}}function he(e,t){let n={};for(let s of Object.keys(t)){let r=e[s],o=t[s];if(me(r)&&me(o)){let i=he(r,o);Object.keys(i).length>0&&(n[s]=i)}else Ge(r,o)||(n[s]=o)}return n}function be(e,t){return he(e,t)}function ve(e,t,n){let s=new Set(e);return n?s.add(t):s.delete(t),L.filter(r=>s.has(r))}var d=require("react/jsx-runtime"),F="var(--dsw-alias-label-secondary, #8b8b8b)",J="var(--dsw-alias-border-secondary, rgba(128, 128, 128, 0.25))",ye="var(--dsw-alias-state-error-primary, #e53e3e)",Ke={fontFamily:"ui-monospace, SFMono-Regular, Menlo, monospace",wordBreak:"break-all",textAlign:"right"};function T({title:e,description:t,children:n}){return(0,d.jsxs)("section",{style:{display:"flex",flexDirection:"column",gap:8,padding:"14px 0",borderTop:`1px solid ${J}`},children:[(0,d.jsxs)("header",{style:{display:"flex",flexDirection:"column",gap:2},children:[(0,d.jsx)("h3",{style:{margin:0,fontSize:14,fontWeight:600},children:e}),t!==void 0&&t.length>0?(0,d.jsx)("p",{style:{margin:0,fontSize:12,color:F},children:t}):null]}),n]})}function a({label:e,children:t}){return(0,d.jsxs)("div",{style:{display:"flex",alignItems:"baseline",gap:12,justifyContent:"space-between",fontSize:13},children:[(0,d.jsx)("span",{style:{color:F},children:e}),(0,d.jsx)("span",{style:Ke,children:t})]})}function c({children:e}){return typeof e=="string"&&(typeof e=="string"?e:"").length===0?null:(0,d.jsx)("p",{style:{margin:0,fontSize:12,color:F,lineHeight:1.5},children:e})}function u({children:e,onClick:t,disabled:n,busy:s}){return(0,d.jsx)("button",{type:"button",onClick:t,disabled:n===!0||s===!0,style:{padding:"4px 10px",fontSize:12,borderRadius:6,border:`1px solid ${J}`,background:"transparent",color:"inherit",cursor:n===!0||s===!0?"default":"pointer",opacity:n===!0||s===!0?.6:1},children:e})}function M({label:e,checked:t,disabled:n,onChange:s}){return(0,d.jsxs)("label",{style:{display:"flex",alignItems:"center",gap:8,fontSize:13,opacity:n===!0?.6:1,cursor:n===!0?"default":"pointer"},children:[(0,d.jsx)("input",{type:"checkbox",checked:t,disabled:n,onChange:r=>s(r.target.checked)}),(0,d.jsx)("span",{children:e})]})}function Se({value:e,options:t,disabled:n,onChange:s}){return(0,d.jsx)("select",{value:e,disabled:n,onChange:r=>s(r.target.value),style:{padding:"3px 6px",fontSize:12,borderRadius:6,border:`1px solid ${J}`,background:"transparent",color:"inherit"},children:t.map(r=>(0,d.jsx)("option",{value:r.value,children:r.label},r.value))})}function X({label:e,description:t,checked:n,disabled:s,onChange:r}){return(0,d.jsxs)("label",{style:{display:"flex",alignItems:"flex-start",gap:8,fontSize:13,opacity:s===!0?.6:1,cursor:s===!0?"default":"pointer"},children:[(0,d.jsx)("input",{type:"radio",checked:n,disabled:s,onChange:()=>r(),style:{marginTop:2}}),(0,d.jsxs)("span",{style:{display:"flex",flexDirection:"column",gap:2},children:[(0,d.jsx)("span",{children:e}),t!==void 0&&t.length>0?(0,d.jsx)("span",{style:{fontSize:12,color:F},children:t}):null]})]})}function D({error:e,title:t}){return e===null?null:(0,d.jsxs)("div",{role:"alert",style:{padding:"8px 10px",borderRadius:6,fontSize:12,lineHeight:1.5,border:`1px solid ${ye}`,color:ye},children:[(0,d.jsx)("strong",{children:t}),": ",(0,d.jsx)("code",{children:e.code})," \u2014 ",e.message]})}var O=require("react/jsx-runtime");function Ce({t:e,status:t,updateSettings:n}){let s=t.settings.agentTools,r=s.allow??[];return(0,O.jsxs)(T,{title:e("agentTitle"),description:e("agentDesc"),children:[(0,O.jsx)(M,{label:e("agentMaster"),checked:s.enabled,onChange:o=>n(i=>({...i,agentTools:{...i.agentTools,enabled:o}}))}),(0,O.jsx)(c,{children:e("agentApproval")}),(0,O.jsx)("div",{style:{display:"flex",flexDirection:"column",gap:6},children:L.map(o=>(0,O.jsx)(M,{label:de(o)?e("agentToolMutating",{name:o}):o,checked:r.includes(o),disabled:!s.enabled,onChange:i=>n(p=>({...p,agentTools:{...p.agentTools,allow:ve(p.agentTools.allow??[],o,i)}}))},o))})]})}var Pe=require("react");async function z(e){try{if(typeof navigator<"u"&&navigator.clipboard!==void 0)return await navigator.clipboard.writeText(e),!0}catch{}return!1}var y=require("react/jsx-runtime"),We={width:"100%",minHeight:60,marginTop:6,padding:8,borderRadius:6,border:"1px solid var(--dsw-alias-border-secondary, rgba(128, 128, 128, 0.25))",background:"transparent",color:"inherit",fontFamily:"ui-monospace, SFMono-Regular, Menlo, monospace",fontSize:12,resize:"vertical"};function Re({t:e,status:t,run:n,updateSettings:s,busy:r}){let o=t.boot,i=t.settings.autostart,p=o.candidates??[],v=o.commands??[],[S,x]=(0,Pe.useState)(!1),w=r==="settings",C=["auto",...p.filter(m=>m.available).map(m=>m.mechanism)];C.includes(i.mechanism)||C.push(i.mechanism);let E=C.map(m=>({value:m,label:m==="auto"?e("bootMechanismAuto"):m})),_=async()=>{x(await z(v.join(`
|
|
4
|
-
`)))};return(0,
|
|
5
|
-
`),
|
|
6
|
-
`)))},
|
|
7
|
-
`)
|
|
3
|
+
"use strict";var Z=Object.defineProperty;var Ge=Object.getOwnPropertyDescriptor;var Ke=Object.getOwnPropertyNames;var We=Object.prototype.hasOwnProperty;var Ye=(e,t)=>{for(var n in t)Z(e,n,{get:t[n],enumerable:!0})},qe=(e,t,n,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of Ke(t))!We.call(e,r)&&r!==n&&Z(e,r,{get:()=>t[r],enumerable:!(i=Ge(t,r))||i.enumerable});return e};var Je=e=>qe(Z({},"__esModule",{value:!0}),e);var ht={};Ye(ht,{apply:()=>bt,inject:()=>mt});module.exports=Je(ht);var j="homeHosted",Q={tab:"Home Hosted",pageDesc:"Boot autostart and home-hosted server management.",loading:"Loading\u2026",refresh:"Refresh",retry:"Retry",errorTitle:"Error",statusUnavailable:"The panel did not answer.",yes:"Yes",no:"No",copy:"Copy",copied:"Copied",panelTitle:"Panel",panelDesc:"Reachability and identity of the home-hosted panel.",panelReachable:"Reachable",panelHome:"$HHOSTED_HOME",panelUrl:"URL",panelVersion:"Version",panelPid:"PID",panelWriteVia:"Writes via",panelToken:"API token",panelCliSource:"CLI",panelCliPath:"CLI path",panelCliConfig:"configured command",panelCliDependency:"pinned dependency",panelCliPathSource:"global install (PATH)",panelCliMissing:"not found",panelCliNotPinned:"This host uses a global home-hosted instead of the plugin's pinned copy ({range}); reinstall the plugin with its dependencies to use the pinned one.",panelCliLauncherFailed:"The boot launcher did not answer; a boot entry may fail to start the panel.",panelStart:"Start the panel",panelReplace:"Replace with {version}",panelAlreadyPreferred:"The running panel is already the preferred copy.",panelTakeoverTitle:"Replace the running panel?",panelTakeoverBody:"This stops the running panel and every server it supervises \u2014 including this dsh, so this page disconnects. It only works when the dsh entry is adopted with autostart enabled.",confirmCancel:"Cancel",confirmReplace:"Replace",writeViaApi:"authenticated API",writeViaFile:"config file",writeViaNone:"unavailable",tokenEnrolled:"enrolled",tokenPresent:"present",tokenAbsent:"absent",tokenUnknown:"unknown",optionsTitle:"Options",optionsDesc:"Which home-hosted to run, and how to get a global copy.",optionsCliUnavailable:"The host did not report any CLI information.",optionsCurrent:"CLI in use",optionsVersion:"Version",optionsPath:"Path",optionsPreferPinned:"Pinned dependency (recommended)",optionsPreferGlobal:"Global install (PATH)",optionsNotResolved:"not resolved",optionsPreferHint:"This choice decides which copy boot autostart and the panel actions run.",optionsInstallHint:"No global home-hosted was found. Install the pinned range, then pick the global copy above:",optionsInstall:"Install globally",optionsOutput:"Command output",optionsConfigOverride:"The plugin row's homeHostedCommand overrides this choice.",bootTitle:"Boot autostart",bootDesc:"Start the panel automatically when the machine boots.",bootEnabled:"Enable autostart",bootMechanism:"Mechanism",bootMechanismAuto:"Automatic (recommended)",bootState:"State",bootStateNotInstalled:"not installed",bootStateInstalledDisabled:"installed, disabled",bootStateEnabledRunning:"enabled, running",bootStateEnabledFailing:"enabled, failing",bootStateUnsupported:"unsupported",bootBootCapable:"Starts before login",bootPrivileged:"This process can install it",bootUnitPath:"Unit path",bootCommands:"Manual commands",bootLoginScope:"This entry starts at login. To start before login, choose a boot-scope mechanism: launchd-daemon on macOS (needs sudo once), or systemd-system / linger on Linux.",bootCommandsExplain:"This process could not elevate. Run these commands yourself to install autostart:",bootRecheck:"Re-check",bootActionInstall:"install",bootActionUninstall:"uninstall",bootRequestedNotInstalled:"Autostart is requested, but no boot entry is installed yet.",bootAttemptFailed:"Last attempt: {action} failed",bootAttemptSucceeded:"Last attempt: {action} succeeded \u2014 {detail}",bootAttemptNoDetail:"The host did not explain the refusal.",bootAttemptCommands:"Commands you can run yourself:",entriesTitle:"Managed entries",entriesDesc:"What this plugin wants each entry to be, and what the panel reports.",entriesEmpty:"No managed entries are configured yet.",entriesExists:"exists",entriesMissing:"missing",entriesManaged:"managed",entriesUnmanaged:"unmanaged",entriesDrift:"Drift",entriesLive:"Live",entriesNotRunning:"not running",entriesAutostart:"Autostart",entriesOnPortConflict:"On port conflict",entriesStopKillPortHolders:"Stop port holders",entriesAdopt:"Adopt",entriesPause:"Pause",entriesRestore:"Restore",agentTitle:"Agent tools",agentDesc:"Which of this plugin\u2019s tools the agent may call.",agentMaster:"Enable agent tools",agentApproval:"Mutating tools ask for approval before they run.",agentToolMutating:"{name} \xB7 asks approval",serversTitle:"Servers",serversDesc:"Servers supervised by the panel.",serversHintPanel:"Add, edit and remove entries in the home-hosted panel:",serversHintNoPanel:"Add, edit and remove entries in the home-hosted panel (it is not running right now).",serversEmpty:"The panel reports no servers.",serversPid:"PID",serversUrl:"URL",serversStart:"Start",serversStop:"Stop",serversRestart:"Restart"},ce={tab:"Home Hosted",pageDesc:"\u5F00\u673A\u81EA\u542F\u4E0E home-hosted \u670D\u52A1\u5668\u7BA1\u7406\u3002",loading:"\u52A0\u8F7D\u4E2D\u2026",refresh:"\u5237\u65B0",retry:"\u91CD\u8BD5",errorTitle:"\u9519\u8BEF",statusUnavailable:"\u9762\u677F\u6CA1\u6709\u54CD\u5E94\u3002",yes:"\u662F",no:"\u5426",copy:"\u590D\u5236",copied:"\u5DF2\u590D\u5236",panelTitle:"\u9762\u677F",panelDesc:"home-hosted \u9762\u677F\u7684\u53EF\u8FBE\u6027\u4E0E\u8EAB\u4EFD\u3002",panelReachable:"\u53EF\u8FBE",panelHome:"$HHOSTED_HOME",panelUrl:"URL",panelVersion:"\u7248\u672C",panelPid:"PID",panelWriteVia:"\u5199\u5165\u65B9\u5F0F",panelToken:"API \u4EE4\u724C",panelCliSource:"CLI",panelCliPath:"CLI \u8DEF\u5F84",panelCliConfig:"\u914D\u7F6E\u7684\u547D\u4EE4",panelCliDependency:"\u56FA\u5B9A\u7684\u4F9D\u8D56\u7248\u672C",panelCliPathSource:"\u5168\u5C40\u5B89\u88C5\uFF08PATH\uFF09",panelCliMissing:"\u672A\u627E\u5230",panelCliNotPinned:"\u6B64\u5BBF\u4E3B\u4F7F\u7528\u5168\u5C40 home-hosted\uFF0C\u800C\u4E0D\u662F\u63D2\u4EF6\u56FA\u5B9A\u7684\u526F\u672C\uFF08{range}\uFF09\uFF1B\u91CD\u65B0\u5B89\u88C5\u63D2\u4EF6\u53CA\u5176\u4F9D\u8D56\u5373\u53EF\u4F7F\u7528\u56FA\u5B9A\u7248\u672C\u3002",panelCliLauncherFailed:"\u542F\u52A8\u5668\u6CA1\u6709\u5E94\u7B54\uFF1B\u5F00\u673A\u9879\u53EF\u80FD\u65E0\u6CD5\u542F\u52A8\u9762\u677F\u3002",panelStart:"\u542F\u52A8\u9762\u677F",panelReplace:"\u66FF\u6362\u4E3A {version}",panelAlreadyPreferred:"\u6B63\u5728\u8FD0\u884C\u7684\u9762\u677F\u5DF2\u7ECF\u662F\u9996\u9009\u526F\u672C\u3002",panelTakeoverTitle:"\u66FF\u6362\u6B63\u5728\u8FD0\u884C\u7684\u9762\u677F\uFF1F",panelTakeoverBody:"\u8FD9\u4F1A\u505C\u6B62\u6B63\u5728\u8FD0\u884C\u7684\u9762\u677F\u4EE5\u53CA\u5B83\u76D1\u7BA1\u7684\u6240\u6709\u670D\u52A1\u5668\u2014\u2014\u5305\u62EC\u672C dsh\uFF0C\u56E0\u6B64\u672C\u9875\u9762\u4F1A\u65AD\u5F00\u8FDE\u63A5\u3002\u4EC5\u5F53 dsh \u6761\u76EE\u5DF2\u63A5\u7BA1\u5E76\u542F\u7528\u81EA\u542F\u65F6\u624D\u53EF\u7528\u3002",confirmCancel:"\u53D6\u6D88",confirmReplace:"\u66FF\u6362",writeViaApi:"\u5DF2\u8BA4\u8BC1 API",writeViaFile:"\u914D\u7F6E\u6587\u4EF6",writeViaNone:"\u4E0D\u53EF\u7528",tokenEnrolled:"\u5DF2\u767B\u8BB0",tokenPresent:"\u5DF2\u5B58\u5728",tokenAbsent:"\u4E0D\u5B58\u5728",tokenUnknown:"\u672A\u77E5",optionsTitle:"\u9009\u9879",optionsDesc:"\u8FD0\u884C\u54EA\u4E2A home-hosted\uFF0C\u4EE5\u53CA\u5982\u4F55\u83B7\u5F97\u5168\u5C40\u526F\u672C\u3002",optionsCliUnavailable:"\u5BBF\u4E3B\u6CA1\u6709\u62A5\u544A\u4EFB\u4F55 CLI \u4FE1\u606F\u3002",optionsCurrent:"\u5F53\u524D CLI",optionsVersion:"\u7248\u672C",optionsPath:"\u8DEF\u5F84",optionsPreferPinned:"\u56FA\u5B9A\u4F9D\u8D56\uFF08\u63A8\u8350\uFF09",optionsPreferGlobal:"\u5168\u5C40\u5B89\u88C5\uFF08PATH\uFF09",optionsNotResolved:"\u672A\u89E3\u6790",optionsPreferHint:"\u8BE5\u9009\u62E9\u51B3\u5B9A\u5F00\u673A\u81EA\u542F\u4E0E\u9762\u677F\u64CD\u4F5C\u8FD0\u884C\u54EA\u4E2A\u526F\u672C\u3002",optionsInstallHint:"\u672A\u627E\u5230\u5168\u5C40 home-hosted\u3002\u5B89\u88C5\u56FA\u5B9A\u7248\u672C\u8303\u56F4\u540E\uFF0C\u5728\u4E0A\u65B9\u9009\u62E9\u5168\u5C40\u526F\u672C\uFF1A",optionsInstall:"\u5168\u5C40\u5B89\u88C5",optionsOutput:"\u547D\u4EE4\u8F93\u51FA",optionsConfigOverride:"\u63D2\u4EF6\u884C\u7684 homeHostedCommand \u4F1A\u8986\u76D6\u6B64\u9009\u62E9\u3002",bootTitle:"\u5F00\u673A\u81EA\u542F",bootDesc:"\u968F\u673A\u5668\u542F\u52A8\u81EA\u52A8\u62C9\u8D77\u9762\u677F\u3002",bootEnabled:"\u542F\u7528\u81EA\u542F",bootMechanism:"\u673A\u5236",bootMechanismAuto:"\u81EA\u52A8\uFF08\u63A8\u8350\uFF09",bootState:"\u72B6\u6001",bootStateNotInstalled:"\u672A\u5B89\u88C5",bootStateInstalledDisabled:"\u5DF2\u5B89\u88C5\uFF0C\u672A\u542F\u7528",bootStateEnabledRunning:"\u5DF2\u542F\u7528\uFF0C\u8FD0\u884C\u4E2D",bootStateEnabledFailing:"\u5DF2\u542F\u7528\uFF0C\u542F\u52A8\u5931\u8D25",bootStateUnsupported:"\u4E0D\u652F\u6301",bootBootCapable:"\u767B\u5F55\u524D\u542F\u52A8",bootPrivileged:"\u672C\u8FDB\u7A0B\u53EF\u5B89\u88C5",bootUnitPath:"\u5355\u5143\u6587\u4EF6\u8DEF\u5F84",bootCommands:"\u624B\u52A8\u547D\u4EE4",bootLoginScope:"\u6B64\u6761\u76EE\u5728\u767B\u5F55\u540E\u542F\u52A8\u3002\u82E5\u8981\u5728\u767B\u5F55\u524D\u542F\u52A8\uFF0C\u8BF7\u9009\u62E9\u5F00\u673A\u7EA7\u673A\u5236\uFF1AmacOS \u7528 launchd-daemon\uFF08\u9700\u4E00\u6B21 sudo\uFF09\uFF0CLinux \u7528 systemd-system \u6216 linger\u3002",bootCommandsExplain:"\u672C\u8FDB\u7A0B\u65E0\u6CD5\u63D0\u6743\u3002\u8BF7\u81EA\u884C\u6267\u884C\u4EE5\u4E0B\u547D\u4EE4\u6765\u5B89\u88C5\u81EA\u542F\uFF1A",bootRecheck:"\u91CD\u65B0\u68C0\u67E5",bootActionInstall:"\u5B89\u88C5",bootActionUninstall:"\u5378\u8F7D",bootRequestedNotInstalled:"\u5DF2\u8BF7\u6C42\u5F00\u673A\u81EA\u542F\uFF0C\u4F46\u5C1A\u672A\u5B89\u88C5\u4EFB\u4F55\u5F00\u673A\u9879\u3002",bootAttemptFailed:"\u4E0A\u6B21\u5C1D\u8BD5\uFF1A{action}\u5931\u8D25",bootAttemptSucceeded:"\u4E0A\u6B21\u5C1D\u8BD5\uFF1A{action}\u6210\u529F \u2014 {detail}",bootAttemptNoDetail:"\u5BBF\u4E3B\u6CA1\u6709\u8BF4\u660E\u5931\u8D25\u539F\u56E0\u3002",bootAttemptCommands:"\u4F60\u53EF\u4EE5\u81EA\u884C\u8FD0\u884C\u4EE5\u4E0B\u547D\u4EE4\uFF1A",entriesTitle:"\u53D7\u7BA1\u6761\u76EE",entriesDesc:"\u672C\u63D2\u4EF6\u5E0C\u671B\u6BCF\u6761\u76EE\u6210\u4E3A\u7684\u6837\u5B50\uFF0C\u4EE5\u53CA\u9762\u677F\u5B9E\u9645\u62A5\u544A\u7684\u72B6\u6001\u3002",entriesEmpty:"\u5C1A\u672A\u914D\u7F6E\u4EFB\u4F55\u53D7\u7BA1\u6761\u76EE\u3002",entriesExists:"\u5B58\u5728",entriesMissing:"\u7F3A\u5931",entriesManaged:"\u5DF2\u63A5\u7BA1",entriesUnmanaged:"\u672A\u63A5\u7BA1",entriesDrift:"\u6F02\u79FB",entriesLive:"\u5B9E\u65F6",entriesNotRunning:"\u672A\u8FD0\u884C",entriesAutostart:"\u81EA\u542F",entriesOnPortConflict:"\u7AEF\u53E3\u51B2\u7A81\u65F6",entriesStopKillPortHolders:"\u505C\u6B62\u7AEF\u53E3\u5360\u7528\u8005",entriesAdopt:"\u63A5\u7BA1",entriesPause:"\u6682\u505C",entriesRestore:"\u8FD8\u539F",agentTitle:"Agent \u5DE5\u5177",agentDesc:"Agent \u53EF\u4EE5\u8C03\u7528\u672C\u63D2\u4EF6\u7684\u54EA\u4E9B\u5DE5\u5177\u3002",agentMaster:"\u542F\u7528 Agent \u5DE5\u5177",agentApproval:"\u4F1A\u6539\u53D8\u72B6\u6001\u7684\u5DE5\u5177\u5728\u8FD0\u884C\u524D\u4F1A\u8BF7\u6C42\u6279\u51C6\u3002",agentToolMutating:"{name} \xB7 \u9700\u6279\u51C6",serversTitle:"\u670D\u52A1\u5668",serversDesc:"\u9762\u677F\u76D1\u7BA1\u7684\u670D\u52A1\u5668\u3002",serversHintPanel:"\u5728 home-hosted \u9762\u677F\u4E2D\u6DFB\u52A0\u3001\u7F16\u8F91\u548C\u5220\u9664\u6761\u76EE\uFF1A",serversHintNoPanel:"\u5728 home-hosted \u9762\u677F\u4E2D\u6DFB\u52A0\u3001\u7F16\u8F91\u548C\u5220\u9664\u6761\u76EE\uFF08\u5F53\u524D\u672A\u8FD0\u884C\uFF09\u3002",serversEmpty:"\u9762\u677F\u672A\u62A5\u544A\u4EFB\u4F55\u670D\u52A1\u5668\u3002",serversPid:"PID",serversUrl:"URL",serversStart:"\u542F\u52A8",serversStop:"\u505C\u6B62",serversRestart:"\u91CD\u542F"};function Xe(e,t){return t===void 0?e:e.replace(/\{(\w+)\}/g,(n,i)=>Object.prototype.hasOwnProperty.call(t,i)?String(t[i]):n)}var ue=(e,t)=>Xe(Q[e]??e,t);function ge(e){if(e!==void 0)try{let t=e.bind(j);if(typeof t=="function")return t}catch{}return ue}function fe(e,t=ue){return e===void 0?t:(n,i)=>{let r;try{r=e(n,i)}catch{r=void 0}return r===void 0||r.length===0||r===n?t(n,i):r}}var L=require("react");var B=require("react");var me="/home-hosted";var z=["status","servers_list","servers_start","servers_stop","servers_restart","servers_create","servers_update","servers_delete","autostart_install","autostart_uninstall"],be=["servers_start","servers_stop","servers_restart","servers_create","servers_update","servers_delete","autostart_install","autostart_uninstall"];var Ze="/api";function H(e,t,n){return{ok:!1,error:n===void 0?{code:e,message:t}:{code:e,message:t,detail:n}}}function ee(e){return typeof e=="object"&&e!==null}function Qe(e){return e instanceof Error?e.message:String(e)}function et(e){if(!ee(e))return H("bad-response","The panel returned a non-object response");if(typeof e.v=="number"&&e.v!==1)return H("version-mismatch",`Response protocol v${e.v} does not match the expected v${1}`);let t=e.result;if(!ee(t))return H("bad-response","The panel returned no result");if(t.ok===!0)return"value"in t?{ok:!0,value:t.value}:H("bad-response","A successful response carried no value");if(t.ok===!1){let n=t.error;return ee(n)&&typeof n.message=="string"?H(typeof n.code=="string"?n.code:"error",n.message,n.detail):H("error","The panel reported a failure without a message")}return H("bad-response","The panel returned an unrecognised result")}async function b(e,t,n={}){let i=n.fetch??globalThis.fetch;if(typeof i!="function")return H("no-fetch","No fetch implementation is available");let r={v:1,endpoint:e,payload:t},o;try{o=await i(`${Ze}${me}`,{method:"POST",credentials:"same-origin",headers:{"content-type":"application/json"},body:JSON.stringify(r)})}catch(u){return H("network",Qe(u))}if(!o.ok){let u=o.statusText.length>0?` ${o.statusText}`:"";return H("http",`HTTP ${o.status}${u}`)}let s;try{s=await o.json()}catch{return H("bad-json","The panel returned invalid JSON")}return et(s)}function G(e,t={}){return b("settings.update",{patch:e},t)}var tt=5e3;function he(e=tt){let[t,n]=(0,B.useState)(null),[i,r]=(0,B.useState)(null),[o,s]=(0,B.useState)(!0),u=(0,B.useRef)(!0),S=(0,B.useCallback)(async()=>{let C=await b("status",{});u.current&&(C.ok?(n(C.value),r(null)):r(C.error),s(!1))},[]);return(0,B.useEffect)(()=>{u.current=!0,S();let C=setInterval(()=>{S()},e);return()=>{u.current=!1,clearInterval(C)}},[S,e]),{data:t,error:i,loading:o,refresh:S}}var K="\u2014";function y(e){if(e==null)return K;let t=String(e);return t.length>0?t:K}function ve(e){return e.length>0?e.join(", "):K}function ye(e){return be.includes(e)}var Se={api:"writeViaApi",file:"writeViaFile",none:"writeViaNone"},Ce={enrolled:"tokenEnrolled",present:"tokenPresent",absent:"tokenAbsent",unknown:"tokenUnknown"},xe={"not-installed":"bootStateNotInstalled","installed-disabled":"bootStateInstalledDisabled","enabled-running":"bootStateEnabledRunning","enabled-failing":"bootStateEnabledFailing",unsupported:"bootStateUnsupported"},W={config:"panelCliConfig",dependency:"panelCliDependency",path:"panelCliPathSource",none:"panelCliMissing"};function ne(e){return e==null?K:`${y(e.version)} \xB7 ${y(e.path)}`}function Pe(e){let t=n=>e.source===n&&e.path!==null?{source:n,path:e.path,version:e.version}:null;return{dependency:e.dependency??t("dependency"),global:e.global??t("path")}}function Re(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function nt(e,t){if(Object.is(e,t))return!0;try{return JSON.stringify(e)===JSON.stringify(t)}catch{return!1}}function we(e,t){let n={};for(let i of Object.keys(t)){let r=e[i],o=t[i];if(Re(r)&&Re(o)){let s=we(r,o);Object.keys(s).length>0&&(n[i]=s)}else nt(r,o)||(n[i]=o)}return n}function Y(e,t){return we(e,t)}function ke(e,t,n){let i=new Set(e);return n?i.add(t):i.delete(t),z.filter(r=>i.has(r))}var p=require("react/jsx-runtime"),D="var(--dsw-alias-label-secondary, #8b8b8b)",oe="var(--dsw-alias-border-secondary, rgba(128, 128, 128, 0.25))",q="var(--dsw-alias-state-error-primary, #e53e3e)",ot={fontFamily:"ui-monospace, SFMono-Regular, Menlo, monospace",wordBreak:"break-all",textAlign:"right"};function k({title:e,description:t,children:n}){return(0,p.jsxs)("section",{style:{display:"flex",flexDirection:"column",gap:8,padding:"14px 0",borderTop:`1px solid ${oe}`},children:[(0,p.jsxs)("header",{style:{display:"flex",flexDirection:"column",gap:2},children:[(0,p.jsx)("h3",{style:{margin:0,fontSize:14,fontWeight:600},children:e}),t!==void 0&&t.length>0?(0,p.jsx)("p",{style:{margin:0,fontSize:12,color:D},children:t}):null]}),n]})}function l({label:e,children:t}){return(0,p.jsxs)("div",{style:{display:"flex",alignItems:"baseline",gap:12,justifyContent:"space-between",fontSize:13},children:[(0,p.jsx)("span",{style:{color:D},children:e}),(0,p.jsx)("span",{style:ot,children:t})]})}function d({children:e}){return typeof e=="string"&&(typeof e=="string"?e:"").length===0?null:(0,p.jsx)("p",{style:{margin:0,fontSize:12,color:D,lineHeight:1.5},children:e})}function U({href:e,children:t}){return(0,p.jsx)("a",{href:e,target:"_blank",rel:"noreferrer noopener",style:{color:D,textDecoration:"underline",overflowWrap:"anywhere"},children:t??e})}function Te({title:e,detail:t}){return(0,p.jsxs)("div",{role:"alert",style:{padding:"8px 10px",borderRadius:6,fontSize:12,lineHeight:1.5,border:`1px solid ${q}`,color:q},children:[(0,p.jsx)("strong",{children:e}),t.length>0?(0,p.jsx)("p",{style:{margin:"4px 0 0"},children:t}):null]})}function g({children:e,onClick:t,disabled:n,busy:i}){return(0,p.jsx)("button",{type:"button",onClick:t,disabled:n===!0||i===!0,style:{padding:"4px 10px",fontSize:12,borderRadius:6,border:`1px solid ${oe}`,background:"transparent",color:"inherit",cursor:n===!0||i===!0?"default":"pointer",opacity:n===!0||i===!0?.6:1},children:e})}function V({label:e,checked:t,disabled:n,onChange:i}){return(0,p.jsxs)("label",{style:{display:"flex",alignItems:"center",gap:8,fontSize:13,opacity:n===!0?.6:1,cursor:n===!0?"default":"pointer"},children:[(0,p.jsx)("input",{type:"checkbox",checked:t,disabled:n,onChange:r=>i(r.target.checked)}),(0,p.jsx)("span",{children:e})]})}function Ee({value:e,options:t,disabled:n,onChange:i}){return(0,p.jsx)("select",{value:e,disabled:n,onChange:r=>i(r.target.value),style:{padding:"3px 6px",fontSize:12,borderRadius:6,border:`1px solid ${oe}`,background:"transparent",color:"inherit"},children:t.map(r=>(0,p.jsx)("option",{value:r.value,children:r.label},r.value))})}function re({label:e,description:t,checked:n,disabled:i,onChange:r}){return(0,p.jsxs)("label",{style:{display:"flex",alignItems:"flex-start",gap:8,fontSize:13,opacity:i===!0?.6:1,cursor:i===!0?"default":"pointer"},children:[(0,p.jsx)("input",{type:"radio",checked:n,disabled:i,onChange:()=>r(),style:{marginTop:2}}),(0,p.jsxs)("span",{style:{display:"flex",flexDirection:"column",gap:2},children:[(0,p.jsx)("span",{children:e}),t!==void 0&&t.length>0?(0,p.jsx)("span",{style:{fontSize:12,color:D},children:t}):null]})]})}function $({error:e,title:t}){return e===null?null:(0,p.jsxs)("div",{role:"alert",style:{padding:"8px 10px",borderRadius:6,fontSize:12,lineHeight:1.5,border:`1px solid ${q}`,color:q},children:[(0,p.jsx)("strong",{children:t}),": ",(0,p.jsx)("code",{children:e.code})," \u2014 ",e.message]})}var _=require("react/jsx-runtime");function Ae({t:e,status:t,updateSettings:n}){let i=t.settings.agentTools,r=i.allow??[];return(0,_.jsxs)(k,{title:e("agentTitle"),description:e("agentDesc"),children:[(0,_.jsx)(V,{label:e("agentMaster"),checked:i.enabled,onChange:o=>n(s=>({...s,agentTools:{...s.agentTools,enabled:o}}))}),(0,_.jsx)(d,{children:e("agentApproval")}),(0,_.jsx)("div",{style:{display:"flex",flexDirection:"column",gap:6},children:z.map(o=>(0,_.jsx)(V,{label:ye(o)?e("agentToolMutating",{name:o}):o,checked:r.includes(o),disabled:!i.enabled,onChange:s=>n(u=>({...u,agentTools:{...u.agentTools,allow:ke(u.agentTools.allow??[],o,s)}}))},o))})]})}var ie=require("react");function He(e){return Array.isArray(e)?e.filter(t=>typeof t=="string"):[]}function Be(e){if(typeof e!="object"||e===null)return null;let t=e.result;if(typeof t!="object"||t===null)return null;let{ok:n,detail:i,commands:r}=t;return n!==!1?null:{detail:typeof i=="string"?i:"",commands:He(r)}}function Ne(e){return e===void 0?null:{ok:e.ok===!0,action:e.action==="uninstall"?"uninstall":"install",detail:typeof e.detail=="string"?e.detail:"",commands:He(e.commands)}}async function J(e){try{if(typeof navigator<"u"&&navigator.clipboard!==void 0)return await navigator.clipboard.writeText(e),!0}catch{}return!1}var c=require("react/jsx-runtime"),rt={width:"100%",minHeight:60,marginTop:6,padding:8,borderRadius:6,border:"1px solid var(--dsw-alias-border-secondary, rgba(128, 128, 128, 0.25))",background:"transparent",color:"inherit",fontFamily:"ui-monospace, SFMono-Regular, Menlo, monospace",fontSize:12,resize:"vertical"};function Oe({text:e,copyLabel:t,copiedLabel:n}){let[i,r]=(0,ie.useState)(!1);return(0,c.jsxs)("div",{children:[(0,c.jsx)("textarea",{readOnly:!0,value:e,rows:Math.min(e.split(`
|
|
4
|
+
`).length,6),style:rt}),(0,c.jsx)("div",{style:{display:"flex",gap:8,marginTop:6},children:(0,c.jsx)(g,{onClick:()=>{J(e).then(r)},children:i?n:t})})]})}function _e({t:e,status:t,run:n,updateSettings:i,busy:r}){let o=t.boot,s=t.settings.autostart,u=o.candidates??[],S=o.commands??[],[C,w]=(0,ie.useState)(null),A=r==="boot.install"||r==="boot.uninstall",R=r==="settings"||A,T=["auto",...u.filter(m=>m.available).map(m=>m.mechanism)];T.includes(s.mechanism)||T.push(s.mechanism);let N=T.map(m=>({value:m,label:m==="auto"?e("bootMechanismAuto"):m})),E=m=>e(m==="install"?"bootActionInstall":"bootActionUninstall"),I=async m=>{let M=m?"install":"uninstall",le=Y(t.settings,{...t.settings,autostart:{...s,enabled:m}}),pe=await n(`boot.${M}`,async()=>{if(Object.keys(le).length>0){let de=await G(le);if(!de.ok)return de}return m?b("boot.install",s.mechanism==="auto"?{}:{mechanism:s.mechanism}):b("boot.uninstall",{})});if(!pe.ok){w(null);return}let X=Be(pe.value);w(X===null?null:{ok:!1,action:M,detail:X.detail,commands:X.commands})},F=Ne(s.lastAttempt),P=C??F;return(0,c.jsxs)(k,{title:e("bootTitle"),description:e("bootDesc"),children:[(0,c.jsx)(V,{label:e("bootEnabled"),checked:s.enabled,disabled:A,onChange:m=>{I(m)}}),(0,c.jsx)(l,{label:e("bootMechanism"),children:(0,c.jsx)(Ee,{value:s.mechanism,options:N,disabled:R,onChange:m=>i(M=>({...M,autostart:{...M.autostart,mechanism:m}}))})}),(0,c.jsx)(l,{label:e("bootState"),children:e(xe[o.state]??"bootStateUnsupported")}),(0,c.jsx)(l,{label:e("bootBootCapable"),children:o.bootCapable?e("yes"):e("no")}),(0,c.jsx)(l,{label:e("bootPrivileged"),children:o.privileged?e("yes"):e("no")}),(0,c.jsx)(l,{label:e("bootUnitPath"),children:y(o.unitPath)}),o.bootCapable||o.state==="unsupported"?null:(0,c.jsx)(d,{children:e("bootLoginScope")}),(0,c.jsx)(d,{children:o.detail}),s.enabled&&o.state==="not-installed"?(0,c.jsx)(d,{children:e("bootRequestedNotInstalled")}):null,P!==null&&!P.ok?(0,c.jsxs)("div",{children:[(0,c.jsx)(Te,{title:e("bootAttemptFailed",{action:E(P.action)}),detail:P.detail.length>0?P.detail:e("bootAttemptNoDetail")}),P.commands.length>0?(0,c.jsxs)("div",{children:[(0,c.jsx)(d,{children:e("bootAttemptCommands")}),(0,c.jsx)(Oe,{text:P.commands.join(`
|
|
5
|
+
`),copyLabel:e("copy"),copiedLabel:e("copied")})]}):null]}):null,P!==null&&P.ok?(0,c.jsx)(d,{children:e("bootAttemptSucceeded",{action:E(P.action),detail:P.detail})}):null,S.length>0?(0,c.jsxs)("div",{children:[(0,c.jsx)(d,{children:e("bootCommandsExplain")}),(0,c.jsx)(Oe,{text:S.join(`
|
|
6
|
+
`),copyLabel:e("copy"),copiedLabel:e("copied")})]}):null,(0,c.jsx)("div",{children:(0,c.jsx)(g,{busy:r==="boot.verify",onClick:()=>n("boot.verify",()=>b("boot.verify",{})),children:e("bootRecheck")})})]})}var x=require("react/jsx-runtime"),it={display:"flex",flexDirection:"column",gap:6,padding:10,borderRadius:6,border:"1px solid var(--dsw-alias-border-secondary, rgba(128, 128, 128, 0.25))"},st={display:"flex",alignItems:"baseline",justifyContent:"space-between",gap:12,fontSize:13},at={display:"flex",flexWrap:"wrap",gap:8};function Ie({t:e,status:t,run:n,busy:i}){let r=t.entries??[];return(0,x.jsx)(k,{title:e("entriesTitle"),description:e("entriesDesc"),children:r.length===0?(0,x.jsx)(d,{children:e("entriesEmpty")}):r.map(o=>{let s=o.intent.id,u=o.live;return(0,x.jsxs)("div",{style:it,children:[(0,x.jsxs)("div",{style:st,children:[(0,x.jsx)("strong",{children:s}),(0,x.jsxs)("span",{style:{color:"var(--dsw-alias-label-secondary, #8b8b8b)"},children:[o.exists?e("entriesExists"):e("entriesMissing")," \xB7 ",o.managed?e("entriesManaged"):e("entriesUnmanaged")]})]}),(0,x.jsx)(l,{label:e("entriesDrift"),children:ve(o.drift)}),(0,x.jsx)(l,{label:e("entriesLive"),children:u===null?e("entriesNotRunning"):`${y(u.status)}${u.pid===null?"":` \xB7 pid ${u.pid}`}`}),(0,x.jsx)(l,{label:e("entriesAutostart"),children:o.intent.autostart?e("yes"):e("no")}),(0,x.jsx)(l,{label:e("entriesOnPortConflict"),children:o.intent.onPortConflict}),(0,x.jsx)(l,{label:e("entriesStopKillPortHolders"),children:o.intent.stopKillPortHolders?e("yes"):e("no")}),(0,x.jsxs)("div",{style:at,children:[(0,x.jsx)(g,{busy:i===`entries.adopt:${s}`,onClick:()=>n(`entries.adopt:${s}`,()=>b("entries.apply",{intents:[o.intent]})),children:e("entriesAdopt")}),(0,x.jsx)(g,{busy:i===`entries.pause:${s}`,onClick:()=>n(`entries.pause:${s}`,()=>b("entries.apply",{intents:[{...o.intent,autostart:!1}]})),children:e("entriesPause")}),(0,x.jsx)(g,{busy:i===`entries.restore:${s}`,disabled:!o.managed,onClick:()=>n(`entries.restore:${s}`,()=>b("entries.restore",{id:s})),children:e("entriesRestore")})]})]},s)})})}var Le=require("react");var a=require("react/jsx-runtime"),lt={display:"flex",flexDirection:"column",gap:8,padding:10,borderRadius:6,border:"1px solid var(--dsw-alias-state-error-primary, #e53e3e)"},se={display:"flex",flexWrap:"wrap",gap:8};function Me({t:e,status:t,run:n,busy:i}){let r=t.panel,o=t.cli,s=o?.prefer??t.settings.cli?.prefer??"pinned",[u,S]=(0,Le.useState)(!1),C=o?.version??null,w=r.version,A=C!==null&&w!==null,R=r.reachable&&A&&C===w,T=r.reachable&&A&&C!==w;return(0,a.jsxs)(k,{title:e("panelTitle"),description:e("panelDesc"),children:[(0,a.jsx)(l,{label:e("panelReachable"),children:r.reachable?e("yes"):e("no")}),(0,a.jsx)(l,{label:e("panelHome"),children:y(r.home)}),(0,a.jsx)(l,{label:e("panelUrl"),children:r.url===null?y(r.url):(0,a.jsx)(U,{href:r.url,children:r.url})}),(0,a.jsx)(l,{label:e("panelVersion"),children:y(r.version)}),(0,a.jsx)(l,{label:e("panelPid"),children:y(r.pid)}),(0,a.jsx)(l,{label:e("panelWriteVia"),children:e(Se[r.writeVia]??"writeViaNone")}),(0,a.jsx)(l,{label:e("panelToken"),children:e(Ce[r.token]??"tokenUnknown")}),o!==void 0&&(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(l,{label:e("panelCliSource"),children:`${e(W[o.source]??"panelCliMissing")} \xB7 ${y(o.version)}`}),(0,a.jsx)(l,{label:e("panelCliPath"),children:y(o.path)}),o.source==="path"&&s!=="global"&&(0,a.jsx)(d,{children:e("panelCliNotPinned",{range:o.expectedRange})}),o.launcherPath!=null&&o.launcherVersion==null&&(0,a.jsx)(d,{children:e("panelCliLauncherFailed")})]}),(0,a.jsx)(d,{children:r.detail}),r.reachable?null:(0,a.jsx)("div",{style:se,children:(0,a.jsx)(g,{busy:i==="panel.start",onClick:()=>{n("panel.start",()=>b("panel.start",{}))},children:e("panelStart")})}),R?(0,a.jsx)(d,{children:e("panelAlreadyPreferred")}):null,T?u?(0,a.jsxs)("div",{style:lt,role:"alertdialog","aria-label":e("panelTakeoverTitle"),children:[(0,a.jsx)("strong",{children:e("panelTakeoverTitle")}),(0,a.jsx)(d,{children:e("panelTakeoverBody")}),(0,a.jsxs)("div",{style:se,children:[(0,a.jsx)(g,{onClick:()=>S(!1),children:e("confirmCancel")}),(0,a.jsx)(g,{busy:i==="panel.takeover",onClick:()=>{S(!1),n("panel.takeover",()=>b("panel.takeover",{}))},children:e("confirmReplace")})]})]}):(0,a.jsx)("div",{style:se,children:(0,a.jsx)(g,{onClick:()=>S(!0),children:e("panelReplace",{version:C})})}):null]})}var ae=require("react");var f=require("react/jsx-runtime"),pt={display:"flex",flexDirection:"column",gap:6,padding:10,borderRadius:6,border:"1px solid var(--dsw-alias-border-secondary, rgba(128, 128, 128, 0.25))"},dt={width:"100%",minHeight:48,padding:8,borderRadius:6,border:"1px solid var(--dsw-alias-border-secondary, rgba(128, 128, 128, 0.25))",background:"transparent",color:"inherit",fontFamily:"ui-monospace, SFMono-Regular, Menlo, monospace",fontSize:12,resize:"vertical"},ct={display:"flex",flexWrap:"wrap",gap:8},ut={maxHeight:180,margin:"6px 0 0",padding:8,overflow:"auto",borderRadius:6,border:"1px solid var(--dsw-alias-border-secondary, rgba(128, 128, 128, 0.25))",fontFamily:"ui-monospace, SFMono-Regular, Menlo, monospace",fontSize:12,whiteSpace:"pre-wrap"};function De({t:e,status:t,run:n,updateSettings:i,busy:r}){let o=t.cli,[s,u]=(0,ae.useState)(!1),[S,C]=(0,ae.useState)(null);if(o===void 0)return(0,f.jsx)(k,{title:e("optionsTitle"),description:e("optionsDesc"),children:(0,f.jsx)(d,{children:e("optionsCliUnavailable")})});let w=o.prefer??t.settings.cli?.prefer??"pinned",{dependency:A,global:R}=Pe(o),T=[`pnpm add -g home-hosted@${o.expectedRange}`,`npm install -g home-hosted@${o.expectedRange}`],N=r==="settings",E=async()=>{u(await J(T.join(`
|
|
7
|
+
`)))},I=async()=>{let P=await n("cli.installGlobal",()=>b("cli.installGlobal",{}));if(!P.ok)return;let m=P.value;C(typeof m?.output=="string"?m.output:null)},F=P=>{i(m=>({...m,cli:{...m.cli,prefer:P}}))};return(0,f.jsxs)(k,{title:e("optionsTitle"),description:e("optionsDesc"),children:[(0,f.jsx)(l,{label:e("optionsCurrent"),children:e(W[o.source]??"cliSourceNone")}),(0,f.jsx)(l,{label:e("optionsVersion"),children:y(o.version)}),(0,f.jsx)(l,{label:e("optionsPath"),children:y(o.path)}),(0,f.jsx)(d,{children:o.detail}),o.source==="config"?(0,f.jsx)(d,{children:e("optionsConfigOverride")}):null,(0,f.jsxs)("div",{style:{display:"flex",flexDirection:"column",gap:8},children:[(0,f.jsx)(re,{label:e("optionsPreferPinned"),description:A===null?e("optionsNotResolved"):ne(A),checked:w==="pinned",disabled:A===null||N,onChange:()=>F("pinned")}),(0,f.jsx)(re,{label:e("optionsPreferGlobal"),description:R===null?e("optionsNotResolved"):ne(R),checked:w==="global",disabled:R===null||N,onChange:()=>F("global")})]}),(0,f.jsx)(d,{children:e("optionsPreferHint")}),R===null?(0,f.jsxs)("div",{style:pt,children:[(0,f.jsx)(d,{children:e("optionsInstallHint")}),(0,f.jsx)("textarea",{readOnly:!0,value:T.join(`
|
|
8
|
+
`),rows:2,style:dt}),(0,f.jsxs)("div",{style:ct,children:[(0,f.jsx)(g,{onClick:()=>{E()},children:e(s?"copied":"copy")}),(0,f.jsx)(g,{busy:r==="cli.installGlobal",onClick:()=>{I()},children:e("optionsInstall")}),(0,f.jsx)(g,{busy:r==="status.refresh",onClick:()=>{n("status.refresh",()=>b("status",{refresh:!0}))},children:e("refresh")})]}),S===null?null:(0,f.jsxs)("details",{children:[(0,f.jsx)("summary",{style:{fontSize:12,cursor:"pointer"},children:e("optionsOutput")}),(0,f.jsx)("pre",{style:ut,children:S})]})]}):null]})}var h=require("react/jsx-runtime"),gt={display:"flex",flexDirection:"column",gap:6,padding:10,borderRadius:6,border:"1px solid var(--dsw-alias-border-secondary, rgba(128, 128, 128, 0.25))"},ft={display:"flex",alignItems:"baseline",justifyContent:"space-between",gap:12,fontSize:13},Ue={display:"flex",flexWrap:"wrap",gap:8};function Ve({t:e,status:t,run:n,busy:i}){let r=t.servers??[];return(0,h.jsxs)(k,{title:e("serversTitle"),description:e("serversDesc"),children:[(0,h.jsx)("div",{style:Ue,children:(0,h.jsx)(g,{busy:i==="status.refresh",onClick:()=>n("status.refresh",()=>b("status",{refresh:!0})),children:e("refresh")})}),(0,h.jsx)(d,{children:t.panel.url===null?e("serversHintNoPanel"):(0,h.jsxs)(h.Fragment,{children:[`${e("serversHintPanel")} `,(0,h.jsx)(U,{href:t.panel.url,children:t.panel.url})]})}),r.length===0?(0,h.jsx)(d,{children:e("serversEmpty")}):r.map(o=>(0,h.jsxs)("div",{style:gt,children:[(0,h.jsxs)("div",{style:ft,children:[(0,h.jsx)("strong",{children:o.id}),(0,h.jsx)("span",{children:y(o.status)})]}),(0,h.jsx)(l,{label:e("serversPid"),children:y(o.pid)}),(0,h.jsx)(l,{label:e("serversUrl"),children:o.url===null?y(o.url):(0,h.jsx)(U,{href:o.url,children:o.url})}),(0,h.jsxs)("div",{style:Ue,children:[(0,h.jsx)(g,{busy:i===`servers.start:${o.id}`,onClick:()=>n(`servers.start:${o.id}`,()=>b("servers.start",{id:o.id})),children:e("serversStart")}),(0,h.jsx)(g,{busy:i===`servers.stop:${o.id}`,onClick:()=>n(`servers.stop:${o.id}`,()=>b("servers.stop",{id:o.id})),children:e("serversStop")}),(0,h.jsx)(g,{busy:i===`servers.restart:${o.id}`,onClick:()=>n(`servers.restart:${o.id}`,()=>b("servers.restart",{id:o.id})),children:e("serversRestart")})]})]},o.id))]})}var v=require("react/jsx-runtime");function $e(e){let t=fe(e.t),{data:n,error:i,loading:r,refresh:o}=he(),[s,u]=(0,L.useState)(null),[S,C]=(0,L.useState)(null),w=(0,L.useCallback)((T,N)=>(C(T),u(null),(async()=>{try{let E=await N();return E.ok||u(E.error),E}catch(E){let I={code:"client",message:E instanceof Error?E.message:String(E)};return u(I),{ok:!1,error:I}}finally{C(null),await o()}})()),[o]),A=(0,L.useCallback)(T=>{if(n===null)return;let N=Y(n.settings,T(n.settings));Object.keys(N).length!==0&&w("settings",()=>G(N))},[n,w]);if(n===null)return(0,v.jsxs)("div",{style:{display:"flex",flexDirection:"column",gap:8},children:[r?(0,v.jsx)(d,{children:t("loading")}):(0,v.jsx)($,{error:i??{code:"status",message:t("statusUnavailable")},title:t("errorTitle")}),r?null:(0,v.jsx)("div",{children:(0,v.jsx)(g,{onClick:()=>{o()},children:t("retry")})})]});let R={t,status:n,run:w,updateSettings:A,busy:S};return(0,v.jsxs)("div",{style:{display:"flex",flexDirection:"column"},children:[(0,v.jsxs)("header",{style:{display:"flex",alignItems:"flex-start",justifyContent:"space-between",gap:12},children:[(0,v.jsxs)("div",{children:[(0,v.jsx)("h2",{style:{margin:0,fontSize:16},children:t("tab")}),(0,v.jsx)("p",{style:{margin:"2px 0 0",fontSize:12,color:"var(--dsw-alias-label-secondary, #8b8b8b)"},children:t("pageDesc")})]}),(0,v.jsx)(g,{busy:S==="status.refresh",onClick:()=>w("status.refresh",()=>b("status",{refresh:!0})),children:t("refresh")})]}),n.lastError===null?null:(0,v.jsx)($,{error:{code:"panel",message:n.lastError},title:t("errorTitle")}),(0,v.jsx)($,{error:i,title:t("errorTitle")}),(0,v.jsx)($,{error:s,title:t("errorTitle")}),(0,v.jsx)(Me,{...R}),(0,v.jsx)(De,{...R}),(0,v.jsx)(_e,{...R}),(0,v.jsx)(Ie,{...R}),(0,v.jsx)(Ae,{...R}),(0,v.jsx)(Ve,{...R})]})}var mt=["slots","locale"],Fe="[dsh-home-hosted]";function O(e,t){t===void 0?console.warn(`${Fe} ${e}`):console.warn(`${Fe} ${e}`,t)}function je(e,t){try{let n=e.get?.(t);if(n!=null)return n}catch{}try{let n=e[t];if(n!=null)return n}catch{}}function ze(e,t,n){if(typeof e.effect=="function")try{e.effect(t,n);return}catch(i){O(`registering the effect "${n}" failed`,i);return}try{t()}catch(i){O(`the effect "${n}" failed`,i)}}function bt(e){try{let t=je(e,"locale"),n=ge(t);t===void 0?O("the locale service is unavailable; the page keeps its bundled English copy"):ze(e,()=>{let r=[];try{r.push(t.register(j,{en:Q,zh:ce}))}catch(o){O("registering the dictionaries failed",o)}return()=>{for(let o of r)try{o()}catch(s){O("disposing a dictionary failed",s)}}},"dsh-home-hosted: dictionaries");let i=je(e,"slots");if(i===void 0){O("the slots service is unavailable; the settings section was not registered");return}ze(e,()=>{try{return i.inject("settings.section",()=>{try{return i.register({name:"settings.section",id:"home-hosted",order:60,label:()=>n("tab"),locale:j,inject:()=>({t:n})},$e)}catch(r){return O("registering the settings section failed",r),()=>{}}})}catch(r){return O("injecting into settings.section failed",r),()=>{}}},"dsh-home-hosted: settings section")}catch(t){O("client bootstrap failed",t)}}
|
|
8
9
|
|
|
9
10
|
return module.exports; } });
|
package/lib/index.js
CHANGED
|
@@ -199,6 +199,16 @@ function currentUser(ctx) {
|
|
|
199
199
|
return null;
|
|
200
200
|
}
|
|
201
201
|
}
|
|
202
|
+
function userNameOf(ctx) {
|
|
203
|
+
const configured = ctx.env.USER?.trim() ?? ctx.env.USERNAME?.trim();
|
|
204
|
+
if (configured !== void 0 && configured.length > 0)
|
|
205
|
+
return configured;
|
|
206
|
+
try {
|
|
207
|
+
return os.userInfo().username;
|
|
208
|
+
} catch {
|
|
209
|
+
return null;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
202
212
|
function uidOf(ctx) {
|
|
203
213
|
const configured = ctx.env.UID?.trim();
|
|
204
214
|
if (configured)
|
|
@@ -868,9 +878,10 @@ function validate2(spec) {
|
|
|
868
878
|
function launchdLabel(spec) {
|
|
869
879
|
return `${LAUNCHD_LABEL_PREFIX}${assertUnitName(spec.unitName)}`;
|
|
870
880
|
}
|
|
871
|
-
function launchdPlist(spec) {
|
|
881
|
+
function launchdPlist(spec, options = {}) {
|
|
872
882
|
validate2(spec);
|
|
873
883
|
const label = launchdLabel(spec);
|
|
884
|
+
const userName = options.userName?.trim();
|
|
874
885
|
const out = path3.posix.join(spec.logDir, `${label}.out.log`);
|
|
875
886
|
const err = path3.posix.join(spec.logDir, `${label}.err.log`);
|
|
876
887
|
const envKeys = Object.keys(spec.env);
|
|
@@ -881,6 +892,7 @@ function launchdPlist(spec) {
|
|
|
881
892
|
"<dict>",
|
|
882
893
|
" <key>Label</key>",
|
|
883
894
|
` <string>${xmlEscape(label)}</string>`,
|
|
895
|
+
...userName === void 0 || userName.length === 0 ? [] : [" <key>UserName</key>", ` <string>${xmlEscape(userName)}</string>`],
|
|
884
896
|
" <key>ProgramArguments</key>",
|
|
885
897
|
" <array>",
|
|
886
898
|
...[spec.command, ...spec.args].map((arg) => ` <string>${xmlEscape(arg)}</string>`),
|
|
@@ -962,19 +974,25 @@ function createLaunchdProvider(ctx, mode) {
|
|
|
962
974
|
const domain = await domainOf();
|
|
963
975
|
return {
|
|
964
976
|
mechanism,
|
|
965
|
-
|
|
977
|
+
// A plist in ~/Library/LaunchAgents is loaded at login whether or not
|
|
978
|
+
// this process can reach launchd right now, so an unreachable domain
|
|
979
|
+
// is a diagnostic, not a reason to refuse.
|
|
980
|
+
available: true,
|
|
966
981
|
bootCapable: false,
|
|
967
982
|
privileged: true,
|
|
968
|
-
reason: domain === null ? `
|
|
983
|
+
reason: domain === null ? `a LaunchAgent loads at login; launchd's domain is not reachable from this process for uid ${uidOf(ctx) ?? "?"} right now, so it is loaded at the next login` : `launchd ${domain} domain is reachable; a LaunchAgent loads at login, not at boot`
|
|
969
984
|
};
|
|
970
985
|
}
|
|
971
986
|
const canElevate = ctx.isRoot || await ctx.sudo();
|
|
972
987
|
return {
|
|
973
988
|
mechanism,
|
|
974
|
-
|
|
975
|
-
|
|
989
|
+
// Always selectable: without root the plugin stages the plist and hands
|
|
990
|
+
// over the three sudo commands, which is the only way to start before
|
|
991
|
+
// login on a Mac that has no passwordless sudo.
|
|
992
|
+
available: true,
|
|
993
|
+
bootCapable: true,
|
|
976
994
|
privileged: canElevate,
|
|
977
|
-
reason: canElevate ? "this process can write /Library/LaunchDaemons, so a LaunchDaemon starts at boot" : "a LaunchDaemon needs root
|
|
995
|
+
reason: canElevate ? "this process can write /Library/LaunchDaemons, so a LaunchDaemon starts at boot" : "a LaunchDaemon starts at boot but needs root here, so the plugin stages the plist and shows the sudo commands"
|
|
978
996
|
};
|
|
979
997
|
},
|
|
980
998
|
async status(spec) {
|
|
@@ -1007,7 +1025,7 @@ function createLaunchdProvider(ctx, mode) {
|
|
|
1007
1025
|
validate2(spec);
|
|
1008
1026
|
const file = pathOf(spec);
|
|
1009
1027
|
const label = launchdLabel(spec);
|
|
1010
|
-
const content = launchdPlist(spec);
|
|
1028
|
+
const content = launchdPlist(spec, mode === "daemon" ? { userName: userNameOf(ctx) } : {});
|
|
1011
1029
|
const own = inspectOwned(file, spec.marker);
|
|
1012
1030
|
if (own.exists && !own.owned)
|
|
1013
1031
|
return failed(own.reason ?? "foreign file");
|
|
@@ -1025,11 +1043,9 @@ function createLaunchdProvider(ctx, mode) {
|
|
|
1025
1043
|
});
|
|
1026
1044
|
}
|
|
1027
1045
|
const domain = await domainOf();
|
|
1028
|
-
if (domain === null)
|
|
1029
|
-
return failed(`launchd has no reachable domain for uid ${uidOf(ctx) ?? "?"}; refusing to write an agent that could never load`);
|
|
1030
1046
|
ensureDirQuiet(path3.posix.dirname(file));
|
|
1031
1047
|
ensureDirQuiet(spec.logDir);
|
|
1032
|
-
const loaded = codeOf2(await ctx.run("launchctl", ["print", `${domain}/${label}`])) === 0;
|
|
1048
|
+
const loaded = domain !== null && codeOf2(await ctx.run("launchctl", ["print", `${domain}/${label}`])) === 0;
|
|
1033
1049
|
const before = { text: own.text, exists: own.exists };
|
|
1034
1050
|
let changed = false;
|
|
1035
1051
|
if (mode === "agent" || ctx.isRoot) {
|
|
@@ -1054,6 +1070,15 @@ function createLaunchdProvider(ctx, mode) {
|
|
|
1054
1070
|
const lint = await runPrivileged("plutil", ["-lint", file]);
|
|
1055
1071
|
if (codeOf2(lint) !== 0)
|
|
1056
1072
|
return failed(`plutil -lint rejected the generated plist: ${(lint.stderr || lint.stdout).trim() || "no output"}`, { changed, commands: commands(file, label) });
|
|
1073
|
+
if (domain === null) {
|
|
1074
|
+
return {
|
|
1075
|
+
ok: true,
|
|
1076
|
+
changed,
|
|
1077
|
+
detail: `${file} is in place; launchd's domain is not reachable from this process, so it loads at the next login`,
|
|
1078
|
+
commands: [],
|
|
1079
|
+
needsPrivilege: false
|
|
1080
|
+
};
|
|
1081
|
+
}
|
|
1057
1082
|
if (loaded && changed) {
|
|
1058
1083
|
const bootout = await runPrivileged("launchctl", ["bootout", `${domain}/${label}`]);
|
|
1059
1084
|
const bootoutCode = codeOf2(bootout);
|
|
@@ -1806,11 +1831,18 @@ function createBootLadder(options = {}) {
|
|
|
1806
1831
|
function recommend(candidates) {
|
|
1807
1832
|
const byMechanism = new Map(candidates.map((candidate) => [candidate.mechanism, candidate]));
|
|
1808
1833
|
const available = providers.map((provider) => provider.mechanism).filter((mechanism) => byMechanism.get(mechanism)?.available === true);
|
|
1809
|
-
const
|
|
1810
|
-
if (bootCapable)
|
|
1811
|
-
return bootCapable;
|
|
1834
|
+
const usable = (mechanism) => mechanism !== "container" && mechanism !== "unsupported";
|
|
1812
1835
|
if (available.includes("container"))
|
|
1813
1836
|
return "container";
|
|
1837
|
+
const readyBoot = available.find((mechanism) => usable(mechanism) && byMechanism.get(mechanism)?.bootCapable === true && byMechanism.get(mechanism)?.privileged === true);
|
|
1838
|
+
if (readyBoot)
|
|
1839
|
+
return readyBoot;
|
|
1840
|
+
const ready = available.find((mechanism) => usable(mechanism) && byMechanism.get(mechanism)?.privileged === true);
|
|
1841
|
+
if (ready)
|
|
1842
|
+
return ready;
|
|
1843
|
+
const bootCapable = available.find((mechanism) => usable(mechanism) && byMechanism.get(mechanism)?.bootCapable === true);
|
|
1844
|
+
if (bootCapable)
|
|
1845
|
+
return bootCapable;
|
|
1814
1846
|
return available.find((mechanism) => mechanism !== "unsupported") ?? available[0] ?? null;
|
|
1815
1847
|
}
|
|
1816
1848
|
async function buildStatus(spec, mechanism) {
|
|
@@ -3208,14 +3240,23 @@ var HomeHostedService = class extends Service {
|
|
|
3208
3240
|
if (spec === null)
|
|
3209
3241
|
throw new HomeHostedError((await this.cli()).resolution.status.detail, "CLI_NOT_FOUND");
|
|
3210
3242
|
const result = await this.ladder().install(spec, mechanism);
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3243
|
+
const current = this.options.settings.get().autostart;
|
|
3244
|
+
this.options.settings.update({
|
|
3245
|
+
autostart: {
|
|
3246
|
+
// The preference follows the outcome for a real install, and the last
|
|
3247
|
+
// attempt is recorded either way so a failure is visible after a reload.
|
|
3248
|
+
enabled: result.ok ? true : current.enabled,
|
|
3249
|
+
mechanism: result.ok ? mechanism ?? result.mechanism ?? current.mechanism : current.mechanism,
|
|
3250
|
+
lastAttempt: {
|
|
3251
|
+
ok: result.ok,
|
|
3252
|
+
action: "install",
|
|
3253
|
+
mechanism: result.mechanism ?? mechanism ?? null,
|
|
3254
|
+
detail: result.detail,
|
|
3255
|
+
commands: result.commands,
|
|
3256
|
+
at: Date.now()
|
|
3216
3257
|
}
|
|
3217
|
-
}
|
|
3218
|
-
}
|
|
3258
|
+
}
|
|
3259
|
+
});
|
|
3219
3260
|
return { result, status: await this.bootStatus(mechanism) };
|
|
3220
3261
|
}
|
|
3221
3262
|
async uninstallBoot(mechanism) {
|
|
@@ -3223,8 +3264,21 @@ var HomeHostedService = class extends Service {
|
|
|
3223
3264
|
if (spec === null)
|
|
3224
3265
|
throw new HomeHostedError((await this.cli()).resolution.status.detail, "CLI_NOT_FOUND");
|
|
3225
3266
|
const result = await this.ladder().uninstall(spec, mechanism);
|
|
3226
|
-
|
|
3227
|
-
|
|
3267
|
+
const current = this.options.settings.get().autostart;
|
|
3268
|
+
this.options.settings.update({
|
|
3269
|
+
autostart: {
|
|
3270
|
+
...current,
|
|
3271
|
+
enabled: result.ok ? false : current.enabled,
|
|
3272
|
+
lastAttempt: {
|
|
3273
|
+
ok: result.ok,
|
|
3274
|
+
action: "uninstall",
|
|
3275
|
+
mechanism: result.mechanism ?? mechanism ?? null,
|
|
3276
|
+
detail: result.detail,
|
|
3277
|
+
commands: result.commands,
|
|
3278
|
+
at: Date.now()
|
|
3279
|
+
}
|
|
3280
|
+
}
|
|
3281
|
+
});
|
|
3228
3282
|
return { result, status: await this.bootStatus(mechanism) };
|
|
3229
3283
|
}
|
|
3230
3284
|
// -------------------------------------------------------------------------
|
|
@@ -3482,10 +3536,12 @@ function normalizeIntent(value, fallbackId) {
|
|
|
3482
3536
|
function normalize(raw, fallbackEntryId) {
|
|
3483
3537
|
const entries = Array.isArray(raw?.entries) ? raw.entries.map((intent) => normalizeIntent(intent, fallbackEntryId)) : [];
|
|
3484
3538
|
const allow = Array.isArray(raw?.agentTools?.allow) ? raw.agentTools.allow.filter(knownTool) : DEFAULT_SETTINGS.agentTools.allow;
|
|
3539
|
+
const attempt = raw?.autostart?.lastAttempt;
|
|
3485
3540
|
return {
|
|
3486
3541
|
autostart: {
|
|
3487
3542
|
enabled: raw?.autostart?.enabled === true,
|
|
3488
|
-
mechanism: raw?.autostart?.mechanism ?? "auto"
|
|
3543
|
+
mechanism: raw?.autostart?.mechanism ?? "auto",
|
|
3544
|
+
...attempt === void 0 ? {} : { lastAttempt: attempt }
|
|
3489
3545
|
},
|
|
3490
3546
|
entries,
|
|
3491
3547
|
agentTools: {
|