fix: pairing admin satisfies write (#23125) (thanks @vignesh07)
This commit is contained in:
parent
426d97797d
commit
5b4409d5d0
@ -16,6 +16,7 @@ Docs: https://docs.openclaw.ai
|
||||
|
||||
### Fixes
|
||||
|
||||
- Gateway/Pairing: treat operator.admin pairing tokens as satisfying operator.write requests so legacy devices stop looping through scope-upgrade prompts introduced in 2026.2.19. (#23125, #23006) Thanks @vignesh07.
|
||||
- Memory/QMD: add optional `memory.qmd.mcporter` search routing so QMD `query/search/vsearch` can run through mcporter keep-alive flows (including multi-collection paths) to reduce cold starts, while keeping searches on agent-scoped QMD state for consistent recall. (#19617) Thanks @nicole-luxe and @vignesh07.
|
||||
- Chat/UI: strip inline reply/audio directive tags (`[[reply_to_current]]`, `[[reply_to:<id>]]`, `[[audio_as_voice]]`) from displayed chat history, live chat event output, and session preview snippets so control tags no longer leak into user-visible surfaces.
|
||||
- BlueBubbles/DM history: restore DM backfill context with account-scoped rolling history, bounded backfill retries, and safer history payload limits. (#20302) Thanks @Ryan-Haines.
|
||||
|
||||
@ -196,6 +196,55 @@ describe("gateway lock", () => {
|
||||
staleSpy.mockRestore();
|
||||
});
|
||||
|
||||
it("keeps lock when fs.stat fails until payload is stale", async () => {
|
||||
vi.useRealTimers();
|
||||
const env = await makeEnv();
|
||||
const { lockPath, configPath } = resolveLockPath(env);
|
||||
const payload = createLockPayload({ configPath, startTime: 111 });
|
||||
await fs.writeFile(lockPath, JSON.stringify(payload), "utf8");
|
||||
|
||||
const procSpy = mockProcStatRead({
|
||||
onProcRead: () => {
|
||||
throw new Error("EACCES");
|
||||
},
|
||||
});
|
||||
const statSpy = vi
|
||||
.spyOn(fs, "stat")
|
||||
.mockRejectedValue(Object.assign(new Error("EPERM"), { code: "EPERM" }));
|
||||
|
||||
const pending = acquireForTest(env, {
|
||||
timeoutMs: 20,
|
||||
staleMs: 10_000,
|
||||
platform: "linux",
|
||||
});
|
||||
await expect(pending).rejects.toBeInstanceOf(GatewayLockError);
|
||||
|
||||
procSpy.mockRestore();
|
||||
|
||||
const stalePayload = createLockPayload({
|
||||
configPath,
|
||||
startTime: 111,
|
||||
createdAt: new Date(0).toISOString(),
|
||||
});
|
||||
await fs.writeFile(lockPath, JSON.stringify(stalePayload), "utf8");
|
||||
|
||||
const staleProcSpy = mockProcStatRead({
|
||||
onProcRead: () => {
|
||||
throw new Error("EACCES");
|
||||
},
|
||||
});
|
||||
|
||||
const lock = await acquireForTest(env, {
|
||||
staleMs: 1,
|
||||
platform: "linux",
|
||||
});
|
||||
expect(lock).not.toBeNull();
|
||||
|
||||
await lock?.release();
|
||||
staleProcSpy.mockRestore();
|
||||
statSpy.mockRestore();
|
||||
});
|
||||
|
||||
it("returns null when multi-gateway override is enabled", async () => {
|
||||
const env = await makeEnv();
|
||||
const lock = await acquireGatewayLock({
|
||||
|
||||
@ -231,7 +231,11 @@ export async function acquireGatewayLock(
|
||||
const st = await fs.stat(lockPath);
|
||||
stale = Date.now() - st.mtimeMs > staleMs;
|
||||
} catch {
|
||||
stale = true;
|
||||
// On Windows or locked filesystems we may be unable to stat the
|
||||
// lock file even though the existing gateway is still healthy.
|
||||
// Treat the lock as non-stale so we keep waiting instead of
|
||||
// forcefully removing another gateway's lock.
|
||||
stale = false;
|
||||
}
|
||||
}
|
||||
if (stale) {
|
||||
|
||||
@ -985,8 +985,9 @@ describe("QmdMemoryManager", () => {
|
||||
);
|
||||
expect(mcporterCall).toBeDefined();
|
||||
const spawnOpts = mcporterCall?.[2] as { env?: NodeJS.ProcessEnv } | undefined;
|
||||
expect(spawnOpts?.env?.XDG_CONFIG_HOME).toContain("/agents/main/qmd/xdg-config");
|
||||
expect(spawnOpts?.env?.XDG_CACHE_HOME).toContain("/agents/main/qmd/xdg-cache");
|
||||
const normalizePath = (value?: string) => value?.replace(/\\/g, "/");
|
||||
expect(normalizePath(spawnOpts?.env?.XDG_CONFIG_HOME)).toContain("/agents/main/qmd/xdg-config");
|
||||
expect(normalizePath(spawnOpts?.env?.XDG_CACHE_HOME)).toContain("/agents/main/qmd/xdg-cache");
|
||||
|
||||
await manager.close();
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user