Commit graph

2 commits

Author SHA1 Message Date
Cursor Agent
1fdda937f7
feat(plugins): OD_SNAPSHOT_RETENTION_DAYS referenced-row TTL (PB2)
Plan M1 / spec PB2 / §16 Phase 5.

Closes the 'expire even referenced rows' knob spec PB2 reserved as
operator-opt-in. When OD_SNAPSHOT_RETENTION_DAYS is set,
pruneExpiredSnapshots additionally retires snapshot rows whose
project_id no longer exists in the projects table AND whose
applied_at is older than the configured window. Live-project rows
stay pinned forever (reproducibility wins).

The 'project deleted' check is the v1 stand-in for the spec's
'referencing run/conversation/project is itself terminal' clause:
runs are in-memory in v1 (no SQLite signal we can read), and
conversations have no archived_at column. Deleting a project is
the loudest 'this is over' signal in v1, and it's the failure mode
that actually accumulates dangling snapshot rows in practice.

apps/daemon/src/plugins/gc.ts threads
readPluginEnvKnobs().snapshotRetentionDays into both the periodic
tick and the synchronous sweep() handle so the operator escape
hatch (od plugin snapshots prune --before <ts>) and the worker
share one rule.

Daemon tests: 1516 → 1519 (+3 cases on plugins-snapshot-gc:
deleted-project + old-enough-row pruned, deleted-project + recent
row survives, live-project + ancient row never pruned).

Co-authored-by: Tom Huang <1043269994@qq.com>
2026-05-09 14:07:02 +00:00
Cursor Agent
39820be28b
feat(plugins): snapshot GC worker + od plugin run shorthand
Plan §3.A5 (snapshot GC) + §3.B3 (od plugin run shorthand).

- New apps/daemon/src/plugins/gc.ts wraps pruneExpiredSnapshots() in a
  periodic worker driven by OD_SNAPSHOT_GC_INTERVAL_MS. Daemon boot
  starts the worker and runs an immediate sweep so a fresh daemon does
  not wait the full interval before reaping pre-existing expired rows.
  Setting the interval to 0 disables the worker entirely.
- New HTTP endpoints:
  * GET  /api/applied-plugins                  → list all snapshots
  * GET  /api/projects/:projectId/applied-plugins → list snapshots for
    one project
  * POST /api/applied-plugins/prune { before? } → operator escape hatch
    that calls pruneExpiredSnapshots() with the optional cutoff so a
    hosted operator can force-delete unreferenced rows older than ts.
- New CLI verbs:
  * od plugin snapshots list  [--project <id>]
  * od plugin snapshots prune [--before <unix-ms>]
  * od plugin run <id> --project <projectId> [--inputs <json>]
    [--grant-caps a,b] (apply + run start shorthand). Capability gate
    failures map to exit 66; missing-input to exit 67.
- ConnectorApiErrorCode gains CONNECTOR_NOT_GRANTED so the §3.A3 gate
  rejection can use the canonical sender.

Daemon tests: 1425 → 1429 (added plugins-snapshot-gc with 4 cases).

Co-authored-by: Tom Huang <1043269994@qq.com>
2026-05-09 11:21:12 +00:00