@dbx-tools/cli-service 0.9.36

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.
@@ -0,0 +1,81 @@
1
+ import { mkdir, rm, writeFile } from "node:fs/promises";
2
+ import { dirname } from "node:path";
3
+ export async function installStartup(definition, paths, runtime, launch) {
4
+ await mkdir(dirname(paths.startupFile), { recursive: true });
5
+ const content = runtime.platform === "darwin"
6
+ ? renderLaunchAgent(definition, launch)
7
+ : runtime.platform === "win32"
8
+ ? renderWindowsStartup(launch)
9
+ : renderDesktopEntry(definition, launch);
10
+ await writeFile(paths.startupFile, content, {
11
+ encoding: "utf8",
12
+ mode: runtime.platform === "win32" ? undefined : 0o644,
13
+ });
14
+ }
15
+ export async function removeStartup(paths) {
16
+ await rm(paths.startupFile, { force: true });
17
+ }
18
+ export function renderLaunchAgent(definition, launch) {
19
+ const argumentsXml = [launch.executable, ...launch.arguments]
20
+ .map((argument) => ` <string>${escapeXml(argument)}</string>`)
21
+ .join("\n");
22
+ return [
23
+ '<?xml version="1.0" encoding="UTF-8"?>',
24
+ '<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">',
25
+ '<plist version="1.0">',
26
+ " <dict>",
27
+ " <key>Label</key>",
28
+ ` <string>${escapeXml(definition.id)}</string>`,
29
+ " <key>ProgramArguments</key>",
30
+ " <array>",
31
+ argumentsXml,
32
+ " </array>",
33
+ " <key>RunAtLoad</key>",
34
+ " <true/>",
35
+ " <key>ProcessType</key>",
36
+ " <string>Interactive</string>",
37
+ " </dict>",
38
+ "</plist>",
39
+ "",
40
+ ].join("\n");
41
+ }
42
+ export function renderDesktopEntry(definition, launch) {
43
+ return [
44
+ "[Desktop Entry]",
45
+ "Type=Application",
46
+ `Name=${escapeDesktopValue(definition.name)}`,
47
+ `Exec=${[launch.executable, ...launch.arguments].map(quoteDesktopArgument).join(" ")}`,
48
+ "Terminal=false",
49
+ "X-GNOME-Autostart-enabled=true",
50
+ "",
51
+ ].join("\n");
52
+ }
53
+ export function renderWindowsStartup(launch) {
54
+ const command = [launch.executable, ...launch.arguments].map(quoteWindowsArgument).join(" ");
55
+ return `@echo off\r\nstart "" /b ${command}\r\n`;
56
+ }
57
+ function escapeDesktopValue(value) {
58
+ return value.replaceAll("\\", "\\\\").replaceAll("\n", "\\n");
59
+ }
60
+ function escapeXml(value) {
61
+ return value
62
+ .replaceAll("&", "&amp;")
63
+ .replaceAll("<", "&lt;")
64
+ .replaceAll(">", "&gt;")
65
+ .replaceAll('"', "&quot;")
66
+ .replaceAll("'", "&apos;");
67
+ }
68
+ function quoteDesktopArgument(value) {
69
+ return `"${value
70
+ .replaceAll("\\", "\\\\")
71
+ .replaceAll('"', '\\"')
72
+ .replaceAll("`", "\\`")
73
+ .replaceAll("$", "\\$")}"`;
74
+ }
75
+ function quoteWindowsArgument(value) {
76
+ const escapedPercent = value.replaceAll("%", "%%");
77
+ const escapedQuotes = escapedPercent.replace(/(\\*)"/g, '$1$1\\"');
78
+ const escapedTrailingSlashes = escapedQuotes.replace(/(\\+)$/, "$1$1");
79
+ return `"${escapedTrailingSlashes}"`;
80
+ }
81
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiX3N0YXJ0dXAuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvX3N0YXJ0dXAudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLEtBQUssRUFBRSxFQUFFLEVBQUUsU0FBUyxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDeEQsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLFdBQVcsQ0FBQztBQVVwQyxNQUFNLENBQUMsS0FBSyxVQUFVLGNBQWMsQ0FDbEMsVUFBZ0MsRUFDaEMsS0FBbUIsRUFDbkIsT0FBOEIsRUFDOUIsTUFBcUI7SUFFckIsTUFBTSxLQUFLLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxXQUFXLENBQUMsRUFBRSxFQUFFLFNBQVMsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO0lBQzdELE1BQU0sT0FBTyxHQUNYLE9BQU8sQ0FBQyxRQUFRLEtBQUssUUFBUTtRQUMzQixDQUFDLENBQUMsaUJBQWlCLENBQUMsVUFBVSxFQUFFLE1BQU0sQ0FBQztRQUN2QyxDQUFDLENBQUMsT0FBTyxDQUFDLFFBQVEsS0FBSyxPQUFPO1lBQzVCLENBQUMsQ0FBQyxvQkFBb0IsQ0FBQyxNQUFNLENBQUM7WUFDOUIsQ0FBQyxDQUFDLGtCQUFrQixDQUFDLFVBQVUsRUFBRSxNQUFNLENBQUMsQ0FBQztJQUMvQyxNQUFNLFNBQVMsQ0FBQyxLQUFLLENBQUMsV0FBVyxFQUFFLE9BQU8sRUFBRTtRQUMxQyxRQUFRLEVBQUUsTUFBTTtRQUNoQixJQUFJLEVBQUUsT0FBTyxDQUFDLFFBQVEsS0FBSyxPQUFPLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsS0FBSztLQUN2RCxDQUFDLENBQUM7QUFDTCxDQUFDO0FBRUQsTUFBTSxDQUFDLEtBQUssVUFBVSxhQUFhLENBQUMsS0FBbUI7SUFDckQsTUFBTSxFQUFFLENBQUMsS0FBSyxDQUFDLFdBQVcsRUFBRSxFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUUsQ0FBQyxD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LE1BQU0sc0JBQXNCLEdBQUcsYUFBYSxDQUFDLE9BQU8sQ0FBQyxRQUFRLEVBQUUsTUFBTSxDQUFDLENBQUM7SUFDdkUsT0FBTyxJQUFJLHNCQUFzQixHQUFHLENBQUM7QUFDdkMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IG1rZGlyLCBybSwgd3JpdGVGaWxlIH0gZnJvbSBcIm5vZGU6ZnMvcHJvbWlzZXNcIjtcbmltcG9ydCB7IGRpcm5hbWUgfSBmcm9tIFwibm9kZTpwYXRoXCI7XG5cbmltcG9ydCB0eXBlIHsgU2VydmljZVBhdGhzLCBTZXJ2aWNlUnVudGltZUNvbnRleHQgfSBmcm9tIFwiLi9fcGF0aHMudHNcIjtcbmltcG9ydCB0eXBlIHsgQ2xpU2VydmljZURlZmluaXRpb24gfSBmcm9tIFwiLi9kZWZpbml0aW9uLnRzXCI7XG5cbmV4cG9ydCBpbnRlcmZhY2UgU2VydmljZUxhdW5jaCB7XG4gIHJlYWRvbmx5IGV4ZWN1dGFibGU6IHN0cmluZztcbiAgcmVhZG9ubHkgYXJndW1lbnRzOiByZWFkb25seSBzdHJpbmdbXTtcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGluc3RhbGxTdGFydHVwKFxuICBkZWZpbml0aW9uOiBDbGlTZXJ2aWNlRGVmaW5pdGlvbixcbiAgcGF0aHM6IFNlcnZpY2VQYXRocyxcbiAgcnVudGltZTogU2VydmljZVJ1bnRpbWVDb250ZXh0LFxuICBsYXVuY2g6IFNlcnZpY2VMYXVuY2gsXG4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgYXdhaXQgbWtkaXIoZGlybmFtZShwYXRocy5zdGFydHVwRmlsZSksIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xuICBjb25zdCBjb250ZW50ID1cbiAgICBydW50aW1lLnBsYXRmb3JtID09PSBcImRhcndpblwiXG4gICAgICA/IHJlbmRlckxhdW5jaEFnZW50KGRlZmluaXRpb24sIGxhdW5jaClcbiAgICAgIDogcnVudGltZS5wbGF0Zm9ybSA9PT0gXCJ3aW4zMlwiXG4gICAgICAgID8gcmVuZGVyV2luZG93c1N0YXJ0dXAobGF1bmNoKVxuICAgICAgICA6IHJlbmRlckRlc2t0b3BFbnRyeShkZWZpbml0aW9uLCBsYXVuY2gpO1xuICBhd2FpdCB3cml0ZUZpbGUocGF0aHMuc3RhcnR1cEZpbGUsIGNvbnRlbnQsIHtcbiAgICBlbmNvZGluZzogXCJ1dGY4XCIsXG4gICAgbW9kZTogcnVudGltZS5wbGF0Zm9ybSA9PT0gXCJ3aW4zMlwiID8gdW5kZWZpbmVkIDogMG82NDQsXG4gIH0pO1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcmVtb3ZlU3RhcnR1cChwYXRoczogU2VydmljZVBhdGhzKTogUHJvbWlzZTx2b2lkPiB7XG4gIGF3YWl0IHJtKHBhdGhzLnN0YXJ0dXBGaWxlLCB7IGZvcmNlOiB0cnVlIH0pO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gcmVuZGVyTGF1bmNoQWdlbnQoZGVmaW5pdGlvbjogQ2xpU2VydmljZURlZmluaXRpb24sIGxhdW5jaDogU2VydmljZUxhdW5jaCk6IHN0cmluZyB7XG4gIGNvbnN0IGFyZ3VtZW50c1htbCA9IFtsYXVuY2guZXhlY3V0YWJsZSwgLi4ubGF1bmNoLmFyZ3VtZW50c11cbiAgICAubWFwKChhcmd1bWVudCkgPT4gYCAgICAgIDxzdHJpbmc+JHtlc2NhcGVYbWwoYXJndW1lbnQpfTwvc3RyaW5nPmApXG4gICAgLmpvaW4oXCJcXG5cIik7XG4gIHJldHVybiBbXG4gICAgJzw/eG1sIHZlcnNpb249XCIxLjBcIiBlbmNvZGluZz1cIlVURi04XCI/PicsXG4gICAgJzwhRE9DVFlQRSBwbGlzdCBQVUJMSUMgXCItLy9BcHBsZS8vRFREIFBMSVNUIDEuMC8vRU5cIiBcImh0dHA6Ly93d3cuYXBwbGUuY29tL0RURHMvUHJvcGVydHlMaXN0LTEuMC5kdGRcIj4nLFxuICAgICc8cGxpc3QgdmVyc2lvbj1cIjEuMFwiPicsXG4gICAgXCIgIDxkaWN0PlwiLFxuICAgIFwiICAgIDxrZXk+TGFiZWw8L2tleT5cIixcbiAgICBgICAgIDxzdHJpbmc+JHtlc2NhcGVYbWwoZGVmaW5pdGlvbi5pZCl9PC9zdHJpbmc+YCxcbiAgICBcIiAgICA8a2V5PlByb2dyYW1Bcmd1bWVudHM8L2tleT5cIixcbiAgICBcIiAgICA8YXJyYXk+XCIsXG4gICAgYXJndW1lbnRzWG1sLFxuICAgIFwiICAgIDwvYXJyYXk+XCIsXG4gICAgXCIgICAgPGtleT5SdW5BdExvYWQ8L2tleT5cIixcbiAgICBcIiAgICA8dHJ1ZS8+XCIsXG4gICAgXCIgICAgPGtleT5Qcm9jZXNzVHlwZTwva2V5PlwiLFxuICAgIFwiICAgIDxzdHJpbmc+SW50ZXJhY3RpdmU8L3N0cmluZz5cIixcbiAgICBcIiAgPC9kaWN0PlwiLFxuICAgIFwiPC9wbGlzdD5cIixcbiAgICBcIlwiLFxuICBdLmpvaW4oXCJcXG5cIik7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiByZW5kZXJEZXNrdG9wRW50cnkoXG4gIGRlZmluaXRpb246IENsaVNlcnZpY2VEZWZpbml0aW9uLFxuICBsYXVuY2g6IFNlcnZpY2VMYXVuY2gsXG4pOiBzdHJpbmcge1xuICByZXR1cm4gW1xuICAgIFwiW0Rlc2t0b3AgRW50cnldXCIsXG4gICAgXCJUeXBlPUFwcGxpY2F0aW9uXCIsXG4gICAgYE5hbWU9JHtlc2NhcGVEZXNrdG9wVmFsdWUoZGVmaW5pdGlvbi5uYW1lKX1gLFxuICAgIGBFeGVjPSR7W2xhdW5jaC5leGVjdXRhYmxlLCAuLi5sYXVuY2guYXJndW1lbnRzXS5tYXAocXVvdGVEZXNrdG9wQXJndW1lbnQpLmpvaW4oXCIgXCIpfWAsXG4gICAgXCJUZXJtaW5hbD1mYWxzZVwiLFxuICAgIFwiWC1HTk9NRS1BdXRvc3RhcnQtZW5hYmxlZD10cnVlXCIsXG4gICAgXCJcIixcbiAgXS5qb2luKFwiXFxuXCIpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gcmVuZGVyV2luZG93c1N0YXJ0dXAobGF1bmNoOiBTZXJ2aWNlTGF1bmNoKTogc3RyaW5nIHtcbiAgY29uc3QgY29tbWFuZCA9IFtsYXVuY2guZXhlY3V0YWJsZSwgLi4ubGF1bmNoLmFyZ3VtZW50c10ubWFwKHF1b3RlV2luZG93c0FyZ3VtZW50KS5qb2luKFwiIFwiKTtcbiAgcmV0dXJuIGBAZWNobyBvZmZcXHJcXG5zdGFydCBcIlwiIC9iICR7Y29tbWFuZH1cXHJcXG5gO1xufVxuXG5mdW5jdGlvbiBlc2NhcGVEZXNrdG9wVmFsdWUodmFsdWU6IHN0cmluZyk6IHN0cmluZyB7XG4gIHJldHVybiB2YWx1ZS5yZXBsYWNlQWxsKFwiXFxcXFwiLCBcIlxcXFxcXFxcXCIpLnJlcGxhY2VBbGwoXCJcXG5cIiwgXCJcXFxcblwiKTtcbn1cblxuZnVuY3Rpb24gZXNjYXBlWG1sKHZhbHVlOiBzdHJpbmcpOiBzdHJpbmcge1xuICByZXR1cm4gdmFsdWVcbiAgICAucmVwbGFjZUFsbChcIiZcIiwgXCImYW1wO1wiKVxuICAgIC5yZXBsYWNlQWxsKFwiPFwiLCBcIiZsdDtcIilcbiAgICAucmVwbGFjZUFsbChcIj5cIiwgXCImZ3Q7XCIpXG4gICAgLnJlcGxhY2VBbGwoJ1wiJywgXCImcXVvdDtcIilcbiAgICAucmVwbGFjZUFsbChcIidcIiwgXCImYXBvcztcIik7XG59XG5cbmZ1bmN0aW9uIHF1b3RlRGVza3RvcEFyZ3VtZW50KHZhbHVlOiBzdHJpbmcpOiBzdHJpbmcge1xuICByZXR1cm4gYFwiJHt2YWx1ZVxuICAgIC5yZXBsYWNlQWxsKFwiXFxcXFwiLCBcIlxcXFxcXFxcXCIpXG4gICAgLnJlcGxhY2VBbGwoJ1wiJywgJ1xcXFxcIicpXG4gICAgLnJlcGxhY2VBbGwoXCJgXCIsIFwiXFxcXGBcIilcbiAgICAucmVwbGFjZUFsbChcIiRcIiwgXCJcXFxcJFwiKX1cImA7XG59XG5cbmZ1bmN0aW9uIHF1b3RlV2luZG93c0FyZ3VtZW50KHZhbHVlOiBzdHJpbmcpOiBzdHJpbmcge1xuICBjb25zdCBlc2NhcGVkUGVyY2VudCA9IHZhbHVlLnJlcGxhY2VBbGwoXCIlXCIsIFwiJSVcIik7XG4gIGNvbnN0IGVzY2FwZWRRdW90ZXMgPSBlc2NhcGVkUGVyY2VudC5yZXBsYWNlKC8oXFxcXCopXCIvZywgJyQxJDFcXFxcXCInKTtcbiAgY29uc3QgZXNjYXBlZFRyYWlsaW5nU2xhc2hlcyA9IGVzY2FwZWRRdW90ZXMucmVwbGFjZSgvKFxcXFwrKSQvLCBcIiQxJDFcIik7XG4gIHJldHVybiBgXCIke2VzY2FwZWRUcmFpbGluZ1NsYXNoZXN9XCJgO1xufVxuIl19
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Commander command group for a system-tray service lifecycle.
3
+ *
4
+ * @module
5
+ */
6
+ import { Command } from "commander";
7
+ import type { CliServiceDefinition } from "./definition.ts";
8
+ import { type CliServiceLifecycle } from "./service.ts";
9
+ /** Static definition or action-time factory used by a service command group. */
10
+ export type CliServiceDefinitionSource = CliServiceDefinition | (() => CliServiceDefinition);
11
+ /** Injectable lifecycle and output boundary for service CLI tests and composition. */
12
+ export interface CliServiceCliDependencies {
13
+ /** Construct the lifecycle manager used by command actions. */
14
+ create(definition: CliServiceDefinition): CliServiceLifecycle;
15
+ /** Write the JSON result of the status command. */
16
+ write(value: string): void;
17
+ }
18
+ /** Build install, start, stop, restart, status, and uninstall commands for a service. */
19
+ export declare function buildServiceCommand(source: CliServiceDefinitionSource, dependencies?: CliServiceCliDependencies): Command;
package/lib/src/cli.js ADDED
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Commander command group for a system-tray service lifecycle.
3
+ *
4
+ * @module
5
+ */
6
+ import { Command } from "commander";
7
+ import { CliService } from "./service.js";
8
+ const DEFAULT_DEPENDENCIES = {
9
+ create: (definition) => new CliService(definition),
10
+ write: (value) => process.stdout.write(value),
11
+ };
12
+ /** Build install, start, stop, restart, status, and uninstall commands for a service. */
13
+ export function buildServiceCommand(source, dependencies = DEFAULT_DEPENDENCIES) {
14
+ const definition = resolveDefinition(source);
15
+ const service = () => dependencies.create(definition());
16
+ const command = new Command("service").description(typeof source === "function"
17
+ ? "Install and manage the desktop service"
18
+ : `Install and manage the ${source.name} desktop service`);
19
+ command
20
+ .command("install")
21
+ .description("Install the service for the current user and start it")
22
+ .option("--no-start", "install without starting the service")
23
+ .action(async (options) => {
24
+ await service().install({ start: options.start });
25
+ });
26
+ command
27
+ .command("start")
28
+ .description("Start the installed service")
29
+ .action(async () => {
30
+ await service().start();
31
+ });
32
+ command
33
+ .command("stop")
34
+ .description("Stop the running service")
35
+ .action(async () => {
36
+ await service().stop();
37
+ });
38
+ command
39
+ .command("restart")
40
+ .description("Restart the installed service")
41
+ .action(async () => {
42
+ await service().restart();
43
+ });
44
+ command
45
+ .command("status")
46
+ .description("Print service installation and process state as JSON")
47
+ .action(async () => {
48
+ dependencies.write(`${JSON.stringify(await service().status(), null, 2)}\n`);
49
+ });
50
+ command
51
+ .command("uninstall")
52
+ .description("Stop and remove the service for the current user")
53
+ .action(async () => {
54
+ await service().uninstall();
55
+ });
56
+ return command;
57
+ }
58
+ function resolveDefinition(source) {
59
+ return typeof source === "function" ? source : () => source;
60
+ }
61
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xpLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NsaS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7OztHQUlHO0FBRUgsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUdwQyxPQUFPLEVBQUUsVUFBVSxFQUE0QixNQUFNLGNBQWMsQ0FBQztBQWFwRSxNQUFNLG9CQUFvQixHQUE4QjtJQUN0RCxNQUFNLEVBQUUsQ0FBQyxVQUFVLEVBQUUsRUFBRSxDQUFDLElBQUksVUFBVSxDQUFDLFVBQVUsQ0FBQztJQUNsRCxLQUFLLEVBQUUsQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQztDQUM5QyxDQUFDO0FBRUYseUZBQXlGO0FBQ3pGLE1BQU0sVUFBVSxtQkFBbUIsQ0FDakMsTUFBa0MsRUFDbEMsZUFBMEMsb0JBQW9CO0lBRTlELE1BQU0sVUFBVSxHQUFHLGlCQUFpQixDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQzdDLE1BQU0sT0FBTyxHQUFHLEdBQUcsRUFBRSxDQUFDLFlBQVksQ0FBQyxNQUFNLENBQUMsVUFBVSxFQUFFLENBQUMsQ0FBQztJQUN4RCxNQUFNLE9BQU8sR0FBRyxJQUFJLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQyxXQUFXLENBQ2hELE9BQU8sTUFBTSxLQUFLLFVBQVU7UUFDMUIsQ0FBQyxDQUFDLHdDQUF3QztRQUMxQyxDQUFDLENBQUMsMEJBQTBCLE1BQU0sQ0FBQyxJQUFJLGtCQUFrQixDQUM1RCxDQUFDO0lBRUYsT0FBTztTQUNKLE9BQU8sQ0FBQyxTQUFTLENBQUM7U0FDbEIsV0FBVyxDQUFDLHVEQUF1RCxDQUFDO1NBQ3BFLE1BQU0sQ0FBQyxZQUFZLEVBQUUsc0NBQXNDLENBQUM7U0FDNUQsTUFBTSxDQUFDLEtBQUssRUFBRSxPQUEyQixFQUFFLEVBQUU7UUFDNUMsTUFBTSxPQUFPLEVBQUUsQ0FBQyxPQUFPLENBQUMsRUFBRSxLQUFLLEVBQUUsT0FBTyxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUM7SUFDcEQsQ0FBQyxDQUFDLENBQUM7SUFFTCxPQUFPO1NBQ0osT0FBTyxDQUFDLE9BQU8sQ0FBQztTQUNoQixXQUFXLENBQUMsNkJBQTZCLENBQUM7U0FDMUMsTUFBTSxDQUFDLEtBQUssSUFBSSxFQUFFO1FBQ2pCLE1BQU0sT0FBTyxFQUFFLENBQUMsS0FBSyxFQUFFLENBQUM7SUFDMUIsQ0FBQyxDQUFDLENBQUM7SUFFTCxPQUFPO1NBQ0osT0FBTyxDQUFDLE1BQU0sQ0FBQztTQUNmLFdBQVcsQ0FBQywwQkFBMEIsQ0FBQztTQUN2QyxNQUFNLENBQUMsS0FBSyxJQUFJLEVBQUU7UUFDakIsTUFBTSxPQUFPLEVBQUUsQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUN6QixDQUFDLENBQUMsQ0FBQztJQUVMLE9BQU87U0FDSixPQUFPLENBQUMsU0FBUyxDQUFDO1NBQ2xCLFdBQVcsQ0FBQywrQkFBK0IsQ0FBQztTQUM1QyxNQUFNLENBQUMsS0FBSyxJQUFJLEVBQUU7UUFDakIsTUFBTSxPQUFPLEVBQUUsQ0FBQyxPQUFPLEVBQUUsQ0FBQztJQUM1QixDQUFDLENBQUMsQ0FBQztJQUVMLE9BQU87U0FDSixPQUFPLENBQUMsUUFBUSxDQUFDO1NBQ2pCLFdBQVcsQ0FBQyxzREFBc0QsQ0FBQztTQUNuRSxNQUFNLENBQUMsS0FBSyxJQUFJLEVBQUU7UUFDakIsWUFBWSxDQUFDLEtBQUssQ0FBQyxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsTUFBTSxPQUFPLEVBQUUsQ0FBQyxNQUFNLEVBQUUsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQy9FLENBQUMsQ0FBQyxDQUFDO0lBRUwsT0FBTztTQUNKLE9BQU8sQ0FBQyxXQUFXLENBQUM7U0FDcEIsV0FBVyxDQUFDLGtEQUFrRCxDQUFDO1NBQy9ELE1BQU0sQ0FBQyxLQUFLLElBQUksRUFBRTtRQUNqQixNQUFNLE9BQU8sRUFBRSxDQUFDLFNBQVMsRUFBRSxDQUFDO0lBQzlCLENBQUMsQ0FBQyxDQUFDO0lBRUwsT0FBTyxPQUFPLENBQUM7QUFDakIsQ0FBQztBQUVELFNBQVMsaUJBQWlCLENBQUMsTUFBa0M7SUFDM0QsT0FBTyxPQUFPLE1BQU0sS0FBSyxVQUFVLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFFLENBQUMsTUFBTSxDQUFDO0FBQzlELENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIENvbW1hbmRlciBjb21tYW5kIGdyb3VwIGZvciBhIHN5c3RlbS10cmF5IHNlcnZpY2UgbGlmZWN5Y2xlLlxuICpcbiAqIEBtb2R1bGVcbiAqL1xuXG5pbXBvcnQgeyBDb21tYW5kIH0gZnJvbSBcImNvbW1hbmRlclwiO1xuXG5pbXBvcnQgdHlwZSB7IENsaVNlcnZpY2VEZWZpbml0aW9uIH0gZnJvbSBcIi4vZGVmaW5pdGlvbi50c1wiO1xuaW1wb3J0IHsgQ2xpU2VydmljZSwgdHlwZSBDbGlTZXJ2aWNlTGlmZWN5Y2xlIH0gZnJvbSBcIi4vc2VydmljZS50c1wiO1xuXG4vKiogU3RhdGljIGRlZmluaXRpb24gb3IgYWN0aW9uLXRpbWUgZmFjdG9yeSB1c2VkIGJ5IGEgc2VydmljZSBjb21tYW5kIGdyb3VwLiAqL1xuZXhwb3J0IHR5cGUgQ2xpU2VydmljZURlZmluaXRpb25Tb3VyY2UgPSBDbGlTZXJ2aWNlRGVmaW5pdGlvbiB8ICgoKSA9PiBDbGlTZXJ2aWNlRGVmaW5pdGlvbik7XG5cbi8qKiBJbmplY3RhYmxlIGxpZmVjeWNsZSBhbmQgb3V0cHV0IGJvdW5kYXJ5IGZvciBzZXJ2aWNlIENMSSB0ZXN0cyBhbmQgY29tcG9zaXRpb24uICovXG5leHBvcnQgaW50ZXJmYWNlIENsaVNlcnZpY2VDbGlEZXBlbmRlbmNpZXMge1xuICAvKiogQ29uc3RydWN0IHRoZSBsaWZlY3ljbGUgbWFuYWdlciB1c2VkIGJ5IGNvbW1hbmQgYWN0aW9ucy4gKi9cbiAgY3JlYXRlKGRlZmluaXRpb246IENsaVNlcnZpY2VEZWZpbml0aW9uKTogQ2xpU2VydmljZUxpZmVjeWNsZTtcbiAgLyoqIFdyaXRlIHRoZSBKU09OIHJlc3VsdCBvZiB0aGUgc3RhdHVzIGNvbW1hbmQuICovXG4gIHdyaXRlKHZhbHVlOiBzdHJpbmcpOiB2b2lkO1xufVxuXG5jb25zdCBERUZBVUxUX0RFUEVOREVOQ0lFUzogQ2xpU2VydmljZUNsaURlcGVuZGVuY2llcyA9IHtcbiAgY3JlYXRlOiAoZGVmaW5pdGlvbikgPT4gbmV3IENsaVNlcnZpY2UoZGVmaW5pdGlvbiksXG4gIHdyaXRlOiAodmFsdWUpID0+IHByb2Nlc3Muc3Rkb3V0LndyaXRlKHZhbHVlKSxcbn07XG5cbi8qKiBCdWlsZCBpbnN0YWxsLCBzdGFydCwgc3RvcCwgcmVzdGFydCwgc3RhdHVzLCBhbmQgdW5pbnN0YWxsIGNvbW1hbmRzIGZvciBhIHNlcnZpY2UuICovXG5leHBvcnQgZnVuY3Rpb24gYnVpbGRTZXJ2aWNlQ29tbWFuZChcbiAgc291cmNlOiBDbGlTZXJ2aWNlRGVmaW5pdGlvblNvdXJjZSxcbiAgZGVwZW5kZW5jaWVzOiBDbGlTZXJ2aWNlQ2xpRGVwZW5kZW5jaWVzID0gREVGQVVMVF9ERVBFTkRFTkNJRVMsXG4pOiBDb21tYW5kIHtcbiAgY29uc3QgZGVmaW5pdGlvbiA9IHJlc29sdmVEZWZpbml0aW9uKHNvdXJjZSk7XG4gIGNvbnN0IHNlcnZpY2UgPSAoKSA9PiBkZXBlbmRlbmNpZXMuY3JlYXRlKGRlZmluaXRpb24oKSk7XG4gIGNvbnN0IGNvbW1hbmQgPSBuZXcgQ29tbWFuZChcInNlcnZpY2VcIikuZGVzY3JpcHRpb24oXG4gICAgdHlwZW9mIHNvdXJjZSA9PT0gXCJmdW5jdGlvblwiXG4gICAgICA/IFwiSW5zdGFsbCBhbmQgbWFuYWdlIHRoZSBkZXNrdG9wIHNlcnZpY2VcIlxuICAgICAgOiBgSW5zdGFsbCBhbmQgbWFuYWdlIHRoZSAke3NvdXJjZS5uYW1lfSBkZXNrdG9wIHNlcnZpY2VgLFxuICApO1xuXG4gIGNvbW1hbmRcbiAgICAuY29tbWFuZChcImluc3RhbGxcIilcbiAgICAuZGVzY3JpcHRpb24oXCJJbnN0YWxsIHRoZSBzZXJ2aWNlIGZvciB0aGUgY3VycmVudCB1c2VyIGFuZCBzdGFydCBpdFwiKVxuICAgIC5vcHRpb24oXCItLW5vLXN0YXJ0XCIsIFwiaW5zdGFsbCB3aXRob3V0IHN0YXJ0aW5nIHRoZSBzZXJ2aWNlXCIpXG4gICAgLmFjdGlvbihhc3luYyAob3B0aW9uczogeyBzdGFydDogYm9vbGVhbiB9KSA9PiB7XG4gICAgICBhd2FpdCBzZXJ2aWNlKCkuaW5zdGFsbCh7IHN0YXJ0OiBvcHRpb25zLnN0YXJ0IH0pO1xuICAgIH0pO1xuXG4gIGNvbW1hbmRcbiAgICAuY29tbWFuZChcInN0YXJ0XCIpXG4gICAgLmRlc2NyaXB0aW9uKFwiU3RhcnQgdGhlIGluc3RhbGxlZCBzZXJ2aWNlXCIpXG4gICAgLmFjdGlvbihhc3luYyAoKSA9PiB7XG4gICAgICBhd2FpdCBzZXJ2aWNlKCkuc3RhcnQoKTtcbiAgICB9KTtcblxuICBjb21tYW5kXG4gICAgLmNvbW1hbmQoXCJzdG9wXCIpXG4gICAgLmRlc2NyaXB0aW9uKFwiU3RvcCB0aGUgcnVubmluZyBzZXJ2aWNlXCIpXG4gICAgLmFjdGlvbihhc3luYyAoKSA9PiB7XG4gICAgICBhd2FpdCBzZXJ2aWNlKCkuc3RvcCgpO1xuICAgIH0pO1xuXG4gIGNvbW1hbmRcbiAgICAuY29tbWFuZChcInJlc3RhcnRcIilcbiAgICAuZGVzY3JpcHRpb24oXCJSZXN0YXJ0IHRoZSBpbnN0YWxsZWQgc2VydmljZVwiKVxuICAgIC5hY3Rpb24oYXN5bmMgKCkgPT4ge1xuICAgICAgYXdhaXQgc2VydmljZSgpLnJlc3RhcnQoKTtcbiAgICB9KTtcblxuICBjb21tYW5kXG4gICAgLmNvbW1hbmQoXCJzdGF0dXNcIilcbiAgICAuZGVzY3JpcHRpb24oXCJQcmludCBzZXJ2aWNlIGluc3RhbGxhdGlvbiBhbmQgcHJvY2VzcyBzdGF0ZSBhcyBKU09OXCIpXG4gICAgLmFjdGlvbihhc3luYyAoKSA9PiB7XG4gICAgICBkZXBlbmRlbmNpZXMud3JpdGUoYCR7SlNPTi5zdHJpbmdpZnkoYXdhaXQgc2VydmljZSgpLnN0YXR1cygpLCBudWxsLCAyKX1cXG5gKTtcbiAgICB9KTtcblxuICBjb21tYW5kXG4gICAgLmNvbW1hbmQoXCJ1bmluc3RhbGxcIilcbiAgICAuZGVzY3JpcHRpb24oXCJTdG9wIGFuZCByZW1vdmUgdGhlIHNlcnZpY2UgZm9yIHRoZSBjdXJyZW50IHVzZXJcIilcbiAgICAuYWN0aW9uKGFzeW5jICgpID0+IHtcbiAgICAgIGF3YWl0IHNlcnZpY2UoKS51bmluc3RhbGwoKTtcbiAgICB9KTtcblxuICByZXR1cm4gY29tbWFuZDtcbn1cblxuZnVuY3Rpb24gcmVzb2x2ZURlZmluaXRpb24oc291cmNlOiBDbGlTZXJ2aWNlRGVmaW5pdGlvblNvdXJjZSk6ICgpID0+IENsaVNlcnZpY2VEZWZpbml0aW9uIHtcbiAgcmV0dXJuIHR5cGVvZiBzb3VyY2UgPT09IFwiZnVuY3Rpb25cIiA/IHNvdXJjZSA6ICgpID0+IHNvdXJjZTtcbn1cbiJdfQ==
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Serializable configuration for a system-tray CLI service.
3
+ *
4
+ * @module
5
+ */
6
+ import { z } from "zod";
7
+ /** A process launched by the system-tray service host. */
8
+ export declare const CliServiceCommandSchema: z.ZodReadonly<z.ZodObject<{
9
+ executable: z.ZodOptional<z.ZodString>;
10
+ entrypoint: z.ZodOptional<z.ZodString>;
11
+ binName: z.ZodOptional<z.ZodString>;
12
+ arguments: z.ZodOptional<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
13
+ environment: z.ZodOptional<z.ZodReadonly<z.ZodRecord<z.ZodString, z.ZodString>>>;
14
+ cwd: z.ZodOptional<z.ZodString>;
15
+ }, z.core.$strip>>;
16
+ /** A process launched by the system-tray service host. */
17
+ export type CliServiceCommand = z.infer<typeof CliServiceCommandSchema>;
18
+ /** A typed custom item inserted between the default service title and Quit item. */
19
+ export declare const CliServiceMenuItemSchema: z.ZodDiscriminatedUnion<[z.ZodReadonly<z.ZodObject<{
20
+ type: z.ZodLiteral<"separator">;
21
+ }, z.core.$strip>>, z.ZodReadonly<z.ZodObject<{
22
+ type: z.ZodLiteral<"url">;
23
+ label: z.ZodString;
24
+ url: z.ZodString;
25
+ }, z.core.$strip>>, z.ZodReadonly<z.ZodObject<{
26
+ type: z.ZodLiteral<"command">;
27
+ label: z.ZodString;
28
+ command: z.ZodReadonly<z.ZodObject<{
29
+ executable: z.ZodOptional<z.ZodString>;
30
+ entrypoint: z.ZodOptional<z.ZodString>;
31
+ binName: z.ZodOptional<z.ZodString>;
32
+ arguments: z.ZodOptional<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
33
+ environment: z.ZodOptional<z.ZodReadonly<z.ZodRecord<z.ZodString, z.ZodString>>>;
34
+ cwd: z.ZodOptional<z.ZodString>;
35
+ }, z.core.$strip>>;
36
+ }, z.core.$strip>>], "type">;
37
+ /** A typed custom item inserted between the default service title and Quit item. */
38
+ export type CliServiceMenuItem = z.infer<typeof CliServiceMenuItemSchema>;
39
+ /** Complete serializable definition consumed by the lifecycle manager and tray host. */
40
+ export declare const CliServiceDefinitionSchema: z.ZodReadonly<z.ZodObject<{
41
+ id: z.ZodString;
42
+ name: z.ZodString;
43
+ packageName: z.ZodString;
44
+ version: z.ZodOptional<z.ZodString>;
45
+ icon: z.ZodString;
46
+ isTemplateIcon: z.ZodOptional<z.ZodBoolean>;
47
+ dataDirectory: z.ZodOptional<z.ZodString>;
48
+ command: z.ZodOptional<z.ZodReadonly<z.ZodObject<{
49
+ executable: z.ZodOptional<z.ZodString>;
50
+ entrypoint: z.ZodOptional<z.ZodString>;
51
+ binName: z.ZodOptional<z.ZodString>;
52
+ arguments: z.ZodOptional<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
53
+ environment: z.ZodOptional<z.ZodReadonly<z.ZodRecord<z.ZodString, z.ZodString>>>;
54
+ cwd: z.ZodOptional<z.ZodString>;
55
+ }, z.core.$strip>>>;
56
+ menu: z.ZodOptional<z.ZodReadonly<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodReadonly<z.ZodObject<{
57
+ type: z.ZodLiteral<"separator">;
58
+ }, z.core.$strip>>, z.ZodReadonly<z.ZodObject<{
59
+ type: z.ZodLiteral<"url">;
60
+ label: z.ZodString;
61
+ url: z.ZodString;
62
+ }, z.core.$strip>>, z.ZodReadonly<z.ZodObject<{
63
+ type: z.ZodLiteral<"command">;
64
+ label: z.ZodString;
65
+ command: z.ZodReadonly<z.ZodObject<{
66
+ executable: z.ZodOptional<z.ZodString>;
67
+ entrypoint: z.ZodOptional<z.ZodString>;
68
+ binName: z.ZodOptional<z.ZodString>;
69
+ arguments: z.ZodOptional<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
70
+ environment: z.ZodOptional<z.ZodReadonly<z.ZodRecord<z.ZodString, z.ZodString>>>;
71
+ cwd: z.ZodOptional<z.ZodString>;
72
+ }, z.core.$strip>>;
73
+ }, z.core.$strip>>], "type">>>>;
74
+ }, z.core.$strip>>;
75
+ /** Complete serializable definition consumed by the lifecycle manager and tray host. */
76
+ export type CliServiceDefinition = z.infer<typeof CliServiceDefinitionSchema>;
77
+ /** Package-derived service fields plus caller-owned icon, process, and menu options. */
78
+ export type CliServiceDefinitionOptions = Omit<CliServiceDefinition, "packageName" | "id" | "name" | "version"> & Partial<Pick<CliServiceDefinition, "id" | "name" | "version">>;
79
+ /** Define a service from an owning module URL or installed package name. */
80
+ export declare function defineService(packageReference: string, options: CliServiceDefinitionOptions): CliServiceDefinition;
81
+ /** Resolve a package's single or explicitly named executable entrypoint. */
82
+ export declare function resolveServicePackageBin(packageReference: string, binName?: string): string;
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Serializable configuration for a system-tray CLI service.
3
+ *
4
+ * @module
5
+ */
6
+ import { z } from "zod";
7
+ import { resolveServicePackage, servicePackageDefaults } from "./_package.js";
8
+ const SAFE_URL_PROTOCOLS = new Set(["http:", "https:", "mailto:"]);
9
+ function isSafeUrl(value) {
10
+ try {
11
+ return SAFE_URL_PROTOCOLS.has(new URL(value).protocol);
12
+ }
13
+ catch {
14
+ return false;
15
+ }
16
+ }
17
+ /** A process launched by the system-tray service host. */
18
+ export const CliServiceCommandSchema = z
19
+ .object({
20
+ executable: z.string().min(1).optional(),
21
+ entrypoint: z.string().min(1).optional(),
22
+ binName: z.string().min(1).optional(),
23
+ arguments: z.array(z.string()).readonly().optional(),
24
+ environment: z.record(z.string(), z.string()).readonly().optional(),
25
+ cwd: z.string().min(1).optional(),
26
+ })
27
+ .superRefine((command, context) => {
28
+ if (Number(command.executable !== undefined) +
29
+ Number(command.entrypoint !== undefined) +
30
+ Number(command.binName !== undefined) >
31
+ 1) {
32
+ context.addIssue({
33
+ code: "custom",
34
+ message: "command accepts at most one of executable, entrypoint, or binName",
35
+ });
36
+ }
37
+ })
38
+ .readonly();
39
+ /** A typed custom item inserted between the default service title and Quit item. */
40
+ export const CliServiceMenuItemSchema = z.discriminatedUnion("type", [
41
+ z.object({ type: z.literal("separator") }).readonly(),
42
+ z
43
+ .object({
44
+ type: z.literal("url"),
45
+ label: z.string().min(1),
46
+ url: z.string().refine(isSafeUrl, "URL must use HTTP, HTTPS, or mailto"),
47
+ })
48
+ .readonly(),
49
+ z
50
+ .object({
51
+ type: z.literal("command"),
52
+ label: z.string().min(1),
53
+ command: CliServiceCommandSchema,
54
+ })
55
+ .readonly(),
56
+ ]);
57
+ /** Complete serializable definition consumed by the lifecycle manager and tray host. */
58
+ export const CliServiceDefinitionSchema = z
59
+ .object({
60
+ id: z
61
+ .string()
62
+ .min(1)
63
+ .max(128)
64
+ .regex(/^[a-z0-9][a-z0-9._-]*$/, "service id must be filesystem safe"),
65
+ name: z.string().min(1),
66
+ packageName: z.string().min(1),
67
+ version: z.string().min(1).optional(),
68
+ icon: z.string().min(1),
69
+ isTemplateIcon: z.boolean().optional(),
70
+ dataDirectory: z.string().min(1).optional(),
71
+ command: CliServiceCommandSchema.optional(),
72
+ menu: z.array(CliServiceMenuItemSchema).readonly().optional(),
73
+ })
74
+ .readonly();
75
+ /** Define a service from an owning module URL or installed package name. */
76
+ export function defineService(packageReference, options) {
77
+ const pkg = resolveServicePackage(packageReference);
78
+ const defaults = servicePackageDefaults(pkg);
79
+ return CliServiceDefinitionSchema.parse({
80
+ ...options,
81
+ packageName: pkg.name,
82
+ id: options.id ?? defaults.id,
83
+ name: options.name ?? defaults.name,
84
+ version: options.version ?? pkg.version,
85
+ });
86
+ }
87
+ /** Resolve a package's single or explicitly named executable entrypoint. */
88
+ export function resolveServicePackageBin(packageReference, binName) {
89
+ return resolveServicePackage(packageReference).bin(binName);
90
+ }
91
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVmaW5pdGlvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9kZWZpbml0aW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7O0dBSUc7QUFFSCxPQUFPLEVBQUUsQ0FBQyxFQUFFLE1BQU0sS0FBSyxDQUFDO0FBRXhCLE9BQU8sRUFBRSxxQkFBcUIsRUFBRSxzQkFBc0IsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUU5RSxNQUFNLGtCQUFrQixHQUFHLElBQUksR0FBRyxDQUFDLENBQUMsT0FBTyxFQUFFLFFBQVEsRUFBRSxTQUFTLENBQUMsQ0FBQyxDQUFDO0FBRW5FLFNBQVMsU0FBUyxDQUFDLEtBQWE7SUFDOUIsSUFBSSxDQUFDO1FBQ0gsT0FBTyxrQkFBa0IsQ0FBQyxHQUFHLENBQUMsSUFBSSxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDekQsQ0FBQztJQUFDLE1BQU0sQ0FBQztRQUNQLE9BQU8sS0FBSyxDQUFDO0lBQ2YsQ0FBQztBQUNILENBQUM7QUFFRCwwREFBMEQ7QUFDMUQsTUFBTSxDQUFDLE1BQU0sdUJBQXVCLEdBQUcsQ0FBQztLQUNyQyxNQUFNLENBQUM7SUFDTixVQUFVLEVBQUUsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxRQUFRLEVBQUU7SUFDeEMsVUFBVSxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsUUFBUSxFQUFFO0lBQ3hDLE9BQU8sRUFBRSxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLFFBQVEsRUFBRTtJQUNyQyxTQUFTLEVBQUUsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxRQUFRLEVBQUU7SUFDcEQsV0FBVyxFQUFFLENBQUMsQ0FBQyxN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QUFFO0NBQzlELENBQUM7S0FDRCxRQUFRLEVBQUUsQ0FBQztBQVlkLDRFQUE0RTtBQUM1RSxNQUFNLFVBQVUsYUFBYSxDQUMzQixnQkFBd0IsRUFDeEIsT0FBb0M7SUFFcEMsTUFBTSxHQUFHLEdBQUcscUJBQXFCLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztJQUNwRCxNQUFNLFFBQVEsR0FBRyxzQkFBc0IsQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUM3QyxPQUFPLDBCQUEwQixDQUFDLEtBQUssQ0FBQztRQUN0QyxHQUFHLE9BQU87UUFDVixXQUFXLEVBQUUsR0FBRyxDQUFDLElBQUk7UUFDckIsRUFBRSxFQUFFLE9BQU8sQ0FBQyxFQUFFLElBQUksUUFBUSxDQUFDLEVBQUU7UUFDN0IsSUFBSSxFQUFFLE9BQU8sQ0FBQyxJQUFJLElBQUksUUFBUSxDQUFDLElBQUk7UUFDbkMsT0FBTyxFQUFFLE9BQU8sQ0FBQyxPQUFPLElBQUksR0FBRyxDQUFDLE9BQU87S0FDeEMsQ0FBQyxDQUFDO0FBQ0wsQ0FBQztBQUVELDRFQUE0RTtBQUM1RSxNQUFNLFVBQVUsd0JBQXdCLENBQUMsZ0JBQXdCLEVBQUUsT0FBZ0I7SUFDakYsT0FBTyxxQkFBcUIsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQztBQUM5RCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBTZXJpYWxpemFibGUgY29uZmlndXJhdGlvbiBmb3IgYSBzeXN0ZW0tdHJheSBDTEkgc2VydmljZS5cbiAqXG4gKiBAbW9kdWxlXG4gKi9cblxuaW1wb3J0IHsgeiB9IGZyb20gXCJ6b2RcIjtcblxuaW1wb3J0IHsgcmVzb2x2ZVNlcnZpY2VQYWNrYWdlLCBzZXJ2aWNlUGFja2FnZURlZmF1bHRzIH0gZnJvbSBcIi4vX3BhY2thZ2UudHNcIjtcblxuY29uc3QgU0FGRV9VUkxfUFJPVE9DT0xTID0gbmV3IFNldChbXCJodHRwOlwiLCBcImh0dHBzOlwiLCBcIm1haWx0bzpcIl0pO1xuXG5mdW5jdGlvbiBpc1NhZmVVcmwodmFsdWU6IHN0cmluZyk6IGJvb2xlYW4ge1xuICB0cnkge1xuICAgIHJldHVybiBTQUZFX1VSTF9QUk9UT0NPTFMuaGFzKG5ldyBVUkwodmFsdWUpLnByb3RvY29sKTtcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG59XG5cbi8qKiBBIHByb2Nlc3MgbGF1bmNoZWQgYnkgdGhlIHN5c3RlbS10cmF5IHNlcnZpY2UgaG9zdC4gKi9cbmV4cG9ydCBjb25zdCBDbGlTZXJ2aWNlQ29tbWFuZFNjaGVtYSA9IHpcbiAgLm9iamVjdCh7XG4gICAgZXhlY3V0YWJsZTogei5zdHJpbmcoKS5taW4oMSkub3B0aW9uYWwoKSxcbiAgICBlbnRyeXBvaW50OiB6LnN0cmluZygpLm1pbigxKS5vcHRpb25hbCgpLFxuICAgIGJpbk5hbWU6IHouc3RyaW5nKCkubWluKDEpLm9wdGlvbmFsKCksXG4gICAgYXJndW1lbnRzOiB6LmFycmF5KHouc3RyaW5nKCkpLnJlYWRvbmx5KCkub3B0aW9uYWwoKSxcbiAgICBlbnZpcm9ubWVudDogei5yZWNvcmQoei5zdHJpbmcoKSwgei5zdHJpbmcoKSkucmVhZG9ubHkoKS5vcHRpb25hbCgpLFxuICAgIGN3ZDogei5zdHJpbmcoKS5taW4oMSkub3B0aW9uYWwoKSxcbiAgfSlcbiAgLnN1cGVyUmVmaW5lKChjb21tYW5kLCBjb250ZXh0KSA9PiB7XG4gICAgaWYgKFxuICAgICAgTnVtYmVyKGNvbW1hbmQuZXhlY3V0YWJsZSAhPT0gdW5kZWZpbmVkKSArXG4gICAgICAgIE51bWJlcihjb21tYW5kLmVudHJ5cG9pbnQgIT09IHVuZGVmaW5lZCkgK1xuICAgICAgICBOdW1iZXIoY29tbWFuZC5iaW5OYW1lICE9PSB1bmRlZmluZWQpID5cbiAgICAgIDFcbiAgICApIHtcbiAgICAgIGNvbnRleHQuYWRkSXNzdWUoe1xuICAgICAgICBjb2RlOiBcImN1c3RvbVwiLFxuICAgICAgICBtZXNzYWdlOiBcImNvbW1hbmQgYWNjZXB0cyBhdCBtb3N0IG9uZSBvZiBleGVjdXRhYmxlLCBlbnRyeXBvaW50LCBvciBiaW5OYW1lXCIsXG4gICAgICB9KTtcbiAgICB9XG4gIH0pXG4gIC5yZWFkb25seSgpO1xuXG4vKiogQSBwcm9jZXNzIGxhdW5jaGVkIGJ5IHRoZSBzeXN0ZW0tdHJheSBzZXJ2aWNlIGhvc3QuICovXG5leHBvcnQgdHlwZSBDbGlTZXJ2aWNlQ29tbWFuZCA9IHouaW5mZXI8dHlwZW9mIENsaVNlcnZpY2VDb21tYW5kU2NoZW1hPjtcblxuLyoqIEEgdHlwZWQgY3VzdG9tIGl0ZW0gaW5zZXJ0ZWQgYmV0d2VlbiB0aGUgZGVmYXVsdCBzZXJ2aWNlIHRpdGxlIGFuZCBRdWl0IGl0ZW0uICovXG5leHBvcnQgY29uc3QgQ2xpU2VydmljZU1lbnVJdGVtU2NoZW1hID0gei5kaXNjcmltaW5hdGVkVW5pb24oXCJ0eXBlXCIsIFtcbiAgei5vYmplY3QoeyB0eXBlOiB6LmxpdGVyYWwoXCJzZXBhcmF0b3JcIikgfSkucmVhZG9ubHkoKSxcbiAgelxuICAgIC5vYmplY3Qoe1xuICAgICAgdHlwZTogei5saXRlcmFsKFwidXJsXCIpLFxuICAgICAgbGFiZWw6IHouc3RyaW5nKCkubWluKDEpLFxuICAgICAgdXJsOiB6LnN0cmluZygpLnJlZmluZShpc1NhZmVVcmwsIFwiVVJMIG11c3QgdXNlIEhUVFAsIEhUVFBTLCBvciBtYWlsdG9cIiksXG4gICAgfSlcbiAgICAucmVhZG9ubHkoKSxcbiAgelxuICAgIC5vYmplY3Qoe1xuICAgICAgdHlwZTogei5saXRlcmFsKFwiY29tbWFuZFwiKSxcbiAgICAgIGxhYmVsOiB6LnN0cmluZygpLm1pbigxKSxcbiAgICAgIGNvbW1hbmQ6IENsaVNlcnZpY2VDb21tYW5kU2NoZW1hLFxuICAgIH0pXG4gICAgLnJlYWRvbmx5KCksXG5dKTtcblxuLyoqIEEgdHlwZWQgY3VzdG9tIGl0ZW0gaW5zZXJ0ZWQgYmV0d2VlbiB0aGUgZGVmYXVsdCBzZXJ2aWNlIHRpdGxlIGFuZCBRdWl0IGl0ZW0uICovXG5leHBvcnQgdHlwZSBDbGlTZXJ2aWNlTWVudUl0ZW0gPSB6LmluZmVyPHR5cGVvZiBDbGlTZXJ2aWNlTWVudUl0ZW1TY2hlbWE+O1xuXG4vKiogQ29tcGxldGUgc2VyaWFsaXphYmxlIGRlZmluaXRpb24gY29uc3VtZWQgYnkgdGhlIGxpZmVjeWNsZSBtYW5hZ2VyIGFuZCB0cmF5IGhvc3QuICovXG5leHBvcnQgY29uc3QgQ2xpU2VydmljZURlZmluaXRpb25TY2hlbWEgPSB6XG4gIC5vYmplY3Qoe1xuICAgIGlkOiB6XG4gICAgICAuc3RyaW5nKClcbiAgICAgIC5taW4oMSlcbiAgICAgIC5tYXgoMTI4KVxuICAgICAgLnJlZ2V4KC9eW2EtejAtOV1bYS16MC05Ll8tXSokLywgXCJzZXJ2aWNlIGlkIG11c3QgYmUgZmlsZXN5c3RlbSBzYWZlXCIpLFxuICAgIG5hbWU6IHouc3RyaW5nKCkubWluKDEpLFxuICAgIHBhY2thZ2VOYW1lOiB6LnN0cmluZygpLm1pbigxKSxcbiAgICB2ZXJzaW9uOiB6LnN0cmluZygpLm1pbigxKS5vcHRpb25hbCgpLFxuICAgIGljb246IHouc3RyaW5nKCkubWluKDEpLFxuICAgIGlzVGVtcGxhdGVJY29uOiB6LmJvb2xlYW4oKS5vcHRpb25hbCgpLFxuICAgIGRhdGFEaXJlY3Rvcnk6IHouc3RyaW5nKCkubWluKDEpLm9wdGlvbmFsKCksXG4gICAgY29tbWFuZDogQ2xpU2VydmljZUNvbW1hbmRTY2hlbWEub3B0aW9uYWwoKSxcbiAgICBtZW51OiB6LmFycmF5KENsaVNlcnZpY2VNZW51SXRlbVNjaGVtYSkucmVhZG9ubHkoKS5vcHRpb25hbCgpLFxuICB9KVxuICAucmVhZG9ubHkoKTtcblxuLyoqIENvbXBsZXRlIHNlcmlhbGl6YWJsZSBkZWZpbml0aW9uIGNvbnN1bWVkIGJ5IHRoZSBsaWZlY3ljbGUgbWFuYWdlciBhbmQgdHJheSBob3N0LiAqL1xuZXhwb3J0IHR5cGUgQ2xpU2VydmljZURlZmluaXRpb24gPSB6LmluZmVyPHR5cGVvZiBDbGlTZXJ2aWNlRGVmaW5pdGlvblNjaGVtYT47XG5cbi8qKiBQYWNrYWdlLWRlcml2ZWQgc2VydmljZSBmaWVsZHMgcGx1cyBjYWxsZXItb3duZWQgaWNvbiwgcHJvY2VzcywgYW5kIG1lbnUgb3B0aW9ucy4gKi9cbmV4cG9ydCB0eXBlIENsaVNlcnZpY2VEZWZpbml0aW9uT3B0aW9ucyA9IE9taXQ8XG4gIENsaVNlcnZpY2VEZWZpbml0aW9uLFxuICBcInBhY2thZ2VOYW1lXCIgfCBcImlkXCIgfCBcIm5hbWVcIiB8IFwidmVyc2lvblwiXG4+ICZcbiAgUGFydGlhbDxQaWNrPENsaVNlcnZpY2VEZWZpbml0aW9uLCBcImlkXCIgfCBcIm5hbWVcIiB8IFwidmVyc2lvblwiPj47XG5cbi8qKiBEZWZpbmUgYSBzZXJ2aWNlIGZyb20gYW4gb3duaW5nIG1vZHVsZSBVUkwgb3IgaW5zdGFsbGVkIHBhY2thZ2UgbmFtZS4gKi9cbmV4cG9ydCBmdW5jdGlvbiBkZWZpbmVTZXJ2aWNlKFxuICBwYWNrYWdlUmVmZXJlbmNlOiBzdHJpbmcsXG4gIG9wdGlvbnM6IENsaVNlcnZpY2VEZWZpbml0aW9uT3B0aW9ucyxcbik6IENsaVNlcnZpY2VEZWZpbml0aW9uIHtcbiAgY29uc3QgcGtnID0gcmVzb2x2ZVNlcnZpY2VQYWNrYWdlKHBhY2thZ2VSZWZlcmVuY2UpO1xuICBjb25zdCBkZWZhdWx0cyA9IHNlcnZpY2VQYWNrYWdlRGVmYXVsdHMocGtnKTtcbiAgcmV0dXJuIENsaVNlcnZpY2VEZWZpbml0aW9uU2NoZW1hLnBhcnNlKHtcbiAgICAuLi5vcHRpb25zLFxuICAgIHBhY2thZ2VOYW1lOiBwa2cubmFtZSxcbiAgICBpZDogb3B0aW9ucy5pZCA/PyBkZWZhdWx0cy5pZCxcbiAgICBuYW1lOiBvcHRpb25zLm5hbWUgPz8gZGVmYXVsdHMubmFtZSxcbiAgICB2ZXJzaW9uOiBvcHRpb25zLnZlcnNpb24gPz8gcGtnLnZlcnNpb24sXG4gIH0pO1xufVxuXG4vKiogUmVzb2x2ZSBhIHBhY2thZ2UncyBzaW5nbGUgb3IgZXhwbGljaXRseSBuYW1lZCBleGVjdXRhYmxlIGVudHJ5cG9pbnQuICovXG5leHBvcnQgZnVuY3Rpb24gcmVzb2x2ZVNlcnZpY2VQYWNrYWdlQmluKHBhY2thZ2VSZWZlcmVuY2U6IHN0cmluZywgYmluTmFtZT86IHN0cmluZyk6IHN0cmluZyB7XG4gIHJldHVybiByZXNvbHZlU2VydmljZVBhY2thZ2UocGFja2FnZVJlZmVyZW5jZSkuYmluKGJpbk5hbWUpO1xufVxuIl19
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Install, start, stop, and inspect a system-tray user service.
3
+ *
4
+ * @module
5
+ */
6
+ import { type CliServiceDefinition } from "./definition.ts";
7
+ /** Compile one TypeScript or JavaScript entrypoint into a standalone executable. */
8
+ export type CliServiceCompiler = (entrypoint: string, output: string, workingDirectory: string, external?: readonly string[]) => Promise<void>;
9
+ /** Install exact external runtime dependencies into the dbx-tools home. */
10
+ export type CliServiceRuntimeInstaller = (bunExecutable: string, directory: string, dependencies: Readonly<Record<string, string>>) => Promise<void>;
11
+ /** Host runtime overrides for tests, embedded distributions, and nonstandard homes. */
12
+ export interface CliServiceRuntimeOptions {
13
+ /** Operating system used for configuration and startup registration. */
14
+ readonly platform?: NodeJS.Platform;
15
+ /** Environment used to locate platform configuration directories. */
16
+ readonly environment?: Readonly<NodeJS.ProcessEnv>;
17
+ /** Home directory used when platform environment variables are absent. */
18
+ readonly homeDirectory?: string;
19
+ /** Temporary directory used for the local control socket. */
20
+ readonly temporaryDirectory?: string;
21
+ /** Shared dbx-tools home containing installed service binaries. */
22
+ readonly globalHomeDirectory?: string;
23
+ /** Package-provided Bun executable override. */
24
+ readonly bunExecutable?: string;
25
+ /** Standalone compiler override. */
26
+ readonly compile?: CliServiceCompiler;
27
+ /** External runtime dependency installer override. */
28
+ readonly installRuntime?: CliServiceRuntimeInstaller;
29
+ /** System-tray host source entrypoint override. */
30
+ readonly hostEntrypoint?: string;
31
+ /** systray2 native executable override. */
32
+ readonly trayExecutable?: string;
33
+ }
34
+ /** Options controlling service installation. */
35
+ export interface CliServiceInstallOptions {
36
+ /** Start the service immediately after writing its configuration and login entry. */
37
+ readonly start?: boolean;
38
+ }
39
+ /** Current installation and process state for a system-tray service. */
40
+ export interface CliServiceStatus {
41
+ /** Whether the serialized service definition exists. */
42
+ readonly installed: boolean;
43
+ /** Whether the tray host answered its local control socket. */
44
+ readonly running: boolean;
45
+ /** Tray host process ID when running. */
46
+ readonly pid?: number;
47
+ /** Managed child process ID when the definition includes a command. */
48
+ readonly servicePid?: number;
49
+ }
50
+ /** Lifecycle contract consumed by CLI command builders. */
51
+ export interface CliServiceLifecycle {
52
+ /** Install the login entry and optionally start the service. */
53
+ install(options?: CliServiceInstallOptions): Promise<void>;
54
+ /** Start the installed service when it is not already running. */
55
+ start(): Promise<void>;
56
+ /** Stop the running tray host and its managed child process. */
57
+ stop(): Promise<void>;
58
+ /** Stop and start the installed service. */
59
+ restart(): Promise<void>;
60
+ /** Stop the service and remove its login entry and package-owned state. */
61
+ uninstall(): Promise<void>;
62
+ /** Read the current installation and process state. */
63
+ status(): Promise<CliServiceStatus>;
64
+ }
65
+ /** Cross-platform lifecycle manager for one system-tray user service. */
66
+ export declare class CliService implements CliServiceLifecycle {
67
+ readonly definition: CliServiceDefinition;
68
+ private readonly runtime;
69
+ private readonly globalHomeDirectory;
70
+ private readonly bunExecutable;
71
+ private readonly compiler;
72
+ private readonly runtimeInstaller;
73
+ private readonly hostEntrypoint;
74
+ private readonly trayExecutable;
75
+ /**
76
+ * Create a lifecycle manager from a serializable definition.
77
+ *
78
+ * @param definition Product-owned service metadata, process, and menu.
79
+ * @param options Host runtime overrides.
80
+ */
81
+ constructor(definition: CliServiceDefinition, options?: CliServiceRuntimeOptions);
82
+ /** Install the login entry and optionally start the service. */
83
+ install(options?: CliServiceInstallOptions): Promise<void>;
84
+ /** Start the installed service when it is not already running. */
85
+ start(): Promise<void>;
86
+ /** Stop the running tray host and its managed child process. */
87
+ stop(): Promise<void>;
88
+ /** Stop and start the installed service. */
89
+ restart(): Promise<void>;
90
+ /** Stop the service and remove its login entry and package-owned state. */
91
+ uninstall(): Promise<void>;
92
+ /** Read the current installation and process state. */
93
+ status(): Promise<CliServiceStatus>;
94
+ private launch;
95
+ private installDefinition;
96
+ private installCommand;
97
+ private ensureCompiledBinary;
98
+ private ensureTrayBinary;
99
+ private binaryContext;
100
+ private binaryName;
101
+ }