dsh-home-hosted 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +48 -0
  3. package/cordis.patch.yml +6 -0
  4. package/docs/DESIGN.md +114 -0
  5. package/lib/client.js +9 -0
  6. package/lib/index.js +3694 -0
  7. package/lib/index.js.map +7 -0
  8. package/lib/types/boot/common.d.ts +40 -0
  9. package/lib/types/boot/escape.d.ts +59 -0
  10. package/lib/types/boot/fallback.d.ts +10 -0
  11. package/lib/types/boot/index.d.ts +12 -0
  12. package/lib/types/boot/ladder.d.ts +4 -0
  13. package/lib/types/boot/launchd.d.ts +8 -0
  14. package/lib/types/boot/systemd.d.ts +10 -0
  15. package/lib/types/boot/types.d.ts +94 -0
  16. package/lib/types/boot/windows.d.ts +16 -0
  17. package/lib/types/boot/xdg.d.ts +3 -0
  18. package/lib/types/config.d.ts +15 -0
  19. package/lib/types/home-hosted/config-file.d.ts +23 -0
  20. package/lib/types/home-hosted/dsh-entry.d.ts +22 -0
  21. package/lib/types/home-hosted/entries.d.ts +20 -0
  22. package/lib/types/home-hosted/launch.d.ts +25 -0
  23. package/lib/types/home-hosted/launcher.d.ts +38 -0
  24. package/lib/types/home-hosted/panel-control.d.ts +34 -0
  25. package/lib/types/home-hosted/panel.d.ts +44 -0
  26. package/lib/types/home-hosted/resolve.d.ts +34 -0
  27. package/lib/types/home-hosted/runtime.d.ts +20 -0
  28. package/lib/types/home-hosted/token.d.ts +20 -0
  29. package/lib/types/index.d.ts +15 -0
  30. package/lib/types/rpc.d.ts +11 -0
  31. package/lib/types/service.d.ts +125 -0
  32. package/lib/types/settings.d.ts +13 -0
  33. package/lib/types/shared/contracts.d.ts +245 -0
  34. package/lib/types/tools.d.ts +14 -0
  35. package/lib/types/util/exec.d.ts +29 -0
  36. package/lib/types/util/fsx.d.ts +9 -0
  37. package/lib/types/util/paths.d.ts +12 -0
  38. package/package.json +108 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 NamesMT
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,48 @@
1
+ # dsh-home-hosted
2
+
3
+ A DeepSeek Harness plugin for [home-hosted](https://github.com/NamesMT/home-hosted): start the panel at boot, and manage its servers from inside dsh.
4
+
5
+ ![The plugin's page under Settings → Home Hosted](https://raw.githubusercontent.com/NamesMT/dsh-home-hosted/main/assets/settings.png)
6
+
7
+ ## What it does
8
+
9
+ - **Boot autostart** — installs, verifies and removes the OS entry that starts `home-hosted` at boot (systemd on Linux, launchd on macOS, Run key / Task Scheduler on Windows). Off by default; opt in from the plugin's page.
10
+ - **Runs its own home-hosted** — the pinned copy ships as a dependency, so the panel that starts at boot is the version this plugin was built against. The page can start that panel, or replace a running one with it.
11
+ - **Server management** — add, edit, start, stop and restart home-hosted's servers without leaving dsh, with the panel's API as the write path so nothing is restarted behind your back.
12
+ - **Reclaim the harness** — a managed `dsh` entry gets `onPortConflict: kill`, so a leftover process holding the web port is reclaimed at boot instead of blocking forever.
13
+ - **Agent tools** — off by default, allowlisted one by one; every tool that changes something asks for approval first.
14
+
15
+ ## Install
16
+
17
+ ```sh
18
+ dsh plugin --profile web add dsh-home-hosted
19
+ ```
20
+
21
+ Then open **Settings → home-hosted**.
22
+
23
+ ## Configuration
24
+
25
+ The Cordis row config is for operator overrides only:
26
+
27
+ ```yaml
28
+ - id: dsh-home-hosted
29
+ name: 'dsh-home-hosted'
30
+ config:
31
+ stateDir: /custom/state/dir # default: $DSH_HOME/dsh-home-hosted
32
+ homeHostedCommand: /usr/bin/home-hosted
33
+ defaultEntryId: dsh
34
+ ```
35
+
36
+ Everything a person toggles lives in `<stateDir>/settings.json`, including **Options → which home-hosted to run**: the pinned dependency (default) or a global install. The page shows both candidates with their versions, and can install the pinned range globally for you.
37
+
38
+ ## Notes
39
+
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
+ - 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.
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
+ - `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
+
46
+ ## License
47
+
48
+ MIT
@@ -0,0 +1,6 @@
1
+ # The layer this bundle contributes to a profile's composition: one row that
2
+ # mounts the host half. The browser half is claimed by dsh.client in
3
+ # package.json and attaches to this same row.
4
+ - insert:
5
+ - id: dsh-home-hosted
6
+ name: 'dsh-home-hosted'
package/docs/DESIGN.md ADDED
@@ -0,0 +1,114 @@
1
+ # Design notes
2
+
3
+ Decisions that are not obvious from the code, and the hazards behind them.
4
+
5
+ ## A plugin cannot act at boot
6
+
7
+ The plugin runs inside dsh. At boot nothing runs yet, so autostart cannot be a
8
+ runtime behaviour: the plugin installs an OS entry while dsh runs, and the OS
9
+ starts home-hosted from then on. Every plugin start re-asserts that entry
10
+ (rewrite-if-changed), which is also what repairs a node path that moved after an
11
+ upgrade.
12
+
13
+ ## Which home-hosted runs
14
+
15
+ The plugin depends on `home-hosted` at a pinned range and prefers it by default,
16
+ so the panel is the version the plugin was built against. The preference is a
17
+ setting (Options → which home-hosted to run); a global install is a supported
18
+ choice, and the page shows both candidates with their versions and can install
19
+ the pinned range globally. An operator's `homeHostedCommand` in the plugin row
20
+ always wins — that is an instruction, not a preference.
21
+
22
+ That copy resolves to a pnpm path carrying a version and a peer hash
23
+ (`…/.pnpm/home-hosted@0.6.1_zod@4.6.5/node_modules/home-hosted/…`), which moves
24
+ on the next install and disappears when the profile is rebuilt. A boot entry
25
+ that baked it in would fail exactly when it matters.
26
+
27
+ So the boot entry runs a generated launcher in the plugin state directory
28
+ (`bin/home-hosted.mjs`, rewritten on every plugin start). At boot the launcher
29
+ finds the pinned copy again — recorded path, then `$DSH_HOME/profiles/*`
30
+ node_modules (flat or pnpm), then PATH — and forwards its argv, so the entry
31
+ survives plugin upgrades and profile reinstalls. The plugin preflights the
32
+ launcher the way the unit invokes it and shows the version it answers.
33
+
34
+ ## Config compatibility
35
+
36
+ `onPortConflict: kill` did not exist before home-hosted 0.6.0, and an older panel
37
+ that is handed it refuses to *boot* (its config schema rejects the value) — a
38
+ plugin must never brick the panel it manages. So the policy is checked before any
39
+ write against the version whose schema will parse it: the answering panel, or the
40
+ CLI that will parse it next. Below 0.6.0 the write is refused with
41
+ `KILL_UNSUPPORTED` and the page offers the fix it already has — replace the panel
42
+ with the preferred copy, or choose another policy.
43
+
44
+ ## Starting and replacing the panel
45
+
46
+ `panel.start` runs the preferred CLI's `up`, which detaches itself and returns
47
+ once the panel answers — that is the whole out-of-the-box path when nothing is
48
+ running.
49
+
50
+ `panel.takeover` replaces an answering panel with the preferred copy. Stopping
51
+ the old panel also stops every server it supervises, this dsh included, so a
52
+ detached helper does the work and the guard refuses unless this session is an
53
+ adopted entry with `autostart: true` (something must bring it back). The response
54
+ says the page will disconnect; the helper logs to `bin/panel-takeover.log`.
55
+
56
+ ## Two writes, and why the API comes first
57
+
58
+ home-hosted's config store compares the bytes it last wrote, so a write through
59
+ `/api/servers` never triggers its file watcher. A write to
60
+ `servers.config.json` does — and the watcher *starts* a newly added entry with
61
+ `autostart: true`.
62
+
63
+ So:
64
+
65
+ - panel answering + this plugin holds a token → API write, nothing is started or
66
+ stopped by surprise;
67
+ - panel not answering → direct file write (nobody is watching the file);
68
+ - panel answering but no token available → file write with the two-phase add:
69
+ write the entry with `autostart: false`, then flip `autostart`. A later write
70
+ to an existing entry is a *changed definition*, which only takes effect at that
71
+ entry's next start.
72
+
73
+ ## What the plugin owns
74
+
75
+ Only `autostart`, `onPortConflict` and `stop.killPortHolders`. Everything else —
76
+ command, args, env, health, restart, labels — is the person's, and a patch never
77
+ touches it.
78
+
79
+ Adopting an entry snapshots those three keys first (absence included). Disabling
80
+ restores the snapshot; a key the snapshot does not carry is restored to the
81
+ panel's schema default, because a PATCH cannot delete a key. `kill` is the only
82
+ policy that reclaims a port held by a process the panel cannot identify as the
83
+ entry's own successor, and it still refuses to touch the panel or any process the
84
+ panel supervises.
85
+
86
+ ## Self-reference
87
+
88
+ This process may itself be the entry being managed (`HHOSTED_SERVER_ID`).
89
+
90
+ - Deleting that entry is refused: it would stop the session doing the deleting.
91
+ - Starting/restarting it is allowed — that is the "reclaim now" case — but the UI
92
+ says the page will disconnect, and the agent tools need approval first.
93
+
94
+ ## Credentials
95
+
96
+ home-hosted keeps only an API token's hash, so a token this plugin did not create
97
+ can never be recovered. On the first write with none enrolled, the plugin mints
98
+ one, passes it to `home-hosted set-token` through `HHOSTED_TOKEN` (the CLI prints
99
+ nothing), and keeps it 0600 in its own state directory. It is never rendered,
100
+ logged, or embedded in a unit file.
101
+
102
+ ## Privilege
103
+
104
+ Boot scope needs privilege somewhere on every platform: a system unit, or
105
+ `loginctl enable-linger` on Linux; a LaunchDaemon on macOS; an elevated task on
106
+ Windows. Login scope needs none. When this process cannot elevate, the page shows
107
+ the exact commands instead of prompting for a password — a headless panel has no
108
+ askpass and `sudo -n` is the only honest probe.
109
+
110
+ ## Tests
111
+
112
+ No fixed ports: every stub listener binds `127.0.0.1` with port 0 and reads the
113
+ assigned port. No test starts dsh, home-hosted, or an OS service manager; the
114
+ subprocess seam and the boot ladder are injected.
package/lib/client.js ADDED
@@ -0,0 +1,9 @@
1
+ window.__ModuleLoader__.load({ id: "dsh-home-hosted", factory: (require) => {
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)}}
8
+
9
+ return module.exports; } });