feat(starters): add htmx+go and fix go starter#132
Conversation
📝 WalkthroughWalkthroughThis PR adds a Go+HTMX starter, refactors the existing Go starter, implements Elements CDN version stamping for starters, updates ProjectService to conditionally run dependency setup based on starter metadata, and updates CI/workspace and site documentation to register the new starter. ChangesGo and Go+HTMX Starters
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Suggested labels
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 golangci-lint (2.12.2)level=error msg="[linters_context] typechecking error: pattern ./...: directory prefix . does not contain main module or its selected dependencies" 🔧 ESLint
ESLint install timed out. The project may have too many dependencies for the sandbox. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@projects/internals/tools/src/project/service.ts`:
- Around line 64-67: The code mixes a synchronous call and an awaited async call
in a single reports.push(...) which reduces clarity; make the async sequencing
explicit by computing or awaiting the values before pushing: call
starterShouldSetupElementsDependencies(type) and then either (a) call const
setupReport = setupProject(projectDir); const updateReport = await
updateProject(projectDir); and push reports.push(setupReport, updateReport) or
(b) await both sequentially with const setupReport = await
setupProject(projectDir); const updateReport = await updateProject(projectDir);
then push; update the code referencing setupProject, updateProject,
starterShouldSetupElementsDependencies, and the reports array accordingly so
there is no mixing of awaited and non-awaited expressions inside reports.push.
In `@projects/internals/tools/src/project/starters.ts`:
- Around line 210-220: The function stampStarterCDNVersionFiles currently
hardcodes the index location via join(dist, 'src/index.html'), which will break
for starters with different layouts; update stampStarterCDNVersionFiles to
resolve the index path per-starter (e.g., add a mapping or config keyed by
projectDir/starter name that returns the relative index path) or implement a
small resolver that checks a list of candidate locations (like 'src/index.html',
'public/index.html', 'index.html') before failing; use the existing
starterDirsWithStampedCDNVersions key or augment it to include the
relativeIndexPath so stampStarterCDNVersionFiles can read the correct file, and
add a brief comment documenting the assumption/behavior.
- Around line 21-22: The REPO_WORKSPACE_DIR constant points two levels up but
must point five levels up from projects/internals/tools/src/project/starters.ts;
update REPO_WORKSPACE_DIR to the correct relative path (use '../../../../../')
so calls in getStarterCDNPackageVersions and readWorkspaceManifest resolve the
actual repository root and workspace manifest correctly.
In `@projects/site/src/_11ty/layouts/common.js`:
- Line 151: The "HTMX + Go" nve-tree-node (href "docs/integrations/go-htmx/") is
currently placed between Golang and Hugo and breaks strict alphabetical
ordering; decide whether the nav should be strictly alphabetical or
intentionally grouped by Go integrations, then either move this nve-tree-node so
its anchor label "HTMX + Go" is placed in the correct alphabetical position
among the other integration nodes, or keep its current position and add a short
code comment near the node indicating intentional grouping (so future editors
understand the choice).
In `@projects/site/src/docs/integrations/go-htmx.md`:
- Line 17: Split the long sentence into 2–3 shorter sentences that each state a
single fact: e.g., one sentence stating that the starter uses the pre-built
Elements CSS and JavaScript bundles, another that HTMX is loaded in the base
HTML page, and a final short sentence that explains the app renders “/” as the
full page and serves “/fragment/time” as a fragment response returning only the
refresh button's swap target; update the paragraph mentioning Elements, HTMX,
“/” and “/fragment/time” accordingly for clarity.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Enterprise
Run ID: 4b46ca1a-0e23-4de2-ac00-98dce9cd5414
⛔ Files ignored due to path filters (2)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yamlprojects/site/public/static/images/integrations/htmx.svgis excluded by!**/*.svg
📒 Files selected for processing (30)
.github/actions/setup-ci/action.ymlpackage.jsonpnpm-workspace.yamlprojects/internals/tools/src/project/service.test.tsprojects/internals/tools/src/project/service.tsprojects/internals/tools/src/project/starters.test.tsprojects/internals/tools/src/project/starters.tsprojects/internals/tools/src/skills/about.mdprojects/site/public/static/images/integrations/NOTICEprojects/site/src/_11ty/layouts/common.jsprojects/site/src/_11ty/shortcodes/svg-logo.jsprojects/site/src/docs/integrations/go-htmx.mdprojects/site/src/docs/integrations/go.mdprojects/site/src/docs/integrations/index.11ty.jsprojects/site/src/index.11tydata.jsprojects/starters/README.mdprojects/starters/go-htmx/.gitignoreprojects/starters/go-htmx/AGENTS.mdprojects/starters/go-htmx/README.mdprojects/starters/go-htmx/main.goprojects/starters/go-htmx/package.jsonprojects/starters/go-htmx/src/index.htmlprojects/starters/go-htmx/src/time.htmlprojects/starters/go/.gitignoreprojects/starters/go/AGENTS.mdprojects/starters/go/README.mdprojects/starters/go/main.goprojects/starters/go/package.jsonprojects/starters/go/src/index.htmlprojects/starters/package.json
| const reports = [createReport, agentReport]; | ||
| if (starterShouldSetupElementsDependencies(type)) { | ||
| reports.push(setupProject(projectDir), await updateProject(projectDir)); | ||
| } |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial | 💤 Low value
Consider clarity: mixing sync and async calls in reports.push().
Line 66 pushes both a synchronous setupProject(projectDir) call and an awaited updateProject(projectDir) call to the reports array. While functionally correct (both resolve before being pushed), this pattern is subtle and may reduce readability for future maintainers.
♻️ Optional: Make the async sequencing explicit
const reports = [createReport, agentReport];
if (starterShouldSetupElementsDependencies(type)) {
- reports.push(setupProject(projectDir), await updateProject(projectDir));
+ const setupProjectReport = setupProject(projectDir);
+ const updateProjectReport = await updateProject(projectDir);
+ reports.push(setupProjectReport, updateProjectReport);
}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@projects/internals/tools/src/project/service.ts` around lines 64 - 67, The
code mixes a synchronous call and an awaited async call in a single
reports.push(...) which reduces clarity; make the async sequencing explicit by
computing or awaiting the values before pushing: call
starterShouldSetupElementsDependencies(type) and then either (a) call const
setupReport = setupProject(projectDir); const updateReport = await
updateProject(projectDir); and push reports.push(setupReport, updateReport) or
(b) await both sequentially with const setupReport = await
setupProject(projectDir); const updateReport = await updateProject(projectDir);
then push; update the code referencing setupProject, updateProject,
starterShouldSetupElementsDependencies, and the reports array accordingly so
there is no mixing of awaited and non-awaited expressions inside reports.push.
| const ELEMENTS_CDN_BASE_URL = 'https://esm.sh'; | ||
| const REPO_WORKSPACE_DIR = '../../'; |
There was a problem hiding this comment.
Critical: Incorrect relative path to repository root.
REPO_WORKSPACE_DIR = '../../' is incorrect for the location of this file. From projects/internals/tools/src/project/starters.ts, the repo root is 5 levels up, not 2.
This will cause getStarterCDNPackageVersions (line 216) and readWorkspaceManifest (line 224) to fail or use the wrong directory.
🐛 Proposed fix
-const REPO_WORKSPACE_DIR = '../../';
+const REPO_WORKSPACE_DIR = '../../../../../';📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const ELEMENTS_CDN_BASE_URL = 'https://esm.sh'; | |
| const REPO_WORKSPACE_DIR = '../../'; | |
| const ELEMENTS_CDN_BASE_URL = 'https://esm.sh'; | |
| const REPO_WORKSPACE_DIR = '../../../../../'; |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@projects/internals/tools/src/project/starters.ts` around lines 21 - 22, The
REPO_WORKSPACE_DIR constant points two levels up but must point five levels up
from projects/internals/tools/src/project/starters.ts; update REPO_WORKSPACE_DIR
to the correct relative path (use '../../../../../') so calls in
getStarterCDNPackageVersions and readWorkspaceManifest resolve the actual
repository root and workspace manifest correctly.
| async function stampStarterCDNVersionFiles(projectDir: string, dist: string) { | ||
| if (!starterDirsWithStampedCDNVersions.has(projectDir)) { | ||
| return; | ||
| } | ||
|
|
||
| const indexPath = join(dist, 'src/index.html'); | ||
| const repoRoot = resolve(REPO_WORKSPACE_DIR); | ||
| const versions = getStarterCDNPackageVersions(repoRoot); | ||
| const content = await readFile(indexPath, 'utf8'); | ||
| await writeFile(indexPath, stampStarterCDNVersions(content, versions)); | ||
| } |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial | ⚖️ Poor tradeoff
Consider: Hardcoded index file path.
Line 215 hardcodes 'src/index.html' for all stamped starters. While this works for the current go and go-htmx starters, this assumption may break if future starters use a different template structure.
Consider adding a configurable path per starter if the structure is expected to vary, or document the assumption in a comment.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@projects/internals/tools/src/project/starters.ts` around lines 210 - 220, The
function stampStarterCDNVersionFiles currently hardcodes the index location via
join(dist, 'src/index.html'), which will break for starters with different
layouts; update stampStarterCDNVersionFiles to resolve the index path
per-starter (e.g., add a mapping or config keyed by projectDir/starter name that
returns the relative index path) or implement a small resolver that checks a
list of candidate locations (like 'src/index.html', 'public/index.html',
'index.html') before failing; use the existing starterDirsWithStampedCDNVersions
key or augment it to include the relativeIndexPath so
stampStarterCDNVersionFiles can read the correct file, and add a brief comment
documenting the assumption/behavior.
| <nve-tree-node ${data.page.url.includes('/docs/integrations/bundles/') ? 'highlighted selected' : ''}><a href="docs/integrations/bundles/">Bundles</a></nve-tree-node> | ||
| <nve-tree-node ${data.page.url.includes('/docs/integrations/custom-elements/') ? 'highlighted selected' : ''}><a href="docs/integrations/custom-elements/">Custom Elements</a></nve-tree-node> | ||
| <nve-tree-node ${data.page.url.includes('/docs/integrations/go/') ? 'highlighted selected' : ''}><a href="docs/integrations/go/">Golang</a></nve-tree-node> | ||
| <nve-tree-node ${data.page.url.includes('/docs/integrations/go-htmx/') ? 'highlighted selected' : ''}><a href="docs/integrations/go-htmx/">HTMX + Go</a></nve-tree-node> |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial | 💤 Low value
Consider navigation ordering.
The "HTMX + Go" entry is placed between "Golang" and "Hugo". While this groups Go-related integrations together, it breaks strict alphabetical ordering. Verify whether this intentional grouping is preferred over alphabetical consistency in the navigation.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@projects/site/src/_11ty/layouts/common.js` at line 151, The "HTMX + Go"
nve-tree-node (href "docs/integrations/go-htmx/") is currently placed between
Golang and Hugo and breaks strict alphabetical ordering; decide whether the nav
should be strictly alphabetical or intentionally grouped by Go integrations,
then either move this nve-tree-node so its anchor label "HTMX + Go" is placed in
the correct alphabetical position among the other integration nodes, or keep its
current position and add a short code comment near the node indicating
intentional grouping (so future editors understand the choice).
|
|
||
| The HTMX + Go starter extends the Go starter with one server-rendered fragment endpoint for HTMX swaps. | ||
|
|
||
| The starter uses the pre-built Elements CSS and JavaScript bundles, loads HTMX in the base HTML page, renders `/` as the full page, and serves `/fragment/time` as a fragment response that returns only the refresh button's swap target. |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial | ⚡ Quick win
Consider breaking this long sentence into multiple sentences for readability.
This sentence contains multiple independent facts (uses pre-built bundles, loads HTMX, renders /, serves /fragment/time). Breaking it into 2-3 shorter sentences would improve clarity and align better with concise documentation style.
Suggested rewording
-The starter uses the pre-built Elements CSS and JavaScript bundles, loads HTMX in the base HTML page, renders `/` as the full page, and serves `/fragment/time` as a fragment response that returns only the refresh button's swap target.
+The starter uses the pre-built Elements CSS and JavaScript bundles. It loads HTMX in the base HTML page and renders `/` as the full page. The `/fragment/time` endpoint serves a fragment response that returns only the refresh button's swap target.📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| The starter uses the pre-built Elements CSS and JavaScript bundles, loads HTMX in the base HTML page, renders `/` as the full page, and serves `/fragment/time` as a fragment response that returns only the refresh button's swap target. | |
| The starter uses the pre-built Elements CSS and JavaScript bundles. It loads HTMX in the base HTML page and renders `/` as the full page. The `/fragment/time` endpoint serves a fragment response that returns only the refresh button's swap target. |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@projects/site/src/docs/integrations/go-htmx.md` at line 17, Split the long
sentence into 2–3 shorter sentences that each state a single fact: e.g., one
sentence stating that the starter uses the pre-built Elements CSS and JavaScript
bundles, another that HTMX is loaded in the base HTML page, and a final short
sentence that explains the app renders “/” as the full page and serves
“/fragment/time” as a fragment response returning only the refresh button's swap
target; update the paragraph mentioning Elements, HTMX, “/” and “/fragment/time”
accordingly for clarity.
Source: Coding guidelines
| - uses: actions/setup-go@v6 | ||
| with: | ||
| go-version: 'stable' | ||
| cache: false |
There was a problem hiding this comment.
If we are going to add Go as a runtime dependency for our CI we should update our dev env setup instructions to ensure the correct Go version is added as well. https://github.com/NVIDIA/elements#setup
|
|
||
| const { ProjectService } = await import('./service.js'); | ||
| const result = await ProjectService.create({ type: 'typescript', cwd: '/test', start: false }); | ||
| const result = await ProjectService.create({ type: 'default', cwd: '/test', start: false }); |
There was a problem hiding this comment.
I think this likely should remain 'typescript' since 'default' is not a type option for the starters and would change the MCP schema as well.
|
|
||
| const { ProjectService } = await import('./service.js'); | ||
| await ProjectService.create({ type: 'typescript', cwd: '/test', start: true }); | ||
| await ProjectService.create({ type: 'default', cwd: '/test', start: true }); |
There was a problem hiding this comment.
I think this likely should remain 'typescript' since 'default' is not a type option for the starters and would change the MCP schema as well.
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
| <meta name="description" content="A simple starter using Elements, HTMX, and Go." /> | ||
| <link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon" /> | ||
| <!-- Starter archive generation stamps these Elements CDN URLs with current package versions. --> |
There was a problem hiding this comment.
Stamping the versions seems reasonable, if the comment is not used for matching where to match the stamping/regex I'd drop it. Otherwise it will be in the generated output which the user doesnt really need to know the implementation details of how its stamped out.
• Added the HTMX + Go starter with a Go-rendered page, HTMX fragment endpoint, refresh-button with swap, agent support, CLI metadata, starter archive wiring, docs updates, and HTMX logo • Fixed the existing Go starter by correcting bad Elements bundle URLs, loading CSS and JS from the right packages, removing the frontend dependency/setup path, fixing stale copy, updating source links, simplifying template data • More Go server functionality with PORT support, root-only routing, explicit HTML content type, and template execution error handling. • Go and HTMX+Go starters are freed from frontend build tooling by using browser CDN bundles, excluding local build/cache outputs, skipping Elements dependency setup, and stamping CDN bundle versions during archive generation. • Test updates including Elements version stamping logic Signed-off-by: Jake Guza <jguza@nvidia.com>
524795b to
013d8af
Compare
There was a problem hiding this comment.
Actionable comments posted: 7
♻️ Duplicate comments (2)
projects/internals/tools/src/project/service.test.ts (1)
15-19:⚠️ Potential issue | 🟠 Major | ⚡ Quick winUse real starter ids in this mock catalog.
These mocked keys (
default,static,hidden) are not members of the realStarterunion fromprojects/internals/tools/src/project/starters.ts, so the calls on Line 51, Line 72, Line 95, and Line 112 drift from the actual MCP schema and can fail type-checking. Use existing starters instead—e.g.typescriptfor the default path andgoorgo-htmxfor the opt-out path this PR adds.💡 Suggested update
vi.mock('./starters.js', () => ({ startersData: { - default: { cli: true, zip: 'default.zip' }, - static: { cli: true, zip: 'static.zip', setupElementsDependencies: false }, - hidden: { cli: false, zip: 'hidden.zip', setupElementsDependencies: false } + typescript: { cli: true, zip: 'typescript.zip' }, + go: { cli: true, zip: 'go.zip', setupElementsDependencies: false }, + lit: { cli: false, zip: null } }, createStarter: vi.fn(), startStarter: vi.fn() }));Then update the affected calls/assertions to use
typescriptandgo.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@projects/internals/tools/src/project/service.test.ts` around lines 15 - 19, The test mock uses invalid starter keys; replace the fake keys in the startersData mock with real Starter ids (e.g., change the `default` key to `typescript` and the opt-out key to `go` or `go-htmx`) so the mock shape matches the real union from starters.ts; then update the related assertions/calls that reference those starters (the tests that currently reference the old keys) to use `typescript` and `go` (or `go-htmx`) so the tests align with the actual MCP schema and type definitions.projects/internals/tools/src/project/starters.ts (1)
21-22:⚠️ Potential issue | 🔴 Critical | ⚡ Quick winAnchor the workspace root to this module, not
process.cwd().
REPO_WORKSPACE_DIR = '../../'is later fed intoresolve()andreadWorkspaceManifest(), so a repo-root invocation resolves outside the repository. That breaks both CDN version lookup instampStarterCDNVersionFiles()(Line 216) and workspace manifest export inexportPackageFromWorkspace()(Line 224). Compute the repo root fromimport.meta.urlhere instead of keeping a cwd-relative string.💡 Minimal fix
+import { fileURLToPath } from 'node:url'; import { basename, dirname, join, parse, resolve } from 'node:path'; ... -const REPO_WORKSPACE_DIR = '../../'; +const REPO_WORKSPACE_DIR = resolve(dirname(fileURLToPath(import.meta.url)), '../../../../../'); ... - const repoRoot = resolve(REPO_WORKSPACE_DIR); + const repoRoot = REPO_WORKSPACE_DIR;🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@projects/internals/tools/src/project/starters.ts` around lines 21 - 22, REPO_WORKSPACE_DIR currently uses a cwd-relative string which causes resolve()/readWorkspaceManifest() to point outside the repo; change it to compute the repository root from this module's location using import.meta.url (e.g. derive a file:// path and resolve up to repo root) and replace the '../../' constant; update any uses in stampStarterCDNVersionFiles and exportPackageFromWorkspace (and calls to resolve()/readWorkspaceManifest) to use the new repo-root constant so CDN version lookup and workspace manifest export resolve inside the repository.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/actions/setup-ci/action.yml:
- Around line 16-19: The workflow uses actions/setup-go@v6 with go-version:
'stable', which is non-deterministic; replace the 'stable' value with a pinned
semantic version (e.g., '1.20.x' or a specific patch like '1.20.7') in the
action.yml go-version field so CI uses a fixed Go release; update the go-version
entry where actions/setup-go@v6 is declared to a specific version string and, if
desired, add a comment explaining the chosen pinned version.
In `@projects/starters/go-htmx/AGENTS.md`:
- Around line 7-9: Update the three bullets in the "Integration Points" section
so they don't all start with "Render"; pick at least one bullet to begin with a
different verb or preposition (e.g., "Use", "Serve", "Through", or "Via") while
keeping the same meaning for lines that mention "Elements markup through
`html/template` in `src/index.html`", "the full page through the root route",
and "HTMX swap content through fragment templates under `src/`". Ensure sentence
structure and punctuation remain consistent with the other bullets.
In `@projects/starters/go-htmx/main.go`:
- Around line 63-64: The code currently sends raw template errors
(templateError.Error()) in HTTP responses; change both occurrences to return a
generic client message (e.g., http.Error(w, "Internal Server Error",
http.StatusInternalServerError)) and log the full error server-side instead
(e.g., log.Printf or your app logger with the templateError value). Replace the
two http.Error calls that reference templateError with the generic message and
add a server-side log call immediately before each return to capture the full
templateError for debugging.
In `@projects/starters/go-htmx/src/index.html`:
- Around line 24-25: Update all anchor elements that use target="_blank" (e.g.,
the "Documentation" <a> element in index.html and the other external links
referenced at lines noted) to include rel="noopener noreferrer"; locate each
anchor with target="_blank" (instances near the "Documentation" link and the
other occurrences) and add the rel attribute to prevent window.opener access and
improve security.
In `@projects/starters/go/main.go`:
- Around line 51-53: Replace the direct exposure of templateError in HTTP
responses with server-side logging and a generic client message: where the code
currently calls http.Error(w, templateError.Error(),
http.StatusInternalServerError) (the occurrences using the templateError
variable in the request handler), change it to log the detailed error (e.g.,
log.Printf("template execution error: %v", templateError) or use the existing
logger) and call http.Error(w, "Internal Server Error",
http.StatusInternalServerError) so internal paths/details are not returned to
clients; apply this change to both occurrences handling templateError.
In `@projects/starters/go/README.md`:
- Around line 7-9: The README's "Commands / npm scripts" lines for `dev`,
`build`, and `preview` are inconsistent with the package.json scripts; update
the README so each listed npm script (`dev`, `build`, `preview`) documents the
actual commands defined in projects/starters/go/package.json (e.g., note that
`build` runs `wireit` rather than a direct `go build`), keeping the labels as
npm scripts and ensuring the `dev`, `build`, and `preview` entries match the
package.json script behavior and wording.
In `@projects/starters/go/src/index.html`:
- Line 22: The external anchor tags that use target="_blank" (e.g., the <a
href="https://nvidia.github.io/elements/docs/integrations/go/" target="_blank">
inside the <nve-button container="flat"> element and the other similar anchors)
are missing rel="noopener noreferrer"; update each anchor with target="_blank"
to include rel="noopener noreferrer" to prevent reverse-tabnabbing and ensure
safe external links.
---
Duplicate comments:
In `@projects/internals/tools/src/project/service.test.ts`:
- Around line 15-19: The test mock uses invalid starter keys; replace the fake
keys in the startersData mock with real Starter ids (e.g., change the `default`
key to `typescript` and the opt-out key to `go` or `go-htmx`) so the mock shape
matches the real union from starters.ts; then update the related
assertions/calls that reference those starters (the tests that currently
reference the old keys) to use `typescript` and `go` (or `go-htmx`) so the tests
align with the actual MCP schema and type definitions.
In `@projects/internals/tools/src/project/starters.ts`:
- Around line 21-22: REPO_WORKSPACE_DIR currently uses a cwd-relative string
which causes resolve()/readWorkspaceManifest() to point outside the repo; change
it to compute the repository root from this module's location using
import.meta.url (e.g. derive a file:// path and resolve up to repo root) and
replace the '../../' constant; update any uses in stampStarterCDNVersionFiles
and exportPackageFromWorkspace (and calls to resolve()/readWorkspaceManifest) to
use the new repo-root constant so CDN version lookup and workspace manifest
export resolve inside the repository.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Enterprise
Run ID: e1474610-8e10-46a4-9d23-48863b6f4597
⛔ Files ignored due to path filters (2)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yamlprojects/site/public/static/images/integrations/htmx.svgis excluded by!**/*.svg
📒 Files selected for processing (31)
.github/actions/setup-ci/action.yml.prettierignorepackage.jsonpnpm-workspace.yamlprojects/internals/tools/src/project/service.test.tsprojects/internals/tools/src/project/service.tsprojects/internals/tools/src/project/starters.test.tsprojects/internals/tools/src/project/starters.tsprojects/internals/tools/src/skills/about.mdprojects/site/public/static/images/integrations/NOTICEprojects/site/src/_11ty/layouts/common.jsprojects/site/src/_11ty/shortcodes/svg-logo.jsprojects/site/src/docs/integrations/go-htmx.mdprojects/site/src/docs/integrations/go.mdprojects/site/src/docs/integrations/index.11ty.jsprojects/site/src/index.11tydata.jsprojects/starters/README.mdprojects/starters/go-htmx/.gitignoreprojects/starters/go-htmx/AGENTS.mdprojects/starters/go-htmx/README.mdprojects/starters/go-htmx/main.goprojects/starters/go-htmx/package.jsonprojects/starters/go-htmx/src/index.htmlprojects/starters/go-htmx/src/time.htmlprojects/starters/go/.gitignoreprojects/starters/go/AGENTS.mdprojects/starters/go/README.mdprojects/starters/go/main.goprojects/starters/go/package.jsonprojects/starters/go/src/index.htmlprojects/starters/package.json
| - uses: actions/setup-go@v6 | ||
| with: | ||
| go-version: 'stable' | ||
| cache: false |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify whether the repo already declares a canonical Go version
# and where CI/docs should align.
set -euo pipefail
echo "== Go module files =="
fd -HI '^go\.mod$'
echo
echo "== Declared Go versions in go.mod files =="
fd -HI '^go\.mod$' -x sh -c '
file="$1"
ver=$(awk "/^go / { print \$2; exit }" "$file")
toolchain=$(awk "/^toolchain / { print \$2; exit }" "$file")
echo "$file :: go=${ver:-<none>} toolchain=${toolchain:-<none>}"
' sh {}
echo
echo "== CI setup-go declarations =="
rg -n -C2 "setup-go|go-version|go-version-file" .github/actions .github/workflows
echo
echo "== Dev/setup docs mentioning Go version =="
rg -n -C2 "Go version|go version|golang|setup.*go" README.md .github projects/starters --glob "*.md"Repository: NVIDIA/elements
Length of output: 674
Pin Go to a deterministic version instead of stable
.github/actions/setup-ci/action.yml (lines 16-19) sets go-version: 'stable', which can drift over time and break CI reproducibility; no other Go version source (no go.mod, no other setup-go/go-version declarations in CI or docs) was found to align on.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/actions/setup-ci/action.yml around lines 16 - 19, The workflow uses
actions/setup-go@v6 with go-version: 'stable', which is non-deterministic;
replace the 'stable' value with a pinned semantic version (e.g., '1.20.x' or a
specific patch like '1.20.7') in the action.yml go-version field so CI uses a
fixed Go release; update the go-version entry where actions/setup-go@v6 is
declared to a specific version string and, if desired, add a comment explaining
the chosen pinned version.
| - Render Elements markup through `html/template` in `src/index.html`. | ||
| - Render the full page through the root route. | ||
| - Render HTMX swap content through fragment templates under `src/`. |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial | ⚡ Quick win
Vary sentence-start words in the Integration Points section.
Lines 7, 8, and 9 all begin with "Render," which violates write-good prose style rules about sentence variety. Restructure at least one bullet to start with a different verb or preposition.
✏️ Example rewording
- Render Elements markup through `html/template` in `src/index.html`.
- Render the full page through the root route.
-- Render HTMX swap content through fragment templates under `src/`.
+- Keep HTMX swap content in fragment templates under `src/` and return only the target fragment.📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| - Render Elements markup through `html/template` in `src/index.html`. | |
| - Render the full page through the root route. | |
| - Render HTMX swap content through fragment templates under `src/`. | |
| - Render Elements markup through `html/template` in `src/index.html`. | |
| - Render the full page through the root route. | |
| - Keep HTMX swap content in fragment templates under `src/` and return only the target fragment. |
🧰 Tools
🪛 LanguageTool
[style] ~9-~9: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...the full page through the root route. - Render HTMX swap content through fragment temp...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@projects/starters/go-htmx/AGENTS.md` around lines 7 - 9, Update the three
bullets in the "Integration Points" section so they don't all start with
"Render"; pick at least one bullet to begin with a different verb or preposition
(e.g., "Use", "Serve", "Through", or "Via") while keeping the same meaning for
lines that mention "Elements markup through `html/template` in
`src/index.html`", "the full page through the root route", and "HTMX swap
content through fragment templates under `src/`". Ensure sentence structure and
punctuation remain consistent with the other bullets.
Source: Coding guidelines
| http.Error(w, templateError.Error(), http.StatusInternalServerError) | ||
| return |
There was a problem hiding this comment.
Avoid returning raw template errors to clients.
Line 63 and Line 70 send internal template parse/execute errors directly in HTTP responses, which can leak filesystem paths and implementation details. Return a generic message to clients and log full details server-side.
Proposed fix
func renderTemplate(w http.ResponseWriter, templatePath string, data interface{}, templatePaths ...string) {
paths := append([]string{templatePath}, templatePaths...)
tmpl, templateError := template.ParseFiles(paths...)
if templateError != nil {
- http.Error(w, templateError.Error(), http.StatusInternalServerError)
+ fmt.Printf("template parse error path=%s err=%v\n", templatePath, templateError)
+ http.Error(w, "Internal Server Error", http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "text/html; charset=utf-8")
templateError = tmpl.ExecuteTemplate(w, filepath.Base(templatePath), data)
if templateError != nil {
- http.Error(w, templateError.Error(), http.StatusInternalServerError)
+ fmt.Printf("template render error path=%s err=%v\n", templatePath, templateError)
+ http.Error(w, "Internal Server Error", http.StatusInternalServerError)
}
}Also applies to: 70-71
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@projects/starters/go-htmx/main.go` around lines 63 - 64, The code currently
sends raw template errors (templateError.Error()) in HTTP responses; change both
occurrences to return a generic client message (e.g., http.Error(w, "Internal
Server Error", http.StatusInternalServerError)) and log the full error
server-side instead (e.g., log.Printf or your app logger with the templateError
value). Replace the two http.Error calls that reference templateError with the
generic message and add a server-side log call immediately before each return to
capture the full templateError for debugging.
| ><a href="https://nvidia.github.io/elements/docs/integrations/go-htmx/" target="_blank" | ||
| >Documentation</a |
There was a problem hiding this comment.
Add rel="noopener noreferrer" to all target="_blank" links.
These anchors open external pages with target="_blank" but no rel protection, enabling opener access.
Proposed fix
-<a href="https://nvidia.github.io/elements/docs/integrations/go-htmx/" target="_blank"
+<a href="https://nvidia.github.io/elements/docs/integrations/go-htmx/" target="_blank" rel="noopener noreferrer"
...
-<a href="https://github.com/NVIDIA/elements/" target="_blank">GitHub</a>
+<a href="https://github.com/NVIDIA/elements/" target="_blank" rel="noopener noreferrer">GitHub</a>
...
-<a target="_blank" href="https://nvidia.github.io/elements/docs/integrations/go-htmx/"
+<a target="_blank" rel="noopener noreferrer" href="https://nvidia.github.io/elements/docs/integrations/go-htmx/"
...
-<a target="_blank" href="https://github.com/NVIDIA/elements/tree/main/projects/starters/go-htmx"
+<a target="_blank" rel="noopener noreferrer" href="https://github.com/NVIDIA/elements/tree/main/projects/starters/go-htmx"
...
-<a nve-text="body sm" target="_blank" href="https://nvidia.github.io/elements/docs/integrations/go-htmx/"
+<a nve-text="body sm" target="_blank" rel="noopener noreferrer" href="https://nvidia.github.io/elements/docs/integrations/go-htmx/"
...
-<a nve-text="body sm" target="_blank" href="https://github.com/NVIDIA/elements/tree/main/projects/starters/go-htmx"
+<a nve-text="body sm" target="_blank" rel="noopener noreferrer" href="https://github.com/NVIDIA/elements/tree/main/projects/starters/go-htmx"Also applies to: 30-30, 37-37, 42-42, 70-70, 75-75
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@projects/starters/go-htmx/src/index.html` around lines 24 - 25, Update all
anchor elements that use target="_blank" (e.g., the "Documentation" <a> element
in index.html and the other external links referenced at lines noted) to include
rel="noopener noreferrer"; locate each anchor with target="_blank" (instances
near the "Documentation" link and the other occurrences) and add the rel
attribute to prevent window.opener access and improve security.
| if templateError != nil { | ||
| http.Error(w, templateError.Error(), http.StatusInternalServerError) | ||
| return |
There was a problem hiding this comment.
Avoid returning internal template errors to clients.
On Line 52 and Line 59, templateError.Error() is sent in the HTTP response. That can leak internal paths/template details. Return a generic message to the client and log the detailed error server-side instead.
Suggested patch
tmpl, templateError := template.ParseFiles(paths...)
if templateError != nil {
- http.Error(w, templateError.Error(), http.StatusInternalServerError)
+ http.Error(w, "Internal Server Error", http.StatusInternalServerError)
+ fmt.Println("template parse error:", templateError)
return
}
@@
templateError = tmpl.ExecuteTemplate(w, filepath.Base(templatePath), data)
if templateError != nil {
- http.Error(w, templateError.Error(), http.StatusInternalServerError)
+ http.Error(w, "Internal Server Error", http.StatusInternalServerError)
+ fmt.Println("template execute error:", templateError)
}Also applies to: 57-60
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@projects/starters/go/main.go` around lines 51 - 53, Replace the direct
exposure of templateError in HTTP responses with server-side logging and a
generic client message: where the code currently calls http.Error(w,
templateError.Error(), http.StatusInternalServerError) (the occurrences using
the templateError variable in the request handler), change it to log the
detailed error (e.g., log.Printf("template execution error: %v", templateError)
or use the existing logger) and call http.Error(w, "Internal Server Error",
http.StatusInternalServerError) so internal paths/details are not returned to
clients; apply this change to both occurrences handling templateError.
| - `dev`: `go run main.go` | ||
| - `build`: `go build -o bin main.go` | ||
| - `preview`: `go build -o bin main.go && ./bin` |
There was a problem hiding this comment.
Keep README script docs consistent with package.json scripts.
This section is labeled “Commands / npm scripts”, but Line 8 documents a direct Go command while build in projects/starters/go/package.json now runs wireit. Please update this section so the documented npm script behavior matches the actual script contract.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@projects/starters/go/README.md` around lines 7 - 9, The README's "Commands /
npm scripts" lines for `dev`, `build`, and `preview` are inconsistent with the
package.json scripts; update the README so each listed npm script (`dev`,
`build`, `preview`) documents the actual commands defined in
projects/starters/go/package.json (e.g., note that `build` runs `wireit` rather
than a direct `go build`), keeping the labels as npm scripts and ensuring the
`dev`, `build`, and `preview` entries match the package.json script behavior and
wording.
| <nve-button container="flat"><a href="https://NVIDIA.github.io/elements/docs/integrations/angular/" target="_blank">Catalog</a></nve-button> | ||
| <nve-button container="flat"><a href="https://NVIDIA.github.io/elements/starters/">Starters</a></nve-button> | ||
| <a slot="prefix" href="https://nvidia.github.io/elements/">Elements</a> | ||
| <nve-button container="flat"><a href="https://nvidia.github.io/elements/docs/integrations/go/" target="_blank">Documentation</a></nve-button> |
There was a problem hiding this comment.
Add rel="noopener noreferrer" to external links opened in new tabs.
On Line 22, Line 29, and Line 43, anchors use target="_blank" without rel. Add rel="noopener noreferrer" to prevent reverse-tabnabbing.
Also applies to: 29-29, 43-43
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@projects/starters/go/src/index.html` at line 22, The external anchor tags
that use target="_blank" (e.g., the <a
href="https://nvidia.github.io/elements/docs/integrations/go/" target="_blank">
inside the <nve-button container="flat"> element and the other similar anchors)
are missing rel="noopener noreferrer"; update each anchor with target="_blank"
to include rel="noopener noreferrer" to prevent reverse-tabnabbing and ensure
safe external links.
• Added the HTMX + Go starter with a Go-rendered page, HTMX fragment endpoint, refresh-button with swap, agent support, CLI metadata, starter archive wiring, docs updates, and HTMX logo • Fixed the existing Go starter by correcting bad Elements bundle URLs, loading CSS and JS from the right packages, removing the frontend dependency/setup path, fixing stale copy, updating source links, simplifying template data • More Go server functionality with PORT support, root-only routing, explicit HTML content type, and template execution error handling. • Go and HTMX+Go starters are freed from frontend build tooling by using browser CDN bundles, excluding local build/cache outputs, skipping Elements dependency setup, and stamping CDN bundle versions during archive generation. • Test updates including Elements version stamping logic
Summary by CodeRabbit
New Features
Improvements
Documentation