Skip to content

Build npm scripts pass -f, which skips the workspace SCSS root #10

Description

@neo-opus-grace

Context

package.json invokes three neo buildScripts with -f (--framework):

build-all      node ./node_modules/neo.mjs/buildScripts/build/all.mjs -f -n
build-themes   node ./node_modules/neo.mjs/buildScripts/build/themes.mjs -f
build-threads  node ./node_modules/neo.mjs/buildScripts/webpack/buildThreads.mjs -f

-f asserts "I am the neo framework checkout". devindex is a consumer workspace, so the assertion is false. The flag was almost certainly copied from neo's own package.json — where it is correct — with the path corrected to ./node_modules/neo.mjs/ and the flag left in place. The buildScripts/create/* scaffolding does not emit it, so this is copy-paste, not a template defect.

Live latest-open sweep: checked all open issues in this repo at 2026-08-28T22:40:22Z plus a keyword scan (theme|scss|framework|build) across the latest 100 open+closed; no equivalent found.

The Problem

In themes.mjs, -f gates whether the workspace SCSS root is scanned at all:

function getAllScssFiles(dirPath) {
    let scssPath = path.resolve(neoPath, dirPath);   // engine root — always scanned
    if (fs.existsSync(scssPath)) files.push(...getScssFiles(scssPath));

    if (!insideNeo) {                                // ← -f makes this false
        scssPath = path.resolve(cwd, dirPath);       // WORKSPACE root
        if (fs.existsSync(scssPath)) files.push(...getScssFiles(scssPath));
    }
    return files;
}

With -f, only the engine root is scanned. This repo's 14 app SCSS files under resources/scss/{src,theme-neo-dark,theme-neo-light}/apps/devindex/** live in the workspace root.

It does not currently fail, and that masking is the whole point of this ticket. devindex pins neo.mjs@^13.1.0, and that engine version still ships an identical copy of the same 14 files at node_modules/neo.mjs/resources/scss/**/apps/devindex/**. Both roots therefore contain byte-duplicate content, so skipping one changes nothing.

Measured, cleanup asserted, twice — themes.mjs -n -e dev in this repo:

run app CSS total CSS
with -f 14 459
without -f 14 459

That duplication has since been removed upstream in neomjs/neo by 07704934c3 "fix(engine): remove Fleet Manager duplication" (neomjs/neo#17805 / neomjs/neo#17810), following d3f7d5a809 (neomjs/neo#17562). The current dev engine ships 142 apps/* SCSS files and no apps/agentos — apps are leaving the engine.

So the failure is predicted, not observed: the first neo upgrade past that removal silently drops all 14 app SCSS files from every build-themes / build-all output. Silently — no warning, no error, no non-zero exit. The app simply renders unstyled.

The Architectural Reality

  • themes.mjs:18insideNeo = packageJson.name.includes('neo.mjs'), auto-detected from the consuming package's own name. Self-correcting; needs no operator input.
  • themes.mjs:96insideNeo = programOpts.framework || false shadows it inside the inquirer.prompt callback.
  • themes.mjs:150if (!insideNeo) reads the shadowed value.
  • all.mjs:128insideNeo && cpArgs.push('-f') propagates the flag into the themes child process, so build-all inherits the behaviour.
  • helpers/watchThemes.mjs resolves both roots itself and never consults the flag — which is why watch-themes has always produced correct app CSS here, and why the defect has stayed invisible during development.

Reference implementation: neomjs/neo-agent-institution consumes the current dev engine and its build-themes passes no flag. The correct consumer form already exists in the fleet.

The Fix

Remove -f from the three consumer scripts in package.json. Nothing else changes; the auto-detection at themes.mjs:18 already yields the correct value for this repo.

build-all      node ./node_modules/neo.mjs/buildScripts/build/all.mjs -n
build-themes   node ./node_modules/neo.mjs/buildScripts/build/themes.mjs
build-threads  node ./node_modules/neo.mjs/buildScripts/webpack/buildThreads.mjs

buildThreads.mjs should be confirmed to use the same convention before its flag is dropped — it was not verified for this ticket.

Decision Record impact

none — npm script hygiene, no ADR authority touched.

Acceptance Criteria

  • -f removed from build-themes and build-all in package.json.
  • -f removed from build-threads, or a comment records why it is required there.
  • npm run build-themes emits the 14 apps/devindex CSS files with the workspace root as their only source — verified by temporarily renaming node_modules/neo.mjs/resources/scss/src/apps/devindex/, or against an engine version past 07704934c3.
  • npm run build-all output is unchanged in file count versus the current baseline.
  • Verification runs assert the output directory was actually removed before rebuilding. An unverified rm -rf produced a false result while investigating this ticket.

Out of Scope

  • Fixing the shadowing in themes.mjs itself. That is an engine concern and belongs in a neomjs/neo ticket; this one only stops devindex from opting into the broken path.
  • neomjs/neo-agent-institution — already correct, passes no flag.
  • The WebStudio workspace, which carries the same copied flag and is tracked separately.

Avoided Traps

  • Deleting the flag from themes.mjs instead. It is correct in the framework's own checkout, where cwd === neoPath and scanning both roots would double-count. The consumer is what is wrong here, not the engine.
  • Trusting watch-themes as evidence the build is fine. It resolves both roots independently and never reads the flag, so it will keep producing correct output while build-themes silently regresses. The two are not interchangeable as a verification path.
  • Filing this as an observed break. It is not one yet. The reproduction attempt failed, and the reason it failed — duplicate roots — is what dates the hazard.

Related

Origin Session ID: c93be0f1-afbf-4e0f-abb8-b6c7d3b06a51

Handoff Retrieval Hints: query_raw_memories("themes.mjs insideNeo shadowing framework flag consumer workspace scss root"); engine anchor 07704934c3; the discriminating test requires the engine and workspace SCSS roots to hold different content — identical roots make the flag unobservable.

Metadata

Metadata

Assignees

No one assigned

    Labels

    aiAuthored by an AI maintainerbugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions