






















@@ -5,6 +5,7 @@ import { formatConfigIssueLines } from "../../config/issue-format.js";
55import { resolveIsNixMode } from "../../config/paths.js";
66import { checkTokenDrift } from "../../daemon/service-audit.js";
77import type { GatewayServiceRestartResult } from "../../daemon/service-types.js";
8+import type { GatewayServiceStartRepairIssue, GatewayServiceState } from "../../daemon/service.js";
89import { describeGatewayServiceRestart, startGatewayService } from "../../daemon/service.js";
910import type { GatewayService } from "../../daemon/service.js";
1011import { renderSystemdUnavailableHints } from "../../daemon/systemd-hints.js";
@@ -16,6 +17,7 @@ import {
1617} from "../../infra/restart.js";
1718import { isWSL } from "../../infra/wsl.js";
1819import { defaultRuntime } from "../../runtime.js";
20+import { formatCliCommand } from "../command-format.js";
1921import { resolveGatewayTokenForDriftCheck } from "./gateway-token-drift.js";
2022import {
2123buildDaemonServiceSnapshot,
@@ -48,6 +50,11 @@ type ServiceRecoveryContext = {
4850fail: (message: string, hints?: string[]) => void;
4951};
505253+type ServiceStartRepairContext = ServiceRecoveryContext & {
54+state: GatewayServiceState;
55+issues: GatewayServiceStartRepairIssue[];
56+};
57+5158async function maybeAugmentSystemdHints(hints: string[]): Promise<string[]> {
5259if (process.platform !== "linux") {
5360return hints;
@@ -221,6 +228,7 @@ export async function runServiceStart(params: {
221228renderStartHints: () => string[];
222229opts?: DaemonLifecycleOptions;
223230onNotLoaded?: (ctx: ServiceRecoveryContext) => Promise<ServiceRecoveryResult | null>;
231+repairLoadedService?: (ctx: ServiceStartRepairContext) => Promise<ServiceRecoveryResult | null>;
224232}) {
225233const json = Boolean(params.opts?.json);
226234const { stdout, emit, fail } = createDaemonActionContext({ action: "start", json });
@@ -298,6 +306,41 @@ export async function runServiceStart(params: {
298306});
299307return;
300308}
309+if (startResult.outcome === "repair-required") {
310+try {
311+const handled = await params.repairLoadedService?.({
312+ json,
313+ stdout,
314+ fail,
315+state: startResult.state,
316+issues: startResult.issues,
317+});
318+if (handled) {
319+emit({
320+ok: true,
321+result: handled.result,
322+message: handled.message,
323+warnings: handled.warnings,
324+service: buildDaemonServiceSnapshot(params.service, handled.loaded ?? true),
325+});
326+if (!json && handled.message) {
327+defaultRuntime.log(handled.message);
328+}
329+return;
330+}
331+} catch (err) {
332+const hints = params.renderStartHints();
333+fail(`${params.serviceNoun} repair failed: ${String(err)}`, hints);
334+return;
335+}
336+fail(
337+`${params.serviceNoun} service needs repair before it can start: ${startResult.issues
338+ .map((issue) => issue.message)
339+ .join("; ")}`,
340+[formatCliCommand("openclaw gateway install --force")],
341+);
342+return;
343+}
301344emit({
302345ok: true,
303346result: "started",
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。