Skip to content

feat(projects): add setup command suggestion#2513

Open
janburzinski wants to merge 3 commits into
mainfrom
emdash/lifecycle-setup-command-suggestion-6x9jx
Open

feat(projects): add setup command suggestion#2513
janburzinski wants to merge 3 commits into
mainfrom
emdash/lifecycle-setup-command-suggestion-6x9jx

Conversation

@janburzinski

Copy link
Copy Markdown
Collaborator

Description

  • adds setup command suggestions for projects without scripts.setup
  • detects common tooling from root markers like lockfiles and manifests
  • show a dismissable toast

Screenshot/Recording (if applicable)

https://streamable.com/p9tsc1

Checklist
  • I kept this PR small and focused
  • I ran a self-review before opening this PR
  • I ran the relevant local checks or explained why not
  • I updated docs when behavior or setup changed
  • I added or updated tests when behavior changed, or explained why not
  • I only added comments where the logic is not obvious
  • I used Conventional Commits for commit
    messages and, when possible, the PR title

@greptile-apps

greptile-apps Bot commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR introduces a one-click setup-command suggestion toast for newly added projects. When a project is created, the app detects common tooling markers (lockfiles, manifests) in the repo root and offers the matching install command as a pre-configured scripts.setup lifecycle hook via a dismissible toast.

  • Detection (detect-setup-suggestion.ts): an ordered rule table maps root markers to ecosystem commands; markerExists wraps each fs.exists call in try/catch so errors are treated as absent without aborting the scan.
  • Eligibility state (setup-suggestion-state.ts): localStorage flags track per-project eligibility and dismiss state; markSetupSuggestionEligible is set only in _setAndOpenProject (project-creation paths), so the toast never fires on app restart for existing projects.
  • Apply path (setSetupScript + toast): the main-process service reads current settings, guards against overwriting an existing script, and emits a project-settings:changed event; the renderer uses a token-based cancellation ref to prevent stale setPhase calls if the user switches projects mid-flight.

Confidence Score: 5/5

Safe to merge — the feature is well-scoped, detection is purely read-only, the apply path has a server-side guard against overwriting existing setup scripts, and the token-based cancellation in the toast handles project-switch races correctly.

The change adds a new, self-contained feature path with no modifications to existing behaviour. Detection errors are silently swallowed, apply conflicts are handled with a typed error variant, and the localStorage state machine correctly limits the toast to first-time project creation. The only gap is a test that does not fully exercise its claimed behaviour.

detect-setup-suggestion.test.ts — the error-handling test needs a stronger assertion to verify anyOf fallthrough after a failing exists() call.

Important Files Changed

Filename Overview
apps/emdash-desktop/src/main/core/projects/setup-suggestion/detect-setup-suggestion.ts Well-structured ordered rule table with error-safe markerExists wrapper; anyOf semantics are clear and the sequential short-circuit is correct.
apps/emdash-desktop/src/main/core/projects/setup-suggestion/detect-setup-suggestion.test.ts Good overall coverage but the error-handling test does not exercise the anyOf fallthrough after a failing exists() call; the test passes trivially because nothing else matches in an empty file set.
apps/emdash-desktop/src/main/core/projects/settings/project-settings-service.ts New setSetupScript method follows the existing read-then-write pattern and correctly guards against overwriting an existing setup script; TOCTOU window is consistent with other methods in this service.
apps/emdash-desktop/src/renderer/features/projects/components/setup-suggestion/setup-suggestion-toast.tsx Token-based cancellation correctly prevents stale setPhase calls on project switches during the async apply flow; dismiss and apply paths are well guarded.
apps/emdash-desktop/src/renderer/features/projects/components/setup-suggestion/setup-suggestion-state.ts Lightweight localStorage facade with try/catch on every operation; eligibility + dismiss key separation is clean and avoids showing the toast on app restart for already-dismissed projects.
apps/emdash-desktop/src/renderer/features/projects/stores/project-manager.ts markSetupSuggestionEligible is correctly placed inside _setAndOpenProject, which is only called on project creation — so the suggestion only fires for new projects, not on every app restart.
apps/emdash-desktop/src/shared/core/projects/setup-suggestion.ts Clean shared type definition for SetupScriptSuggestion; well-documented fields.
apps/emdash-desktop/src/shared/projects.ts Adds setup-script-already-configured to the UpdateProjectSettingsError union; correctly handled in the toast component.
apps/emdash-desktop/src/main/core/projects/controller.ts Exposes suggestSetupScript and applySetupScript via the RPC controller; applySetupScript is a thin inline wrapper that correctly delegates to setSetupScript.
apps/emdash-desktop/src/renderer/features/projects/components/main-panel/active-project.tsx Minimal one-line addition mounting SetupSuggestionToast inside the active project view; no impact on existing layout logic.
apps/emdash-desktop/src/main/core/projects/setup-suggestion/suggest-setup-script.ts Clean entry point: guards for missing project, pre-existing setup script, and detection errors are all handled gracefully with fallthrough logging.

Sequence Diagram

sequenceDiagram
    participant PM as ProjectManagerStore
    participant LS as localStorage
    participant Toast as SetupSuggestionToast
    participant RPC as rpc.projects
    participant Main as Main Process

    PM->>LS: markSetupSuggestionEligible(projectId)
    Note over PM,LS: only on project creation

    Toast->>LS: shouldShowSetupSuggestion(projectId)
    LS-->>Toast: "true (eligible && !dismissed)"

    Toast->>RPC: suggestSetupScript(projectId)
    RPC->>Main: suggestSetupScript(projectId)
    Main->>Main: check scripts.setup configured?
    Main->>Main: detectSetupSuggestion(project.fs)
    Main-->>RPC: "SetupScriptSuggestion | null"
    RPC-->>Toast: suggestion

    alt suggestion found
        Toast->>Toast: setPhase('visible')
        Note over Toast: user sees dismissible toast
        alt user clicks Add setup script
            Toast->>RPC: applySetupScript(projectId, command)
            RPC->>Main: setSetupScript(projectId, command)
            Main->>Main: guard: setup already set?
            Main->>Main: "settings.update({...current, scripts.setup})"
            Main->>Main: emitSettingsChanged
            Main-->>RPC: ok(updatedSettings)
            RPC-->>Toast: result
            Toast->>LS: dismissSetupSuggestion(projectId)
            Toast->>Toast: setPhase('applied') then 'hidden'
        else user dismisses
            Toast->>LS: dismissSetupSuggestion(projectId)
            Toast->>Toast: setPhase('hidden')
        end
    else no suggestion
        Toast->>LS: clearSetupSuggestionEligibility(projectId)
    end
Loading

Reviews (2): Last reviewed commit: "fix(projects): harden setup suggestion a..." | Re-trigger Greptile

@janburzinski

Copy link
Copy Markdown
Collaborator Author

@greptileai

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant