

























@@ -147,6 +147,27 @@ function createCliBackendConfig(
147147} satisfies OpenClawConfig;
148148}
149149150+function setClaudeCliBackendForPrepareTest() {
151+cliBackendsTesting.setDepsForTest({
152+resolvePluginSetupCliBackend: () => undefined,
153+resolveRuntimeCliBackends: () => [
154+{
155+id: "claude-cli",
156+pluginId: "anthropic",
157+bundleMcp: false,
158+config: {
159+command: "claude",
160+args: ["--print"],
161+resumeArgs: ["--resume", "{sessionId}"],
162+output: "jsonl",
163+input: "stdin",
164+sessionMode: "existing",
165+},
166+},
167+],
168+});
169+}
170+150171function createSessionFile() {
151172const dir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-cli-prepare-"));
152173vi.stubEnv("OPENCLAW_STATE_DIR", dir);
@@ -1407,27 +1428,12 @@ describe("shouldSkipLocalCliCredentialEpoch", () => {
14071428it("drops the claude-cli sessionId when the on-disk transcript is missing (#77011)", async () => {
14081429const { dir, sessionFile } = createSessionFile();
14091430try {
1410-cliBackendsTesting.setDepsForTest({
1411-resolvePluginSetupCliBackend: () => undefined,
1412-resolveRuntimeCliBackends: () => [
1413-{
1414-id: "claude-cli",
1415-pluginId: "anthropic",
1416-bundleMcp: false,
1417-config: {
1418-command: "claude",
1419-args: ["--print"],
1420-resumeArgs: ["--resume", "{sessionId}"],
1421-output: "jsonl",
1422-input: "stdin",
1423-sessionMode: "existing",
1424-},
1425-},
1426-],
1427-});
1431+setClaudeCliBackendForPrepareTest();
14281432const transcriptCheck = vi.fn(async () => false);
1433+const orphanCheck = vi.fn(async () => true);
14291434setCliRunnerPrepareTestDeps({
14301435claudeCliSessionTranscriptHasContent: transcriptCheck,
1436+claudeCliSessionTranscriptHasOrphanedToolUse: orphanCheck,
14311437});
1432143814331439const context = await prepareCliRunContext({
@@ -1449,36 +1455,78 @@ describe("shouldSkipLocalCliCredentialEpoch", () => {
14491455sessionId: "stale-claude-sid",
14501456workspaceDir: dir,
14511457});
1458+expect(orphanCheck).not.toHaveBeenCalled();
14521459expect(context.reusableCliSession).toEqual({ invalidatedReason: "missing-transcript" });
14531460} finally {
14541461fs.rmSync(dir, { recursive: true, force: true });
14551462}
14561463});
145714641458-it("keeps the claude-cli sessionId when the on-disk transcript is present", async () => {
1465+it("invalidates orphaned claude-cli transcripts and reseeds OpenClaw history", async () => {
14591466const { dir, sessionFile } = createSessionFile();
1467+appendTranscriptEntry(sessionFile, {
1468+id: "msg-1",
1469+parentId: null,
1470+timestamp: new Date(1).toISOString(),
1471+message: {
1472+role: "user",
1473+content: "prior orphan-safe ask",
1474+timestamp: 1,
1475+},
1476+});
1477+14601478try {
1461-cliBackendsTesting.setDepsForTest({
1462-resolvePluginSetupCliBackend: () => undefined,
1463-resolveRuntimeCliBackends: () => [
1464-{
1465-id: "claude-cli",
1466-pluginId: "anthropic",
1467-bundleMcp: false,
1468-config: {
1469-command: "claude",
1470-args: ["--print"],
1471-resumeArgs: ["--resume", "{sessionId}"],
1472-output: "jsonl",
1473-input: "stdin",
1474-sessionMode: "existing",
1475-},
1476-},
1477-],
1479+setClaudeCliBackendForPrepareTest();
1480+const transcriptCheck = vi.fn(async () => true);
1481+const orphanCheck = vi.fn(async () => true);
1482+setCliRunnerPrepareTestDeps({
1483+claudeCliSessionTranscriptHasContent: transcriptCheck,
1484+claudeCliSessionTranscriptHasOrphanedToolUse: orphanCheck,
14781485});
1486+1487+const context = await prepareCliRunContext({
1488+sessionId: "session-test",
1489+sessionKey: "agent:main:telegram:direct:peer",
1490+ sessionFile,
1491+workspaceDir: dir,
1492+prompt: "follow-up",
1493+provider: "claude-cli",
1494+model: "opus",
1495+timeoutMs: 1_000,
1496+runId: "run-orphan-tool-use",
1497+cliSessionBinding: {
1498+sessionId: "orphaned-claude-sid",
1499+cwdHash: hashCliSessionText(dir),
1500+},
1501+cliSessionId: "orphaned-claude-sid",
1502+config: createCliBackendConfig(),
1503+});
1504+1505+expect(transcriptCheck).toHaveBeenCalledWith({
1506+sessionId: "orphaned-claude-sid",
1507+workspaceDir: dir,
1508+});
1509+expect(orphanCheck).toHaveBeenCalledWith({
1510+sessionId: "orphaned-claude-sid",
1511+workspaceDir: dir,
1512+});
1513+expect(context.reusableCliSession).toEqual({ invalidatedReason: "orphaned-tool-use" });
1514+expect(context.openClawHistoryPrompt).toContain("prior orphan-safe ask");
1515+expect(context.openClawHistoryPrompt).toContain("follow-up");
1516+} finally {
1517+fs.rmSync(dir, { recursive: true, force: true });
1518+}
1519+});
1520+1521+it("keeps the claude-cli sessionId when the on-disk transcript is present", async () => {
1522+const { dir, sessionFile } = createSessionFile();
1523+try {
1524+setClaudeCliBackendForPrepareTest();
14791525const transcriptCheck = vi.fn(async () => true);
1526+const orphanCheck = vi.fn(async () => false);
14801527setCliRunnerPrepareTestDeps({
14811528claudeCliSessionTranscriptHasContent: transcriptCheck,
1529+claudeCliSessionTranscriptHasOrphanedToolUse: orphanCheck,
14821530});
1483153114841532const context = await prepareCliRunContext({
@@ -1500,6 +1548,10 @@ describe("shouldSkipLocalCliCredentialEpoch", () => {
15001548sessionId: "live-claude-sid",
15011549workspaceDir: dir,
15021550});
1551+expect(orphanCheck).toHaveBeenCalledWith({
1552+sessionId: "live-claude-sid",
1553+workspaceDir: dir,
1554+});
15031555expect(context.reusableCliSession).toEqual({ sessionId: "live-claude-sid" });
15041556} finally {
15051557fs.rmSync(dir, { recursive: true, force: true });
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。