mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-09 09:47:40 +00:00
refactor: extract shared dedupe helpers for runtime paths
This commit is contained in:
@@ -42,3 +42,27 @@ export async function requestExecApprovalDecision(
|
||||
: undefined;
|
||||
return typeof decisionValue === "string" ? decisionValue : null;
|
||||
}
|
||||
|
||||
export async function requestExecApprovalDecisionForHost(params: {
|
||||
approvalId: string;
|
||||
command: string;
|
||||
workdir: string;
|
||||
host: "gateway" | "node";
|
||||
security: ExecSecurity;
|
||||
ask: ExecAsk;
|
||||
agentId?: string;
|
||||
resolvedPath?: string;
|
||||
sessionKey?: string;
|
||||
}): Promise<string | null> {
|
||||
return await requestExecApprovalDecision({
|
||||
id: params.approvalId,
|
||||
command: params.command,
|
||||
cwd: params.workdir,
|
||||
host: params.host,
|
||||
security: params.security,
|
||||
ask: params.ask,
|
||||
agentId: params.agentId,
|
||||
resolvedPath: params.resolvedPath,
|
||||
sessionKey: params.sessionKey,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
} from "../infra/exec-approvals.js";
|
||||
import type { SafeBinProfile } from "../infra/exec-safe-bin-policy.js";
|
||||
import { markBackgrounded, tail } from "./bash-process-registry.js";
|
||||
import { requestExecApprovalDecision } from "./bash-tools.exec-approval-request.js";
|
||||
import { requestExecApprovalDecisionForHost } from "./bash-tools.exec-approval-request.js";
|
||||
import {
|
||||
DEFAULT_APPROVAL_TIMEOUT_MS,
|
||||
DEFAULT_NOTIFY_TAIL_CHARS,
|
||||
@@ -81,6 +81,19 @@ export async function processGatewayAllowlist(
|
||||
const analysisOk = allowlistEval.analysisOk;
|
||||
const allowlistSatisfied =
|
||||
hostSecurity === "allowlist" && analysisOk ? allowlistEval.allowlistSatisfied : false;
|
||||
const recordMatchedAllowlistUse = (resolvedPath?: string) => {
|
||||
if (allowlistMatches.length === 0) {
|
||||
return;
|
||||
}
|
||||
const seen = new Set<string>();
|
||||
for (const match of allowlistMatches) {
|
||||
if (seen.has(match.pattern)) {
|
||||
continue;
|
||||
}
|
||||
seen.add(match.pattern);
|
||||
recordAllowlistUse(approvals.file, params.agentId, match, params.command, resolvedPath);
|
||||
}
|
||||
};
|
||||
const hasHeredocSegment = allowlistEval.segments.some((segment) =>
|
||||
segment.argv.some((token) => token.startsWith("<<")),
|
||||
);
|
||||
@@ -113,10 +126,10 @@ export async function processGatewayAllowlist(
|
||||
void (async () => {
|
||||
let decision: string | null = null;
|
||||
try {
|
||||
decision = await requestExecApprovalDecision({
|
||||
id: approvalId,
|
||||
decision = await requestExecApprovalDecisionForHost({
|
||||
approvalId,
|
||||
command: params.command,
|
||||
cwd: params.workdir,
|
||||
workdir: params.workdir,
|
||||
host: "gateway",
|
||||
security: hostSecurity,
|
||||
ask: hostAsk,
|
||||
@@ -186,22 +199,7 @@ export async function processGatewayAllowlist(
|
||||
return;
|
||||
}
|
||||
|
||||
if (allowlistMatches.length > 0) {
|
||||
const seen = new Set<string>();
|
||||
for (const match of allowlistMatches) {
|
||||
if (seen.has(match.pattern)) {
|
||||
continue;
|
||||
}
|
||||
seen.add(match.pattern);
|
||||
recordAllowlistUse(
|
||||
approvals.file,
|
||||
params.agentId,
|
||||
match,
|
||||
params.command,
|
||||
resolvedPath ?? undefined,
|
||||
);
|
||||
}
|
||||
}
|
||||
recordMatchedAllowlistUse(resolvedPath ?? undefined);
|
||||
|
||||
let run: Awaited<ReturnType<typeof runExecProcess>> | null = null;
|
||||
try {
|
||||
@@ -321,22 +319,7 @@ export async function processGatewayAllowlist(
|
||||
}
|
||||
}
|
||||
|
||||
if (allowlistMatches.length > 0) {
|
||||
const seen = new Set<string>();
|
||||
for (const match of allowlistMatches) {
|
||||
if (seen.has(match.pattern)) {
|
||||
continue;
|
||||
}
|
||||
seen.add(match.pattern);
|
||||
recordAllowlistUse(
|
||||
approvals.file,
|
||||
params.agentId,
|
||||
match,
|
||||
params.command,
|
||||
allowlistEval.segments[0]?.resolution?.resolvedPath,
|
||||
);
|
||||
}
|
||||
}
|
||||
recordMatchedAllowlistUse(allowlistEval.segments[0]?.resolution?.resolvedPath);
|
||||
|
||||
return { execCommandOverride };
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
resolveExecApprovalsFromFile,
|
||||
} from "../infra/exec-approvals.js";
|
||||
import { buildNodeShellCommand } from "../infra/node-shell.js";
|
||||
import { requestExecApprovalDecision } from "./bash-tools.exec-approval-request.js";
|
||||
import { requestExecApprovalDecisionForHost } from "./bash-tools.exec-approval-request.js";
|
||||
import {
|
||||
DEFAULT_APPROVAL_TIMEOUT_MS,
|
||||
createApprovalSlug,
|
||||
@@ -178,10 +178,10 @@ export async function executeNodeHostCommand(
|
||||
void (async () => {
|
||||
let decision: string | null = null;
|
||||
try {
|
||||
decision = await requestExecApprovalDecision({
|
||||
id: approvalId,
|
||||
decision = await requestExecApprovalDecisionForHost({
|
||||
approvalId,
|
||||
command: params.command,
|
||||
cwd: params.workdir,
|
||||
workdir: params.workdir,
|
||||
host: "node",
|
||||
security: hostSecurity,
|
||||
ask: hostAsk,
|
||||
|
||||
@@ -317,35 +317,10 @@ export function subscribeEmbeddedPiSession(params: SubscribeEmbeddedPiSessionPar
|
||||
}
|
||||
return `\`\`\`txt\n${trimmed}\n\`\`\``;
|
||||
};
|
||||
const emitToolSummary = (toolName?: string, meta?: string) => {
|
||||
const emitToolResultMessage = (toolName: string | undefined, message: string) => {
|
||||
if (!params.onToolResult) {
|
||||
return;
|
||||
}
|
||||
const agg = formatToolAggregate(toolName, meta ? [meta] : undefined, {
|
||||
markdown: useMarkdown,
|
||||
});
|
||||
const { text: cleanedText, mediaUrls } = parseReplyDirectives(agg);
|
||||
const filteredMediaUrls = filterToolResultMediaUrls(toolName, mediaUrls ?? []);
|
||||
if (!cleanedText && filteredMediaUrls.length === 0) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
void params.onToolResult({
|
||||
text: cleanedText,
|
||||
mediaUrls: filteredMediaUrls.length ? filteredMediaUrls : undefined,
|
||||
});
|
||||
} catch {
|
||||
// ignore tool result delivery failures
|
||||
}
|
||||
};
|
||||
const emitToolOutput = (toolName?: string, meta?: string, output?: string) => {
|
||||
if (!params.onToolResult || !output) {
|
||||
return;
|
||||
}
|
||||
const agg = formatToolAggregate(toolName, meta ? [meta] : undefined, {
|
||||
markdown: useMarkdown,
|
||||
});
|
||||
const message = `${agg}\n${formatToolOutputBlock(output)}`;
|
||||
const { text: cleanedText, mediaUrls } = parseReplyDirectives(message);
|
||||
const filteredMediaUrls = filterToolResultMediaUrls(toolName, mediaUrls ?? []);
|
||||
if (!cleanedText && filteredMediaUrls.length === 0) {
|
||||
@@ -360,6 +335,22 @@ export function subscribeEmbeddedPiSession(params: SubscribeEmbeddedPiSessionPar
|
||||
// ignore tool result delivery failures
|
||||
}
|
||||
};
|
||||
const emitToolSummary = (toolName?: string, meta?: string) => {
|
||||
const agg = formatToolAggregate(toolName, meta ? [meta] : undefined, {
|
||||
markdown: useMarkdown,
|
||||
});
|
||||
emitToolResultMessage(toolName, agg);
|
||||
};
|
||||
const emitToolOutput = (toolName?: string, meta?: string, output?: string) => {
|
||||
if (!output) {
|
||||
return;
|
||||
}
|
||||
const agg = formatToolAggregate(toolName, meta ? [meta] : undefined, {
|
||||
markdown: useMarkdown,
|
||||
});
|
||||
const message = `${agg}\n${formatToolOutputBlock(output)}`;
|
||||
emitToolResultMessage(toolName, message);
|
||||
};
|
||||
|
||||
const stripBlockTags = (
|
||||
text: string,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import path from "node:path";
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import { evaluateEntryMetadataRequirementsForCurrentPlatform } from "../shared/entry-status.js";
|
||||
import { evaluateEntryRequirementsForCurrentPlatform } from "../shared/entry-status.js";
|
||||
import type { RequirementConfigCheck, Requirements } from "../shared/requirements.js";
|
||||
import { CONFIG_DIR } from "../utils.js";
|
||||
import {
|
||||
@@ -191,17 +191,15 @@ function buildSkillStatus(
|
||||
? bundledNames.has(entry.skill.name)
|
||||
: entry.skill.source === "openclaw-bundled";
|
||||
|
||||
const requirementStatus = evaluateEntryMetadataRequirementsForCurrentPlatform({
|
||||
always,
|
||||
metadata: entry.metadata,
|
||||
frontmatter: entry.frontmatter,
|
||||
hasLocalBin: hasBinary,
|
||||
remote: eligibility?.remote,
|
||||
isEnvSatisfied,
|
||||
isConfigSatisfied,
|
||||
});
|
||||
const { emoji, homepage, required, missing, requirementsSatisfied, configChecks } =
|
||||
requirementStatus;
|
||||
evaluateEntryRequirementsForCurrentPlatform({
|
||||
always,
|
||||
entry,
|
||||
hasLocalBin: hasBinary,
|
||||
remote: eligibility?.remote,
|
||||
isEnvSatisfied,
|
||||
isConfigSatisfied,
|
||||
});
|
||||
const eligible = !disabled && !blockedByAllowlist && requirementsSatisfied;
|
||||
|
||||
return {
|
||||
|
||||
@@ -5,6 +5,7 @@ import type { MemoryCitationsMode } from "../config/types.memory.js";
|
||||
import { listDeliverableMessageChannels } from "../utils/message-channel.js";
|
||||
import type { ResolvedTimeFormat } from "./date-time.js";
|
||||
import type { EmbeddedContextFile } from "./pi-embedded-helpers.js";
|
||||
import type { EmbeddedSandboxInfo } from "./pi-embedded-runner/types.js";
|
||||
import { sanitizeForPromptLiteral } from "./sanitize-for-prompt.js";
|
||||
|
||||
/**
|
||||
@@ -229,20 +230,7 @@ export function buildAgentSystemPrompt(params: {
|
||||
repoRoot?: string;
|
||||
};
|
||||
messageToolHints?: string[];
|
||||
sandboxInfo?: {
|
||||
enabled: boolean;
|
||||
workspaceDir?: string;
|
||||
containerWorkspaceDir?: string;
|
||||
workspaceAccess?: "none" | "ro" | "rw";
|
||||
agentWorkspaceMount?: string;
|
||||
browserBridgeUrl?: string;
|
||||
browserNoVncUrl?: string;
|
||||
hostBrowserAllowed?: boolean;
|
||||
elevated?: {
|
||||
allowed: boolean;
|
||||
defaultLevel: "on" | "off" | "ask" | "full";
|
||||
};
|
||||
};
|
||||
sandboxInfo?: EmbeddedSandboxInfo;
|
||||
/** Reaction guidance for the agent (for Telegram minimal/extensive modes). */
|
||||
reactionGuidance?: {
|
||||
level: "minimal" | "extensive";
|
||||
|
||||
Reference in New Issue
Block a user