(first time reporting an issue, apologies if something is incorrect)
CLI Version
8.14.0
Node.js Version
24.19.0
Operating System
Windows 10
Description
Running hs project upload on a plain CMS-theme project (no app/ component) always prints two warnings that cannot be resolved, because both checks are bugged independently:
⚠ WARNING Project lint: lint packages not installed for src\theme\themedir. Run `hs project lint` to install them.
⚠ WARNING npm audit: skipped for src\theme\themedir(npm not available in PATH)
Bug 1 — "lint packages not installed" can never be fixed for theme-only projects
validateLintConfigOnUpload (lib/projects/validateLintConfigOnUpload.ts) warns about every package.json in the project:
for (const { dir } of parsedPackageJsons) {
lintRoots.add(dir);
}
...
if (!areAllLintPackagesInstalled(lintRoot)) { warnMessage = ...lintPackagesNotConfigured... }
But the command that's supposed to fix it — hs project lint --install-missing-deps — only ever operates on UI-Extension component directories. getUieLintablePackageJsonLocations (lib/projects/uieLinting.ts:172-185) filters to:
const UIE_COMPONENTS = [Components[CARDS_KEY], Components[SETTINGS_KEY], Components[PAGES_KEY]];
...
return allLocations.filter(location =>
uiePackageDirPrefixes.some(prefix => resolvedLocation.startsWith(prefix))
);
A CMS-theme project with no app/cards, app/settings, or app/pages directory produces an empty result here. hs project lint exits near-instantly (exit 0, no eslint invocation, no "nothing to lint" message — looks like it succeeded), having installed nothing. hs project upload's check then warns forever, because the two commands disagree on scope: upload's check is project-wide, lint's fixer is UIE-only.
Repro:
hs project create # or any existing theme-only project with no app/ dir
hs project lint --install-missing-deps # exits instantly, installs nothing, no explanation
hs project upload # still warns "lint packages not installed"
Suggested fix: either scope validateLintConfigOnUpload to the same UIE-only directories hs project lint actually covers, or make hs project lint install/lint eslint config for all project package.json locations (not just UIE ones), or at minimum have hs project lint print "nothing to lint here" instead of silently no-op'ing when its scope is empty.
Bug 2 — "npm not available in PATH" is a false positive caused by a missing shell: true
Source: @hubspot/ui-extensions-dev-server/dist/lib/npmSecurityAudit.js:43 (invoked from hubspot-cli's lib/projects/npmAuditOnUpload.ts):
const { stdout } = await execFileAsync('npm', ['audit', '--json'], {
cwd: auditRoot,
encoding: 'utf8',
maxBuffer: MAX_NPM_AUDIT_JSON_BUFFER,
});
On Windows, npm is npm.cmd/npm.ps1, not a real executable. child_process.execFile (unlike exec) does not go through a shell, and Windows' CreateProcess doesn't consult PATHEXT the way cmd.exe does — so this throws ENOENT regardless of whether npm is on PATH. The catch block maps that straight to exit code 127:
function resolveExecErrorCode(e) {
if (e.code === 'ENOENT') { return 127; }
...
}
...which npmAuditOnUpload.ts reports as "npm not available in PATH" — even on machines where npm audit run directly in the same shell works fine.
Repro:
node -e "require('child_process').execFile('npm', ['-v'], (e) => console.log(e && e.code))"
# → ENOENT, even though `npm -v` works in the same terminal
Suggested fix: pass shell: true to the execFile call, or resolve to npm.cmd explicitly on win32 (what cross-spawn does), consistent with how lib/npm/npmCli.ts elsewhere in this codebase uses exec() and doesn't hit this.
Steps to Reproduce
bug 1:
hs project create # or any existing theme-only project with no app/ dir
hs project lint --install-missing-deps # exits instantly, installs nothing, no explanation
hs project upload # still warns "lint packages not installed"
bug 2
node -e "require('child_process').execFile('npm', ['-v'], (e) => console.log(e && e.code))"
# → ENOENT, even though `npm -v` works in the same terminal
Expected Behavior
I explain above.
Screenshots
No response
Debug Output
No response
Additional Context
No response
(first time reporting an issue, apologies if something is incorrect)
CLI Version
8.14.0
Node.js Version
24.19.0
Operating System
Windows 10
Description
Running hs project upload on a plain CMS-theme project (no app/ component) always prints two warnings that cannot be resolved, because both checks are bugged independently:
Bug 1 — "lint packages not installed" can never be fixed for theme-only projects
validateLintConfigOnUpload(lib/projects/validateLintConfigOnUpload.ts) warns about everypackage.jsonin the project:But the command that's supposed to fix it —
hs project lint --install-missing-deps— only ever operates on UI-Extension component directories.getUieLintablePackageJsonLocations(lib/projects/uieLinting.ts:172-185) filters to:A CMS-theme project with no
app/cards,app/settings, orapp/pagesdirectory produces an empty result here.hs project lintexits near-instantly (exit 0, no eslint invocation, no "nothing to lint" message — looks like it succeeded), having installed nothing.hs project upload's check then warns forever, because the two commands disagree on scope: upload's check is project-wide, lint's fixer is UIE-only.Repro:
Suggested fix: either scope
validateLintConfigOnUploadto the same UIE-only directorieshs project lintactually covers, or makehs project lintinstall/lint eslint config for all project package.json locations (not just UIE ones), or at minimum havehs project lintprint "nothing to lint here" instead of silently no-op'ing when its scope is empty.Bug 2 — "npm not available in PATH" is a false positive caused by a missing
shell: trueSource:
@hubspot/ui-extensions-dev-server/dist/lib/npmSecurityAudit.js:43(invoked fromhubspot-cli'slib/projects/npmAuditOnUpload.ts):On Windows,
npmisnpm.cmd/npm.ps1, not a real executable.child_process.execFile(unlikeexec) does not go through a shell, and Windows'CreateProcessdoesn't consultPATHEXTthe waycmd.exedoes — so this throwsENOENTregardless of whethernpmis on PATH. The catch block maps that straight to exit code 127:...which
npmAuditOnUpload.tsreports as "npm not available in PATH" — even on machines wherenpm auditrun directly in the same shell works fine.Repro:
Suggested fix: pass
shell: trueto theexecFilecall, or resolve tonpm.cmdexplicitly onwin32(whatcross-spawndoes), consistent with howlib/npm/npmCli.tselsewhere in this codebase usesexec()and doesn't hit this.Steps to Reproduce
bug 1:
bug 2
Expected Behavior
I explain above.
Screenshots
No response
Debug Output
No response
Additional Context
No response