@astralyn/sash 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/README.md +17 -5
- package/THIRD_PARTY_NOTICES.md +9 -0
- package/dist/api.js +14 -45
- package/dist/app-state.js +99 -0
- package/dist/autostart/command.js +24 -0
- package/dist/autostart/context.js +43 -0
- package/dist/autostart/files.js +60 -0
- package/dist/autostart/installation.js +48 -0
- package/dist/autostart/start.js +47 -0
- package/dist/autostart/windows-registry.js +88 -0
- package/dist/autostart/windows.js +59 -0
- package/dist/autostart-contract.js +31 -0
- package/dist/autostart-entry.js +10 -0
- package/dist/autostart.js +69 -0
- package/dist/cli.js +11 -11
- package/dist/commands/auto.js +15 -0
- package/dist/commands/lifecycle.js +5 -15
- package/dist/commands/logs.js +11 -4
- package/dist/commands/shared.js +2 -4
- package/dist/commands/status.js +5 -1
- package/dist/commands/update.js +7 -3
- package/dist/commands/web.js +14 -50
- package/dist/contracts.js +168 -348
- package/dist/core-config-validation.js +22 -38
- package/dist/core-update.js +126 -762
- package/dist/core.js +20 -46
- package/dist/daemon/app.js +129 -117
- package/dist/daemon/context.js +13 -7
- package/dist/daemon/entry.js +21 -38
- package/dist/daemon/errors.js +3 -0
- package/dist/daemon/handlers/autostart.js +18 -0
- package/dist/daemon/handlers/core.js +32 -9
- package/dist/daemon/handlers/daemon.js +17 -6
- package/dist/daemon/handlers/profiles.js +12 -2
- package/dist/daemon/handlers/settings.js +9 -36
- package/dist/daemon/router.js +26 -21
- package/dist/daemon/scheduler.js +3 -1
- package/dist/daemon/server.js +5 -2
- package/dist/daemon-client.js +13 -3
- package/dist/daemon-http.js +6 -0
- package/dist/daemon-lifecycle.js +19 -196
- package/dist/github.js +7 -2
- package/dist/http.js +7 -5
- package/dist/mihomo-config.js +2 -1
- package/dist/paths.js +5 -7
- package/dist/profile-model.js +87 -0
- package/dist/profile-service.js +250 -587
- package/dist/profiles.js +43 -171
- package/dist/runtime-lifecycle.js +112 -194
- package/dist/runtime-owner.js +37 -76
- package/dist/sash-client.js +40 -19
- package/dist/settings-service.js +29 -224
- package/dist/settings.js +61 -289
- package/dist/status.js +24 -16
- package/dist/supervisor.js +1 -14
- package/dist/sysproxy/common.js +5 -45
- package/dist/sysproxy/factory.js +24 -65
- package/dist/sysproxy/snapshot.js +24 -257
- package/dist/sysproxy.js +1 -4
- package/dist/system-proxy-manager.js +37 -35
- package/dist/ui/assets/{ConnectionsView-CfaOG2JV.js → ConnectionsView-BgXQM6Z4.js} +1 -1
- package/dist/ui/assets/{LogsView-BDiRATXN.js → LogsView-2f542P8z.js} +1 -1
- package/dist/ui/assets/{PaginationFooter-DTytr1iu.js → PaginationFooter-cj1tcZej.js} +1 -1
- package/dist/ui/assets/ProfileEditorDialog-C9M8uKZC.css +1 -0
- package/dist/ui/assets/ProfileEditorDialog-DD4y4GBC.js +14 -0
- package/dist/ui/assets/ProfilesView-BXU2DOA7.css +1 -0
- package/dist/ui/assets/ProfilesView-DNnzYIEY.js +7 -0
- package/dist/ui/assets/{RulesView-CjEyCN1A.js → RulesView-CtKvlckZ.js} +1 -1
- package/dist/ui/assets/SettingsView-BaeKFF_N.js +1 -0
- package/dist/ui/assets/SettingsView-CWjIe05v.css +1 -0
- package/dist/ui/assets/index-CBInDvdJ.js +19 -0
- package/dist/ui/assets/index-mOLy7fkB.css +1 -0
- package/dist/ui/assets/{theme-BwDBMsKO.js → theme-D40MF8cQ.js} +1 -1
- package/dist/ui/index.html +2 -2
- package/docs/architecture-proposal.md +109 -0
- package/docs/autostart.md +101 -0
- package/docs/backend.md +92 -224
- package/docs/frontend.md +60 -106
- package/docs/usage.md +92 -164
- package/package.json +3 -3
- package/dist/commands/upgrade.js +0 -43
- package/dist/core-install-transaction.js +0 -114
- package/dist/core-update-coordination.js +0 -105
- package/dist/core-update-service.js +0 -245
- package/dist/managed-state-transaction.js +0 -375
- package/dist/offline-mutation.js +0 -58
- package/dist/profile-migration.js +0 -101
- package/dist/runtime-recovery.js +0 -31
- package/dist/sysproxy/darwin.js +0 -287
- package/dist/sysproxy/gnome.js +0 -181
- package/dist/sysproxy/legacy.js +0 -58
- package/dist/ui/assets/CodeEditorModal-6m0TJWyF.css +0 -1
- package/dist/ui/assets/CodeEditorModal-D1zn-jRS.js +0 -14
- package/dist/ui/assets/ProfileEditorDialog-CyyP6OF1.js +0 -1
- package/dist/ui/assets/ProfilesView-ByqdFNHN.css +0 -1
- package/dist/ui/assets/ProfilesView-hFa7-O72.js +0 -2
- package/dist/ui/assets/SettingsFileDialog-CjBSyH4K.js +0 -1
- package/dist/ui/assets/SettingsView-D5QvJId6.css +0 -1
- package/dist/ui/assets/SettingsView-DsRntRfn.js +0 -2
- package/dist/ui/assets/index-CxQTf_P9.css +0 -1
- package/dist/ui/assets/index-_mb4OfYp.js +0 -19
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { hasExactOwnKeys, isPlainObject } from "./json-shape.js";
|
|
2
|
+
export const AUTOSTART_STATES = [
|
|
3
|
+
"on",
|
|
4
|
+
"off",
|
|
5
|
+
"stale",
|
|
6
|
+
"disabled",
|
|
7
|
+
"unknown",
|
|
8
|
+
"unsupported",
|
|
9
|
+
];
|
|
10
|
+
export function parseAutostartStatus(value) {
|
|
11
|
+
if (!isPlainObject(value) ||
|
|
12
|
+
!hasExactOwnKeys(value, ["state", "canEnable", "reason"]) ||
|
|
13
|
+
!AUTOSTART_STATES.some((state) => state === value.state) ||
|
|
14
|
+
typeof value.canEnable !== "boolean" ||
|
|
15
|
+
(value.reason !== null && typeof value.reason !== "string")) {
|
|
16
|
+
throw new Error("Invalid autostart status");
|
|
17
|
+
}
|
|
18
|
+
return {
|
|
19
|
+
state: value.state,
|
|
20
|
+
canEnable: value.canEnable,
|
|
21
|
+
reason: value.reason,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export function parseAutostartEnabled(value) {
|
|
25
|
+
if (!isPlainObject(value) ||
|
|
26
|
+
!hasExactOwnKeys(value, ["enabled"]) ||
|
|
27
|
+
typeof value.enabled !== "boolean") {
|
|
28
|
+
throw new Error("Expected an object containing only an enabled boolean");
|
|
29
|
+
}
|
|
30
|
+
return value.enabled;
|
|
31
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import "./node-version-guard.js";
|
|
2
|
+
import { startAtLogin } from "./autostart/start.js";
|
|
3
|
+
import { errorMessage } from "./error-utils.js";
|
|
4
|
+
try {
|
|
5
|
+
await startAtLogin();
|
|
6
|
+
}
|
|
7
|
+
catch (error) {
|
|
8
|
+
console.error(`[sash] Login startup failed: ${errorMessage(error)}`);
|
|
9
|
+
process.exitCode = 1;
|
|
10
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { autostartContext, } from "./autostart/context.js";
|
|
3
|
+
import { installationIssue } from "./autostart/installation.js";
|
|
4
|
+
import { windowsAutostart } from "./autostart/windows.js";
|
|
5
|
+
import { errorMessage } from "./error-utils.js";
|
|
6
|
+
import { StateMutationQueue } from "./state-lock.js";
|
|
7
|
+
export class AutostartUnavailableError extends Error {
|
|
8
|
+
}
|
|
9
|
+
export class AutostartService {
|
|
10
|
+
context;
|
|
11
|
+
backend;
|
|
12
|
+
queue;
|
|
13
|
+
checkInstallation;
|
|
14
|
+
constructor(options = {}) {
|
|
15
|
+
this.context = autostartContext(options);
|
|
16
|
+
this.backend =
|
|
17
|
+
options.backend ??
|
|
18
|
+
(this.context.platform === "win32" ? windowsAutostart(this.context) : undefined);
|
|
19
|
+
this.queue = new StateMutationQueue(path.join(this.context.controlDir, "registration.lock"));
|
|
20
|
+
this.checkInstallation = options.checkInstallation ?? installationIssue;
|
|
21
|
+
}
|
|
22
|
+
async inspect() {
|
|
23
|
+
if (!this.backend) {
|
|
24
|
+
return {
|
|
25
|
+
state: "unsupported",
|
|
26
|
+
canEnable: false,
|
|
27
|
+
reason: `Autostart is not supported on ${this.context.platform}`,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
const issue = this.checkInstallation(this.context);
|
|
31
|
+
try {
|
|
32
|
+
return {
|
|
33
|
+
state: await this.backend.inspect(),
|
|
34
|
+
canEnable: issue === null,
|
|
35
|
+
reason: issue,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
return {
|
|
40
|
+
state: "unknown",
|
|
41
|
+
canEnable: issue === null,
|
|
42
|
+
reason: errorMessage(error),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
async set(enabled) {
|
|
47
|
+
const backend = this.backend;
|
|
48
|
+
if (!backend) {
|
|
49
|
+
throw new AutostartUnavailableError(`Autostart is not supported on ${this.context.platform}`);
|
|
50
|
+
}
|
|
51
|
+
return this.queue.run("configure autostart", async () => {
|
|
52
|
+
if (enabled) {
|
|
53
|
+
const issue = this.checkInstallation(this.context);
|
|
54
|
+
if (issue)
|
|
55
|
+
throw new AutostartUnavailableError(issue);
|
|
56
|
+
}
|
|
57
|
+
await backend.set(enabled);
|
|
58
|
+
if (!enabled) {
|
|
59
|
+
const issue = this.checkInstallation(this.context);
|
|
60
|
+
return { state: "off", canEnable: issue === null, reason: issue };
|
|
61
|
+
}
|
|
62
|
+
const status = await this.inspect();
|
|
63
|
+
if (status.state !== "on") {
|
|
64
|
+
throw new Error(`Could not verify autostart: ${status.reason ?? status.state}`);
|
|
65
|
+
}
|
|
66
|
+
return status;
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|
package/dist/cli.js
CHANGED
|
@@ -3,13 +3,13 @@ import "./node-version-guard.js";
|
|
|
3
3
|
import fs from "node:fs";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
|
-
import { Command, CommanderError, InvalidArgumentError } from "commander";
|
|
6
|
+
import { Argument, Command, CommanderError, InvalidArgumentError } from "commander";
|
|
7
7
|
import { withCliErrors } from "./cli-errors.js";
|
|
8
|
+
import { runAuto } from "./commands/auto.js";
|
|
8
9
|
import { runRestart, runStart, runStop } from "./commands/lifecycle.js";
|
|
9
10
|
import { runLogs } from "./commands/logs.js";
|
|
10
11
|
import { runStatus } from "./commands/status.js";
|
|
11
12
|
import { runUpdate } from "./commands/update.js";
|
|
12
|
-
import { runUpgrade } from "./commands/upgrade.js";
|
|
13
13
|
import { runWeb } from "./commands/web.js";
|
|
14
14
|
import { parseLogLineCount } from "./log-follow.js";
|
|
15
15
|
function packageVersion() {
|
|
@@ -35,7 +35,6 @@ Examples:
|
|
|
35
35
|
$ sash web open the web dashboard
|
|
36
36
|
$ sash status show runtime state, endpoints, and system proxy status
|
|
37
37
|
$ sash update upgrade the core binary
|
|
38
|
-
$ sash upgrade upgrade Sash itself via npm
|
|
39
38
|
|
|
40
39
|
Data directory: %LOCALAPPDATA%\\Sash (Windows), ~/Library/Application Support/Sash (macOS),
|
|
41
40
|
$XDG_DATA_HOME/sash (Linux). Override with the SASH_HOME environment variable.`);
|
|
@@ -49,8 +48,13 @@ program
|
|
|
49
48
|
.action(withCliErrors(() => runStop()));
|
|
50
49
|
program
|
|
51
50
|
.command("restart")
|
|
52
|
-
.description("
|
|
51
|
+
.description("apply saved configuration and restart the core")
|
|
53
52
|
.action(withCliErrors(() => runRestart()));
|
|
53
|
+
program
|
|
54
|
+
.command("auto")
|
|
55
|
+
.description("inspect or set automatic startup at login for the current user")
|
|
56
|
+
.addArgument(new Argument("[mode]", "set autostart or inspect its state").choices(["on", "off", "status"]))
|
|
57
|
+
.action(withCliErrors((mode) => runAuto(mode)));
|
|
54
58
|
program
|
|
55
59
|
.command("status")
|
|
56
60
|
.description("show runtime state, versions, endpoints, and system proxy status")
|
|
@@ -63,26 +67,22 @@ program
|
|
|
63
67
|
.option("-f, --follow", "follow the log output")
|
|
64
68
|
.option("--errors", "read the stderr log instead of stdout")
|
|
65
69
|
.option("--daemon", "read sashd daemon logs instead of core logs")
|
|
70
|
+
.option("--startup", "read login startup diagnostics")
|
|
66
71
|
.action(withCliErrors((opts) => runLogs({
|
|
67
72
|
lines: opts.lines ?? 50,
|
|
68
73
|
follow: opts.follow,
|
|
69
74
|
errors: opts.errors,
|
|
70
75
|
daemon: opts.daemon,
|
|
76
|
+
startup: opts.startup,
|
|
71
77
|
})));
|
|
72
78
|
program
|
|
73
79
|
.command("update")
|
|
74
80
|
.description("upgrade the core binary")
|
|
75
81
|
.option("--version <tag>", "install a specific core version, e.g. v1.19.30")
|
|
76
|
-
.option("--force", "reinstall the target version and repair inconsistent Core state")
|
|
77
82
|
.action(withCliErrors((opts) => runUpdate(opts)));
|
|
78
|
-
program
|
|
79
|
-
.command("upgrade")
|
|
80
|
-
.description("upgrade Sash itself via npm")
|
|
81
|
-
.option("--version <version>", "install a specific Sash version")
|
|
82
|
-
.action(withCliErrors((opts) => runUpgrade(opts)));
|
|
83
83
|
program
|
|
84
84
|
.command("web")
|
|
85
|
-
.description("open the web dashboard
|
|
85
|
+
.description("open the web dashboard without starting the core")
|
|
86
86
|
.option("--no-open", "print the URL without opening a browser")
|
|
87
87
|
.action(withCliErrors((opts) => runWeb({ noOpen: !opts.open })));
|
|
88
88
|
program
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { AutostartService } from "../autostart.js";
|
|
2
|
+
import { log } from "../log.js";
|
|
3
|
+
import { ensureManagement } from "../runtime-owner.js";
|
|
4
|
+
import { runtimeContext } from "./shared.js";
|
|
5
|
+
export async function runAuto(mode = "status", controller = {
|
|
6
|
+
inspect: () => new AutostartService().inspect(),
|
|
7
|
+
set: async (enabled) => (await ensureManagement(runtimeContext())).client.setAutostart(enabled),
|
|
8
|
+
}) {
|
|
9
|
+
const status = mode === "status" ? await controller.inspect() : await controller.set(mode === "on");
|
|
10
|
+
log.kv("autostart", status.state);
|
|
11
|
+
if (status.reason)
|
|
12
|
+
log.warn(status.reason);
|
|
13
|
+
if (mode === "status" && status.state === "unknown")
|
|
14
|
+
process.exitCode = 2;
|
|
15
|
+
}
|
|
@@ -6,25 +6,15 @@ export async function runStart() {
|
|
|
6
6
|
const { owner, result } = await ensureRunning(ctx);
|
|
7
7
|
log.ok(`core started (PID=${result.pid}${result.version ? `, version ${result.version}` : ""})`);
|
|
8
8
|
printEndpoints(ctx, owner.daemon.port);
|
|
9
|
-
if (ctx.settings.systemProxy)
|
|
10
|
-
log.ok("system proxy enabled");
|
|
11
9
|
}
|
|
12
10
|
export async function runStop() {
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
if (wasRunning) {
|
|
16
|
-
log.ok("sash stopped; system proxy restored to its pre-Sash state");
|
|
17
|
-
}
|
|
18
|
-
else {
|
|
19
|
-
log.info("sash is not running; stale runtime state was reconciled");
|
|
20
|
-
}
|
|
11
|
+
const result = await stopRuntime(runtimeContext());
|
|
12
|
+
log.info(result.wasRunning ? "sash stopped; previous system proxy state restored" : "sash is stopped");
|
|
21
13
|
}
|
|
22
|
-
export async function runRestart(
|
|
14
|
+
export async function runRestart() {
|
|
23
15
|
const ctx = runtimeContext();
|
|
24
|
-
const { owner, result
|
|
25
|
-
|
|
26
|
-
log.ok(`sashd ${verb} (PID=${daemonPid})`);
|
|
27
|
-
log.ok(`core ${verb} (PID=${result.pid}${result.version ? `, version ${result.version}` : ""})`);
|
|
16
|
+
const { owner, result } = await restartRuntime(ctx);
|
|
17
|
+
log.ok(`core restarted (PID=${result.pid})`);
|
|
28
18
|
printEndpoints(ctx, owner.daemon.port);
|
|
29
19
|
}
|
|
30
20
|
export function printEndpoints(ctx, daemonPort) {
|
package/dist/commands/logs.js
CHANGED
|
@@ -1,16 +1,23 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import { log } from "../log.js";
|
|
3
3
|
import { followLogFile, logCursorAtEnd, normalizeLines } from "../log-follow.js";
|
|
4
|
+
import { sashLayout } from "../paths.js";
|
|
4
5
|
import { tailFile } from "../process.js";
|
|
5
6
|
import { runtimeContext } from "./shared.js";
|
|
6
7
|
export async function runLogs(opts = {}) {
|
|
7
|
-
|
|
8
|
+
if (opts.startup && (opts.daemon || opts.errors)) {
|
|
9
|
+
throw new Error("--startup cannot be combined with --daemon or --errors");
|
|
10
|
+
}
|
|
11
|
+
const layout = opts.startup ? sashLayout() : runtimeContext().layout;
|
|
8
12
|
let file;
|
|
9
|
-
if (opts.
|
|
10
|
-
file =
|
|
13
|
+
if (opts.startup) {
|
|
14
|
+
file = layout.sashLogFile;
|
|
15
|
+
}
|
|
16
|
+
else if (opts.daemon) {
|
|
17
|
+
file = opts.errors ? layout.daemonErrLogFile : layout.daemonLogFile;
|
|
11
18
|
}
|
|
12
19
|
else {
|
|
13
|
-
file = opts.errors ?
|
|
20
|
+
file = opts.errors ? layout.coreErrLogFile : layout.coreLogFile;
|
|
14
21
|
}
|
|
15
22
|
const lines = normalizeLines(opts.lines);
|
|
16
23
|
const cursor = logCursorAtEnd(file);
|
package/dist/commands/shared.js
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
|
+
import { loadSettings } from "../app-state.js";
|
|
1
2
|
import { sashLayout } from "../paths.js";
|
|
2
|
-
import { loadSettings } from "../settings.js";
|
|
3
|
-
export { runOfflineMutation } from "../offline-mutation.js";
|
|
4
3
|
export function runtimeContext() {
|
|
5
4
|
const layout = sashLayout();
|
|
6
|
-
|
|
7
|
-
return { layout, settings };
|
|
5
|
+
return { layout, settings: loadSettings(layout) };
|
|
8
6
|
}
|
package/dist/commands/status.js
CHANGED
|
@@ -13,6 +13,10 @@ export async function runStatus(opts = {}, collect = () => collectRuntimeStatus(
|
|
|
13
13
|
if (status.queryError)
|
|
14
14
|
log.warn(`status incomplete: ${status.queryError}`);
|
|
15
15
|
log.kv("root", status.paths.root);
|
|
16
|
+
log.kv("autostart", status.autostart.state);
|
|
17
|
+
if (status.autostart.state === "stale" || status.autostart.state === "disabled") {
|
|
18
|
+
log.warn("Run sash auto on to repair the login startup registration");
|
|
19
|
+
}
|
|
16
20
|
log.kv("config", status.paths.config);
|
|
17
21
|
log.kv("mixed port", status.endpoints.mixedProxy);
|
|
18
22
|
log.kv("proxy desired", status.systemProxy.desired ? "on" : "off");
|
|
@@ -26,7 +30,7 @@ export async function runStatus(opts = {}, collect = () => collectRuntimeStatus(
|
|
|
26
30
|
log.kv("os proxy", formatObservedProxy(status.systemProxy.osObserved));
|
|
27
31
|
log.kv("sash api", status.endpoints.daemonApi);
|
|
28
32
|
log.kv("dashboard", status.endpoints.dashboard);
|
|
29
|
-
log.kv("
|
|
33
|
+
log.kv("selected profile", status.activeProfile
|
|
30
34
|
? `${status.activeProfile.name} (${status.activeProfile.url || "local file"})`
|
|
31
35
|
: "(none)");
|
|
32
36
|
log.kv("core version", status.core.installedVersion || "(not installed)");
|
package/dist/commands/update.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { log } from "../log.js";
|
|
2
|
+
import { ensureManagement } from "../runtime-owner.js";
|
|
2
3
|
import { runtimeContext } from "./shared.js";
|
|
3
|
-
export async function runUpdate(opts = {}
|
|
4
|
-
await
|
|
4
|
+
export async function runUpdate(opts = {}) {
|
|
5
|
+
const owner = await ensureManagement(runtimeContext());
|
|
6
|
+
log.info("downloading and verifying Core; the dashboard remains available");
|
|
7
|
+
const result = await owner.client.updateCore(opts.version);
|
|
8
|
+
log.ok(`core updated to ${result.version}`);
|
|
5
9
|
}
|
package/dist/commands/web.js
CHANGED
|
@@ -1,61 +1,25 @@
|
|
|
1
1
|
import { openInBrowser } from "../browser.js";
|
|
2
2
|
import { log } from "../log.js";
|
|
3
|
-
import {
|
|
3
|
+
import { ensureManagement } from "../runtime-owner.js";
|
|
4
4
|
import { writeBootstrapFile } from "../web-bootstrap.js";
|
|
5
|
-
import { runStart } from "./lifecycle.js";
|
|
6
5
|
import { runtimeContext } from "./shared.js";
|
|
7
|
-
export function dashboardUrl(
|
|
8
|
-
return `http://127.0.0.1:${
|
|
6
|
+
export function dashboardUrl(port) {
|
|
7
|
+
return `http://127.0.0.1:${port}/ui/`;
|
|
9
8
|
}
|
|
10
9
|
export async function runWeb(opts = {}, deps = {}) {
|
|
11
|
-
const logger = deps.log ?? log;
|
|
12
|
-
const resolve = deps.resolveRuntimeOwner ?? resolveRuntimeOwner;
|
|
13
10
|
const ctx = (deps.runtimeContext ?? runtimeContext)();
|
|
14
|
-
|
|
15
|
-
let coreRunning = null;
|
|
16
|
-
if (owner.kind === "daemon") {
|
|
17
|
-
try {
|
|
18
|
-
coreRunning = (await owner.client.status()).core.running;
|
|
19
|
-
}
|
|
20
|
-
catch {
|
|
21
|
-
logger.warn("Core state is unavailable; opening the dashboard for recovery.");
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
if (owner.kind === "offline" || coreRunning === false) {
|
|
25
|
-
logger.info("sash is not running; starting it first...");
|
|
26
|
-
let started = false;
|
|
27
|
-
try {
|
|
28
|
-
await (deps.runStart ?? runStart)();
|
|
29
|
-
started = true;
|
|
30
|
-
}
|
|
31
|
-
catch (error) {
|
|
32
|
-
try {
|
|
33
|
-
owner = await resolve(ctx);
|
|
34
|
-
}
|
|
35
|
-
catch {
|
|
36
|
-
throw error;
|
|
37
|
-
}
|
|
38
|
-
if (owner.kind !== "daemon")
|
|
39
|
-
throw error;
|
|
40
|
-
logger.warn(`Core startup failed; opening the dashboard for recovery: ${error instanceof Error ? error.message : String(error)}`);
|
|
41
|
-
}
|
|
42
|
-
if (started)
|
|
43
|
-
owner = await resolve(ctx);
|
|
44
|
-
}
|
|
45
|
-
if (owner.kind !== "daemon") {
|
|
46
|
-
throw new Error("sashd did not become healthy before opening the dashboard");
|
|
47
|
-
}
|
|
11
|
+
const owner = await (deps.ensureManagement ?? ensureManagement)(ctx);
|
|
48
12
|
const url = dashboardUrl(owner.daemon.port);
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
13
|
+
const logger = deps.log ?? log;
|
|
14
|
+
if (!opts.noOpen) {
|
|
15
|
+
const bootstrap = await owner.client.createWebBootstrap();
|
|
16
|
+
const file = (deps.writeBootstrap ?? writeBootstrapFile)(ctx.layout, {
|
|
17
|
+
dashboardUrl: url,
|
|
18
|
+
...bootstrap,
|
|
19
|
+
});
|
|
20
|
+
(deps.openInBrowser ?? openInBrowser)(file.fileUrl);
|
|
53
21
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
dashboardUrl: url,
|
|
57
|
-
...bootstrap,
|
|
58
|
-
});
|
|
59
|
-
(deps.openInBrowser ?? openInBrowser)(file.fileUrl);
|
|
22
|
+
else
|
|
23
|
+
logger.info("run 'sash web' without --no-open to authorize a browser session");
|
|
60
24
|
logger.ok(`dashboard: ${url}`);
|
|
61
25
|
}
|