Skip to content

Commit a3c44d5

Browse files
committed
docs: document daemon audit helpers
1 parent feeaff2 commit a3c44d5

8 files changed

Lines changed: 33 additions & 1 deletion

src/daemon/runtime-hints.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/** Builds platform-specific log and start hints for daemon status output. */
12
import { toPosixPath } from "./output.js";
23
import { resolveGatewayRestartLogPath, resolveGatewaySupervisorLogPaths } from "./restart-logs.js";
34

@@ -16,6 +17,8 @@ export function buildPlatformRuntimeLogHints(params: {
1617
const env = { ...process.env, ...params.env };
1718
if (platform === "darwin") {
1819
const logs = resolveGatewaySupervisorLogPaths(env, { platform });
20+
// Display launchd paths as POSIX-style paths even in cross-platform tests
21+
// where mocked env values may carry Windows drive prefixes.
1922
return [
2023
`Launchd stdout (if installed): ${toDarwinDisplayPath(logs.stdoutPath)}`,
2124
"Launchd stderr (if installed): suppressed",
@@ -47,6 +50,8 @@ export function buildPlatformServiceStartHints(params: {
4750
}): string[] {
4851
const platform = params.platform ?? process.platform;
4952
const base = [params.installCommand, params.startCommand];
53+
// Native service-manager commands are supplemental hints; the OpenClaw
54+
// commands stay first because they know the generated profile/env paths.
5055
switch (platform) {
5156
case "darwin":
5257
return [...base, `launchctl bootstrap gui/$UID ${params.launchAgentPlistPath}`];

src/daemon/runtime-parse.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/** Parses daemon runtime command output into normalized key-value maps. */
12
import { normalizeLowercaseStringOrEmpty } from "@openclaw/normalization-core/string-coerce";
23

34
/** Parses command output key-value lines using a caller-supplied separator. */

src/daemon/runtime-paths.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/** Selects stable Node runtime paths for daemon installs across platforms. */
12
import { execFile } from "node:child_process";
23
import fs from "node:fs/promises";
34
import path from "node:path";
@@ -44,6 +45,8 @@ function buildSystemNodeCandidates(
4445
env: Record<string, string | undefined>,
4546
platform: NodeJS.Platform,
4647
): string[] {
48+
// Prefer system package-manager Node paths over shell-managed shims; daemons
49+
// launch without interactive shell init files.
4750
if (platform === "darwin") {
4851
return [
4952
"/opt/homebrew/bin/node",
@@ -104,6 +107,7 @@ async function isVersionManagedRealNodePath(
104107
): Promise<boolean> {
105108
try {
106109
const realPath = await fs.realpath(nodePath);
110+
// Symlinks in /usr/local/bin can resolve into version-manager trees.
107111
return isVersionManagedNodePath(realPath, platform);
108112
} catch {
109113
return false;
@@ -218,7 +222,8 @@ export async function resolvePreferredNodePath(params: {
218222
if (!isVersionManagedNodePath(currentExecPath, platform)) {
219223
return stableCurrentPath;
220224
}
221-
// Prefer system Node over a version-manager shim so daemon launch survives shell setup.
225+
// Prefer system Node over a version-manager shim so daemon launch survives
226+
// shell setup differences and package manager upgrades.
222227
const systemNode = await resolveSystemNodeInfo({
223228
env: params.env,
224229
platform,

src/daemon/schtasks-exec.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/** Executes Windows Task Scheduler commands with daemon-friendly timeouts. */
12
import { runCommandWithTimeout } from "../process/exec.js";
23

34
const SCHTASKS_TIMEOUT_MS = 15_000;
@@ -17,6 +18,8 @@ export async function execSchtasks(
1718
: result.termination === "no-output-timeout"
1819
? `schtasks produced no output for ${SCHTASKS_NO_OUTPUT_TIMEOUT_MS}ms`
1920
: "";
21+
// schtasks can hang without output on some Windows hosts; convert both timeout
22+
// modes into ordinary process-like failures for service fallback logic.
2023
return {
2124
stdout: result.stdout,
2225
stderr: result.stderr || timeoutDetail,

src/daemon/schtasks.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/** Windows Task Scheduler installer, startup fallback, and lifecycle controls. */
12
import { spawn, spawnSync } from "node:child_process";
23
import fs from "node:fs/promises";
34
import os from "node:os";
@@ -43,6 +44,8 @@ function resolveTaskName(env: GatewayServiceEnv): string {
4344
}
4445

4546
function shouldFallbackToStartupEntry(params: { code: number; detail: string }): boolean {
47+
// Permission failures and hung schtasks calls can still be served by the
48+
// per-user Startup folder fallback.
4649
return (
4750
params.code === 1 ||
4851
/(?:access is denied|acceso denegado)/i.test(params.detail) ||
@@ -93,6 +96,8 @@ function resolveStartupEntryPath(env: GatewayServiceEnv, extension?: "cmd" | "vb
9396
function resolveStartupEntryPaths(env: GatewayServiceEnv): string[] {
9497
const primaryPath = resolveStartupEntryPath(env);
9598
const legacyCmdPath = resolveStartupEntryPath(env, "cmd");
99+
// Hidden VBS launchers supersede cmd launchers, but uninstall must remove the
100+
// legacy cmd path from older installs too.
96101
return uniqueStrings([primaryPath, legacyCmdPath]);
97102
}
98103

@@ -257,6 +262,7 @@ export async function readScheduledTaskCommand(
257262
if (lower.startsWith("set ")) {
258263
const assignment = parseCmdSetAssignment(line.slice(4));
259264
if (assignment) {
265+
// Generated cmd launchers inline service env before the final command.
260266
environment[assignment.key] = assignment.value;
261267
}
262268
continue;

src/daemon/service-audit.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/** Audits installed daemon service definitions for drift and repair candidates. */
12
import fs from "node:fs/promises";
23
import path from "node:path";
34
import {
@@ -73,6 +74,7 @@ export const SERVICE_AUDIT_CODES = {
7374
systemdKillModeProcessOrNone: "systemd-kill-mode-process-or-none",
7475
} as const;
7576

77+
/** Returns whether audit issues require migrating a daemon to a stable Node runtime. */
7678
export function needsNodeRuntimeMigration(issues: ServiceConfigIssue[]): boolean {
7779
return issues.some(
7880
(issue) =>
@@ -96,6 +98,8 @@ function parseSystemdUnit(content: string): {
9698
let restartSec: string | undefined;
9799
let killMode: string | undefined;
98100

101+
// Parse only unit keys relevant to service resilience; this is not a full
102+
// systemd parser and intentionally ignores sections.
99103
for (const rawLine of content.split(/\r?\n/)) {
100104
const line = rawLine.trim();
101105
if (!line) {

src/daemon/service-env-plan.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/** Builds normalized environment plans for managed daemon service rendering. */
12
import { normalizeEnvVarKey } from "../infra/host-env-security.js";
23
import type { GatewayServiceEnvironmentValueSource } from "./service-types.js";
34

@@ -53,6 +54,8 @@ export function addServiceEnvPlanEntries(
5354
for (const [rawKey, rawValue] of Object.entries(entries)) {
5455
if (typeof rawValue !== "string" || !rawValue.trim()) {
5556
if (options.includeRawKeys) {
57+
// Preserve explicit blank raw keys only when callers need round-trip
58+
// visibility in generated service env.
5659
plan.environment[rawKey] = rawValue;
5760
plan.environmentValueSources[rawKey] = "inline";
5861
}
@@ -69,6 +72,8 @@ export function addServiceEnvPlanEntries(
6972
? options.valueSource({ rawKey, normalizedKey })
7073
: options.valueSource;
7174
plan.environmentValueSources[rawKey] = valueSource ?? "inline";
75+
// Last writer wins per normalized key so later, higher-priority env sources
76+
// can decide render policy without scanning duplicate casing.
7277
plan.entriesByNormalizedKey.set(normalizedKey, {
7378
rawKey,
7479
normalizedKey,

src/daemon/service-env-render-policy.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/** Applies platform render policy for managed daemon service environment values. */
12
import type { MutableServiceEnvPlan } from "./service-env-plan.js";
23
import {
34
readManagedServiceEnvKeysFromEnvironment,
@@ -38,6 +39,8 @@ export function applyManagedServiceEnvRenderPolicy(params: {
3839
if (entry.source !== "state-dotenv" || !managedKeys.has(entry.normalizedKey)) {
3940
continue;
4041
}
42+
// launchd does not read shell dotenv files; inline only the managed dotenv
43+
// keys declared for this service.
4144
params.plan.environment[entry.rawKey] = entry.value;
4245
params.plan.environmentValueSources[entry.rawKey] = "inline";
4346
}

0 commit comments

Comments
 (0)