





























@@ -7,6 +7,7 @@ import os from "node:os";
77import path from "node:path";
88import process from "node:process";
99import { pathToFileURL } from "node:url";
10+import { stripLeadingPackageManagerSeparator } from "./lib/arg-utils.mjs";
1011import { readBoundedResponseText } from "./lib/bounded-response.mjs";
11121213const ISSUE_FILE_COUNTS = [
@@ -63,6 +64,28 @@ Options:
6364}
64656566const NON_NEGATIVE_INTEGER_PATTERN = /^(0|[1-9]\d*)$/u;
67+const ARGUMENT_FLAGS = new Set([
68+"--allow-non-darwin",
69+"--expect-leak",
70+"--files",
71+"--full",
72+"--help",
73+"--invoke-timeout-ms",
74+"--keep",
75+"--max-workspace-reg-fds",
76+"--min-leaked-fds",
77+"--mode",
78+"--output-dir",
79+"--report-only",
80+"--sample-delay-ms",
81+"--settle-delay-ms",
82+]);
83+84+function stripPackageManagerSeparatorForKnownFlags(argv) {
85+return argv[0] === "--" && ARGUMENT_FLAGS.has(argv[1])
86+ ? stripLeadingPackageManagerSeparator(argv)
87+ : argv;
88+}
66896790export function readNumber(value, label) {
6891const raw = String(value).trim();
@@ -95,6 +118,7 @@ function readPositiveNumberEnv(name, fallback) {
95118}
9611997120export function parseArgs(argv) {
121+const args = stripPackageManagerSeparatorForKnownFlags(argv);
98122const stamp = new Date().toISOString().replace(/[:.]/g, "-");
99123const options = {
100124fileCount: undefined,
@@ -109,9 +133,9 @@ export function parseArgs(argv) {
109133allowNonDarwin: process.env.OPENCLAW_MEMORY_FD_REPRO_ALLOW_NON_DARWIN === "1",
110134};
111135112- parseArgv: for (let i = 0; i < argv.length; i += 1) {
113-const arg = argv[i];
114-const next = argv[i + 1];
136+ parseArgv: for (let i = 0; i < args.length; i += 1) {
137+const arg = args[i];
138+const next = args[i + 1];
115139const readValue = () => {
116140if (!next) {
117141throw new Error(`Missing value for ${arg}`);
@@ -435,6 +459,122 @@ export async function stopGatewayWithRuntime({
435459436460export { readBoundedResponseText };
437461462+function parseJsonValue(text) {
463+try {
464+return JSON.parse(text);
465+} catch {
466+return null;
467+}
468+}
469+470+function asRecord(value) {
471+return value && typeof value === "object" && !Array.isArray(value) ? value : null;
472+}
473+474+function readStringProperty(record, key) {
475+const value = record?.[key];
476+return typeof value === "string" && value.trim() ? value : undefined;
477+}
478+479+function parseToolTextContent(result) {
480+const content = Array.isArray(result?.content) ? result.content : [];
481+for (const entry of content) {
482+const text = entry?.type === "text" && typeof entry.text === "string" ? entry.text : null;
483+if (!text) {
484+continue;
485+}
486+const parsed = asRecord(parseJsonValue(text));
487+if (parsed) {
488+return parsed;
489+}
490+}
491+return null;
492+}
493+494+export function classifyMemorySearchInvokeResponse({ httpOk, status, bodyText }) {
495+const parsedBody = parseJsonValue(bodyText);
496+const body = asRecord(parsedBody);
497+if (!httpOk) {
498+const errorRecord = asRecord(body?.error);
499+return {
500+ok: false,
501+ httpOk,
502+ status,
503+gatewayOk: body?.ok === true ? true : body?.ok === false ? false : undefined,
504+error:
505+readStringProperty(errorRecord, "message") ??
506+readStringProperty(body, "error") ??
507+`memory_search HTTP request failed with status ${status}`,
508+};
509+}
510+if (!body) {
511+return {
512+ok: false,
513+ httpOk,
514+ status,
515+error: "memory_search response was not JSON",
516+};
517+}
518+519+const gatewayOk = body.ok === true ? true : body.ok === false ? false : undefined;
520+if (gatewayOk === false) {
521+const errorRecord = asRecord(body.error);
522+return {
523+ok: false,
524+ httpOk,
525+ status,
526+ gatewayOk,
527+error:
528+readStringProperty(errorRecord, "message") ??
529+readStringProperty(body, "error") ??
530+"memory_search gateway invocation failed",
531+};
532+}
533+534+const result = asRecord(body.result);
535+const details = asRecord(result?.details);
536+const directResult = Array.isArray(result?.results) ? result : null;
537+const directBody =
538+Array.isArray(body.results) || body.disabled === true || body.unavailable === true
539+ ? body
540+ : null;
541+const payload = details ?? parseToolTextContent(result) ?? directResult ?? directBody;
542+if (!payload) {
543+return {
544+ok: false,
545+ httpOk,
546+ status,
547+ gatewayOk,
548+error: "memory_search result payload missing or invalid",
549+};
550+}
551+const resultCount = Array.isArray(payload.results) ? payload.results.length : undefined;
552+const toolDisabled = payload.disabled === true;
553+const toolUnavailable = payload.unavailable === true;
554+const toolError = readStringProperty(payload, "error");
555+const ok = gatewayOk === true && !toolDisabled && !toolUnavailable && !toolError;
556+557+return {
558+ ok,
559+ httpOk,
560+ status,
561+ gatewayOk,
562+ resultCount,
563+ toolDisabled,
564+ toolUnavailable,
565+ ...(toolError ? { toolError } : {}),
566+ ...(ok
567+ ? {}
568+ : {
569+error:
570+toolError ??
571+(toolDisabled || toolUnavailable
572+ ? "memory_search returned disabled/unavailable"
573+ : "memory_search result payload missing or invalid"),
574+}),
575+};
576+}
577+438578async function invokeMemorySearch({ port, token, timeoutMs }) {
439579const controller = new AbortController();
440580const timer = setTimeout(() => controller.abort(), timeoutMs);
@@ -462,9 +602,13 @@ async function invokeMemorySearch({ port, token, timeoutMs }) {
462602"memory_search",
463603MEMORY_SEARCH_RESPONSE_MAX_BYTES,
464604);
465-return {
466-ok: res.ok,
605+const result = classifyMemorySearchInvokeResponse({
606+httpOk: res.ok,
467607status: res.status,
608+bodyText: text,
609+});
610+return {
611+ ...result,
468612durationMs: Date.now() - startedAt,
469613bodyPreview: text.slice(0, 500),
470614};
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。