


























@@ -99,6 +99,10 @@ type ConfigShape = {
9999authMode?: unknown;
100100tailscale?: unknown;
101101};
102+discovery?: {
103+mdnsMode?: unknown;
104+bonjourEnvOverride: "unset" | "force-enabled" | "force-disabled" | "unrecognized";
105+};
102106channels?: {
103107count: number;
104108ids: string[];
@@ -135,6 +139,21 @@ type FailedSanitizedLogTail = Omit<IncludedSanitizedLogTail, "status"> & {
135139136140type SanitizedLogTail = IncludedSanitizedLogTail | FailedSanitizedLogTail;
137141142+type BonjourLogSummary = {
143+count: number;
144+warnings: number;
145+last?: {
146+time?: string;
147+level?: string;
148+kind: "disabled" | "restarted" | "ciao_suppressed" | "conflict" | "watchdog" | "other";
149+};
150+flags: {
151+disabled: boolean;
152+restarted: boolean;
153+ciaoSuppressed: boolean;
154+};
155+};
156+138157type SupportSnapshotStatus =
139158| {
140159status: "included";
@@ -180,14 +199,44 @@ function safeScalar(value: unknown): unknown {
180199return undefined;
181200}
182201202+function resolveBonjourEnvOverride(
203+env: NodeJS.ProcessEnv,
204+): NonNullable<ConfigShape["discovery"]>["bonjourEnvOverride"] {
205+const raw = env.OPENCLAW_DISABLE_BONJOUR?.trim().toLowerCase();
206+if (!raw) {
207+return "unset";
208+}
209+switch (raw) {
210+case "1":
211+case "true":
212+case "yes":
213+case "on":
214+return "force-disabled";
215+case "0":
216+case "false":
217+case "no":
218+case "off":
219+return "force-enabled";
220+default:
221+return "unrecognized";
222+}
223+}
224+183225function sortedObjectKeys(value: unknown): string[] {
184226return Object.keys(asOptionalRecord(value) ?? {}).toSorted((a, b) => a.localeCompare(b));
185227}
186228187-function sanitizeConfigShape(parsed: unknown, configPath: string, stat: fs.Stats): ConfigShape {
229+function sanitizeConfigShape(
230+parsed: unknown,
231+configPath: string,
232+stat: fs.Stats,
233+env: NodeJS.ProcessEnv,
234+): ConfigShape {
188235const root = asOptionalRecord(parsed) ?? {};
189236const gateway = asOptionalRecord(root.gateway);
190237const auth = asOptionalRecord(gateway?.auth);
238+const discovery = asOptionalRecord(root.discovery);
239+const mdns = asOptionalRecord(discovery?.mdns);
191240const channels = asOptionalRecord(root.channels);
192241const plugins = asOptionalRecord(root.plugins);
193242const agents = Array.isArray(root.agents) ? root.agents : undefined;
@@ -211,6 +260,14 @@ function sanitizeConfigShape(parsed: unknown, configPath: string, stat: fs.Stats
211260};
212261}
213262263+const bonjourEnvOverride = resolveBonjourEnvOverride(env);
264+if (mdns || bonjourEnvOverride !== "unset") {
265+shape.discovery = {
266+mdnsMode: safeScalar(mdns?.mode),
267+ bonjourEnvOverride,
268+};
269+}
270+214271if (channels) {
215272shape.channels = {
216273count: Object.keys(channels).length,
@@ -293,7 +350,7 @@ function readConfigExport(options: {
293350};
294351}
295352return {
296-shape: sanitizeConfigShape(parsed.parsed, redactedConfigPath, stat),
353+shape: sanitizeConfigShape(parsed.parsed, redactedConfigPath, stat, options.env),
297354sanitized: sanitizeConfigDetails(parsed.parsed, options),
298355};
299356} catch (error) {
@@ -397,6 +454,73 @@ function failedLogTail(error: unknown, redaction: SupportRedactionContext): Sani
397454};
398455}
399456457+function logString(record: Record<string, unknown>, key: string): string | undefined {
458+const value = record[key];
459+return typeof value === "string" && value.trim() ? value : undefined;
460+}
461+462+function isBonjourLogRecord(record: Record<string, unknown>): boolean {
463+const sourceFields = ["subsystem", "logger", "module", "pluginId", "component"];
464+if (sourceFields.some((field) => logString(record, field)?.toLowerCase().includes("bonjour"))) {
465+return true;
466+}
467+return logString(record, "msg")?.toLowerCase().startsWith("bonjour:") === true;
468+}
469+470+function classifyBonjourLogKind(
471+normalizedMsg: string,
472+): NonNullable<BonjourLogSummary["last"]>["kind"] {
473+if (normalizedMsg.includes("disabling")) {
474+return "disabled";
475+}
476+if (normalizedMsg.includes("restarting")) {
477+return "restarted";
478+}
479+if (normalizedMsg.includes("suppressing ciao")) {
480+return "ciao_suppressed";
481+}
482+if (normalizedMsg.includes("conflict")) {
483+return "conflict";
484+}
485+if (normalizedMsg.includes("watchdog")) {
486+return "watchdog";
487+}
488+return "other";
489+}
490+491+function summarizeBonjourLogs(logTail: SanitizedLogTail): BonjourLogSummary {
492+const summary: BonjourLogSummary = {
493+count: 0,
494+warnings: 0,
495+flags: {
496+disabled: false,
497+restarted: false,
498+ciaoSuppressed: false,
499+},
500+};
501+for (const record of logTail.lines) {
502+if (!isBonjourLogRecord(record)) {
503+continue;
504+}
505+summary.count += 1;
506+const level = logString(record, "level")?.toLowerCase();
507+if (level === "warn" || level === "error") {
508+summary.warnings += 1;
509+}
510+const msg = logString(record, "msg");
511+const normalizedMsg = msg?.toLowerCase() ?? "";
512+summary.flags.disabled ||= normalizedMsg.includes("disabling");
513+summary.flags.restarted ||= normalizedMsg.includes("restarting");
514+summary.flags.ciaoSuppressed ||= normalizedMsg.includes("suppressing ciao");
515+summary.last = {
516+ ...(logString(record, "time") ? { time: logString(record, "time") } : {}),
517+ ...(logString(record, "level") ? { level: logString(record, "level") } : {}),
518+kind: classifyBonjourLogKind(normalizedMsg),
519+};
520+}
521+return summary;
522+}
523+400524async function collectSupportLogTail(params: {
401525readLogTail: typeof readConfiguredLogTail;
402526limit: number;
@@ -492,7 +616,7 @@ function renderSummary(params: {
492616"## Maintainer Quick Read",
493617"",
494618"- `manifest.json`: file inventory and privacy notes",
495-"- `diagnostics.json`: top-level summary of config, logs, stability, status, and health",
619+"- `diagnostics.json`: top-level summary of config, logs, Bonjour/mDNS, stability, status, and health",
496620"- `config/sanitized.json`: config values with credentials, private identifiers, and prompt text redacted",
497621"- `status/gateway-status.json`: sanitized service/connectivity snapshot",
498622"- `health/gateway-health.json`: sanitized Gateway health snapshot",
@@ -596,6 +720,7 @@ export async function buildDiagnosticSupportExport(
596720reset: logTail.reset,
597721},
598722stability: describeStabilityForDiagnostics(stability, redaction),
723+bonjour: summarizeBonjourLogs(logTail),
599724status: statusSnapshot.summary,
600725health: healthSnapshot.summary,
601726};
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。