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 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) scope needs privilege somewhere — a system unit, or `loginctl enable-linger` on Linux. When the process cannot elevate, the page shows the exact commands to run by hand.
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,y.jsxs)(T,{title:e("bootTitle"),description:e("bootDesc"),children:[(0,y.jsx)(M,{label:e("bootEnabled"),checked:i.enabled,disabled:w,onChange:m=>s(H=>({...H,autostart:{...H.autostart,enabled:m}}))}),(0,y.jsx)(a,{label:e("bootMechanism"),children:(0,y.jsx)(Se,{value:i.mechanism,options:E,disabled:w,onChange:m=>s(H=>({...H,autostart:{...H.autostart,mechanism:m}}))})}),(0,y.jsx)(a,{label:e("bootState"),children:e(ge[o.state]??"bootStateUnsupported")}),(0,y.jsx)(a,{label:e("bootBootCapable"),children:o.bootCapable?e("yes"):e("no")}),(0,y.jsx)(a,{label:e("bootPrivileged"),children:o.privileged?e("yes"):e("no")}),(0,y.jsx)(a,{label:e("bootUnitPath"),children:b(o.unitPath)}),(0,y.jsx)(c,{children:o.detail}),v.length>0?(0,y.jsxs)("div",{children:[(0,y.jsx)(c,{children:e("bootCommandsExplain")}),(0,y.jsx)("textarea",{readOnly:!0,value:v.join(`
5
- `),rows:Math.min(v.length,6),style:We}),(0,y.jsx)("div",{style:{display:"flex",gap:8,marginTop:6},children:(0,y.jsx)(u,{onClick:()=>{_()},children:e(S?"copied":"copy")})})]}):null,(0,y.jsx)("div",{children:(0,y.jsx)(u,{busy:r==="boot.verify",onClick:()=>n("boot.verify",()=>h("boot.verify",{})),children:e("bootRecheck")})})]})}var P=require("react/jsx-runtime"),Ye={display:"flex",flexDirection:"column",gap:6,padding:10,borderRadius:6,border:"1px solid var(--dsw-alias-border-secondary, rgba(128, 128, 128, 0.25))"},qe={display:"flex",alignItems:"baseline",justifyContent:"space-between",gap:12,fontSize:13},Je={display:"flex",flexWrap:"wrap",gap:8};function xe({t:e,status:t,run:n,busy:s}){let r=t.entries??[];return(0,P.jsx)(T,{title:e("entriesTitle"),description:e("entriesDesc"),children:r.length===0?(0,P.jsx)(c,{children:e("entriesEmpty")}):r.map(o=>{let i=o.intent.id,p=o.live;return(0,P.jsxs)("div",{style:Ye,children:[(0,P.jsxs)("div",{style:qe,children:[(0,P.jsx)("strong",{children:i}),(0,P.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,P.jsx)(a,{label:e("entriesDrift"),children:pe(o.drift)}),(0,P.jsx)(a,{label:e("entriesLive"),children:p===null?e("entriesNotRunning"):`${b(p.status)}${p.pid===null?"":` \xB7 pid ${p.pid}`}`}),(0,P.jsx)(a,{label:e("entriesAutostart"),children:o.intent.autostart?e("yes"):e("no")}),(0,P.jsx)(a,{label:e("entriesOnPortConflict"),children:o.intent.onPortConflict}),(0,P.jsx)(a,{label:e("entriesStopKillPortHolders"),children:o.intent.stopKillPortHolders?e("yes"):e("no")}),(0,P.jsxs)("div",{style:Je,children:[(0,P.jsx)(u,{busy:s===`entries.adopt:${i}`,onClick:()=>n(`entries.adopt:${i}`,()=>h("entries.apply",{intents:[o.intent]})),children:e("entriesAdopt")}),(0,P.jsx)(u,{busy:s===`entries.pause:${i}`,onClick:()=>n(`entries.pause:${i}`,()=>h("entries.apply",{intents:[{...o.intent,autostart:!1}]})),children:e("entriesPause")}),(0,P.jsx)(u,{busy:s===`entries.restore:${i}`,disabled:!o.managed,onClick:()=>n(`entries.restore:${i}`,()=>h("entries.restore",{id:i})),children:e("entriesRestore")})]})]},i)})})}var Te=require("react");var l=require("react/jsx-runtime"),Xe={display:"flex",flexDirection:"column",gap:8,padding:10,borderRadius:6,border:"1px solid var(--dsw-alias-state-error-primary, #e53e3e)"},Z={display:"flex",flexWrap:"wrap",gap:8};function we({t:e,status:t,run:n,busy:s}){let r=t.panel,o=t.cli,i=o?.prefer??t.settings.cli?.prefer??"pinned",[p,v]=(0,Te.useState)(!1),S=o?.version??null,x=r.version,w=S!==null&&x!==null,C=r.reachable&&w&&S===x,E=r.reachable&&w&&S!==x;return(0,l.jsxs)(T,{title:e("panelTitle"),description:e("panelDesc"),children:[(0,l.jsx)(a,{label:e("panelReachable"),children:r.reachable?e("yes"):e("no")}),(0,l.jsx)(a,{label:e("panelHome"),children:b(r.home)}),(0,l.jsx)(a,{label:e("panelUrl"),children:b(r.url)}),(0,l.jsx)(a,{label:e("panelVersion"),children:b(r.version)}),(0,l.jsx)(a,{label:e("panelPid"),children:b(r.pid)}),(0,l.jsx)(a,{label:e("panelWriteVia"),children:e(ce[r.writeVia]??"writeViaNone")}),(0,l.jsx)(a,{label:e("panelToken"),children:e(ue[r.token]??"tokenUnknown")}),o!==void 0&&(0,l.jsxs)(l.Fragment,{children:[(0,l.jsx)(a,{label:e("panelCliSource"),children:`${e(j[o.source]??"panelCliMissing")} \xB7 ${b(o.version)}`}),(0,l.jsx)(a,{label:e("panelCliPath"),children:b(o.path)}),o.source==="path"&&i!=="global"&&(0,l.jsx)(c,{children:e("panelCliNotPinned",{range:o.expectedRange})}),o.launcherPath!=null&&o.launcherVersion==null&&(0,l.jsx)(c,{children:e("panelCliLauncherFailed")})]}),(0,l.jsx)(c,{children:r.detail}),r.reachable?null:(0,l.jsx)("div",{style:Z,children:(0,l.jsx)(u,{busy:s==="panel.start",onClick:()=>{n("panel.start",()=>h("panel.start",{}))},children:e("panelStart")})}),C?(0,l.jsx)(c,{children:e("panelAlreadyPreferred")}):null,E?p?(0,l.jsxs)("div",{style:Xe,role:"alertdialog","aria-label":e("panelTakeoverTitle"),children:[(0,l.jsx)("strong",{children:e("panelTakeoverTitle")}),(0,l.jsx)(c,{children:e("panelTakeoverBody")}),(0,l.jsxs)("div",{style:Z,children:[(0,l.jsx)(u,{onClick:()=>v(!1),children:e("confirmCancel")}),(0,l.jsx)(u,{busy:s==="panel.takeover",onClick:()=>{v(!1),n("panel.takeover",()=>h("panel.takeover",{}))},children:e("confirmReplace")})]})]}):(0,l.jsx)("div",{style:Z,children:(0,l.jsx)(u,{onClick:()=>v(!0),children:e("panelReplace",{version:S})})}):null]})}var Q=require("react");var g=require("react/jsx-runtime"),Ze={display:"flex",flexDirection:"column",gap:6,padding:10,borderRadius:6,border:"1px solid var(--dsw-alias-border-secondary, rgba(128, 128, 128, 0.25))"},Qe={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"},et={display:"flex",flexWrap:"wrap",gap:8},tt={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 ke({t:e,status:t,run:n,updateSettings:s,busy:r}){let o=t.cli,[i,p]=(0,Q.useState)(!1),[v,S]=(0,Q.useState)(null);if(o===void 0)return(0,g.jsx)(T,{title:e("optionsTitle"),description:e("optionsDesc"),children:(0,g.jsx)(c,{children:e("optionsCliUnavailable")})});let x=o.prefer??t.settings.cli?.prefer??"pinned",{dependency:w,global:C}=fe(o),E=[`pnpm add -g home-hosted@${o.expectedRange}`,`npm install -g home-hosted@${o.expectedRange}`],_=r==="settings",m=async()=>{p(await z(E.join(`
6
- `)))},H=async()=>{let U=await n("cli.installGlobal",()=>h("cli.installGlobal",{}));if(!U.ok)return;let I=U.value;S(typeof I?.output=="string"?I.output:null)},ee=U=>{s(I=>({...I,cli:{...I.cli,prefer:U}}))};return(0,g.jsxs)(T,{title:e("optionsTitle"),description:e("optionsDesc"),children:[(0,g.jsx)(a,{label:e("optionsCurrent"),children:e(j[o.source]??"cliSourceNone")}),(0,g.jsx)(a,{label:e("optionsVersion"),children:b(o.version)}),(0,g.jsx)(a,{label:e("optionsPath"),children:b(o.path)}),(0,g.jsx)(c,{children:o.detail}),o.source==="config"?(0,g.jsx)(c,{children:e("optionsConfigOverride")}):null,(0,g.jsxs)("div",{style:{display:"flex",flexDirection:"column",gap:8},children:[(0,g.jsx)(X,{label:e("optionsPreferPinned"),description:w===null?e("optionsNotResolved"):q(w),checked:x==="pinned",disabled:w===null||_,onChange:()=>ee("pinned")}),(0,g.jsx)(X,{label:e("optionsPreferGlobal"),description:C===null?e("optionsNotResolved"):q(C),checked:x==="global",disabled:C===null||_,onChange:()=>ee("global")})]}),(0,g.jsx)(c,{children:e("optionsPreferHint")}),C===null?(0,g.jsxs)("div",{style:Ze,children:[(0,g.jsx)(c,{children:e("optionsInstallHint")}),(0,g.jsx)("textarea",{readOnly:!0,value:E.join(`
7
- `),rows:2,style:Qe}),(0,g.jsxs)("div",{style:et,children:[(0,g.jsx)(u,{onClick:()=>{m()},children:e(i?"copied":"copy")}),(0,g.jsx)(u,{busy:r==="cli.installGlobal",onClick:()=>{H()},children:e("optionsInstall")}),(0,g.jsx)(u,{busy:r==="status.refresh",onClick:()=>{n("status.refresh",()=>h("status",{refresh:!0}))},children:e("refresh")})]}),v===null?null:(0,g.jsxs)("details",{children:[(0,g.jsx)("summary",{style:{fontSize:12,cursor:"pointer"},children:e("optionsOutput")}),(0,g.jsx)("pre",{style:tt,children:v})]})]}):null]})}var R=require("react/jsx-runtime"),nt={display:"flex",flexDirection:"column",gap:6,padding:10,borderRadius:6,border:"1px solid var(--dsw-alias-border-secondary, rgba(128, 128, 128, 0.25))"},ot={display:"flex",alignItems:"baseline",justifyContent:"space-between",gap:12,fontSize:13},Ee={display:"flex",flexWrap:"wrap",gap:8};function He({t:e,status:t,run:n,busy:s}){let r=t.servers??[];return(0,R.jsxs)(T,{title:e("serversTitle"),description:e("serversDesc"),children:[(0,R.jsx)("div",{style:Ee,children:(0,R.jsx)(u,{busy:s==="status.refresh",onClick:()=>n("status.refresh",()=>h("status",{refresh:!0})),children:e("refresh")})}),(0,R.jsx)(c,{children:t.panel.url===null?e("serversHintNoPanel"):e("serversHintPanel",{url:t.panel.url})}),r.length===0?(0,R.jsx)(c,{children:e("serversEmpty")}):r.map(o=>(0,R.jsxs)("div",{style:nt,children:[(0,R.jsxs)("div",{style:ot,children:[(0,R.jsx)("strong",{children:o.id}),(0,R.jsx)("span",{children:b(o.status)})]}),(0,R.jsx)(a,{label:e("serversPid"),children:b(o.pid)}),(0,R.jsx)(a,{label:e("serversUrl"),children:b(o.url)}),(0,R.jsxs)("div",{style:Ee,children:[(0,R.jsx)(u,{busy:s===`servers.start:${o.id}`,onClick:()=>n(`servers.start:${o.id}`,()=>h("servers.start",{id:o.id})),children:e("serversStart")}),(0,R.jsx)(u,{busy:s===`servers.stop:${o.id}`,onClick:()=>n(`servers.stop:${o.id}`,()=>h("servers.stop",{id:o.id})),children:e("serversStop")}),(0,R.jsx)(u,{busy:s===`servers.restart:${o.id}`,onClick:()=>n(`servers.restart:${o.id}`,()=>h("servers.restart",{id:o.id})),children:e("serversRestart")})]})]},o.id))]})}var f=require("react/jsx-runtime");function Ae(e){let t=re(e.t),{data:n,error:s,loading:r,refresh:o}=le(),[i,p]=(0,B.useState)(null),[v,S]=(0,B.useState)(null),x=(0,B.useCallback)((E,_)=>(S(E),p(null),(async()=>{try{let m=await _();return m.ok||p(m.error),m}catch(m){let H={code:"client",message:m instanceof Error?m.message:String(m)};return p(H),{ok:!1,error:H}}finally{S(null),await o()}})()),[o]),w=(0,B.useCallback)(E=>{if(n===null)return;let _=be(n.settings,E(n.settings));Object.keys(_).length!==0&&x("settings",()=>ae(_))},[n,x]);if(n===null)return(0,f.jsxs)("div",{style:{display:"flex",flexDirection:"column",gap:8},children:[r?(0,f.jsx)(c,{children:t("loading")}):(0,f.jsx)(D,{error:s??{code:"status",message:t("statusUnavailable")},title:t("errorTitle")}),r?null:(0,f.jsx)("div",{children:(0,f.jsx)(u,{onClick:()=>{o()},children:t("retry")})})]});let C={t,status:n,run:x,updateSettings:w,busy:v};return(0,f.jsxs)("div",{style:{display:"flex",flexDirection:"column"},children:[(0,f.jsxs)("header",{style:{display:"flex",alignItems:"flex-start",justifyContent:"space-between",gap:12},children:[(0,f.jsxs)("div",{children:[(0,f.jsx)("h2",{style:{margin:0,fontSize:16},children:t("tab")}),(0,f.jsx)("p",{style:{margin:"2px 0 0",fontSize:12,color:"var(--dsw-alias-label-secondary, #8b8b8b)"},children:t("pageDesc")})]}),(0,f.jsx)(u,{busy:v==="status.refresh",onClick:()=>x("status.refresh",()=>h("status",{refresh:!0})),children:t("refresh")})]}),n.lastError===null?null:(0,f.jsx)(D,{error:{code:"panel",message:n.lastError},title:t("errorTitle")}),(0,f.jsx)(D,{error:s,title:t("errorTitle")}),(0,f.jsx)(D,{error:i,title:t("errorTitle")}),(0,f.jsx)(we,{...C}),(0,f.jsx)(ke,{...C}),(0,f.jsx)(Re,{...C}),(0,f.jsx)(xe,{...C}),(0,f.jsx)(Ce,{...C}),(0,f.jsx)(He,{...C})]})}var rt=["slots","locale"],_e="[dsh-home-hosted]";function N(e,t){t===void 0?console.warn(`${_e} ${e}`):console.warn(`${_e} ${e}`,t)}function Ne(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 Oe(e,t,n){if(typeof e.effect=="function")try{e.effect(t,n);return}catch(s){N(`registering the effect "${n}" failed`,s);return}try{t()}catch(s){N(`the effect "${n}" failed`,s)}}function st(e){try{let t=Ne(e,"locale"),n=oe(t);t===void 0?N("the locale service is unavailable; the page keeps its bundled English copy"):Oe(e,()=>{let r=[];try{r.push(t.register($,{en:K,zh:te}))}catch(o){N("registering the dictionaries failed",o)}return()=>{for(let o of r)try{o()}catch(i){N("disposing a dictionary failed",i)}}},"dsh-home-hosted: dictionaries");let s=Ne(e,"slots");if(s===void 0){N("the slots service is unavailable; the settings section was not registered");return}Oe(e,()=>{try{return s.inject("settings.section",()=>{try{return s.register({name:"settings.section",id:"home-hosted",order:60,label:()=>n("tab"),locale:$,inject:()=>({t:n})},Ae)}catch(r){return N("registering the settings section failed",r),()=>{}}})}catch(r){return N("injecting into settings.section failed",r),()=>{}}},"dsh-home-hosted: settings section")}catch(t){N("client bootstrap failed",t)}}
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
- available: domain !== null,
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 ? `no launchd gui/$UID or user/$UID domain is reachable for uid ${uidOf(ctx) ?? "?"}` : `launchd ${domain} domain is reachable; a LaunchAgent loads at login, not at boot`
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
- available: canElevate,
975
- bootCapable: canElevate,
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 or passwordless sudo"
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 bootCapable = available.find((mechanism) => mechanism !== "container" && byMechanism.get(mechanism)?.bootCapable === true);
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
- if (result.ok) {
3212
- this.options.settings.update({
3213
- autostart: {
3214
- enabled: true,
3215
- mechanism: mechanism ?? result.mechanism ?? this.options.settings.get().autostart.mechanism
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
- if (result.ok)
3227
- this.options.settings.update({ autostart: { ...this.options.settings.get().autostart, enabled: false } });
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: {