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.
- package/LICENSE +21 -0
- package/README.md +48 -0
- package/cordis.patch.yml +6 -0
- package/docs/DESIGN.md +114 -0
- package/lib/client.js +9 -0
- package/lib/index.js +3694 -0
- package/lib/index.js.map +7 -0
- package/lib/types/boot/common.d.ts +40 -0
- package/lib/types/boot/escape.d.ts +59 -0
- package/lib/types/boot/fallback.d.ts +10 -0
- package/lib/types/boot/index.d.ts +12 -0
- package/lib/types/boot/ladder.d.ts +4 -0
- package/lib/types/boot/launchd.d.ts +8 -0
- package/lib/types/boot/systemd.d.ts +10 -0
- package/lib/types/boot/types.d.ts +94 -0
- package/lib/types/boot/windows.d.ts +16 -0
- package/lib/types/boot/xdg.d.ts +3 -0
- package/lib/types/config.d.ts +15 -0
- package/lib/types/home-hosted/config-file.d.ts +23 -0
- package/lib/types/home-hosted/dsh-entry.d.ts +22 -0
- package/lib/types/home-hosted/entries.d.ts +20 -0
- package/lib/types/home-hosted/launch.d.ts +25 -0
- package/lib/types/home-hosted/launcher.d.ts +38 -0
- package/lib/types/home-hosted/panel-control.d.ts +34 -0
- package/lib/types/home-hosted/panel.d.ts +44 -0
- package/lib/types/home-hosted/resolve.d.ts +34 -0
- package/lib/types/home-hosted/runtime.d.ts +20 -0
- package/lib/types/home-hosted/token.d.ts +20 -0
- package/lib/types/index.d.ts +15 -0
- package/lib/types/rpc.d.ts +11 -0
- package/lib/types/service.d.ts +125 -0
- package/lib/types/settings.d.ts +13 -0
- package/lib/types/shared/contracts.d.ts +245 -0
- package/lib/types/tools.d.ts +14 -0
- package/lib/types/util/exec.d.ts +29 -0
- package/lib/types/util/fsx.d.ts +9 -0
- package/lib/types/util/paths.d.ts +12 -0
- 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
|
+

|
|
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
|
package/cordis.patch.yml
ADDED
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; } });
|