@jiayunxie/aerial 0.2.1 → 0.2.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.
Files changed (63) hide show
  1. package/README.md +1 -1
  2. package/docs/usage.md +2 -2
  3. package/package.json +5 -5
  4. package/src/cli/args.js +28 -0
  5. package/src/cli/config-command.js +39 -0
  6. package/src/cli/disable-command.js +28 -0
  7. package/src/{doctor.js → cli/doctor.js} +3 -3
  8. package/src/cli/help.js +23 -0
  9. package/src/cli/index.js +92 -0
  10. package/src/cli/key-command.js +20 -0
  11. package/src/cli/login-command.js +28 -0
  12. package/src/{model-selection.js → cli/model-selection.js} +5 -5
  13. package/src/cli/output.js +75 -0
  14. package/src/{probe.js → cli/probe.js} +3 -3
  15. package/src/cli/proxy-command.js +120 -0
  16. package/src/cli/runtime-auth.js +21 -0
  17. package/src/cli/service-command.js +120 -0
  18. package/src/cli/setup-command.js +122 -0
  19. package/src/{setup-selection.js → cli/setup-selection.js} +3 -20
  20. package/src/cli/start-command.js +11 -0
  21. package/src/cli/status-command.js +26 -0
  22. package/src/{version.js → cli/version.js} +1 -1
  23. package/src/proxy/cache-policy.js +89 -0
  24. package/src/proxy/cache-telemetry.js +172 -0
  25. package/src/proxy/effort.js +120 -0
  26. package/src/proxy/headers.js +33 -0
  27. package/src/proxy/index.js +85 -0
  28. package/src/proxy/models.js +27 -0
  29. package/src/{responses-websocket.js → proxy/responses-websocket.js} +2 -2
  30. package/src/{server.js → proxy/server.js} +5 -5
  31. package/src/proxy/transport.js +55 -0
  32. package/src/service/health.js +54 -0
  33. package/src/service/index.js +38 -0
  34. package/src/service/lifecycle.js +301 -0
  35. package/src/service/platform.js +227 -0
  36. package/src/service/runner.js +45 -0
  37. package/src/service/status.js +296 -0
  38. package/src/service/wrapper-render.js +228 -0
  39. package/src/setup/backup.js +38 -0
  40. package/src/{setup.js → setup/clients.js} +11 -198
  41. package/src/setup/index.js +4 -0
  42. package/src/setup/restore.js +90 -0
  43. package/src/setup/status.js +24 -0
  44. package/src/setup/toml.js +41 -0
  45. package/src/{auth.js → shared/auth.js} +1 -1
  46. package/src/{config.js → shared/config.js} +2 -2
  47. package/src/shared/effort.js +19 -0
  48. package/src/shared/file-utils.js +31 -0
  49. package/src/{paths.js → shared/paths.js} +2 -3
  50. package/src/{upstream-fetch.js → upstream/fetch.js} +1 -1
  51. package/src/cli.js +0 -684
  52. package/src/copilot.js +0 -572
  53. package/src/service.js +0 -1182
  54. /package/src/{app-status.js → cli/app-status.js} +0 -0
  55. /package/src/{model-catalog.js → proxy/model-catalog.js} +0 -0
  56. /package/src/{model-utils.js → proxy/model-utils.js} +0 -0
  57. /package/src/{constants.js → shared/constants.js} +0 -0
  58. /package/src/{crypto.js → shared/crypto.js} +0 -0
  59. /package/src/{http-utils.js → shared/http-utils.js} +0 -0
  60. /package/src/{log.js → shared/log.js} +0 -0
  61. /package/src/{prompt-utils.js → shared/prompt-utils.js} +0 -0
  62. /package/src/{proxy-config.js → upstream/proxy-config.js} +0 -0
  63. /package/src/{socks5-bridge.js → upstream/socks5-bridge.js} +0 -0
@@ -0,0 +1,120 @@
1
+ import { loadConfig } from "../shared/config.js";
2
+ import { logEvent } from "../shared/log.js";
3
+ import { canonicalClaudeFamily, findCompatibleModel as findCompatibleModelShared } from "./model-catalog.js";
4
+ import { withDefaultAnthropicCache, withDefaultPromptCache } from "./cache-policy.js";
5
+
6
+ function normalizeProxyEffort(effort) {
7
+ return effort === "max" ? "xhigh" : effort;
8
+ }
9
+
10
+ function openAIEffortRoute(model, effort) {
11
+ if (effort === undefined) return undefined;
12
+ const normalized = normalizeProxyEffort(effort);
13
+ if (/^gpt-5-mini(?:-|$)/.test(model) && normalized === "xhigh") return "high";
14
+ if (normalized !== effort) return normalized;
15
+ return undefined;
16
+ }
17
+
18
+ function withSupportedOpenAIEffort(payload) {
19
+ const model = typeof payload?.model === "string" ? payload.model : "";
20
+ const reasoningEffort = payload?.reasoning && typeof payload.reasoning === "object" ? payload.reasoning.effort : undefined;
21
+ const nextReasoningEffort = openAIEffortRoute(model, reasoningEffort);
22
+ const nextFlatEffort = openAIEffortRoute(model, payload?.reasoning_effort);
23
+ if (!nextReasoningEffort && !nextFlatEffort) return payload;
24
+
25
+ const next = { ...payload };
26
+ if (nextReasoningEffort) next.reasoning = { ...payload.reasoning, effort: nextReasoningEffort };
27
+ if (nextFlatEffort) next.reasoning_effort = nextFlatEffort;
28
+ logEvent("openai_effort_route", {
29
+ model,
30
+ effort: reasoningEffort ?? payload?.reasoning_effort,
31
+ routedEffort: nextReasoningEffort ?? nextFlatEffort
32
+ });
33
+ return next;
34
+ }
35
+
36
+ export function withOpenAIDefaults(payload) {
37
+ return withDefaultPromptCache(withSupportedOpenAIEffort(payload));
38
+ }
39
+
40
+ function objectOrEmpty(value) {
41
+ return value && typeof value === "object" && !Array.isArray(value) ? value : {};
42
+ }
43
+
44
+ function withSupportedAnthropicEffort(payload, models) {
45
+ const effort = payload?.output_config?.effort;
46
+ if (effort === undefined) return payload;
47
+ const model = typeof payload?.model === "string" ? payload.model : "";
48
+ const family = canonicalClaudeFamily(model);
49
+ if (!family) return payload;
50
+ const nextEffort = normalizeProxyEffort(effort);
51
+ if (!["low", "medium", "high", "xhigh"].includes(nextEffort)) return payload;
52
+ const routed = findCompatibleModelShared({
53
+ models,
54
+ family,
55
+ route: "/v1/messages",
56
+ adaptiveThinking: true,
57
+ effort: nextEffort,
58
+ preferredId: model
59
+ });
60
+ const nextModel = routed?.id || model;
61
+ if (model === nextModel && effort === nextEffort) return payload;
62
+ logEvent("anthropic_effort_route", { model, effort, routedModel: nextModel, routedEffort: nextEffort });
63
+ return { ...payload, model: nextModel, output_config: { ...payload.output_config, effort: nextEffort } };
64
+ }
65
+
66
+ function legacyThinkingEffort(thinking) {
67
+ if (typeof thinking?.effort === "string" && thinking.effort.trim()) return thinking.effort.trim();
68
+ const budget = Number(thinking?.budget_tokens);
69
+ if (!Number.isFinite(budget) || budget <= 0) return "medium";
70
+ if (budget <= 4096) return "low";
71
+ if (budget <= 16000) return "medium";
72
+ if (budget <= 64000) return "high";
73
+ return "xhigh";
74
+ }
75
+
76
+ function isLegacyThinkingEnabled(thinking) {
77
+ if (!thinking || typeof thinking !== "object" || Array.isArray(thinking)) return false;
78
+ if (thinking.type === "enabled") return true;
79
+ return Boolean(thinking.type && typeof thinking.type === "object" && thinking.type.enabled);
80
+ }
81
+
82
+ function withSupportedAnthropicThinking(payload) {
83
+ if (!isLegacyThinkingEnabled(payload?.thinking)) return payload;
84
+ const outputConfig = objectOrEmpty(payload?.output_config);
85
+ const effort = outputConfig.effort ?? legacyThinkingEffort(payload.thinking);
86
+ logEvent("anthropic_thinking_route", { model: payload.model, routedType: "adaptive", routedEffort: effort });
87
+ return {
88
+ ...payload,
89
+ thinking: { type: "adaptive" },
90
+ output_config: { ...outputConfig, effort }
91
+ };
92
+ }
93
+
94
+ function shouldLoadAnthropicCatalog(payload) {
95
+ const effort = payload?.output_config?.effort;
96
+ const model = typeof payload?.model === "string" ? payload.model : "";
97
+ return effort !== undefined && Boolean(canonicalClaudeFamily(model));
98
+ }
99
+
100
+ function withDefaultAnthropicEffort(payload) {
101
+ if (payload?.output_config?.effort !== undefined) return payload;
102
+ if (payload?.thinking?.type === "adaptive") return payload;
103
+ const model = typeof payload?.model === "string" ? payload.model : "";
104
+ if (!canonicalClaudeFamily(model)) return payload;
105
+ const config = loadConfig();
106
+ const effort = config.defaultEffort || "medium";
107
+ const outputConfig = objectOrEmpty(payload?.output_config);
108
+ logEvent("anthropic_default_effort", { model, effort });
109
+ return { ...payload, output_config: { ...outputConfig, effort } };
110
+ }
111
+
112
+ export async function withAnthropicDefaults(payload, loadModels) {
113
+ const cached = withDefaultAnthropicCache(payload);
114
+ const thinkingApplied = withSupportedAnthropicThinking(cached);
115
+ const next = withDefaultAnthropicEffort(thinkingApplied);
116
+ const models = shouldLoadAnthropicCatalog(next)
117
+ ? await loadModels().catch(() => undefined)
118
+ : undefined;
119
+ return withSupportedAnthropicEffort(next, models);
120
+ }
@@ -0,0 +1,33 @@
1
+ import crypto from "node:crypto";
2
+ import { loadConfig } from "../shared/config.js";
3
+
4
+ export function upstreamHeaders(token, extra = {}) {
5
+ const config = loadConfig();
6
+ const requestId = extra["x-request-id"] || crypto.randomUUID();
7
+ return {
8
+ authorization: `Bearer ${token}`,
9
+ accept: extra.accept || "application/json",
10
+ "content-type": extra["content-type"] || "application/json",
11
+ "copilot-integration-id": "vscode-chat",
12
+ "editor-device-id": config.deviceId || "aerial-local",
13
+ "editor-version": `vscode/${config.versions.vscode}`,
14
+ "editor-plugin-version": `copilot-chat/${config.versions.copilotChat}`,
15
+ "user-agent": `GitHubCopilotChat/${config.versions.copilotChat}`,
16
+ "openai-intent": "conversation-agent",
17
+ "x-github-api-version": "2026-01-09",
18
+ "x-request-id": requestId,
19
+ "x-agent-task-id": requestId,
20
+ "x-interaction-type": "conversation-agent",
21
+ "x-vscode-user-agent-library-version": "electron-fetch",
22
+ ...extra
23
+ };
24
+ }
25
+
26
+ export function copyResponseHeaders(upstream) {
27
+ const headers = new Headers();
28
+ const contentType = upstream.headers.get("content-type");
29
+ if (contentType) headers.set("content-type", contentType);
30
+ const cacheControl = upstream.headers.get("cache-control");
31
+ if (cacheControl) headers.set("cache-control", cacheControl);
32
+ return headers;
33
+ }
@@ -0,0 +1,85 @@
1
+ import { DEFAULT_ANTHROPIC_VERSION } from "../shared/constants.js";
2
+ import { getCopilotToken } from "../shared/auth.js";
3
+ import { logEvent } from "../shared/log.js";
4
+ import { isResponsesWebSocketOptIn, proxyResponsesWebSocket, shouldUseResponsesWebSocket } from "./responses-websocket.js";
5
+ import { annotateModelsResponse } from "./models.js";
6
+ import { upstreamHeaders } from "./headers.js";
7
+ import { withAnthropicDefaults, withOpenAIDefaults } from "./effort.js";
8
+ import {
9
+ cacheRequestFields,
10
+ createSseCacheObserver,
11
+ hasExplicitCacheRequest,
12
+ responseHasVision,
13
+ responseInitiator
14
+ } from "./cache-telemetry.js";
15
+ import { fetchModelsCatalogForCopilot, proxyFetch, requestWithJsonBody } from "./transport.js";
16
+
17
+ function responseModelFromCatalog(modelId, models) {
18
+ return models.find((model) => model.id === modelId);
19
+ }
20
+
21
+ export async function proxyModels(request) {
22
+ const upstreamRequest = new Request(request.url, { method: "GET", headers: request.headers });
23
+ return annotateModelsResponse(await proxyFetch("/models", upstreamRequest));
24
+ }
25
+
26
+ export async function proxyResponses(request) {
27
+ const payload = withOpenAIDefaults(await request.json());
28
+ const body = Buffer.from(JSON.stringify(payload));
29
+
30
+ if (payload?.stream && isResponsesWebSocketOptIn()) {
31
+ const models = await fetchModelsCatalogForCopilot().catch(() => undefined);
32
+ const model = models ? responseModelFromCatalog(payload.model, models) : undefined;
33
+ if (shouldUseResponsesWebSocket(payload, model)) {
34
+ const requestCache = cacheRequestFields(payload);
35
+ if (hasExplicitCacheRequest(requestCache)) logEvent("cache_request", { route: "/responses", ...requestCache });
36
+ const token = await getCopilotToken();
37
+ const initiator = responseInitiator(payload);
38
+ const headers = upstreamHeaders(token, {
39
+ accept: "text/event-stream",
40
+ "content-type": request.headers.get("content-type") || "application/json",
41
+ ...(responseHasVision(payload) ? { "copilot-vision-request": "true" } : {})
42
+ });
43
+ logEvent("responses_websocket", { model: payload.model });
44
+ const response = await proxyResponsesWebSocket(payload, headers, { initiator });
45
+ if (!response.body) return response;
46
+ const observer = createSseCacheObserver("/responses", requestCache);
47
+ return new Response(response.body.pipeThrough(observer), { status: response.status, headers: response.headers });
48
+ }
49
+ logEvent("responses_websocket_skip", {
50
+ model: payload.model,
51
+ reason: !model ? "model_unknown" : "model_no_ws_endpoint"
52
+ });
53
+ }
54
+
55
+ const upstreamRequest = new Request(request.url, { method: request.method, headers: request.headers, body, duplex: "half" });
56
+ return proxyFetch("/responses", upstreamRequest, { bodyOverride: body });
57
+ }
58
+
59
+ export async function proxyMessages(request) {
60
+ const extraHeaders = {
61
+ "anthropic-version": request.headers.get("anthropic-version") || DEFAULT_ANTHROPIC_VERSION
62
+ };
63
+ const beta = request.headers.get("anthropic-beta");
64
+ if (beta) extraHeaders["anthropic-beta"] = beta;
65
+ const upstreamRequest = await requestWithJsonBody(request, (payload) => withAnthropicDefaults(payload, fetchModelsCatalogForCopilot));
66
+ return proxyFetch("/v1/messages", upstreamRequest, { extraHeaders });
67
+ }
68
+
69
+ export async function proxyChatCompletions(request) {
70
+ const upstreamRequest = await requestWithJsonBody(request, (payload) => {
71
+ payload = withOpenAIDefaults(payload);
72
+ if (payload.max_tokens !== undefined && payload.max_completion_tokens === undefined) {
73
+ const { max_tokens, ...rest } = payload;
74
+ return { ...rest, max_completion_tokens: max_tokens };
75
+ }
76
+ return payload;
77
+ });
78
+ return proxyFetch("/chat/completions", upstreamRequest);
79
+ }
80
+
81
+ export async function localCountTokens(request) {
82
+ const payload = await request.json().catch(() => ({}));
83
+ const serialized = JSON.stringify(payload.messages || payload.input || payload);
84
+ return Response.json({ input_tokens: Math.ceil(serialized.length / 4) });
85
+ }
@@ -0,0 +1,27 @@
1
+ export function aerialSupportForModel(model) {
2
+ const endpoints = Array.isArray(model.supported_endpoints) ? model.supported_endpoints : [];
3
+ const routes = [];
4
+ const notes = [];
5
+ if (endpoints.includes("/responses")) routes.push("responses");
6
+ if (endpoints.includes("ws:/responses")) routes.push("responses_websocket");
7
+ if (endpoints.includes("/v1/messages")) routes.push("messages");
8
+ if (endpoints.includes("/chat/completions")) routes.push("chat");
9
+ if (model.capabilities?.type === "embeddings") notes.push("embeddings_not_implemented");
10
+ if (routes.length === 0 && notes.length === 0) notes.push("no_supported_endpoint_advertised");
11
+ return {
12
+ supported: routes.length > 0,
13
+ routes,
14
+ notes
15
+ };
16
+ }
17
+
18
+ export async function annotateModelsResponse(response) {
19
+ const contentType = response.headers.get("content-type") || "";
20
+ if (!response.ok || !contentType.includes("application/json")) return response;
21
+ const payload = await response.json();
22
+ if (!Array.isArray(payload.data)) return Response.json(payload, { status: response.status, headers: response.headers });
23
+ return Response.json({
24
+ ...payload,
25
+ data: payload.data.map((model) => ({ ...model, aerial: aerialSupportForModel(model) }))
26
+ }, { status: response.status });
27
+ }
@@ -1,6 +1,6 @@
1
1
  import { WebSocket } from "undici";
2
- import { COPILOT_API_ORIGIN } from "./constants.js";
3
- import { upstreamDispatcher } from "./upstream-fetch.js";
2
+ import { COPILOT_API_ORIGIN } from "../shared/constants.js";
3
+ import { upstreamDispatcher } from "../upstream/fetch.js";
4
4
 
5
5
  const TERMINAL_RESPONSE_TYPES = new Set([
6
6
  "response.completed",
@@ -1,9 +1,9 @@
1
1
  import http from "node:http";
2
- import { DEFAULT_HOST, DEFAULT_PORT } from "./constants.js";
3
- import { loadConfig, validateLocalAuth } from "./config.js";
4
- import { proxyChatCompletions, proxyMessages, proxyModels, proxyResponses, localCountTokens } from "./copilot.js";
5
- import { readGitHubToken } from "./auth.js";
6
- import { logEvent } from "./log.js";
2
+ import { DEFAULT_HOST, DEFAULT_PORT } from "../shared/constants.js";
3
+ import { loadConfig, validateLocalAuth } from "../shared/config.js";
4
+ import { proxyChatCompletions, proxyMessages, proxyModels, proxyResponses, localCountTokens } from "./index.js";
5
+ import { readGitHubToken } from "../shared/auth.js";
6
+ import { logEvent } from "../shared/log.js";
7
7
 
8
8
  const MAX_BODY_BYTES = 32 * 1024 * 1024;
9
9
 
@@ -0,0 +1,55 @@
1
+ import { COPILOT_API_ORIGIN } from "../shared/constants.js";
2
+ import { getCopilotToken } from "../shared/auth.js";
3
+ import { logEvent } from "../shared/log.js";
4
+ import { upstreamFetch } from "../upstream/fetch.js";
5
+ import { fetchModelsCatalog as fetchModelsCatalogShared, tokenFingerprintOf } from "./model-catalog.js";
6
+ import { copyResponseHeaders, upstreamHeaders } from "./headers.js";
7
+ import {
8
+ cacheRequestFields,
9
+ hasExplicitCacheRequest,
10
+ parseJsonBody,
11
+ wrapResponseWithCacheObserver
12
+ } from "./cache-telemetry.js";
13
+
14
+ export async function requestWithJsonBody(request, transform) {
15
+ const payload = await request.json();
16
+ const nextPayload = await transform(payload);
17
+ return new Request(request.url, {
18
+ method: request.method,
19
+ headers: request.headers,
20
+ body: JSON.stringify(nextPayload),
21
+ duplex: "half"
22
+ });
23
+ }
24
+
25
+ export async function proxyFetch(path, request, { extraHeaders = {}, bodyOverride } = {}) {
26
+ const token = await getCopilotToken();
27
+ const body = bodyOverride ?? (request.method === "GET" || request.method === "HEAD" ? undefined : await request.arrayBuffer());
28
+ const accept = request.headers.get("accept") || "application/json";
29
+ const contentType = request.headers.get("content-type") || "application/json";
30
+ const requestCache = cacheRequestFields(parseJsonBody(body, contentType));
31
+ if (hasExplicitCacheRequest(requestCache)) logEvent("cache_request", { route: path, ...requestCache });
32
+ const headers = upstreamHeaders(token, { accept, "content-type": contentType, ...extraHeaders });
33
+ let upstream = await upstreamFetch(`${COPILOT_API_ORIGIN}${path}`, { method: request.method, headers, body });
34
+ if (upstream.status === 401) {
35
+ const refreshed = await getCopilotToken({ force: true });
36
+ upstream = await upstreamFetch(`${COPILOT_API_ORIGIN}${path}`, { method: request.method, headers: upstreamHeaders(refreshed, { accept, "content-type": contentType, ...extraHeaders }), body });
37
+ }
38
+ if (path === "/models") {
39
+ return new Response(upstream.body, { status: upstream.status, headers: copyResponseHeaders(upstream) });
40
+ }
41
+ return wrapResponseWithCacheObserver(upstream, path, requestCache);
42
+ }
43
+
44
+ export async function fetchModelsCatalogForCopilot() {
45
+ const token = await getCopilotToken();
46
+ return fetchModelsCatalogShared({
47
+ tokenFingerprint: tokenFingerprintOf(token),
48
+ fetchImpl: async () => {
49
+ const response = await upstreamFetch(`${COPILOT_API_ORIGIN}/models`, { method: "GET", headers: upstreamHeaders(token) });
50
+ if (!response.ok) return undefined;
51
+ const payload = await response.json().catch(() => ({}));
52
+ return Array.isArray(payload?.data) ? payload.data : undefined;
53
+ }
54
+ });
55
+ }
@@ -0,0 +1,54 @@
1
+ const HEALTH_TIMEOUT_MS = 1500;
2
+ const HEALTH_START_TIMEOUT_MS = 5000;
3
+ const HEALTH_POLL_INTERVAL_MS = 250;
4
+
5
+ export async function defaultHealthFetch(host, port) {
6
+ if (process.env.AERIAL_SERVICE_DRYRUN === "1") {
7
+ return { ok: false, error: "dryrun" };
8
+ }
9
+ const controller = new AbortController();
10
+ const timer = setTimeout(() => controller.abort(), HEALTH_TIMEOUT_MS);
11
+ try {
12
+ const res = await fetch(`http://${host}:${port}/health`, { signal: controller.signal });
13
+ let body;
14
+ let parseFailed = false;
15
+ try {
16
+ body = await res.json();
17
+ } catch {
18
+ parseFailed = true;
19
+ }
20
+ return { ok: res.ok, status: res.status, body, parseFailed };
21
+ } catch (err) {
22
+ return { ok: false, error: err.message };
23
+ } finally {
24
+ clearTimeout(timer);
25
+ }
26
+ }
27
+
28
+ export function classifyHealth(probe) {
29
+ if (!probe || probe.error) return { mode: "absent" };
30
+ if (probe.status !== 200) return { mode: "absent", httpStatus: probe.status };
31
+ if (probe.parseFailed) return { mode: "port_conflict", reason: "health body is not JSON" };
32
+ if (!probe.body || probe.body.service !== "aerial") {
33
+ return { mode: "port_conflict", reason: "200 response but not Aerial" };
34
+ }
35
+ return { mode: "aerial_running", body: probe.body };
36
+ }
37
+
38
+ export async function pollForAerialUp(host, port, healthFetch, deadlineMs = HEALTH_START_TIMEOUT_MS) {
39
+ const fetcher = healthFetch || defaultHealthFetch;
40
+ const start = Date.now();
41
+ let lastProbe;
42
+ let lastCls;
43
+ let attempts = 0;
44
+ while (Date.now() - start < deadlineMs) {
45
+ attempts += 1;
46
+ lastProbe = await fetcher(host, port);
47
+ lastCls = classifyHealth(lastProbe);
48
+ if (lastCls.mode === "aerial_running" || lastCls.mode === "port_conflict") {
49
+ return { cls: lastCls, probe: lastProbe, attempts, elapsedMs: Date.now() - start };
50
+ }
51
+ await new Promise((r) => setTimeout(r, HEALTH_POLL_INTERVAL_MS));
52
+ }
53
+ return { cls: lastCls || { mode: "absent" }, probe: lastProbe, attempts, elapsedMs: Date.now() - start };
54
+ }
@@ -0,0 +1,38 @@
1
+ import {
2
+ SERVICE_LABEL,
3
+ WIN_TASK_NAME,
4
+ aerialLogPath,
5
+ buildSchtasksArgs,
6
+ darwinWrapperPath,
7
+ nodeBinary,
8
+ plistPath,
9
+ quoteSchtasksTR,
10
+ renderDarwinWrapper,
11
+ renderPlist,
12
+ renderWindowsWrapper,
13
+ stdioLogPath,
14
+ winWrapperPath
15
+ } from "./wrapper-render.js";
16
+ import { classifyHealth } from "./health.js";
17
+ import { parseWrapperLogValues, parseWrapperPaths, wrapperBlock } from "./status.js";
18
+
19
+ export { renderPlist, renderDarwinWrapper, renderWindowsWrapper, buildSchtasksCreateArgs } from "./wrapper-render.js";
20
+ export { serviceInstall, serviceStart, serviceStop, serviceRestart, serviceUninstall } from "./lifecycle.js";
21
+ export { serviceStatus } from "./status.js";
22
+
23
+ export const _internal = {
24
+ SERVICE_LABEL,
25
+ WIN_TASK_NAME,
26
+ plistPath,
27
+ darwinWrapperPath,
28
+ winWrapperPath,
29
+ aerialLogPath,
30
+ stdioLogPath,
31
+ parseWrapperLogValues,
32
+ parseWrapperPaths,
33
+ wrapperBlock,
34
+ buildSchtasksArgs,
35
+ quoteSchtasksTR,
36
+ classifyHealth,
37
+ nodeBinary
38
+ };