Skip to content

chore(setup): add SDK init/injection library and templates - #751

Merged
ffantl-ld merged 19 commits into
setup-ldfrom
ffantl/setup-ld/3-initializer
Aug 5, 2026
Merged

chore(setup): add SDK init/injection library and templates#751
ffantl-ld merged 19 commits into
setup-ldfrom
ffantl/setup-ld/3-initializer

Conversation

@ffantl-ld

@ffantl-ld ffantl-ld commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Describe the solution you've provided

Third layer of the guided setup command: SDK initialization. Renders per-SDK code snippets from embedded templates and injects them into the project (Initializer, RenderTemplate, InjectIntoFile), plus docs-URL helpers. Ships the sdk_init_templates/ for the supported SDKs.

Independent library layer.

Related issues

Part of the setup-ld feature. Stacked PR — base is ffantl/setup-ld/2-installer.

Requirements

  • I have added test coverage for new or changed functionality

Note

Medium Risk
The library writes user project files on disk for append-safe SDKs; incorrect prologue or module-syntax handling could break entry points, though coverage is extensive.

Overview
Adds the SDK initialization layer for guided setup: embedded per-SDK templates, rendering with InitConfig, and InjectIntoFile that either writes runnable init into entry files or returns snippets plus docs links.

Append-safe Node, Python, and Ruby server SDKs get imports merged after preserved prologues (shebangs, encoding cookies, __future__, 'use strict') and init appended at file scope. Node picks CommonJS require vs ESM import from file extension and nearest package.json "type".

Go, Java, C#, Swift, Android, React, and React Native do not modify the project; InitResult carries Success=false, a copy-paste Snippet, and DocsURL. Unknown SDKs get docs URLs only. Helpers include GetDocsURL, InjectsInPlace, DefaultEntryPoint, and SupportedSDKIDs. Tests cover prologue handling, module syntax, guidance-only paths, mobile template correctness, and installer package name alignment with template imports.

Reviewed by Cursor Bugbot for commit 1d4cf46. Bugbot is set up for automated code reviews on this repo. Configure here.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ffantl-ld
ffantl-ld marked this pull request as ready for review July 27, 2026 17:23
@ffantl-ld
ffantl-ld requested review from Vadman97 and erangeles July 27, 2026 17:23
Comment thread internal/setup/sdk_init_templates/react-native.tmpl Outdated
Comment thread internal/setup/initializer.go
Comment thread internal/setup/initializer.go Outdated
Comment thread internal/setup/sdk_init_templates/js-client-sdk.tmpl
@ffantl-ld
ffantl-ld requested review from a team and removed request for Vadman97 July 28, 2026 16:38
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>
@ffantl-ld
ffantl-ld force-pushed the ffantl/setup-ld/3-initializer branch from c56c506 to 6a44381 Compare July 31, 2026 17:47
Comment thread internal/setup/sdk_init_templates/swift-client-sdk.tmpl Outdated
Comment thread internal/setup/sdk_init_templates/android.tmpl
ffantl-ld and others added 2 commits July 31, 2026 13:57
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>
@ffantl-ld
ffantl-ld force-pushed the ffantl/setup-ld/3-initializer branch from 6a44381 to 2efb79d Compare July 31, 2026 18:25
Comment thread internal/setup/sdk_init_templates/node-server.tmpl
ffantl-ld and others added 2 commits July 31, 2026 16:00
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>
@ffantl-ld
ffantl-ld force-pushed the ffantl/setup-ld/3-initializer branch from 2efb79d to 43d2d15 Compare August 3, 2026 18:52
Comment thread internal/setup/initializer.go
Comment thread internal/setup/sdk_init_templates/swift-client-sdk.tmpl
ffantl-ld and others added 8 commits August 3, 2026 15:45
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>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
`gem install` left the Gemfile untouched, so the SDK stayed unavailable under
bundler and IsInstalled kept returning false. Use `bundle add` when the project
is Bundler-managed, and poetry, uv or pipenv when one of those manages the
Python dependencies.

Unrecognised package managers fall back to pip rather than being run as a
command, since the value reaches InstallArgs from the detector.

InstallArgs added launchdarkly-react-native-client-sdk, which npm marks
deprecated in favour of @launchdarkly/react-native-client-sdk. The unscoped
launchdarkly-js-client-sdk is the v3 package whose initialize API the init
template uses; the scoped one is v4 and exposes createClient.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
IsInstalled tested for its package name as a substring, so
@launchdarkly/node-server-sdk-redis, launchdarkly-server-sdk-otel, and
LaunchDarkly.ServerSdk.Telemetry each counted as the SDK itself and the real
install was skipped. Require a non-name character on both sides, which every
manifest format supplies.

Detection accepts a solution with no project file beside it, but install ran a
bare `dotnet add package`, which needs the working directory to hold exactly
one project. Resolve the project the solution refers to and pass --project;
with none or several, stop and say so rather than adding the SDK to an
arbitrary assembly.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
react-native.tmpl bound the default export of
@launchdarkly/react-native-client-sdk, which has no default export, so the
snippet could not compile. The client is the named export ReactNativeLDClient.

Register the android template under the SDK ID the detector reports, keeping
android-client-sdk as an alias.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The Swift and Android snippets did not compile. LDConfig's only public
initializer takes autoEnvAttributes, and LDConfig.Builder's only constructor
takes AutoEnvAttributes, so neither config could be built as written. These
SDKs return a snippet for the user to paste rather than writing a file, so the
snippet is the entire deliverable.

AutoEnvAttributes is nested in LDConfig.Builder, which the package wildcard
import does not cover, so import it explicitly.

Add DefaultEntryPoint, naming the file to create for the SDKs that write one
when detection found no entry point for them.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
LDContextBuilder.build returns a Result, and the snippet unwrapped it with
`try ...get()`. try only compiles inside a throwing function, and the places
this snippet gets pasted — application(_:didFinishLaunchingWithOptions:) and
similar startup hooks — do not throw. Match on the Result instead.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@ffantl-ld
ffantl-ld force-pushed the ffantl/setup-ld/3-initializer branch from 43d2d15 to 8daf723 Compare August 3, 2026 19:48
Base automatically changed from ffantl/setup-ld/2-installer to setup-ld August 4, 2026 16:40
ffantl-ld and others added 3 commits August 4, 2026 12:48
Keep TestInstallArgs_PackageMatchesTemplateImport in installer_test.go: it
asserts the init templates import the package the installer installs.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
InjectIntoFile prepended the import section at byte 0, which displaced a leading
shebang and an encoding cookie. Django's manage.py is one of the Python entry
points detection targets, so `./manage.py` stopped being executable after setup
wrote to it, and Python stopped honoring a coding declaration pushed past line 2.

Peel the prologue off first and insert imports after it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The node-server template loaded the SDK with require, but detection targets
TypeScript and ESM entry points such as Next.js instrumentation.ts and NestJS
src/main.ts, where require is not defined at runtime. Setup wrote that code and
reported success, so the failure only showed up when the app started.

Pick the CommonJS or ESM template from the entry extension, falling back to the
nearest package.json "type" for a plain .js file.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Comment thread internal/setup/initializer.go
Injecting imports after only the shebang and encoding cookie broke the other
constructs a file has to open with. A Python __future__ import below the injected
imports is a SyntaxError, a module docstring pushed down is demoted to a plain
expression, and Ruby magic comments and a CommonJS 'use strict' are silently
ignored once code precedes them. All of it was written with Success: true.

Peel the shebang, the leading comment block, and the language's own leading
constructs, then insert imports after them.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ 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 26827c0. Configure here.

Comment thread internal/setup/initializer.go
A /* */ license or JSDoc header stopped the prologue scan, so imports landed
above it and above the 'use strict' that followed, silently dropping the file out
of strict mode. A directive with a trailing same-line comment was missed for the
same reason.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@ffantl-ld
ffantl-ld merged commit ab2522d into setup-ld Aug 5, 2026
6 checks passed
@ffantl-ld
ffantl-ld deleted the ffantl/setup-ld/3-initializer branch August 5, 2026 18:06
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.

2 participants