fix(sisyphus-orchestrator): add cross-platform path validation for Windows support
Add isSisyphusPath() helper function that handles both forward slashes (Unix) and backslashes (Windows) using regex pattern /\.sisyphus[/\\]/. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
parent
83d958580f
commit
571810f1e7
@ -506,6 +506,90 @@ describe("sisyphus-orchestrator hook", () => {
|
|||||||
// #then
|
// #then
|
||||||
expect(output.output).toBe(originalOutput)
|
expect(output.output).toBe(originalOutput)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("cross-platform path validation (Windows support)", () => {
|
||||||
|
test("should NOT append reminder when orchestrator writes inside .sisyphus\\ (Windows backslash)", async () => {
|
||||||
|
// #given
|
||||||
|
const hook = createSisyphusOrchestratorHook(createMockPluginInput())
|
||||||
|
const originalOutput = "File written successfully"
|
||||||
|
const output = {
|
||||||
|
title: "Write",
|
||||||
|
output: originalOutput,
|
||||||
|
metadata: { filePath: ".sisyphus\\plans\\work-plan.md" },
|
||||||
|
}
|
||||||
|
|
||||||
|
// #when
|
||||||
|
await hook["tool.execute.after"](
|
||||||
|
{ tool: "Write", sessionID: ORCHESTRATOR_SESSION },
|
||||||
|
output
|
||||||
|
)
|
||||||
|
|
||||||
|
// #then
|
||||||
|
expect(output.output).toBe(originalOutput)
|
||||||
|
expect(output.output).not.toContain("DELEGATION REQUIRED")
|
||||||
|
})
|
||||||
|
|
||||||
|
test("should NOT append reminder when orchestrator writes inside .sisyphus with mixed separators", async () => {
|
||||||
|
// #given
|
||||||
|
const hook = createSisyphusOrchestratorHook(createMockPluginInput())
|
||||||
|
const originalOutput = "File written successfully"
|
||||||
|
const output = {
|
||||||
|
title: "Write",
|
||||||
|
output: originalOutput,
|
||||||
|
metadata: { filePath: ".sisyphus\\plans/work-plan.md" },
|
||||||
|
}
|
||||||
|
|
||||||
|
// #when
|
||||||
|
await hook["tool.execute.after"](
|
||||||
|
{ tool: "Write", sessionID: ORCHESTRATOR_SESSION },
|
||||||
|
output
|
||||||
|
)
|
||||||
|
|
||||||
|
// #then
|
||||||
|
expect(output.output).toBe(originalOutput)
|
||||||
|
expect(output.output).not.toContain("DELEGATION REQUIRED")
|
||||||
|
})
|
||||||
|
|
||||||
|
test("should NOT append reminder for absolute Windows path inside .sisyphus\\", async () => {
|
||||||
|
// #given
|
||||||
|
const hook = createSisyphusOrchestratorHook(createMockPluginInput())
|
||||||
|
const originalOutput = "File written successfully"
|
||||||
|
const output = {
|
||||||
|
title: "Write",
|
||||||
|
output: originalOutput,
|
||||||
|
metadata: { filePath: "C:\\Users\\test\\project\\.sisyphus\\plans\\x.md" },
|
||||||
|
}
|
||||||
|
|
||||||
|
// #when
|
||||||
|
await hook["tool.execute.after"](
|
||||||
|
{ tool: "Write", sessionID: ORCHESTRATOR_SESSION },
|
||||||
|
output
|
||||||
|
)
|
||||||
|
|
||||||
|
// #then
|
||||||
|
expect(output.output).toBe(originalOutput)
|
||||||
|
expect(output.output).not.toContain("DELEGATION REQUIRED")
|
||||||
|
})
|
||||||
|
|
||||||
|
test("should append reminder for Windows path outside .sisyphus\\", async () => {
|
||||||
|
// #given
|
||||||
|
const hook = createSisyphusOrchestratorHook(createMockPluginInput())
|
||||||
|
const output = {
|
||||||
|
title: "Write",
|
||||||
|
output: "File written successfully",
|
||||||
|
metadata: { filePath: "C:\\Users\\test\\project\\src\\code.ts" },
|
||||||
|
}
|
||||||
|
|
||||||
|
// #when
|
||||||
|
await hook["tool.execute.after"](
|
||||||
|
{ tool: "Write", sessionID: ORCHESTRATOR_SESSION },
|
||||||
|
output
|
||||||
|
)
|
||||||
|
|
||||||
|
// #then
|
||||||
|
expect(output.output).toContain("DELEGATION REQUIRED")
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -14,7 +14,14 @@ import type { BackgroundManager } from "../../features/background-agent"
|
|||||||
|
|
||||||
export const HOOK_NAME = "sisyphus-orchestrator"
|
export const HOOK_NAME = "sisyphus-orchestrator"
|
||||||
|
|
||||||
const ALLOWED_PATH_PREFIX = ".sisyphus/"
|
/**
|
||||||
|
* Cross-platform check if a path is inside .sisyphus/ directory.
|
||||||
|
* Handles both forward slashes (Unix) and backslashes (Windows).
|
||||||
|
*/
|
||||||
|
function isSisyphusPath(filePath: string): boolean {
|
||||||
|
return /\.sisyphus[/\\]/.test(filePath)
|
||||||
|
}
|
||||||
|
|
||||||
const WRITE_EDIT_TOOLS = ["Write", "Edit", "write", "edit"]
|
const WRITE_EDIT_TOOLS = ["Write", "Edit", "write", "edit"]
|
||||||
|
|
||||||
const DIRECT_WORK_REMINDER = `
|
const DIRECT_WORK_REMINDER = `
|
||||||
@ -549,7 +556,7 @@ export function createSisyphusOrchestratorHook(
|
|||||||
// Check Write/Edit tools for orchestrator - inject strong warning
|
// Check Write/Edit tools for orchestrator - inject strong warning
|
||||||
if (WRITE_EDIT_TOOLS.includes(input.tool)) {
|
if (WRITE_EDIT_TOOLS.includes(input.tool)) {
|
||||||
const filePath = (output.args.filePath ?? output.args.path ?? output.args.file) as string | undefined
|
const filePath = (output.args.filePath ?? output.args.path ?? output.args.file) as string | undefined
|
||||||
if (filePath && !filePath.includes(ALLOWED_PATH_PREFIX)) {
|
if (filePath && !isSisyphusPath(filePath)) {
|
||||||
// Store filePath for use in tool.execute.after
|
// Store filePath for use in tool.execute.after
|
||||||
if (input.callID) {
|
if (input.callID) {
|
||||||
pendingFilePaths.set(input.callID, filePath)
|
pendingFilePaths.set(input.callID, filePath)
|
||||||
@ -593,7 +600,7 @@ export function createSisyphusOrchestratorHook(
|
|||||||
if (!filePath) {
|
if (!filePath) {
|
||||||
filePath = output.metadata?.filePath as string | undefined
|
filePath = output.metadata?.filePath as string | undefined
|
||||||
}
|
}
|
||||||
if (filePath && !filePath.includes(ALLOWED_PATH_PREFIX)) {
|
if (filePath && !isSisyphusPath(filePath)) {
|
||||||
output.output = (output.output || "") + DIRECT_WORK_REMINDER
|
output.output = (output.output || "") + DIRECT_WORK_REMINDER
|
||||||
log(`[${HOOK_NAME}] Direct work reminder appended`, {
|
log(`[${HOOK_NAME}] Direct work reminder appended`, {
|
||||||
sessionID: input.sessionID,
|
sessionID: input.sessionID,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user