2 Commits

Author SHA1 Message Date
PerishCode cba8bf151d chore: align namespace lifecycle packaging 2026-05-14 16:35:46 +08:00
Cursor Agent 561da49019 feat(plugins): patch-edit atom impl (Phase 7 entry slice)
Plan O4 / spec §20.3 / §21.3.2.

apps/daemon/src/plugins/atoms/patch-edit.ts ships the daemon-side
unified-diff applier behind the SKILL.md fragment landed in §3.M4.

Public surface:

  applyPatchForStep({ cwd, stepId, diff, rationale?, allowOutOfStepCreation? })
    → { status: 'completed' | 'failed' | 'skipped',
        filesTouched, added, removed, reason? }

  skipStep({ cwd, stepId, rationale })   — explicit skip path
  readPlanProgress(cwd)                  — { total, terminal } for
                                            the pipeline runner's
                                            until expression
                                            'plan.steps.terminal === plan.steps.total'

Diff parsing supports:

  - plain edits with @@ headers and ' '/-/+ body lines
  - file creation via '--- /dev/null' + '+++ b/<path>'
  - file deletion via '--- a/<path>' + '+++ /dev/null'
  - multiple file hunks in one diff (split on '--- ')

Safety contract enforced before any file is written:

  1. Path traversal guard ('..', leading '/').
  2. Every touched file MUST be in step.files[]. Out-of-step file
     creation requires allowOutOfStepCreation=true (test harness
     escape hatch).
  3. Touching a file classified as 'shell' tier in
     plan/ownership.json requires step.risk='high'. Spec §11.5.1
     boundary: layout.tsx / theme.ts / globals.css / providers.tsx
     can't be edited under risk='low'/'medium'.
  4. Context lines must match exactly; stale patches surface
     'context mismatch at line N' WITHOUT mutating disk.

After a successful apply, the runner:

  - sets plan/steps.json[id].status='completed' + completedAt
  - writes plan/receipts/step-<id>.json with files[], added, removed,
    rationale, completedAt

skipStep() and 'already in terminal state' returns are idempotent
so the pipeline runner can safely re-call after a crash.

Daemon tests: 1571 → 1581 (+10 cases on plugins-patch-edit:
single-file edit + receipt persistence, /dev/null file creation,
/dev/null file deletion, off-step file rejection, shell-tier risk
gate, path-traversal rejection, stale-patch context mismatch
rollback, idempotent terminal-state return, skipStep + receipt,
readPlanProgress aggregate).

Co-authored-by: Tom Huang <1043269994@qq.com>
2026-05-09 15:14:09 +00:00