feat(DIS-102): sanitizeForDiscord strips paths and tokens before Discord send #46
2 changed files with 38 additions and 5 deletions
|
|
@ -107,30 +107,43 @@ export async function routeMessage(
|
||||||
message.author.username
|
message.author.username
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Sanitize the full response once, then use the sanitized version
|
||||||
|
// for both Discord output and conversation history storage.
|
||||||
|
// This prevents a feedback loop where raw paths in stored history
|
||||||
|
// get fed back to the agent as context, causing it to reproduce them.
|
||||||
|
const sanitizeOpts = {
|
||||||
|
repoRoot: workspace.workspace_path,
|
||||||
|
home: os.homedir(),
|
||||||
|
};
|
||||||
|
const sanitizedResponse = sanitizeForDiscord(response, sanitizeOpts);
|
||||||
|
|
||||||
// Split and send response
|
// Split and send response
|
||||||
const chunks = splitMessage(response);
|
const chunks = splitMessage(sanitizedResponse);
|
||||||
let firstMsgId: string | null = null;
|
let firstMsgId: string | null = null;
|
||||||
|
|
||||||
for (const chunk of chunks) {
|
for (const chunk of chunks) {
|
||||||
const sent = await channel.send(sanitizeForDiscord(chunk, { home: os.homedir() }));
|
const sent = await channel.send(chunk);
|
||||||
if (!firstMsgId) {
|
if (!firstMsgId) {
|
||||||
firstMsgId = sent.id;
|
firstMsgId = sent.id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store assistant response (use first message id for dedup)
|
// Store sanitized assistant response (use first message id for dedup)
|
||||||
if (firstMsgId) {
|
if (firstMsgId) {
|
||||||
db.addConversation(
|
db.addConversation(
|
||||||
workspace.id,
|
workspace.id,
|
||||||
firstMsgId,
|
firstMsgId,
|
||||||
"assistant",
|
"assistant",
|
||||||
response,
|
sanitizedResponse,
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const msg = error instanceof Error ? error.message : "Unbekannter Fehler";
|
const msg = error instanceof Error ? error.message : "Unbekannter Fehler";
|
||||||
const safeMsg = sanitizeForDiscord(`Fehler bei der Verarbeitung: ${msg}`, { home: os.homedir() });
|
const safeMsg = sanitizeForDiscord(`Fehler bei der Verarbeitung: ${msg}`, {
|
||||||
|
repoRoot: workspace.workspace_path,
|
||||||
|
home: os.homedir(),
|
||||||
|
});
|
||||||
await channel.send(safeMsg).catch(() => {});
|
await channel.send(safeMsg).catch(() => {});
|
||||||
} finally {
|
} finally {
|
||||||
clearInterval(typingInterval);
|
clearInterval(typingInterval);
|
||||||
|
|
|
||||||
|
|
@ -64,4 +64,24 @@ describe("sanitizeForDiscord", () => {
|
||||||
});
|
});
|
||||||
expect(result).toBe("<disclaw>/src/index.ts and ~/other.ts");
|
expect(result).toBe("<disclaw>/src/index.ts and ~/other.ts");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Windows-style backslash paths are sanitized
|
||||||
|
it("replaces Windows backslash paths", () => {
|
||||||
|
const text = "File at C:\\Users\\dev\\.disclaw\\workspaces\\agent-x\\src\\main.ts";
|
||||||
|
const result = sanitizeForDiscord(text, {
|
||||||
|
repoRoot: "C:\\Users\\dev\\.disclaw\\workspaces\\agent-x",
|
||||||
|
home: "C:\\Users\\dev",
|
||||||
|
});
|
||||||
|
expect(result).toBe("File at <disclaw>\\src\\main.ts");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Mixed slash styles (common on Windows when tools output forward slashes)
|
||||||
|
it("replaces forward-slash variants of Windows paths", () => {
|
||||||
|
const text = "File at C:/Users/dev/.disclaw/workspaces/agent-x/src/main.ts";
|
||||||
|
const result = sanitizeForDiscord(text, {
|
||||||
|
repoRoot: "C:\\Users\\dev\\.disclaw\\workspaces\\agent-x",
|
||||||
|
home: "C:\\Users\\dev",
|
||||||
|
});
|
||||||
|
expect(result).toBe("File at <disclaw>/src/main.ts");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue