Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 75c9c80c72
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| lastScannedRoot !== root || | ||
| lastScannedKeeplistName !== keeplistName || | ||
| lastScannedMode !== mode |
There was a problem hiding this comment.
Re-validate keeplist before applying cached clean plan
cleanFiles now gates execution only on cached root/name/mode and then runs cleanFromPlan, but it no longer verifies that the active keeplist file still exists and has keep rules at clean time. After a successful scan, deleting or emptying the keeplist still allows cleanup to proceed from the stale plan, whereas the previous cleanFolderDetailed path re-ran buildScanPlan and raised explicit keeplist errors. This regresses the documented safety behavior for missing/empty keeplists and can apply destructive removals under invalid current config.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Pull request overview
Adds the ability to execute a previously generated ScanPlan deterministically (without recomputing) so the UI can ensure “the plan applied is the plan the user reviewed,” and gates Clean on a matching cached scan context.
Changes:
- Introduces
cleanFromPlan(root, plan, options)and updatescleanFolderDetailedto delegate to it. - Updates the UI flow to cache the last
ScanPlan+ scan inputs (root / keeplist / mode) and require a match before allowing Clean. - Adds tests to ensure
cleanFromPlanexecutes exactly the cached plan and validates clean mode values.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| main.ts | Caches last scan plan/context and requires an exact match before running Clean; invalidates cache when inputs change. |
| logic.ts | Adds cleanFromPlan and routes existing clean execution through it. |
| logic_test.ts | Adds coverage for plan-based execution and invalid clean mode rejection. |
Comments suppressed due to low confidence (1)
logic.ts:575
- With plan-based execution there can be a longer gap between scan and clean, so individual files in
plan.removableFilesmay legitimately be missing by the timecleanFromPlanruns. Consider treatingDeno.errors.NotFoundduring per-file delete/quarantine as a no-op (continue cleaning) so one missing file doesn't abort the entire run.
const mode = options.mode ?? "delete";
if (mode !== "delete" && mode !== "quarantine") {
throw new Error(`Invalid clean mode: ${mode}`);
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| export async function cleanFromPlan( | ||
| root: string, | ||
| plan: ScanPlan, | ||
| options: CleanFromPlanOptions = {}, | ||
| ): Promise<CleanResult> { |
There was a problem hiding this comment.
Because cleanFromPlan is exported and accepts a ScanPlan from callers, it should defensively validate that plan.removableFiles and plan.plannedRenames contain only clean relative paths (no absolute paths, no .. segments) before executing filesystem operations. Without this, a crafted plan could cause path traversal (deleting/renaming outside root).
|
Addressed locally and pushed in 8c450d5. The follow-up keeps the cached-plan feature but moves the safety enforcement back into logic.ts, which is where these invariants belong:
Added regression coverage for missing/empty keeplists at clean time and for missing planned removals. deno task test passes locally (69/69). |
Motivation
Cleanoperates on an explicitly reviewed, previously producedScanPlanso the UI can guarantee the plan applied is the plan the user inspected.root, activekeeplist, and chosenclean modeto match the cached plan before allowingCleanto proceed.Description
cleanFromPlan(root, plan, options)andCleanFromPlanOptionsinlogic.tsand madecleanFolderDetaileddelegate to it so clean execution can be driven from aScanPlanwithout recomputing.cleanFromPlan, preserving deterministic removal ordering, quarantine handling, rename ordering, and existing rename outcome semantics.main.tsto cache the last scan context (lastScanPlan,lastScannedRoot,lastScannedKeeplistName,lastScannedMode), invalidate the cache when inputs change (including mode changes viamarkScanDirty()), and require a matching cached plan before permittingClean.logic_test.tsverifying thatcleanFromPlanexecutes only the previously built plan (leaving files created after the scan untouched) and that invalidmodevalues are rejected.Testing
deno fmt main.ts logic.ts logic_test.tssuccessfully to normalize formatting.deno task testbut the test run failed in this environment due to an external dependency fetch error fetching JSR metadata for@std/assert, so the updated test suite could not be executed here; test cases were added tologic_test.tsto cover the new contract.Codex Task