mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-08 18:48:27 +00:00
refactor: dedupe chat envelope + daemon output + skills UI
This commit is contained in:
@@ -3,7 +3,6 @@ import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import { promisify } from "node:util";
|
||||
import type { GatewayServiceRuntime } from "./service-runtime.js";
|
||||
import { colorize, isRich, theme } from "../terminal/theme.js";
|
||||
import {
|
||||
formatGatewayServiceDescription,
|
||||
GATEWAY_LAUNCH_AGENT_LABEL,
|
||||
@@ -14,16 +13,11 @@ import {
|
||||
buildLaunchAgentPlist as buildLaunchAgentPlistImpl,
|
||||
readLaunchAgentProgramArgumentsFromFile,
|
||||
} from "./launchd-plist.js";
|
||||
import { formatLine, toPosixPath } from "./output.js";
|
||||
import { resolveGatewayStateDir, resolveHomeDir } from "./paths.js";
|
||||
import { parseKeyValueOutput } from "./runtime-parse.js";
|
||||
|
||||
const execFileAsync = promisify(execFile);
|
||||
const toPosixPath = (value: string) => value.replace(/\\/g, "/");
|
||||
|
||||
const formatLine = (label: string, value: string) => {
|
||||
const rich = isRich();
|
||||
return `${colorize(rich, theme.muted, `${label}:`)} ${colorize(rich, theme.command, value)}`;
|
||||
};
|
||||
|
||||
function resolveLaunchAgentLabel(args?: { env?: Record<string, string | undefined> }): string {
|
||||
const envLabel = args?.env?.OPENCLAW_LAUNCHD_LABEL?.trim();
|
||||
|
||||
8
src/daemon/output.ts
Normal file
8
src/daemon/output.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { colorize, isRich, theme } from "../terminal/theme.js";
|
||||
|
||||
export const toPosixPath = (value: string) => value.replace(/\\/g, "/");
|
||||
|
||||
export function formatLine(label: string, value: string): string {
|
||||
const rich = isRich();
|
||||
return `${colorize(rich, theme.muted, `${label}:`)} ${colorize(rich, theme.command, value)}`;
|
||||
}
|
||||
@@ -1,17 +1,12 @@
|
||||
import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import type { GatewayServiceRuntime } from "./service-runtime.js";
|
||||
import { colorize, isRich, theme } from "../terminal/theme.js";
|
||||
import { formatGatewayServiceDescription, resolveGatewayWindowsTaskName } from "./constants.js";
|
||||
import { formatLine } from "./output.js";
|
||||
import { resolveGatewayStateDir } from "./paths.js";
|
||||
import { parseKeyValueOutput } from "./runtime-parse.js";
|
||||
import { execSchtasks } from "./schtasks-exec.js";
|
||||
|
||||
const formatLine = (label: string, value: string) => {
|
||||
const rich = isRich();
|
||||
return `${colorize(rich, theme.muted, `${label}:`)} ${colorize(rich, theme.command, value)}`;
|
||||
};
|
||||
|
||||
function resolveTaskName(env: Record<string, string | undefined>): string {
|
||||
const override = env.OPENCLAW_WINDOWS_TASK_NAME?.trim();
|
||||
if (override) {
|
||||
|
||||
@@ -3,12 +3,12 @@ import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import { promisify } from "node:util";
|
||||
import type { GatewayServiceRuntime } from "./service-runtime.js";
|
||||
import { colorize, isRich, theme } from "../terminal/theme.js";
|
||||
import {
|
||||
formatGatewayServiceDescription,
|
||||
LEGACY_GATEWAY_SYSTEMD_SERVICE_NAMES,
|
||||
resolveGatewaySystemdServiceName,
|
||||
} from "./constants.js";
|
||||
import { formatLine, toPosixPath } from "./output.js";
|
||||
import { resolveHomeDir } from "./paths.js";
|
||||
import { parseKeyValueOutput } from "./runtime-parse.js";
|
||||
import {
|
||||
@@ -23,12 +23,6 @@ import {
|
||||
} from "./systemd-unit.js";
|
||||
|
||||
const execFileAsync = promisify(execFile);
|
||||
const toPosixPath = (value: string) => value.replace(/\\/g, "/");
|
||||
|
||||
const formatLine = (label: string, value: string) => {
|
||||
const rich = isRich();
|
||||
return `${colorize(rich, theme.muted, `${label}:`)} ${colorize(rich, theme.command, value)}`;
|
||||
};
|
||||
|
||||
function resolveSystemdUnitPathForName(
|
||||
env: Record<string, string | undefined>,
|
||||
|
||||
@@ -1,52 +1,6 @@
|
||||
const ENVELOPE_PREFIX = /^\[([^\]]+)\]\s*/;
|
||||
const ENVELOPE_CHANNELS = [
|
||||
"WebChat",
|
||||
"WhatsApp",
|
||||
"Telegram",
|
||||
"Signal",
|
||||
"Slack",
|
||||
"Discord",
|
||||
"Google Chat",
|
||||
"iMessage",
|
||||
"Teams",
|
||||
"Matrix",
|
||||
"Zalo",
|
||||
"Zalo Personal",
|
||||
"BlueBubbles",
|
||||
];
|
||||
import { stripEnvelope, stripMessageIdHints } from "../shared/chat-envelope.js";
|
||||
|
||||
const MESSAGE_ID_LINE = /^\s*\[message_id:\s*[^\]]+\]\s*$/i;
|
||||
|
||||
function looksLikeEnvelopeHeader(header: string): boolean {
|
||||
if (/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}Z\b/.test(header)) {
|
||||
return true;
|
||||
}
|
||||
if (/\d{4}-\d{2}-\d{2} \d{2}:\d{2}\b/.test(header)) {
|
||||
return true;
|
||||
}
|
||||
return ENVELOPE_CHANNELS.some((label) => header.startsWith(`${label} `));
|
||||
}
|
||||
|
||||
export function stripEnvelope(text: string): string {
|
||||
const match = text.match(ENVELOPE_PREFIX);
|
||||
if (!match) {
|
||||
return text;
|
||||
}
|
||||
const header = match[1] ?? "";
|
||||
if (!looksLikeEnvelopeHeader(header)) {
|
||||
return text;
|
||||
}
|
||||
return text.slice(match[0].length);
|
||||
}
|
||||
|
||||
function stripMessageIdHints(text: string): string {
|
||||
if (!text.includes("[message_id:")) {
|
||||
return text;
|
||||
}
|
||||
const lines = text.split(/\r?\n/);
|
||||
const filtered = lines.filter((line) => !MESSAGE_ID_LINE.test(line));
|
||||
return filtered.length === lines.length ? text : filtered.join("\n");
|
||||
}
|
||||
export { stripEnvelope };
|
||||
|
||||
function stripEnvelopeFromContent(content: unknown[]): { content: unknown[]; changed: boolean } {
|
||||
let changed = false;
|
||||
|
||||
49
src/shared/chat-envelope.ts
Normal file
49
src/shared/chat-envelope.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
const ENVELOPE_PREFIX = /^\[([^\]]+)\]\s*/;
|
||||
const ENVELOPE_CHANNELS = [
|
||||
"WebChat",
|
||||
"WhatsApp",
|
||||
"Telegram",
|
||||
"Signal",
|
||||
"Slack",
|
||||
"Discord",
|
||||
"Google Chat",
|
||||
"iMessage",
|
||||
"Teams",
|
||||
"Matrix",
|
||||
"Zalo",
|
||||
"Zalo Personal",
|
||||
"BlueBubbles",
|
||||
];
|
||||
|
||||
const MESSAGE_ID_LINE = /^\s*\[message_id:\s*[^\]]+\]\s*$/i;
|
||||
|
||||
function looksLikeEnvelopeHeader(header: string): boolean {
|
||||
if (/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}Z\b/.test(header)) {
|
||||
return true;
|
||||
}
|
||||
if (/\d{4}-\d{2}-\d{2} \d{2}:\d{2}\b/.test(header)) {
|
||||
return true;
|
||||
}
|
||||
return ENVELOPE_CHANNELS.some((label) => header.startsWith(`${label} `));
|
||||
}
|
||||
|
||||
export function stripEnvelope(text: string): string {
|
||||
const match = text.match(ENVELOPE_PREFIX);
|
||||
if (!match) {
|
||||
return text;
|
||||
}
|
||||
const header = match[1] ?? "";
|
||||
if (!looksLikeEnvelopeHeader(header)) {
|
||||
return text;
|
||||
}
|
||||
return text.slice(match[0].length);
|
||||
}
|
||||
|
||||
export function stripMessageIdHints(text: string): string {
|
||||
if (!text.includes("[message_id:")) {
|
||||
return text;
|
||||
}
|
||||
const lines = text.split(/\r?\n/);
|
||||
const filtered = lines.filter((line) => !MESSAGE_ID_LINE.test(line));
|
||||
return filtered.length === lines.length ? text : filtered.join("\n");
|
||||
}
|
||||
Reference in New Issue
Block a user