Skip to content

fix(cli): version and updater checks#155

Open
coryrylan wants to merge 1 commit into
mainfrom
topic-cli-version-updater
Open

fix(cli): version and updater checks#155
coryrylan wants to merge 1 commit into
mainfrom
topic-cli-version-updater

Conversation

@coryrylan

@coryrylan coryrylan commented Jun 26, 2026

Copy link
Copy Markdown
Collaborator
  • Added support for versioning output files in the build process, ensuring that the correct version is written to bundled files.
  • Introduced a new utility function to replace bundled constants in the output files, improving maintainability.
  • Updated the installation script to utilize the embedded build SHA and version, enhancing the manifest generation.
  • Refactored error handling in the update check to ensure proper feedback when the SHA is missing.

Summary by CodeRabbit

  • New Features
    • Manifest generation now always includes sha, version, and per-platform checksums derived from bundled build outputs.
  • Bug Fixes
    • Update detection is strictly SHA-based; malformed manifests now fail earlier with clearer “failed to fetch latest build info” behavior.
    • Global skill installation overwrites an existing SKILL.md without prompting (including CI), reporting “Installed” vs “Updated”.
    • CLI tool execution now has unified completion/error handling, improved upgrade flow messaging, and better argument handling (including variadic names and array parsing).
  • Documentation
    • Updated nve api.get usage and command signature.
  • Chores
    • Centralized Elements URL configuration across builds and site, with expanded test coverage.

@coryrylan coryrylan self-assigned this Jun 26, 2026
@coderabbitai

coderabbitai Bot commented Jun 26, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The PR centralizes Elements environment injection, updates CLI build metadata generation, refactors CLI exit handling, tightens update checks, and changes global skill installation to overwrite existing files without prompting.

Changes

Release and CLI flow

Layer / File(s) Summary
Shared env constants
projects/internals/vite/src/configs/{env.js,build.js,build.node.js,test.js,test.node.js}
getElementsEnvValues() and getElementsEnv() replace inline Elements env literals in the shared Vite configs.
Injected URL consumers
projects/internals/tools/src/{api/utils.ts,playground/utils.ts,playground/utils.test.ts}, projects/site/src/_11ty/utils/env.js
Registry, ESM CDN, playground, and site env consumers now read build-provided globals, and the playground import map test expects an exact @nvidia-elements/core URL.
API.get command wiring
projects/cli/src/index.ts, projects/cli/src/index.test.ts, projects/cli/README.md, projects/site/src/docs/cli/index.md
The CLI help, command parsing, and integration tests now use variadic api.get names and an explicit --format option.
Build version and manifest
projects/cli/vite.config.ts, projects/cli/scripts/write-install-manifest.mjs, projects/cli/src/install.test.ts
The CLI build config falls back to package.json version data, and the install-manifest script reads bundled BUILD_SHA and VERSION values to write sha, version, and platforms.
Upgrade command URLs
projects/internals/tools/src/cli/{utils.ts,utils.test.ts}
upgradeCommands now run the macOS/Linux installer pipeline under bash -o pipefail -c, and the CLI utils tests check the wrapper and public pages host URLs.
Tool execution helpers
projects/cli/src/{utils.ts,utils.test.ts}
runAsyncTool accepts interactiveProgress, spinner cleanup moves into finally, and the new exit helpers format results, compute exit codes, and terminate the process.
CLI upgrade completion
projects/cli/src/index.ts
The CLI upgrade path logs the upgrade message, disables interactive progress, and delegates completed tool output and exit handling to the shared helper.
Update manifest checks
projects/cli/src/{update.ts,update.test.ts}
fetchLatestSha validates manifest sha values, and update tests cover sha-driven availability checks.
Global Elements skill install
projects/cli/src/{install.ts,install.test.ts}
installGlobalElementsSkill distinguishes missing-path warnings from existing-file updates, skips prompting when the skill file already exists, and logs installed versus updated outcomes.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Suggested labels

scope(internals)

Suggested reviewers

  • johnyanarella
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.69% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and matches the PR’s main focus on versioning output and update-check behavior in the CLI.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch topic-cli-version-updater

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
projects/cli/src/utils.ts (1)

145-150: 🎯 Functional Correctness | 🟠 Major

Tighten isReport to validate report entries.
isReport() accepts any truthy status/message, so malformed data can be narrowed to Report and exitCodeForResult() can return success. Require each entry to be an object, message to be a string, and status to match the supported report statuses.

🤖 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/cli/src/utils.ts` around lines 145 - 150, The isReport guard is too
permissive and can incorrectly narrow malformed data to Report. Update isReport
to validate each entry in the object is itself an object, ensure message is a
string, and verify status matches the supported report statuses instead of just
being truthy. Keep the check localized in isReport so exitCodeForResult
continues to rely on a correctly validated Report shape.

Source: Coding guidelines

🤖 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/cli/src/install.test.ts`:
- Around line 760-782: In the install test that calls spawnSync for
writeInstallManifest, assert the subprocess result succeeded before reading and
parsing dist/manifest.json. Move the check on result.status (and include
result.stderr in the failure path if needed) ahead of the readFile/JSON.parse
step in the test using createInstallerContext and writeInstallManifest, so
failures surface the actual exit error instead of a file-not-found.

In `@projects/cli/src/utils.ts`:
- Line 185: The formatted result in the rendering logic is appending the debug
metadata directly after the prior content, so update the formatting in the utils
rendering path to prepend a separator before the debug block. Locate the
concatenation that adds the [debug] metadata in the result-building flow and
ensure it starts on a new line so the output is separated cleanly from the
rendered content.

---

Outside diff comments:
In `@projects/cli/src/utils.ts`:
- Around line 145-150: The isReport guard is too permissive and can incorrectly
narrow malformed data to Report. Update isReport to validate each entry in the
object is itself an object, ensure message is a string, and verify status
matches the supported report statuses instead of just being truthy. Keep the
check localized in isReport so exitCodeForResult continues to rely on a
correctly validated Report shape.
🪄 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: 872843f0-0461-4b73-9063-626b276e6d00

📥 Commits

Reviewing files that changed from the base of the PR and between c58c856 and 9cd318b.

📒 Files selected for processing (20)
  • projects/cli/scripts/write-install-manifest.mjs
  • projects/cli/src/index.ts
  • projects/cli/src/install.test.ts
  • projects/cli/src/install.ts
  • projects/cli/src/update.test.ts
  • projects/cli/src/update.ts
  • projects/cli/src/utils.test.ts
  • projects/cli/src/utils.ts
  • projects/cli/vite.config.ts
  • projects/internals/tools/src/api/utils.ts
  • projects/internals/tools/src/cli/utils.test.ts
  • projects/internals/tools/src/cli/utils.ts
  • projects/internals/tools/src/playground/utils.test.ts
  • projects/internals/tools/src/playground/utils.ts
  • projects/internals/vite/src/configs/build.js
  • projects/internals/vite/src/configs/build.node.js
  • projects/internals/vite/src/configs/env.js
  • projects/internals/vite/src/configs/test.js
  • projects/internals/vite/src/configs/test.node.js
  • projects/site/src/_11ty/utils/env.js

Comment thread projects/cli/src/install.test.ts
Comment thread projects/cli/src/utils.ts
@coryrylan coryrylan force-pushed the topic-cli-version-updater branch from 9cd318b to b9fc8cd Compare June 26, 2026 20:32

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

🤖 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/cli/src/update.test.ts`:
- Around line 58-69: Add a regression test in fetchLatestSha coverage for a
manifest that returns an empty sha string, since the current test only covers a
missing sha shape. Update the existing test suite in update.test.ts alongside
the fetchLatestSha cases to stub fetch with a manifest containing sha: '' and
assert it rejects with the same failure path as the missing-sha case, so the
runtime guard in fetchLatestSha stays enforced for both invalid manifest shapes.

In `@projects/cli/src/update.ts`:
- Around line 24-28: The SHA guard in the manifest-fetching logic is too loose
because the `sha` value can be an empty string and still pass. Update the `sha`
validation in the update flow so the `sha` returned from `res.json()` must be a
non-empty string before returning it, and continue throwing the missing-SHA
error for blank values; this change should be applied in the manifest parsing
path used by `isUpdateAvailable()` so invalid manifests do not get treated as
“no update available.”
🪄 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: dc3c67f8-cb01-45f2-b49c-5749b00c7bd5

📥 Commits

Reviewing files that changed from the base of the PR and between 9cd318b and b9fc8cd.

📒 Files selected for processing (20)
  • projects/cli/scripts/write-install-manifest.mjs
  • projects/cli/src/index.ts
  • projects/cli/src/install.test.ts
  • projects/cli/src/install.ts
  • projects/cli/src/update.test.ts
  • projects/cli/src/update.ts
  • projects/cli/src/utils.test.ts
  • projects/cli/src/utils.ts
  • projects/cli/vite.config.ts
  • projects/internals/tools/src/api/utils.ts
  • projects/internals/tools/src/cli/utils.test.ts
  • projects/internals/tools/src/cli/utils.ts
  • projects/internals/tools/src/playground/utils.test.ts
  • projects/internals/tools/src/playground/utils.ts
  • projects/internals/vite/src/configs/build.js
  • projects/internals/vite/src/configs/build.node.js
  • projects/internals/vite/src/configs/env.js
  • projects/internals/vite/src/configs/test.js
  • projects/internals/vite/src/configs/test.node.js
  • projects/site/src/_11ty/utils/env.js

Comment on lines +58 to +69
it('should throw error when manifest is missing sha', async () => {
vi.stubGlobal(
'fetch',
vi.fn().mockResolvedValue({
ok: true,
json: () => Promise.resolve({ version: '2.1.0' })
})
);

await expect(fetchLatestSha()).rejects.toThrow('Failed to fetch latest build info');
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Add a blank-sha regression case.

This covers sha being absent, but '' is another invalid manifest shape that should be pinned down once the runtime guard is tightened. Otherwise the remaining bad-manifest path can regress unnoticed.

🤖 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/cli/src/update.test.ts` around lines 58 - 69, Add a regression test
in fetchLatestSha coverage for a manifest that returns an empty sha string,
since the current test only covers a missing sha shape. Update the existing test
suite in update.test.ts alongside the fetchLatestSha cases to stub fetch with a
manifest containing sha: '' and assert it rejects with the same failure path as
the missing-sha case, so the runtime guard in fetchLatestSha stays enforced for
both invalid manifest shapes.

Comment on lines +24 to +28
const { sha } = (await res.json()) as { sha?: string };
if (typeof sha !== 'string') {
throw new Error('Missing sha');
}
return sha;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Reject blank manifest SHAs too.

typeof sha === 'string' still accepts '', which means an invalid manifest can pass this guard and then get treated downstream as "no update available" because isUpdateAvailable() only reports when latestSha !== ''. That leaves the missing-SHA failure mode only partially covered.

Proposed fix
-    if (typeof sha !== 'string') {
+    if (typeof sha !== 'string' || sha.trim() === '') {
       throw new Error('Missing sha');
     }
📝 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.

Suggested change
const { sha } = (await res.json()) as { sha?: string };
if (typeof sha !== 'string') {
throw new Error('Missing sha');
}
return sha;
const { sha } = (await res.json()) as { sha?: string };
if (typeof sha !== 'string' || sha.trim() === '') {
throw new Error('Missing sha');
}
return sha;
🤖 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/cli/src/update.ts` around lines 24 - 28, The SHA guard in the
manifest-fetching logic is too loose because the `sha` value can be an empty
string and still pass. Update the `sha` validation in the update flow so the
`sha` returned from `res.json()` must be a non-empty string before returning it,
and continue throwing the missing-SHA error for blank values; this change should
be applied in the manifest parsing path used by `isUpdateAvailable()` so invalid
manifests do not get treated as “no update available.”

@coryrylan coryrylan force-pushed the topic-cli-version-updater branch from b9fc8cd to 76d2980 Compare June 26, 2026 21:08

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

♻️ Duplicate comments (1)
projects/cli/src/utils.ts (1)

185-185: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Missing separator before [debug] block.

Line 185 still appends [debug] directly onto the rendered result (...}[debug]), with no leading newline, despite the prior fix being marked as addressed. Prefix the debug block with \n.

Suggested fix
-    formattedResult += `[debug]\n[command]: ${tool.metadata.command}`;
+    formattedResult += `\n[debug]\n[command]: ${tool.metadata.command}`;
🤖 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/cli/src/utils.ts` at line 185, The rendered output in utils.ts still
appends the [debug] block directly after the main result, so update the
formatting in the code that builds formattedResult to prefix the debug section
with a leading newline before [debug]. Use the existing string assembly around
formattedResult and tool.metadata.command to keep the debug block separated from
the prior content.
🤖 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/cli/scripts/write-install-manifest.mjs`:
- Around line 29-34: The getBundledConstant helper builds a RegExp from the
unescaped name argument, so update that pattern construction to safely escape
any regex metacharacters before interpolation. Keep the lookup logic in
getBundledConstant and preserve the missing-constant error path, but make the
guard/message reflect that this is a no-match case rather than a falsy value
check.

In `@projects/cli/src/install.ts`:
- Around line 398-405: The install flow in installSkill should keep the
CI/non-interactive policy check from shouldInstallGlobalElementsSkill(context)
separate from the existing-file shortcut. Call the policy gate first so CI still
blocks global installation, then use hasExistingSkill only to decide whether to
skip the prompt and whether to avoid overwriting an existing SKILL.md without
confirmation. Preserve the behavior around writeGlobalElementsSkill(skillPath)
and the Installed/Updated log message, but make sure reruns cannot bypass the
gate or silently replace a preexisting file.

---

Duplicate comments:
In `@projects/cli/src/utils.ts`:
- Line 185: The rendered output in utils.ts still appends the [debug] block
directly after the main result, so update the formatting in the code that builds
formattedResult to prefix the debug section with a leading newline before
[debug]. Use the existing string assembly around formattedResult and
tool.metadata.command to keep the debug block separated from the prior content.
🪄 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: 983fe57d-b011-4197-a3cc-586d20e1abac

📥 Commits

Reviewing files that changed from the base of the PR and between b9fc8cd and 76d2980.

📒 Files selected for processing (21)
  • projects/cli/scripts/write-install-manifest.mjs
  • projects/cli/src/index.ts
  • projects/cli/src/install.test.ts
  • projects/cli/src/install.ts
  • projects/cli/src/update.test.ts
  • projects/cli/src/update.ts
  • projects/cli/src/utils.test.ts
  • projects/cli/src/utils.ts
  • projects/cli/vite.config.ts
  • projects/internals/tools/src/api/utils.ts
  • projects/internals/tools/src/cli/utils.test.ts
  • projects/internals/tools/src/cli/utils.ts
  • projects/internals/tools/src/playground/utils.test.ts
  • projects/internals/tools/src/playground/utils.ts
  • projects/internals/vite/src/configs/build.js
  • projects/internals/vite/src/configs/build.node.js
  • projects/internals/vite/src/configs/env.js
  • projects/internals/vite/src/configs/test.js
  • projects/internals/vite/src/configs/test.node.js
  • projects/site/src/_11ty/utils/env.js
  • projects/site/src/_11ty/utils/env.test.ts
💤 Files with no reviewable changes (1)
  • projects/site/src/_11ty/utils/env.test.ts

Comment on lines +29 to +34
function getBundledConstant(content, name) {
const value = content.match(new RegExp(`(?:var|const|let)\\s+${name}\\s*=\\s*["']([^"']+)["']`))?.[1];
if (!value) {
throw new Error(`Missing bundled ${name} constant`);
}
return value;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Minor: escape name before building the RegExp.

name is interpolated unescaped into the pattern. Today the only callers pass BUILD_SHA/VERSION (regex-safe), but a future caller with regex metacharacters would silently produce a wrong pattern. Also consider that !value rejects a legitimately empty constant — though the [^"']+ group already requires at least one character, so the guard is effectively a missing-match check; a clearer message would help.

🤖 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/cli/scripts/write-install-manifest.mjs` around lines 29 - 34, The
getBundledConstant helper builds a RegExp from the unescaped name argument, so
update that pattern construction to safely escape any regex metacharacters
before interpolation. Keep the lookup logic in getBundledConstant and preserve
the missing-constant error path, but make the guard/message reflect that this is
a no-match case rather than a falsy value check.

Comment on lines +398 to +405
const hasExistingSkill = existsSync(skillPath);
if (!hasExistingSkill && !(await shouldInstallGlobalElementsSkill(context))) {
return;
}

try {
await writeGlobalElementsSkill(skillPath);
context.log(`Installed agent skill at ${skillPath}`);
context.log(`${hasExistingSkill ? 'Updated' : 'Installed'} agent skill at ${skillPath}`);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Keep the CI/install-policy gate separate from the prompt shortcut.

Lines 398-400 now skip shouldInstallGlobalElementsSkill() whenever SKILL.md already exists, but that helper is also the only place that blocks global installs in CI. As written, a rerun in CI will overwrite an existing ~/.agents/skills/elements/SKILL.md without any prompt, and it will silently replace any preexisting file at that path. Preserve the non-interactive policy check before the hasExistingSkill fast path, then use the existence check only to suppress the prompt.

Suggested fix
 async function installGlobalElementsSkill(context: InstallContext): Promise<void> {
   const skillPath = getGlobalElementsSkillPath(context.env, context.platform);
   if (!skillPath) {
     context.warn('Could not install Elements agent skill. HOME is not set.');
     return;
   }

+  if (context.env.CI) {
+    return;
+  }
+
   const hasExistingSkill = existsSync(skillPath);
   if (!hasExistingSkill && !(await shouldInstallGlobalElementsSkill(context))) {
     return;
   }

   try {
📝 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.

Suggested change
const hasExistingSkill = existsSync(skillPath);
if (!hasExistingSkill && !(await shouldInstallGlobalElementsSkill(context))) {
return;
}
try {
await writeGlobalElementsSkill(skillPath);
context.log(`Installed agent skill at ${skillPath}`);
context.log(`${hasExistingSkill ? 'Updated' : 'Installed'} agent skill at ${skillPath}`);
const skillPath = getGlobalElementsSkillPath(context.env, context.platform);
if (!skillPath) {
context.warn('Could not install Elements agent skill. HOME is not set.');
return;
}
if (context.env.CI) {
return;
}
const hasExistingSkill = existsSync(skillPath);
if (!hasExistingSkill && !(await shouldInstallGlobalElementsSkill(context))) {
return;
}
try {
await writeGlobalElementsSkill(skillPath);
context.log(`${hasExistingSkill ? 'Updated' : 'Installed'} agent skill at ${skillPath}`);
🤖 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/cli/src/install.ts` around lines 398 - 405, The install flow in
installSkill should keep the CI/non-interactive policy check from
shouldInstallGlobalElementsSkill(context) separate from the existing-file
shortcut. Call the policy gate first so CI still blocks global installation,
then use hasExistingSkill only to decide whether to skip the prompt and whether
to avoid overwriting an existing SKILL.md without confirmation. Preserve the
behavior around writeGlobalElementsSkill(skillPath) and the Installed/Updated
log message, but make sure reruns cannot bypass the gate or silently replace a
preexisting file.

@coryrylan coryrylan force-pushed the topic-cli-version-updater branch from 76d2980 to 42deb6f Compare June 29, 2026 17:49

@coderabbitai coderabbitai 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.

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/cli/src/utils.ts`:
- Around line 47-52: `runAsyncTool` is using `interactiveProgress` to decide
whether to wire `onProgress`, which changes execution flow instead of just
disabling the spinner. Update the `isInteractive`/options handling in
`projects/cli/src/utils.ts` so `onProgress` is still passed through whenever the
async path should be used, even when `interactiveProgress` is false. In
`projects/cli/src/index.ts` and the `ManagedToolMethod` call site, keep a
callback attached and make it a no-op or logger-only implementation when
progress UI is off, so `projects/internals/tools/src/cli/utils.ts` does not fall
back to `runSync()`.
- Around line 182-187: The debug token usage display in utils.ts uses the raw
pct value for the “remaining” text, which can go negative when formattedResult
exceeds MAX_CONTEXT_TOKENS. In the debug block inside the tool/start/end check,
clamp pct to the 0–100 range before using it for the remaining calculation,
while still passing the clamped value to progressBar() so the output stays
consistent.

In `@projects/internals/tools/src/api/utils.ts`:
- Line 171: Normalize the injected registry base before it is used to build
package fetch URLs, since getElementsEnvValues() currently only trims whitespace
and leaves trailing slashes intact. Update the NPM_REGISTRY_URL handling in
utils.ts so the composed endpoint for `@nvidia-elements/core/latest` does not end
up with a double slash when ELEMENTS_REGISTRY_URL already ends with "/". Use the
existing getElementsEnvValues() and NPM_REGISTRY_URL symbols to locate the
parsing/composition logic and strip any trailing slash from the registry base
before concatenation.

In `@projects/internals/tools/src/playground/utils.ts`:
- Line 13: Normalize the injected ESM CDN base before it is used by
createImportMap(), since ELEMENTS_ESM_CDN_BASE_URL may include a trailing slash
and that combines badly with package paths that already start with a slash.
Update the shared constant in utils.ts, or the common env helper that feeds it,
so any trailing slash is stripped once and all custom CDN hosts remain valid
when building import maps.

In `@projects/internals/vite/src/configs/env.js`:
- Around line 20-35: The env mapping in getElementsEnv() is missing the
__ELEMENTS_ASSETS_CDN_BASE_URL__ define even though getElementsEnvValues()
already reads ELEMENTS_ASSETS_CDN_BASE_URL. Update getElementsEnv() to emit that
constant alongside the other Vite defines so callers like animated-build.ts
receive the assets CDN base URL correctly.
🪄 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: d1c89635-2724-4e0f-b9bf-ea5e4204072c

📥 Commits

Reviewing files that changed from the base of the PR and between 76d2980 and 42deb6f.

📒 Files selected for processing (21)
  • projects/cli/scripts/write-install-manifest.mjs
  • projects/cli/src/index.ts
  • projects/cli/src/install.test.ts
  • projects/cli/src/install.ts
  • projects/cli/src/update.test.ts
  • projects/cli/src/update.ts
  • projects/cli/src/utils.test.ts
  • projects/cli/src/utils.ts
  • projects/cli/vite.config.ts
  • projects/internals/tools/src/api/utils.ts
  • projects/internals/tools/src/cli/utils.test.ts
  • projects/internals/tools/src/cli/utils.ts
  • projects/internals/tools/src/playground/utils.test.ts
  • projects/internals/tools/src/playground/utils.ts
  • projects/internals/vite/src/configs/build.js
  • projects/internals/vite/src/configs/build.node.js
  • projects/internals/vite/src/configs/env.js
  • projects/internals/vite/src/configs/test.js
  • projects/internals/vite/src/configs/test.node.js
  • projects/site/src/_11ty/utils/env.js
  • projects/site/src/_11ty/utils/env.test.ts
💤 Files with no reviewable changes (1)
  • projects/site/src/_11ty/utils/env.test.ts

Comment thread projects/cli/src/utils.ts
Comment on lines +47 to +52
export async function runAsyncTool(
args: Record<string, unknown>,
fn: ManagedToolMethod<unknown>,
options: RunAsyncToolOptions = {}
) {
const isInteractive = (options.interactiveProgress ?? true) && !args.start && !args.log && !process.env.CI;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Don't use interactiveProgress to suppress onProgress wiring.

interactiveProgress: false is changing execution semantics, not just the UI. projects/internals/tools/src/cli/utils.ts falls back to runSync() when the callback is missing, so the new upgrade path in projects/cli/src/index.ts now drops the async spawn()/stderr-capture path simply by disabling the spinner. Keep passing an onProgress callback when interactive output is off; make it a no-op or plain logger if you do not want spinner updates.

🤖 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/cli/src/utils.ts` around lines 47 - 52, `runAsyncTool` is using
`interactiveProgress` to decide whether to wire `onProgress`, which changes
execution flow instead of just disabling the spinner. Update the
`isInteractive`/options handling in `projects/cli/src/utils.ts` so `onProgress`
is still passed through whenever the async path should be used, even when
`interactiveProgress` is false. In `projects/cli/src/index.ts` and the
`ManagedToolMethod` call site, keep a callback attached and make it a no-op or
logger-only implementation when progress UI is off, so
`projects/internals/tools/src/cli/utils.ts` does not fall back to `runSync()`.

Comment thread projects/cli/src/utils.ts
Comment on lines +182 to +187
if (tool && start !== undefined && end !== undefined && isDebug()) {
const tokens = formattedResult.length / 4;
const pct = (tokens / MAX_CONTEXT_TOKENS) * 100;
formattedResult += `[debug]\n[command]: ${tool.metadata.command}`;
formattedResult += `\n[execution time]: ${((end - start) / 1000).toFixed(2)} seconds`;
formattedResult += `\n[token usage]: ${progressBar(pct)} ${tokens.toLocaleString()} / ${MAX_CONTEXT_TOKENS.toLocaleString()} (${(100 - pct).toFixed(1)}% remaining)`;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Clamp the displayed token percentage before computing “remaining”.

progressBar() clamps over-100 values, but the trailing text uses the raw percentage. Once debug output exceeds MAX_CONTEXT_TOKENS, this prints a negative remaining percentage.

Suggested fix
-    const pct = (tokens / MAX_CONTEXT_TOKENS) * 100;
+    const pct = Math.max(0, Math.min(100, (tokens / MAX_CONTEXT_TOKENS) * 100));
📝 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.

Suggested change
if (tool && start !== undefined && end !== undefined && isDebug()) {
const tokens = formattedResult.length / 4;
const pct = (tokens / MAX_CONTEXT_TOKENS) * 100;
formattedResult += `[debug]\n[command]: ${tool.metadata.command}`;
formattedResult += `\n[execution time]: ${((end - start) / 1000).toFixed(2)} seconds`;
formattedResult += `\n[token usage]: ${progressBar(pct)} ${tokens.toLocaleString()} / ${MAX_CONTEXT_TOKENS.toLocaleString()} (${(100 - pct).toFixed(1)}% remaining)`;
if (tool && start !== undefined && end !== undefined && isDebug()) {
const tokens = formattedResult.length / 4;
const pct = Math.max(0, Math.min(100, (tokens / MAX_CONTEXT_TOKENS) * 100));
formattedResult += `[debug]\n[command]: ${tool.metadata.command}`;
formattedResult += `\n[execution time]: ${((end - start) / 1000).toFixed(2)} seconds`;
formattedResult += `\n[token usage]: ${progressBar(pct)} ${tokens.toLocaleString()} / ${MAX_CONTEXT_TOKENS.toLocaleString()} (${(100 - pct).toFixed(1)}% remaining)`;
🤖 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/cli/src/utils.ts` around lines 182 - 187, The debug token usage
display in utils.ts uses the raw pct value for the “remaining” text, which can
go negative when formattedResult exceeds MAX_CONTEXT_TOKENS. In the debug block
inside the tool/start/end check, clamp pct to the 0–100 range before using it
for the remaining calculation, while still passing the clamped value to
progressBar() so the output stays consistent.

}

const NPM_REGISTRY_URL = 'https://registry.npmjs.org';
const NPM_REGISTRY_URL = __ELEMENTS_REGISTRY_URL__;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Normalize the injected registry base before composing fetch URLs.

getElementsEnvValues() only trims whitespace, so a common setting like ELEMENTS_REGISTRY_URL=https://registry.npmjs.org/ becomes https://registry.npmjs.org//@nvidia-elements/core/latest here. That makes the new configurable registry endpoint brittle for trailing-slash inputs.

Proposed fix
-const NPM_REGISTRY_URL = __ELEMENTS_REGISTRY_URL__;
+const NPM_REGISTRY_URL = __ELEMENTS_REGISTRY_URL__.replace(/\/+$/, '');
📝 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.

Suggested change
const NPM_REGISTRY_URL = __ELEMENTS_REGISTRY_URL__;
const NPM_REGISTRY_URL = __ELEMENTS_REGISTRY_URL__.replace(/\/+$/, '');
🤖 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/api/utils.ts` at line 171, Normalize the
injected registry base before it is used to build package fetch URLs, since
getElementsEnvValues() currently only trims whitespace and leaves trailing
slashes intact. Update the NPM_REGISTRY_URL handling in utils.ts so the composed
endpoint for `@nvidia-elements/core/latest` does not end up with a double slash
when ELEMENTS_REGISTRY_URL already ends with "/". Use the existing
getElementsEnvValues() and NPM_REGISTRY_URL symbols to locate the
parsing/composition logic and strip any trailing slash from the registry base
before concatenation.


const ELEMENTS_PLAYGROUND_BASE_URL = process.env.ELEMENTS_PLAYGROUND_BASE_URL ?? '';
const ELEMENTS_ESM_CDN_BASE_URL = process.env.ELEMENTS_ESM_CDN_BASE_URL ?? '';
const ELEMENTS_ESM_CDN_BASE_URL = __ELEMENTS_ESM_CDN_BASE_URL__;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Strip trailing slashes from the injected ESM CDN base.

createImportMap() appends package paths with a leading /, so ELEMENTS_ESM_CDN_BASE_URL=https://esm.sh/ generates https://esm.sh//@nvidia-elements/core@latest. Normalize the base here (or once in the shared env helper) so custom CDN hosts stay valid.

Proposed fix
-const ELEMENTS_ESM_CDN_BASE_URL = __ELEMENTS_ESM_CDN_BASE_URL__;
+const ELEMENTS_ESM_CDN_BASE_URL = __ELEMENTS_ESM_CDN_BASE_URL__.replace(/\/+$/, '');
📝 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.

Suggested change
const ELEMENTS_ESM_CDN_BASE_URL = __ELEMENTS_ESM_CDN_BASE_URL__;
const ELEMENTS_ESM_CDN_BASE_URL = __ELEMENTS_ESM_CDN_BASE_URL__.replace(/\/+$/, '');
🤖 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/playground/utils.ts` at line 13, Normalize the
injected ESM CDN base before it is used by createImportMap(), since
ELEMENTS_ESM_CDN_BASE_URL may include a trailing slash and that combines badly
with package paths that already start with a slash. Update the shared constant
in utils.ts, or the common env helper that feeds it, so any trailing slash is
stripped once and all custom CDN hosts remain valid when building import maps.

Comment on lines +20 to +35
ELEMENTS_PLAYGROUND_BASE_URL: getEnvValue('ELEMENTS_PLAYGROUND_BASE_URL'),
ELEMENTS_ASSETS_CDN_BASE_URL: getEnvValue('ELEMENTS_ASSETS_CDN_BASE_URL')
};
}

export function getElementsEnv() {
const env = getElementsEnvValues();
return {
__ELEMENTS_REPO_BASE_URL__: JSON.stringify(env.ELEMENTS_REPO_BASE_URL),
__ELEMENTS_PAGES_BASE_URL__: JSON.stringify(env.ELEMENTS_PAGES_BASE_URL),
__ELEMENTS_REGISTRY_URL__: JSON.stringify(env.ELEMENTS_REGISTRY_URL),
__ELEMENTS_CDN_BASE_URL__: JSON.stringify(env.ELEMENTS_CDN_BASE_URL),
__ELEMENTS_ESM_CDN_BASE_URL__: JSON.stringify(env.ELEMENTS_ESM_CDN_BASE_URL),
__ELEMENTS_SITE_URL__: JSON.stringify(env.ELEMENTS_SITE_URL),
__ELEMENTS_PLAYGROUND_BASE_URL__: JSON.stringify(env.ELEMENTS_PLAYGROUND_BASE_URL)
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Add the missing assets CDN define.

ELEMENTS_ASSETS_CDN_BASE_URL is read on Line 21, but getElementsEnv() never emits __ELEMENTS_ASSETS_CDN_BASE_URL__. Since the other Vite configs now delegate entirely to this helper, consumers like projects/site/src/_internal/animated-build/animated-build.ts will never receive that constant and will fail to build/resolve asset URLs correctly.

Proposed fix
 export function getElementsEnv() {
   const env = getElementsEnvValues();
   return {
     __ELEMENTS_REPO_BASE_URL__: JSON.stringify(env.ELEMENTS_REPO_BASE_URL),
     __ELEMENTS_PAGES_BASE_URL__: JSON.stringify(env.ELEMENTS_PAGES_BASE_URL),
     __ELEMENTS_REGISTRY_URL__: JSON.stringify(env.ELEMENTS_REGISTRY_URL),
     __ELEMENTS_CDN_BASE_URL__: JSON.stringify(env.ELEMENTS_CDN_BASE_URL),
     __ELEMENTS_ESM_CDN_BASE_URL__: JSON.stringify(env.ELEMENTS_ESM_CDN_BASE_URL),
     __ELEMENTS_SITE_URL__: JSON.stringify(env.ELEMENTS_SITE_URL),
-    __ELEMENTS_PLAYGROUND_BASE_URL__: JSON.stringify(env.ELEMENTS_PLAYGROUND_BASE_URL)
+    __ELEMENTS_PLAYGROUND_BASE_URL__: JSON.stringify(env.ELEMENTS_PLAYGROUND_BASE_URL),
+    __ELEMENTS_ASSETS_CDN_BASE_URL__: JSON.stringify(env.ELEMENTS_ASSETS_CDN_BASE_URL)
   };
 }
📝 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.

Suggested change
ELEMENTS_PLAYGROUND_BASE_URL: getEnvValue('ELEMENTS_PLAYGROUND_BASE_URL'),
ELEMENTS_ASSETS_CDN_BASE_URL: getEnvValue('ELEMENTS_ASSETS_CDN_BASE_URL')
};
}
export function getElementsEnv() {
const env = getElementsEnvValues();
return {
__ELEMENTS_REPO_BASE_URL__: JSON.stringify(env.ELEMENTS_REPO_BASE_URL),
__ELEMENTS_PAGES_BASE_URL__: JSON.stringify(env.ELEMENTS_PAGES_BASE_URL),
__ELEMENTS_REGISTRY_URL__: JSON.stringify(env.ELEMENTS_REGISTRY_URL),
__ELEMENTS_CDN_BASE_URL__: JSON.stringify(env.ELEMENTS_CDN_BASE_URL),
__ELEMENTS_ESM_CDN_BASE_URL__: JSON.stringify(env.ELEMENTS_ESM_CDN_BASE_URL),
__ELEMENTS_SITE_URL__: JSON.stringify(env.ELEMENTS_SITE_URL),
__ELEMENTS_PLAYGROUND_BASE_URL__: JSON.stringify(env.ELEMENTS_PLAYGROUND_BASE_URL)
};
ELEMENTS_PLAYGROUND_BASE_URL: getEnvValue('ELEMENTS_PLAYGROUND_BASE_URL'),
ELEMENTS_ASSETS_CDN_BASE_URL: getEnvValue('ELEMENTS_ASSETS_CDN_BASE_URL')
};
}
export function getElementsEnv() {
const env = getElementsEnvValues();
return {
__ELEMENTS_REPO_BASE_URL__: JSON.stringify(env.ELEMENTS_REPO_BASE_URL),
__ELEMENTS_PAGES_BASE_URL__: JSON.stringify(env.ELEMENTS_PAGES_BASE_URL),
__ELEMENTS_REGISTRY_URL__: JSON.stringify(env.ELEMENTS_REGISTRY_URL),
__ELEMENTS_CDN_BASE_URL__: JSON.stringify(env.ELEMENTS_CDN_BASE_URL),
__ELEMENTS_ESM_CDN_BASE_URL__: JSON.stringify(env.ELEMENTS_ESM_CDN_BASE_URL),
__ELEMENTS_SITE_URL__: JSON.stringify(env.ELEMENTS_SITE_URL),
__ELEMENTS_PLAYGROUND_BASE_URL__: JSON.stringify(env.ELEMENTS_PLAYGROUND_BASE_URL),
__ELEMENTS_ASSETS_CDN_BASE_URL__: JSON.stringify(env.ELEMENTS_ASSETS_CDN_BASE_URL)
};
🤖 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/vite/src/configs/env.js` around lines 20 - 35, The env
mapping in getElementsEnv() is missing the __ELEMENTS_ASSETS_CDN_BASE_URL__
define even though getElementsEnvValues() already reads
ELEMENTS_ASSETS_CDN_BASE_URL. Update getElementsEnv() to emit that constant
alongside the other Vite defines so callers like animated-build.ts receive the
assets CDN base URL correctly.

@coryrylan coryrylan force-pushed the topic-cli-version-updater branch from 42deb6f to 10805ab Compare June 30, 2026 03:31

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

🤖 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/cli/src/index.ts`:
- Around line 101-104: The command synopsis builder in index.ts is incorrectly
hiding all optional args when `hasVariadicArg` is true, which removes flag-style
options like `--format` from help output. Update the `command` construction
logic so the variadic path still appends optional flag arguments from
`optionalArgs` while excluding only extra positional placeholders, keeping
`tool.metadata.command` help text consistent for commands such as `api.get`.

In `@projects/internals/tools/src/project/health.ts`:
- Around line 190-212: The dependency checks in checkDependencies and
getVersionHealth are using different package filters, which can leave unknown
`@nvidia-elements` package names in the version map and cause getVersionStatus to
fail on undefined data. Update the logic around currentVersions,
allDependencies, and getVersionHealth so both paths apply the same known-package
filter (or share one helper) and skip any dependency names that are not present
in currentVersions before building or reading versions.
🪄 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: 21e6c348-57a9-4ec3-8f6e-2acba88121a3

📥 Commits

Reviewing files that changed from the base of the PR and between 42deb6f and 10805ab.

📒 Files selected for processing (27)
  • projects/cli/README.md
  • projects/cli/scripts/write-install-manifest.mjs
  • projects/cli/src/index.test.ts
  • projects/cli/src/index.ts
  • projects/cli/src/install.test.ts
  • projects/cli/src/install.ts
  • projects/cli/src/update.test.ts
  • projects/cli/src/update.ts
  • projects/cli/src/utils.test.ts
  • projects/cli/src/utils.ts
  • projects/cli/vite.config.ts
  • projects/internals/tools/src/api/utils.test.ts
  • projects/internals/tools/src/api/utils.ts
  • projects/internals/tools/src/cli/utils.test.ts
  • projects/internals/tools/src/cli/utils.ts
  • projects/internals/tools/src/playground/utils.test.ts
  • projects/internals/tools/src/playground/utils.ts
  • projects/internals/tools/src/project/health.test.ts
  • projects/internals/tools/src/project/health.ts
  • projects/internals/vite/src/configs/build.js
  • projects/internals/vite/src/configs/build.node.js
  • projects/internals/vite/src/configs/env.js
  • projects/internals/vite/src/configs/test.js
  • projects/internals/vite/src/configs/test.node.js
  • projects/site/src/_11ty/utils/env.js
  • projects/site/src/_11ty/utils/env.test.ts
  • projects/site/src/docs/cli/index.md
💤 Files with no reviewable changes (1)
  • projects/site/src/_11ty/utils/env.test.ts

Comment thread projects/cli/src/index.ts
Comment on lines +101 to +104
const command = `${tool.metadata.command} ${[
...positionalArgs,
...(hasVariadicArg ? [] : optionalArgs.map(key => `[${key}]`))
].join(' ')}`.trim();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '--- index.ts around command generation ---\n'
sed -n '80,130p' projects/cli/src/index.ts

printf '\n--- index.test.ts around help assertions ---\n'
sed -n '1,220p' projects/cli/src/index.test.ts

printf '\n--- docs references for api.get / --format ---\n'
rg -n "api\.get|--format|<names\.\.>" projects -g '!**/node_modules/**'

Repository: NVIDIA/elements

Length of output: 244


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- index.ts around command generation ---'
sed -n '80,130p' projects/cli/src/index.ts

echo
echo '--- index.test.ts around help assertions ---'
sed -n '1,220p' projects/cli/src/index.test.ts

echo
echo '--- docs references for api.get / --format ---'
rg -n "api\.get|--format|<names\.\.>" projects -g '!**/node_modules/**'

Repository: NVIDIA/elements

Length of output: 12946


Keep --format in variadic command usage.
The variadic branch drops every optional arg from the displayed synopsis, so nve --help no longer advertises api.get’s --format flag. Keep flag-style options visible, e.g. nve api.get <names..> [--format <format>].

🤖 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/cli/src/index.ts` around lines 101 - 104, The command synopsis
builder in index.ts is incorrectly hiding all optional args when
`hasVariadicArg` is true, which removes flag-style options like `--format` from
help output. Update the `command` construction logic so the variadic path still
appends optional flag arguments from `optionalArgs` while excluding only extra
positional placeholders, keeping `tool.metadata.command` help text consistent
for commands such as `api.get`.

Comment on lines 190 to +212
const elementPackages = Object.keys(currentVersions);
const allDependencies = [...dependencies, ...devDependencies, ...peerDependencies];
let status: 'success' | 'danger' | 'warning' = 'success';
let message = '@nvidia-elements packages are up to date';

if (!allDependencies.some(dependency => elementPackages.includes(dependency))) {
status = 'warning';
message = 'No @nvidia-elements packages found in the project';
return {
versions: {},
status: 'warning' as const,
message: 'No @nvidia-elements packages found in the project'
};
}

const unavailablePackages = Object.entries(currentVersions)
.filter(([packageName, version]) => allDependencies.includes(packageName) && version === '0.0.0')
.map(([packageName]) => packageName);
if (unavailablePackages.length > 0) {
return {
versions: {},
status: 'danger' as const,
message: `Could not verify latest versions for ${unavailablePackages.join(', ')}`
};
}

const versions = await getVersionHealth(packageJson, currentVersions);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== checkDependencies / getVersionHealth =="
nl -ba projects/internals/tools/src/project/health.ts | sed -n '29,225p'

echo
echo "== ElementVersions contract =="
nl -ba projects/internals/tools/src/api/utils.ts | sed -n '159,210p'

echo
echo "== Existing tests touching checkDependencies =="
rg -n "checkDependencies\\(" projects/internals/tools/src/project/health.test.ts

echo
echo "== Any test covering an unknown `@nvidia-elements` package? =="
rg -n "`@nvidia-elements/`" projects/internals/tools/src/project/health.test.ts

Repository: NVIDIA/elements

Length of output: 236


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== projects/internals/tools/src/project/health.ts =="
sed -n '1,260p' projects/internals/tools/src/project/health.ts

echo
echo "== projects/internals/tools/src/api/utils.ts =="
sed -n '140,220p' projects/internals/tools/src/api/utils.ts

echo
echo "== projects/internals/tools/src/project/health.test.ts =="
sed -n '1,260p' projects/internals/tools/src/project/health.test.ts

echo
echo "== Search for any callers or related package filtering =="
grep -RIn --exclude-dir=node_modules --exclude-dir=.git -E "getVersionHealth|checkDependencies|`@nvidia-elements/`" projects/internals/tools/src | head -n 200

Repository: NVIDIA/elements

Length of output: 45742


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path

path = Path('projects/internals/tools/src/project/health.test.ts')
lines = path.read_text().splitlines()
for start, end in [(150, 280), (280, 380)]:
    print(f"== {path} lines {start}-{end} ==")
    for i in range(start, min(end, len(lines)) + 1):
        print(f"{i:4d}: {lines[i-1]}")
    print()
PY

Repository: NVIDIA/elements

Length of output: 9431


Align the dependency filter with getVersionHealth(). checkDependencies() only counts packages already present in currentVersions, but getVersionHealth() still iterates any @nvidia-elements/* dependency. If a project has one known Elements package and one unknown one, versions[packageName]! can be undefined and getVersionStatus() will throw. Skip unknown package names in both places or share the same filter.

🤖 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/health.ts` around lines 190 - 212, The
dependency checks in checkDependencies and getVersionHealth are using different
package filters, which can leave unknown `@nvidia-elements` package names in the
version map and cause getVersionStatus to fail on undefined data. Update the
logic around currentVersions, allDependencies, and getVersionHealth so both
paths apply the same known-package filter (or share one helper) and skip any
dependency names that are not present in currentVersions before building or
reading versions.

- Added support for versioning output files in the build process, ensuring that the correct version is written to bundled files.
- Introduced a new utility function to replace bundled constants in the output files, improving maintainability.
- Updated the installation script to utilize the embedded build SHA and version, enhancing the manifest generation.
- Refactored error handling in the update check to ensure proper feedback when the SHA is missing.

Signed-off-by: Cory Rylan <crylan@nvidia.com>
@coryrylan coryrylan force-pushed the topic-cli-version-updater branch from 10805ab to 0f578a5 Compare June 30, 2026 03:45
@github-actions github-actions Bot added the dependencies Pull requests that update a dependency file label Jun 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file scope(cli) scope(docs) scope(internals)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant