Skip to content

refactor(cli): share the banner renderer through a shared .cts boundary - #8589

Open
harjothkhara wants to merge 5 commits into
NVIDIA:mainfrom
harjothkhara:oss-find/nemoclaw-2026-08-07
Open

refactor(cli): share the banner renderer through a shared .cts boundary#8589
harjothkhara wants to merge 5 commits into
NVIDIA:mainfrom
harjothkhara:oss-find/nemoclaw-2026-08-07

Conversation

@harjothkhara

@harjothkhara harjothkhara commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Summary

The renderBox terminal-banner renderer was duplicated byte-for-byte in src/lib/cli/banner.ts (CLI) and nemoclaw/src/banner.ts (plugin). Move the one implementation into a shared .cts boundary and reduce both files to thin re-export wrappers, so the two packages render the banner from one source. No behavior changes.

Related Issue

Refs #8291 — one slice of "Use shared .cts boundaries for pure CLI and plugin parity code": the third bullet, "Share the banner renderer while retaining package entry wrappers." The other bullets are separate PRs.

Changes

  • Add nemoclaw/src/shared/banner-boundary.cts with renderBox, BannerLine, and RenderBoxOptions, following the existing boundary pattern (sandbox-name.cts, openshell-policy-boundary.cts, snapshot-sanitizer-boundary.cts).
  • Reduce src/lib/cli/banner.ts and nemoclaw/src/banner.ts to re-export wrappers. Their import paths (../cli/banner, ./banner.js) stay stable for src/lib/tunnel/services.ts and nemoclaw/src/index.ts.
  • Add the boundary to nemoclaw/tsconfig.shared.json so build:cli compiles it before both packages.
  • Register the .cjs.cts source alias in the three required places: vitest.config.ts, nemoclaw/vitest.project.ts, and the alias contract test test/plugin-vitest-project.test.ts.
  • Converge the two per-package parity suites (src/lib/cli/banner.test.ts, nemoclaw/src/banner.test.ts) into one direct shared-core contract test nemoclaw/src/shared/banner-boundary.test.ts — the change Use shared .cts boundaries for pure CLI and plugin parity code #8291 asks for.
  • Add test/package-contract/banner-boundary.test.ts. Under Vitest the source alias maps every banner-boundary.cjs specifier to the .cts source, so an in-process compare would prove source-equals-source. This test runs a native Node subprocess to compare the real compiled dist artifacts and assert both shipped wrappers resolve to the one generated renderBox, plus that the .cjs/.d.cts artifacts ship.

Net delta is −2 LOC, per epic #8281's negative-net-LOC rule. The two former copies had already drifted in a comment; the consolidated boundary keeps the more general wording ("long URLs or endpoints"). The boundary header carries a sourceBoundary: tag noting the renderer only sizes and truncates — callers own content safety.

Type of Change

  • Code change (feature, bug fix, or refactor)
  • Code change with doc updates
  • Doc only (prose changes, no code sample modifications)
  • Doc only (includes code sample changes)

Quality Gates

  • Tests added or updated for changed behavior — one direct shared-core contract test plus a compiled-artifact package-contract test.
  • Existing tests cover changed behavior — justification:
  • Tests not applicable — justification:
  • Docs updated for user-facing behavior changes
  • Docs not applicable — justification: Internal renderer consolidation; renderBox output is byte-identical and no public API, CLI, config, or output changes. A docs review found no stale references.
  • Sensitive paths changed (security, policy, credentials, preflight, onboarding, inference, runner, sandbox, or messaging)
  • Sensitive-path review completed or maintainer-approved waiver recorded — reviewer/approval link/justification:
  • Non-success, skipped, or missing CI check accepted by maintainer — check name, approval link, and follow-up issue:

Documentation Writer Review

  • Documentation writer subagent reviewed the completed changes
  • Result: no-docs-needed
  • Evidence: No user-visible surface changes. Grep of docs/, *.md, and *.mdx for renderBox, banner-boundary, the boundary list, and sandbox-name.cts returned zero stale references. The only banner hits in docs describe the runtime registration banner, which is unchanged. No contributor or architecture doc enumerates the shared boundaries.
  • Agent: Claude Code

Verification

  • PR description includes a Signed-off-by: line and every commit appears as Verified in GitHub
  • Normal pre-commit, commit-msg, and pre-push hooks passed, or npm run validate:pr passed after refreshing origin/main when hooks were skipped or unavailable
  • Targeted behavior tests pass for the current change set, or tests are marked not applicable above — command/result: vitest run --project cli src/lib/tunnel/services.test.ts --project plugin nemoclaw/src/shared/banner-boundary.test.ts nemoclaw/src/register.test.ts --project integration test/plugin-vitest-project.test.ts --project e2e-support and vitest run --project package-contract test/package-contract/banner-boundary.test.ts → all pass. typecheck:cli and plugin typecheck pass.
  • Applicable broad gate passed — npm test for broad runtime/test-harness changes; npm run check for repo-wide validation/coverage changes — command/result: Not run in full. The change adds one additive test alias mirroring three existing ones; the affected lanes (cli, plugin, integration alias contract, e2e-support) and both typechecks pass. Two package-contract failures (onboard-stdin-eof, credentials-cli-command) are pre-existing on clean origin/main and unrelated to this change.
  • Quality Gates section completed with required justifications or waivers
  • No secrets, API keys, or credentials committed

Proof

Drift hazard removed — before, on origin/main (two copies), mutating only the CLI copy (drop the two-space safety gap) failed just the CLI suite; the plugin suite was blind. Now there is one source.

  • Behavior: mutating nemoclaw/src/shared/banner-boundary.cts fails the shared-core test (Tests 1 failed | 4 passed), then passes once reverted.
  • Compiled single-source: the package-contract subprocess asserts both built wrappers resolve to the one renderBox function; removing nemoclaw/dist/shared/banner-boundary.cjs fails it (Cannot find module ...), and it passes once built.

Limitations

  • The three sibling boundaries are named in two CI presence-guard lists (e2e.yaml, the restore action). Extending those to banner-boundary.cjs requires bumping the restore action's immutable content-pin, an integrity anchor. That is left to the maintainers; the boundary still ships in the artifact tar (the whole nemoclaw/dist/shared directory is packaged).

Signed-off-by: Harjoth Khara harjoth.khara@gmail.com

Summary by CodeRabbit

  • Improvements
    • Improved terminal banner rendering across the CLI and NemoClaw tools.
    • Banners now adapt more reliably to available terminal width.
    • Oversized content is safely truncated while preserving clear spacing from the border.
    • Blank separator rows and Unicode box styling are handled consistently.
    • Shared rendering behavior ensures the same banner appearance across supported entry points.

The renderBox terminal-banner renderer was duplicated byte-for-byte in
src/lib/cli/banner.ts (CLI) and nemoclaw/src/banner.ts (plugin). The two
copies had already drifted in a comment, and a change to one was invisible
to the other package's tests.

Move the one implementation into nemoclaw/src/shared/banner-boundary.cts,
following the existing shared-boundary pattern (sandbox-name.cts,
openshell-policy-boundary.cts, snapshot-sanitizer-boundary.cts). Both
banner.ts files become thin re-export wrappers, so the ../cli/banner and
./banner.js import paths stay stable for their consumers.

Register the .cjs -> .cts source alias in the three required places
(vitest.config.ts, nemoclaw/vitest.project.ts, and the alias contract
test test/plugin-vitest-project.test.ts) and add the boundary to
nemoclaw/tsconfig.shared.json.

Refs: NVIDIA#8291
Signed-off-by: harjoth <harjoth.khara@gmail.com>
@copy-pr-bot

copy-pr-bot Bot commented Aug 7, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 80f97abb-d218-48b9-bb45-ef2351af997d

📥 Commits

Reviewing files that changed from the base of the PR and between a5f9fbf and a72464d.

📒 Files selected for processing (4)
  • nemoclaw/src/banner.test.ts
  • nemoclaw/src/shared/banner-boundary.cts
  • nemoclaw/src/shared/banner-boundary.test.ts
  • test/package-contract/banner-boundary.test.ts
💤 Files with no reviewable changes (1)
  • nemoclaw/src/banner.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • nemoclaw/src/shared/banner-boundary.cts

📝 Walkthrough

Walkthrough

The pull request moves banner rendering and its public types into a shared canonical boundary. Existing wrappers delegate to that implementation. TypeScript and Vitest include and alias the boundary. Tests validate rendering behavior, wrapper identity, and generated artifacts.

Changes

Banner boundary consolidation

Layer / File(s) Summary
Canonical renderer and public contract
nemoclaw/src/shared/banner-boundary.cts, nemoclaw/tsconfig.shared.json
The shared module defines banner types, rendering options, terminal-width handling, truncation, blank rows, and Unicode box output. TypeScript includes the module.
Wrapper integration and source aliases
nemoclaw/src/banner.ts, src/lib/cli/banner.ts, nemoclaw/vitest.project.ts, vitest.config.ts
Both banner wrappers re-export the shared types and delegate renderBox. Vitest aliases generated .cjs imports to the canonical .cts source.
Built package contract validation
nemoclaw/src/shared/banner-boundary.test.ts, test/package-contract/banner-boundary.test.ts, test/plugin-vitest-project.test.ts
Tests validate shared rendering behavior, wrapper identity, narrow-terminal output, generated boundary artifacts, and alias policy.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Suggested reviewers: apurvvkumaria, brandonpelfrey

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: sharing the CLI and plugin banner renderer through a shared .cts boundary.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

…rappers

The source banner tests alias the .cjs boundary back to its .cts source, so
they cannot catch a missing or stale compiled nemoclaw/dist/shared/banner-boundary.cjs.
Add a package-contract test that imports the built CLI and plugin wrappers by
file URL, renders through the real generated boundary, and asserts both wrappers
render identically and that the .cjs and .d.cts artifacts ship. Mirrors the
openshell-policy-boundary package contract.

Refs: NVIDIA#8291
Signed-off-by: harjoth <harjoth.khara@gmail.com>
@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

PR Review Advisor — No blocking findings reported

Advisor assessment: No blocking advisor findings reported
Next action: No advisor follow-up needed.
Findings: 0 blockers · 0 warnings · 0 suggestions

Model lanes

  • GPT-5.6 Terra (primary): Completed · medium confidence · 0 blockers · 0 warnings · 0 suggestions
  • Nemotron 3 Ultra (second opinion): Completed · high confidence · 0 blockers · 0 warnings · 0 suggestions
  • Model comparison: normalized findings match; normalized terminology decisions differ; normalized E2E selections match; severity counts match.
8 terminology differences from the second opinion

Advisory only. These are normalized differences from the primary terminology receipt.

  • sourceOfTruth at nemoclaw/src/shared/banner-boundary.cts:4: selected only by the second-opinion lane as established.
  • sourceBoundary at nemoclaw/src/shared/banner-boundary.cts:11: selected only by the second-opinion lane as established.
  • regressionTest at nemoclaw/src/shared/banner-boundary.cts:13: selected only by the second-opinion lane as established.
  • removalCondition at nemoclaw/src/shared/banner-boundary.cts:16: selected only by the second-opinion lane as established.
  • generatedBoundary at src/lib/cli/banner.ts:5: selected only by the second-opinion lane as established.
  • package contract at test/package-contract/banner-boundary.test.ts:14: selected only by the second-opinion lane as established.
  • parity at nemoclaw/src/shared/banner-boundary.test.ts:7: selected only by the second-opinion lane as justified.
  • boundary at nemoclaw/src/banner.ts:6: selected only by the second-opinion lane as conflict.

Second-opinion terminology and E2E selections are advisory. Live E2E does not run automatically for pull requests.

3 semantic terminology decisions

Terminology decisions are advisory. They affect the assessment only when a separate finding identifies concrete semantic impact.

  • established — package contract at nemoclaw/src/shared/banner-boundary.cts:14: Keep `package contract`; it matches the controlled word list and existing repository usage.
  • justified — source alias at test/package-contract/banner-boundary.test.ts:16: Keep `source alias`; the modifier distinguishes the test-runner mapping from native module resolution.
  • justified — generated boundary at test/package-contract/banner-boundary.test.ts:15: Keep `generated boundary`; the modifier identifies the compiled artifact that the package contract evaluates.

E2E guidance

Advisory only. A maintainer can dispatch the default E2E suite against this exact revision.

Recommended E2E: cloud-inference, cloud-onboard, managed-image-multiarch-startup, security-posture

Workflow run details

This automated review informs maintainers. Warnings and suggestions do not require a response. A maintainer decides whether to merge.

@harjothkhara
harjothkhara marked this pull request as ready for review August 7, 2026 22:53

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
test/package-contract/banner-boundary.test.ts (1)

29-45: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Prove that the plugin wrapper loads the canonical boundary.

Lines 43-45 only compare output for one input. A stale or reintroduced plugin-local renderer can produce the same output and pass this test.

Import nemoclaw/dist/shared/banner-boundary.cjs and assert that plugin.renderBox is its exported renderBox function. This proves that the superseded plugin path cannot execute.

Proposed test change
     const cli = await importBuilt("dist", "lib", "cli", "banner.js");
     const plugin = await importBuilt("nemoclaw", "dist", "banner.js");
+    const pluginBoundary = await importBuilt(
+      "nemoclaw",
+      "dist",
+      "shared",
+      "banner-boundary.cjs",
+    );
+
+    expect(plugin.renderBox).toBe(pluginBoundary.renderBox);

As per path instructions, “Migration tests must prove the superseded path is unreachable or removed, not merely prove that the new path also works.”

🤖 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 `@test/package-contract/banner-boundary.test.ts` around lines 29 - 45, Update
the test around the built plugin wrapper import to also import the canonical
boundary module from nemoclaw/dist/shared/banner-boundary.cjs and assert that
plugin.renderBox is exactly its exported renderBox function. Keep the existing
output comparison, using the identity assertion to prove the superseded
plugin-local renderer cannot be used.

Source: Path instructions

🤖 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.

Nitpick comments:
In `@test/package-contract/banner-boundary.test.ts`:
- Around line 29-45: Update the test around the built plugin wrapper import to
also import the canonical boundary module from
nemoclaw/dist/shared/banner-boundary.cjs and assert that plugin.renderBox is
exactly its exported renderBox function. Keep the existing output comparison,
using the identity assertion to prove the superseded plugin-local renderer
cannot be used.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 8dbbeb32-c91c-41d9-83bc-4f93d607b72b

📥 Commits

Reviewing files that changed from the base of the PR and between cdaefe8 and 2c51fd8.

📒 Files selected for processing (8)
  • nemoclaw/src/banner.ts
  • nemoclaw/src/shared/banner-boundary.cts
  • nemoclaw/tsconfig.shared.json
  • nemoclaw/vitest.project.ts
  • src/lib/cli/banner.ts
  • test/package-contract/banner-boundary.test.ts
  • test/plugin-vitest-project.test.ts
  • vitest.config.ts

…ction

Comparing rendered output alone would still pass if a plugin-local renderer
were reintroduced. Assert plugin.renderBox is the boundary's exported function,
so the superseded path cannot execute.

Refs: NVIDIA#8291
Signed-off-by: harjoth <harjoth.khara@gmail.com>
@harjothkhara
harjothkhara marked this pull request as draft August 8, 2026 00:55
…t test

Address epic NVIDIA#8281's negative-net-LOC rule and NVIDIA#8291's requirement that existing
parity tests become direct shared-core contract tests.

- Replace src/lib/cli/banner.test.ts and nemoclaw/src/banner.test.ts (two copies
  testing two wrappers) with one nemoclaw/src/shared/banner-boundary.test.ts that
  imports the boundary directly.
- Rewrite the package-contract test to compare the real compiled dist artifacts
  in a native Node subprocess. Under Vitest the source alias maps the .cjs
  boundary to its .cts source, so an in-process compare proves source==source,
  not that the shipped wrappers load the generated boundary; the subprocess
  bypasses the alias and asserts both built wrappers share one function.
- Add the sourceBoundary tag and point regressionTest at the direct test.

Net delta is now negative. Refs: NVIDIA#8291

Signed-off-by: harjoth <harjoth.khara@gmail.com>
Assert the built wrappers' exports are callable and render correctly, not just
reference-equal, so the identity check cannot pass vacuously. Add a subprocess
timeout.

Refs: NVIDIA#8291
Signed-off-by: harjoth <harjoth.khara@gmail.com>
@harjothkhara
harjothkhara marked this pull request as ready for review August 8, 2026 01:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant