chore(setup): add SDK/project detection library - #749
Conversation
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
| if result := detectDotnet(dir); result != nil { | ||
| return result, nil | ||
| } | ||
| return nil, errors.New("could not detect project language from directory; try specifying --sdk-id manually") |
There was a problem hiding this comment.
"could not detect project language from directory")
Should probably mean "Hey, here's a link to the docs and a blurb about how to do this install manually"
If we're doing a hybrid approach to setup, then we should definitely
|
@ffantl-ld there is some valid bug bot issues flagged, wanted to make sure you were aware of them (either to fix now or punt on) |
| // firstExistingIn returns the first candidate that exists as a file in dir, | ||
| // or the last candidate if none exist (as a suggested path). | ||
| // Returns an empty string if candidates is empty. | ||
| func firstExistingIn(dir string, candidates []string) string { |
There was a problem hiding this comment.
suggestion: we should return whether the entry point actually exists so downstream steps can prompt the user instead
type DetectResult struct {
// ...
EntryPoint string `json:"entry_point"`
EntryPointExists bool `json:"entry_point_exists"`
}
// firstExistingIn returns the first candidate that exists in dir and true,
// or the last candidate and false as a suggestion if none exist.
func firstExistingIn(dir string, candidates []string) (string, bool) {
if len(candidates) == 0 {
return "", false
}
for _, c := range candidates {
if _, err := os.Stat(filepath.Join(dir, c)); err == nil {
return c, true
}
}
return candidates[len(candidates)-1], false
}Then the wizard can branch: exists → inject; doesn't → ask the user for the entry file (or show the snippet).
There was a problem hiding this comment.
DetectResult now carries EntryPointExists. Good find. :)
|
@ffantl-ld bump, just wanted to make sure you saw my earlier comments |
DetectResult carries EntryPointExists so callers can tell an entry file the detector found from one it merely suggests, and never write initialization code into a path the project does not load. PackageManager names the tool that manages the project's dependencies: bundle rather than gem when a Gemfile is present, and poetry, uv or pipenv rather than always pip. Locate MainActivity and Main under their real package directory rather than assuming an unqualified class name, derive the Android source root from whichever manifest matched, find the Swift entry point where SwiftPM and Xcode nest it, look for src/main.tsx where Vite mounts a React app, and recognise bun.lockb. Rename the Android SDK ID to android for consistency with the other IDs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Next.js detection targeted whichever page module happened to exist, and node-server is append-safe, so setup wrote server SDK init — including the SDK key — into app/page.tsx or pages/index.tsx. A page module may carry 'use client' or be imported by something that does, which bundles it for the browser, and nothing in the detector can tell which. Only instrumentation.ts, Next's server-startup hook, is guaranteed to stay server-side, so suggest creating it rather than picking a page. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Each candidate list encodes a claim about where a toolchain puts its entry file. Link the documentation that claim rests on so it can be rechecked when the frameworks move. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A root package.json is often only build tooling — Rails with jsbundling, Django with Tailwind, a Go binary published to npm — so preferring Node whenever one parsed meant those projects were handed the Node SDK. This repo hit it too. Confine the Sources/ search to single-target Swift packages. Across several targets there is no way to tell an executable's entry file from a library's, so an arbitrary hit was reported as found. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The existing tests check one or two fields each, so a field detection stops populating passes as long as the SDK id stays right. Compare the full DetectResult across the project layouts real toolchains produce. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 0b61639. Configure here.
| // Maven layout: https://maven.apache.org/guides/introduction/introduction-to-the-pom.html | ||
| ep, exists := entryPoint(dir, "src/main/java/Main.java", | ||
| findFileUnder(dir, "src/main/java", "Main.java", "Application.java", "App.java"), | ||
| ) |
There was a problem hiding this comment.
Java entry search too narrow
Medium Severity
Java server entry detection only accepts exact Main.java, Application.java, or App.java under src/main/java. Typical Spring Boot apps use names like DemoApplication.java, and Kotlin JVM apps live under src/main/kotlin with .kt files. findFileUnder already supports suffix patterns (used for Swift), so these common entry points are missed and EntryPointExists stays false.
Reviewed by Cursor Bugbot for commit 0b61639. Configure here.
NestJS and similar apps start from src/main.ts, which the candidate list skipped, so detection suggested a nonexistent index.js. node-server appends to the entry file, so setup created that index.js and left the real entry point without the SDK. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>


Describe the solution you've provided
First layer of the guided
setupcommand: theinternal/setupdetection library. Inspects a project directory and identifies the language/package manager and the most likely LaunchDarkly SDK (Detectorinterface,FileDetector,KnownSDKs).Pure library with no consumer yet — the
setupcommand wires it up later in this stack.Related issues
Part of the
setup-ldfeature. Stacked PR — base issetup-ld.Requirements
Note
Low Risk
New library-only code with no CLI integration yet; heuristics may mis-detect polyglot repos but failures are overridable via
--sdk-id.Overview
Adds
internal/setup, a filesystem-based project detector for the upcoming guidedldcli setupflow.FileDetectorscans a directory and returns language, framework, package manager, recommended LaunchDarklysdk_id, and an entry-point path, withEntryPointExistsso callers only auto-edit files that actually exist.Detection runs Go → Python → Ruby → Java → Swift → .NET → Node so backend manifests win over a root
package.jsonused only for asset tooling. Node logic distinguishes Next.js (server SDK +instrumentation.ts), React Native, React, other browser frameworks, and generic Node; lockfiles drive npm/yarn/pnpm/bun.KnownSDKslists manual override options when detection fails.Heavy test coverage includes table-driven project shapes and edge cases (Next.js instrumentation vs pages, Android
MainActivitysearch, ambiguous Go/Swift multi-binary layouts).Reviewed by Cursor Bugbot for commit b5d737c. Bugbot is set up for automated code reviews on this repo. Configure here.