Skip to content

refactor(cli): sequential await-in-loop across plugin fetch, marketplace refresh, and drift checks #466

Description

@blafourcade

Problem

Five separate hot paths share the same anti-pattern: a for...of loop awaiting one I/O operation (git clone, file read+hash) per iteration instead of batching with bounded concurrency.

Where

  • src/application/use-cases/plugin/plugin-update-use-case.ts:46-56,74-86 — N plugins = N sequential git clone calls
  • src/application/use-cases/marketplace/marketplace-refresh-use-case.ts:42-51 — sequential per-marketplace fetch (also hit from aidd update)
  • src/application/use-cases/status-use-case.ts:181-198,252-268 — sequential per-file fileExists+readFileHash; status-all-use-case.ts:44-58 runs this 3x sequentially for --all
  • src/application/use-cases/doctor/doctor-tracked-files-use-case.ts:37-77 — same drift-check pattern, duplicated instead of shared with status

Caution

marketplace-refresh-use-case.ts's target, marketplace-registry-adapter.ts:44-66, does read-modify-write on one shared marketplaces.json per scope — a naive Promise.all on the writes would race and drop updates. Parallelize the fetch step, keep registry writes serial (or batched into one combined read-modify-write) after all fetches resolve. Same caution applies to file-count concurrency for the drift checks — use bounded concurrency (chunked), not unbounded Promise.all, to avoid EMFILE on large trees.

Fix

  1. Parallelize plugin-update-use-case.ts's fetch+compare phase, keep the manifest save serial after.
  2. Parallelize marketplace-refresh-use-case.ts's fetch phase, batch registry writes serially after.
  3. Extract one shared, bounded-concurrency drift-check helper used by both status-use-case.ts and doctor-tracked-files-use-case.ts.

Acceptance criteria

  • aidd plugin update/aidd update clone plugins concurrently (bounded), not one at a time
  • aidd marketplace refresh fetches marketplaces concurrently, registry writes stay correct (no lost updates under concurrent refresh)
  • status/doctor drift checks use one shared, bounded-concurrency helper instead of two duplicated sequential loops

Found by a performance audit of cli/ — full report: cli/aidd_docs/tasks/2026_07/2026_07_22_audit/performance.md.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Fields

    Priority

    None yet

    Projects

    Status
    Todo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions