Files
kdletters 2ac97b3f5e
Project CI / Repository checks (push) Successful in 3m50s
Project CI / Frontend tests (push) Successful in 4m41s
Project CI / Backend tests (push) Successful in 5m35s
Project CI / Native shell tests (push) Failing after 9m59s
退役客户端 MCP 约束与运行链路
删除客户端 MCP 配置、Runtime 工具和安全门禁

移除 MCP E2E 套件、测试夹具和测试辅助代码

清理 MCP 依赖及 Skill/Prompt 中的 MCP 约束
2026-08-26 02:32:05 +08:00

419 lines
14 KiB
JavaScript

import {
assert,
codedError,
hashValue,
recordError,
summarizeRecordedError,
} from '../assertions/core.mjs';
import { fs, os, path, TextDecoder } from '../dependencies.mjs';
import {
mainAgentId,
projectSupervisorAgentId,
sentinelFileName,
sentinelSchema,
state,
} from '../runtime-state.mjs';
import { isContextCompactionSuite } from '../suites/context-compaction.mjs';
import { isGoalRuntimeSuite } from '../suites/goal.mjs';
import { isParallelReadSuite } from '../suites/parallel-read.mjs';
import { isProjectSkillSuite } from '../suites/project-skill.mjs';
import { isResponseStreamSuite } from '../suites/response-stream.mjs';
import { isScopedAgentsSuite } from '../suites/scoped-agents.mjs';
import { isSteerRunnerKillSuite } from '../suites/steer-runner-kill.mjs';
import { isSupervisorAutonomousPlayableLaneDefenseSuite } from '../suites/supervisor-autonomous-playable.mjs';
import { isSupervisorSwarmSuite } from '../suites/supervisor-swarm.mjs';
import { isUserInputRuntimeSuite } from '../suites/user-input.mjs';
import { isWebSearchSuite } from '../suites/web-search.mjs';
import { isPathInside, readJson } from './io.mjs';
export async function removeDisposableProject() {
const [realTemp, realProject] = await Promise.all([
fs.realpath(os.tmpdir()),
fs.realpath(state.projectRoot),
]);
if (!isPathInside(realTemp, realProject)) return false;
const sentinelPath = path.join(realProject, sentinelFileName);
const metadata = await fs.lstat(sentinelPath).catch(() => null);
if (!metadata?.isFile() || metadata.isSymbolicLink()) return false;
const sentinel = await readJson(sentinelPath).catch(() => null);
if (
sentinel?.schemaVersion !== sentinelSchema ||
sentinel?.token !== state.sentinelToken
) {
return false;
}
await fs.rm(realProject, { recursive: true, force: false });
return true;
}
export function providerUsedFromEvidence(evidence) {
const requestIdentityCount = evidence?.providerRequestIdentityCount;
const startedCount = evidence?.providerLifecycleStartedCount;
const terminalCount = evidence?.providerLifecycleTerminalCount;
const completedCount = evidence?.providerLifecycleCompletedCount;
return (
evidence?.evidenceCompleteness === 'complete' &&
evidence.providerAgentMode === 'provider' &&
evidence.providerBindingMatched === true &&
typeof evidence.providerModel === 'string' &&
evidence.providerModel.trim().length > 0 &&
typeof evidence.providerApiKind === 'string' &&
evidence.providerApiKind.trim().length > 0 &&
typeof evidence.providerReasoningEffort === 'string' &&
evidence.providerReasoningEffort.trim().length > 0 &&
/^[0-9a-f]{64}$/u.test(evidence.providerBaseUrlSha256 ?? '') &&
Number.isSafeInteger(evidence.providerBoundAgentCount) &&
evidence.providerBoundAgentCount > 0 &&
Number.isSafeInteger(requestIdentityCount) &&
Number.isSafeInteger(startedCount) &&
Number.isSafeInteger(terminalCount) &&
Number.isSafeInteger(completedCount) &&
requestIdentityCount > 0 &&
startedCount === requestIdentityCount &&
terminalCount === requestIdentityCount &&
completedCount === requestIdentityCount &&
evidence.providerLifecycleFailedCount === 0 &&
evidence.openProviderLifecycleCount === 0 &&
evidence.duplicateProviderLifecycleCount === 0
);
}
export function buildSummary() {
const secretLeakCount =
state.transcriptLeakCount + state.projectLeakCount + state.reportLeakCount;
const base = {
status: state.status,
suite: state.suite,
providerUsed: providerUsedFromEvidence(state.evidence),
config: state.config,
blocked: state.blocked,
run: {
agentId:
isUserInputRuntimeSuite() ||
isSupervisorAutonomousPlayableLaneDefenseSuite() ||
isSupervisorSwarmSuite()
? projectSupervisorAgentId
: mainAgentId,
runIdHash: hashValue(state.initialRunId),
sessionIdHash: hashValue(state.initialSessionId),
runnerKilled: isSupervisorAutonomousPlayableLaneDefenseSuite()
? false
: state.runnerKilled,
resumed: state.resumed,
identityStable: state.identityStable,
},
evidence: {
...state.evidence,
secretLeakCount,
lureLeakCount: state.lureLeakCount,
projectPathTranscriptLeakCount: state.projectPathTranscriptLeakCount,
projectPathReportLeakCount: state.projectPathReportLeakCount,
...(isWebSearchSuite() ||
isContextCompactionSuite() ||
isUserInputRuntimeSuite() ||
isScopedAgentsSuite() ||
isProjectSkillSuite() ||
isParallelReadSuite() ||
isSupervisorAutonomousPlayableLaneDefenseSuite() ||
isSupervisorSwarmSuite() ||
isSteerRunnerKillSuite()
? {
formalConfigPathTranscriptLeakCount:
state.formalConfigPathTranscriptLeakCount,
formalConfigPathReportLeakCount:
state.formalConfigPathReportLeakCount,
}
: {}),
},
cleanup: {
performed: state.cleanupPerformed,
kept: Boolean(state.options?.keepProject),
},
errorCount: state.errors.length,
errorHashes: state.errors.map(summarizeRecordedError),
};
base.summaryHash = hashValue(JSON.stringify(base));
return base;
}
export function emptyEvidence() {
return {
taskCount: 0,
eventCount: 0,
agentDbRecordCount: 0,
successfulToolExecutionCount: 0,
toolPlanProtocolCount: 0,
structuredPlanUpdateCount: 0,
structuredPlanRevision: 0,
structuredPlanCompletedStepCount: 0,
structuredPlanRegressionCount: 0,
structuredPlanPreKillRevision: 0,
structuredPlanPreKillCompletedStepCount: 0,
structuredPlanPreKillIncompleteStepCount: 0,
structuredPlanPreKillTerminalStepHash: null,
structuredPlanRecoveredRevision: 0,
structuredPlanRecoveredCompletedStepCount: 0,
structuredPlanRecoveredTerminalStepHash: null,
structuredPlanTimelineUpdateCount: 0,
structuredPlanTimelineAnchoredUpdateCount: 0,
structuredPlanCompletionTransitionCount: 0,
structuredPlanCompletionObservationCount: 0,
structuredPlanPrematureCompletionCount: 0,
structuredPlanTimelineHash: null,
steerAcceptedPlanRevision: 0,
steerSequence: 0,
steerIdHash: null,
steerMessageIdHash: null,
steerInstructionSha256: null,
steerProviderInterrupted: false,
steerProviderPlanningWaitMatched: false,
steerCompletedStepCountAtAcceptance: 0,
steerIncompleteStepCountAtAcceptance: 0,
steerFirstPostPlanRevision: 0,
steerFirstPostIncompleteStepCount: 0,
steerIncompletePlanReordered: false,
steerOldPendingActionCount: 0,
steerOldPendingActionSetHash: null,
steerOldPendingExecutionCount: 0,
steerOldPlanMaterializedActionCount: 0,
steerAcceptanceWindowExecutionCount: 0,
steerSideEffectReceiptCountAtAcceptance: 0,
steerSideEffectSnapshotHash: null,
steerPreSideEffectReplayCount: 0,
steerLedgerRecordCount: 0,
steerAppliedCount: 0,
steerClosedCount: 0,
steerAuditCount: 0,
steerTaskRunCountBefore: 0,
steerTaskRunCountAfter: 0,
steerTaskRunSetHash: null,
finalTargetMainRunCount: 0,
finalLegalMainLineageRunCount: 0,
finalUnexpectedMainRunCount: 0,
finalTargetMainRunSetHash: null,
steerPublicInstructionLeakCount: 0,
steerInstructionReportLeakCount: 0,
confirmedActionLifecycleCount: 0,
sideEffectActionCount: 0,
sideEffectReplayCount: 0,
idempotentReplayActionCount: 0,
actionReceiptReplayRecordCount: 0,
completedProjectionCount: 0,
finalAssistantAuditCount: 0,
projectRevision: 0,
projectIndexExecutionCount: 0,
gitInspectExecutionCount: 0,
gitInspectChangedFileCount: 0,
gitInspectRevisionNeutral: false,
gitInspectPostCommitSelectedPathsClean: false,
gitCommitExecutionCount: 0,
gitCommitPathCount: 0,
gitCommitAuditCount: 0,
gitCommitReceiptCount: 0,
gitCommitParentMatched: false,
gitCommitTreeMatched: false,
gitCommitReflogMatched: false,
gitCommitPostInspectSelectedPathsClean: false,
repositoryContextSourceCount: 0,
checkpointFileCount: 0,
patchsetExecutionCount: 0,
patchsetPreparedAuditCount: 0,
patchsetCompletedAuditCount: 0,
patchsetChangeCount: 0,
patchsetRevisionDelta: 0,
patchsetContentDiffFileCount: 0,
patchsetCheckpointBound: false,
patchsetExpectedSha256Matched: false,
halfCompletedFileCount: 0,
commandExecRunCount: 0,
commandExecFailedCount: 0,
commandExecSucceededCount: 0,
commandOutputReadExecutionCount: 0,
commandOutputPageCount: 0,
commandOutputMarkerSidecarCount: 0,
commandOutputMarkerContextCount: 0,
commandOutputMarkerTaskLeakCount: 0,
commandOutputMarkerEventLeakCount: 0,
commandOutputMarkerAgentDbLeakCount: 0,
commandOutputMarkerConversationLeakCount: 0,
commandOutputMarkerActivityLeakCount: 0,
commandOutputMarkerOutputLeakCount: 0,
commandOutputMarkerRuntimeStateLeakCount: 0,
commandOutputMarkerReceiptLeakCount: 0,
commandOutputReadReceiptCount: 0,
commandOutputMarkerReportLeakCount: 0,
editorApiAssetCount: 0,
verificationPassed: false,
browserValidationCount: 0,
imageInspectExecutionCount: 0,
imageInspectImageCount: 0,
imageInspectDedicatedAuditCount: 0,
imageInspectReceiptCount: 0,
imageInspectResponseIdPresent: false,
persistedImagePayloadLeakCount: 0,
isolatedInstanceCount: 0,
isolatedTemplateCount: 0,
isolatedJoinCount: 0,
isolatedJoinDeliveryTarget: null,
isolatedParentWakeDispatchCount: 0,
actionHistoryExecutionCount: 0,
actionHistoryResultCount: 0,
actionHistoryRecursiveResultCount: 0,
actionReceiptCount: 0,
mainRunActionReceiptCount: 0,
actionReceiptRequiredToolCount: 0,
actionReceiptDuplicateIdentityCount: 0,
actionReceiptSecretLeakCount: 0,
actionReceiptLureLeakCount: 0,
conversationMessageCount: 0,
targetSessionMessageCount: 0,
targetSessionUserMessageCount: 0,
targetSessionAssistantMessageCount: 0,
targetSessionConversationAuditCount: 0,
finalAssistantCount: 0,
duplicateActionCount: 0,
duplicateMessageCount: 0,
duplicateReceiptCount: 0,
confirmedActionCount: 0,
projectPathPublicLeakCount: 0,
projectPathPublicSurfaceCount: 0,
projectPathTranscriptLeakCount: 0,
projectPathReportLeakCount: 0,
secretLeakCount: 0,
lureLeakCount: 0,
paths: [],
};
}
export async function collectPartialRuntimeJsonlSurface(
suitePrefix,
surface,
resolveFiles,
) {
let files;
try {
files = await resolveFiles();
} catch {
const errors = ['surface-list-failed'];
recordError(
`${suitePrefix}-partial-${surface}-read-failed`,
codedError(errors[0]),
);
return { records: [], errors };
}
const result = await readJsonlFilesPreservingValidRecords(files);
if (result.errors.length > 0) {
recordError(
`${suitePrefix}-partial-${surface}-read-failed`,
codedError([...new Set(result.errors)].join(',')),
);
}
return {
records: result.records,
errors: [...new Set(result.errors)],
};
}
export async function readJsonlFilesPreservingValidRecords(files) {
const records = [];
const errors = [];
for (const file of files) {
const result = await readJsonlPreservingValidRecords(file);
records.push(...result.records);
errors.push(...result.errors);
}
return { records, errors };
}
export async function readJsonlPreservingValidRecords(file) {
let content;
try {
content = await fs.readFile(file);
} catch (error) {
return {
records: [],
errors: [
error?.code === 'ENOENT' ? 'file-disappeared' : 'file-read-failed',
],
};
}
const records = [];
const errors = [];
const lines = splitJsonlBufferLines(content);
for (const lineRecord of lines) {
let line;
try {
line = decodeUtf8Fatal(lineRecord.bytes, 'jsonl-invalid-utf8');
} catch {
errors.push('invalid-utf8');
continue;
}
if (line.trim().length === 0) continue;
try {
const record = JSON.parse(line);
if (!record || typeof record !== 'object' || Array.isArray(record)) {
errors.push('invalid-record');
continue;
}
records.push(record);
} catch {
errors.push(lineRecord.terminated ? 'invalid-record' : 'truncated-tail');
}
}
return { records, errors };
}
export function splitJsonlBufferLines(content) {
assert(Buffer.isBuffer(content), 'jsonl-content-not-buffer');
const lines = [];
let start = 0;
for (let index = 0; index < content.length; index += 1) {
if (content[index] !== 0x0a) continue;
let end = index;
if (end > start && content[end - 1] === 0x0d) end -= 1;
lines.push({ bytes: content.subarray(start, end), terminated: true });
start = index + 1;
}
if (start < content.length) {
lines.push({ bytes: content.subarray(start), terminated: false });
}
return lines;
}
export function decodeUtf8Fatal(content, code = 'invalid-utf8') {
try {
return new TextDecoder('utf-8', { fatal: true }).decode(content);
} catch (error) {
throw codedError(code, error);
}
}
export async function readLatestJsonFile(files) {
const candidates = [];
for (const file of files.filter((entry) => entry.endsWith('.json'))) {
const metadata = await fs.stat(file).catch(() => null);
if (metadata?.isFile())
candidates.push({ file, mtimeMs: metadata.mtimeMs });
}
candidates.sort((left, right) => right.mtimeMs - left.mtimeMs);
return candidates.length > 0
? readJson(candidates[0].file).catch(() => null)
: null;
}
export function isIsolatedRunnerSuite() {
return (
isSteerRunnerKillSuite() ||
isGoalRuntimeSuite() ||
isResponseStreamSuite() ||
isWebSearchSuite() ||
isContextCompactionSuite() ||
isUserInputRuntimeSuite() ||
isScopedAgentsSuite() ||
isProjectSkillSuite() ||
isParallelReadSuite() ||
isSupervisorAutonomousPlayableLaneDefenseSuite() ||
isSupervisorSwarmSuite()
);
}