diff --git a/.gemini/settings.json b/.gemini/settings.json deleted file mode 100644 index 82694e2..0000000 --- a/.gemini/settings.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "mcpServers": { - "neo.mjs-github-workflow": { - "command": "npm", - "args" : ["run", "ai:mcp-server-github-workflow"] - } - } -} diff --git a/.github/workflows/engine-parity.yml b/.github/workflows/engine-parity.yml index 6e356c4..a3e7842 100644 --- a/.github/workflows/engine-parity.yml +++ b/.github/workflows/engine-parity.yml @@ -1,6 +1,7 @@ name: Engine parity -# The scaffold's generated devDependencies must match the engine release its `neo.mjs` pin resolves to, read from npm. +# The scaffold's generated devDependencies and overrides must match the engine release its `neo.mjs` pin resolves to, +# read from npm. # See scripts/check-engine-parity.mjs for the scope and why the engine is never read from a checkout. on: push: @@ -23,5 +24,5 @@ jobs: - name: Parity check contract run: node scripts/test-check-engine-parity.mjs - - name: Generated devDependencies match the pinned engine release + - name: Generated devDependencies and overrides match the pinned engine release run: node scripts/check-engine-parity.mjs diff --git a/README.md b/README.md index 09909cb..723ab2d 100644 --- a/README.md +++ b/README.md @@ -22,17 +22,16 @@ Please take a couple of minutes to read this Quick Overview 2. Script Options -3. AI Tooling & MCP Servers -4. Starting a local web-server -5. Viewing your app in development mode -6. Viewing your app in dist modes -7. Workspace Content -8. package.json Scripts -9. Working on your new neo.mjs App -10. Learning neo.mjs -11. Feedback and Questions -12. Alternative options to create an App -13. Kudos +3. Starting a local web-server +4. Viewing your app in development mode +5. Viewing your app in dist modes +6. Workspace Content +7. package.json Scripts +8. Working on your new neo.mjs App +9. Learning neo.mjs +10. Feedback and Questions +11. Alternative options to create an App +12. Kudos ## Quick Overview > npx neo-app @@ -62,27 +61,6 @@ Choose the themes: Of course, you can combine the options, e.g.: > npx neo-app -w workspace -n MyApp -t all -## AI Tooling & MCP Servers -The created workspace comes pre-configured with Model Context Protocol (MCP) servers for advanced AI integration (e.g., with Gemini or Claude). - -**Important:** These servers rely on the `neo.mjs` framework being fully installed. -A `postinstall` script is included in your workspace `package.json` to automatically ensure the `neo.mjs` node module is correctly set up: - -> "postinstall": "cd node_modules/neo.mjs && npm i" - -If you run into issues with the AI scripts, try running `npm install` in your workspace root to trigger this hook. - -### Configuration (.env) -To use the AI features, you must create a `.env` file in your workspace root. This file is git-ignored by default to keep your credentials safe. - -Add the following keys: -```env -GEMINI_API_KEY=your_api_key_here -GH_TOKEN=your_github_token_here -``` -* `GEMINI_API_KEY`: Required for the generative AI agents. -* `GH_TOKEN`: Required for the GitHub Workflow MCP server to interact with your repository. - ## Starting a local web-server By default, npx neo-app will start a webpack dev-server right after the build. @@ -136,7 +114,6 @@ framework version update would require to re-create it) your app as well as all neo.mjs examples 6. node_modules => all related dependencies which are required for the build scripts & the dev-server 7. package.json => defines scripts and dependencies. -8. .gemini => contains configuration for the Gemini CLI and MCP servers. ## package.json Scripts @@ -154,14 +131,7 @@ You can run each script via * `build-threads`: builds main, data & vdom (or any combinations) for dev and / or prod. * `create-app`: add an additional app to your project. You can also trigger npx neo-app multiple times. * `generate-docs-json`: When you change your app code (e.g. adding new files) and want to see those changes inside the Docs app, you need to run this script to update the content. - -### AI & MCP Scripts -* `ai:mcp-client`: Starts the MCP CLI client. -* `ai:mcp-server-github-workflow`: Starts the MCP server for GitHub interactions (requires config). -* `ai:mcp-server-knowledge-base`: Starts the MCP server for Knowledge Base access (requires config). -* `ai:mcp-server-memory-core`: Starts the MCP server for persistent memory (requires config). -* `ai:server`: Starts the ChromaDB server for the knowledge base (default port). -* `ai:server-memory`: Starts the ChromaDB server for memory core (port 8001). +* `bundle-browser-deps`: builds the browser bundles the engine loads from `node_modules/neo.mjs/dist/`. The npm package ships none of them. `npm install` builds the two the engine imports at startup (`parse5`, `marked`); run this script for the ones loaded on demand (Mermaid, Monaco, highlight.js). ## Working on your new neo.mjs App It is recommended to use the development mode (non dist version) for developing your App(s). diff --git a/ai/mcp/server/github-workflow/config.json b/ai/mcp/server/github-workflow/config.json deleted file mode 100644 index 6378429..0000000 --- a/ai/mcp/server/github-workflow/config.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "repo": "create-app" -} diff --git a/package.json b/package.json index 2a78fd2..cde4ca8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name" : "neo-app", - "version" : "12.1.0", + "version" : "13.2.0", "description" : "Neo.mjs: Create app via npx", "type" : "module", "repository" : { @@ -8,9 +8,8 @@ "url" : "git+https://github.com/neomjs/create-app.git" }, "scripts" : { - "ai:mcp-server-github-workflow": "node ./node_modules/neo.mjs/ai/mcp/server/github-workflow/mcp-stdio.mjs -c ./ai/mcp/server/github-workflow/config.json", - "neo-app" : "node ./tasks/neo-app.mjs", - "test" : "node scripts/test-check-engine-parity.mjs && node scripts/check-engine-parity.mjs" + "neo-app": "node ./tasks/neo-app.mjs", + "test" : "node scripts/test-check-engine-parity.mjs && node scripts/check-engine-parity.mjs" }, "bin" : { "neo-app": "./tasks/neo-app.mjs" @@ -39,7 +38,7 @@ "envinfo" : "^7.21.0", "fs-extra" : "^11.3.4", "inquirer" : "^13.3.0", - "neo.mjs" : "^12.1.0" + "neo.mjs" : "^13.2.0" }, "funding" : { "type": "GitHub Sponsors", diff --git a/scripts/check-engine-parity.mjs b/scripts/check-engine-parity.mjs index 6dd5d1b..aca55f6 100644 --- a/scripts/check-engine-parity.mjs +++ b/scripts/check-engine-parity.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env node /** - * @summary Fails when a devDependency the scaffold generates differs from the engine release its `neo.mjs` pin resolves - * to. + * @summary Fails when a devDependency or an override the scaffold generates differs from the engine release its + * `neo.mjs` pin resolves to. * * `tasks/createPackageJson.mjs` writes every scaffolded app's devDependencies, which advertise the engine's own ranges. * They once fell a whole major behind with nothing noticing. Whether a scaffolded app's bundle scripts build from these @@ -12,6 +12,10 @@ * because a scaffolded app installs the published package and a checkout can be ahead of it. The pin decides which * release: the newest published version its range allows. A package only the scaffold declares has no engine * counterpart to drift from, so it is listed and not compared. + * + * Overrides are compared in full, both ways. npm reads them only in the root project, so the engine's floors reach an + * app's own install only through the scaffold's copy. An override only the scaffold declares is stale, or it is what a + * registry answer without the field looks like; both need a look, so both fail. */ import {execFileSync} from 'node:child_process'; @@ -50,11 +54,37 @@ export function findDrift(scaffold, engine) { } } +/** + * @summary JSON with object keys sorted at every depth, so two equal override trees compare equal. + * @param {*} value + * @returns {String|undefined} + */ +const canonical = value => value !== null && typeof value === 'object' + ? `{${Object.keys(value).sort().map(key => `${JSON.stringify(key)}:${canonical(value[key])}`).join(',')}}` + : JSON.stringify(value); + +/** + * @summary Compares the scaffold's overrides with the engine's, across the names either side declares. + * @param {Object} [scaffold={}] The generated overrides + * @param {Object} [engine={}] The engine release's overrides + * @returns {Object[]} `{name, scaffold, engine}` for each override that differs; a side that lacks it reads `undefined` + */ +export function findOverrideDrift(scaffold = {}, engine = {}) { + return [...new Set([...Object.keys(engine), ...Object.keys(scaffold)])] + .filter(name => canonical(scaffold[name]) !== canonical(engine[name])) + .map(name => ({name, scaffold: scaffold[name], engine: engine[name]})) +} + /** * @param {...String} args - * @returns {*} the parsed `npm view … --json` answer + * @returns {*} the parsed `npm view … --json` answer, `undefined` for a field the release does not declare */ -const npmView = (...args) => JSON.parse(execFileSync('npm', ['view', ...args, '--json'], {encoding: 'utf8'})); +const npmView = (...args) => { + const text = execFileSync('npm', ['view', ...args, '--json'], {encoding: 'utf8'}).trim(); + + // An absent field answers with no output at all + return text ? JSON.parse(text) : undefined +}; if (process.argv[1] && realpathSync(process.argv[1]) === realpathSync(fileURLToPath(import.meta.url))) { const @@ -62,7 +92,8 @@ if (process.argv[1] && realpathSync(process.argv[1]) === realpathSync(fileURLToP range = packageJson.dependencies['neo.mjs'], // One matching version answers as a string, several as an ascending list version = [].concat(npmView(`neo.mjs@${range}`, 'version')).at(-1), - {drift, scaffoldOnly} = findDrift(packageJson.devDependencies, npmView(`neo.mjs@${version}`, 'devDependencies')); + {drift, scaffoldOnly} = findDrift(packageJson.devDependencies, npmView(`neo.mjs@${version}`, 'devDependencies')), + overrideDrift = findOverrideDrift(packageJson.overrides, npmView(`neo.mjs@${version}`, 'overrides')); if (scaffoldOnly.length > 0) { console.log(`check-engine-parity: not compared, no engine counterpart: ${scaffoldOnly.join(', ')}`) @@ -77,4 +108,14 @@ if (process.argv[1] && realpathSync(process.argv[1]) === realpathSync(fileURLToP } else { console.log(`check-engine-parity: every devDependency the scaffold shares with neo.mjs@${version} matches.`) } + + if (overrideDrift.length > 0) { + console.error(`check-engine-parity: ${overrideDrift.length} generated overrides differ from neo.mjs@${version}:`); + overrideDrift.forEach(({name, scaffold, engine}) => + console.error(` ${name} scaffold ${JSON.stringify(scaffold) ?? '(none)'} engine ${JSON.stringify(engine) ?? '(none)'}`)); + console.error('Copy the engine\'s overrides into tasks/createPackageJson.mjs.'); + process.exitCode = 1 + } else { + console.log(`check-engine-parity: the scaffold's overrides equal neo.mjs@${version}'s.`) + } } diff --git a/scripts/test-check-engine-parity.mjs b/scripts/test-check-engine-parity.mjs index 1dda489..3dd17fa 100644 --- a/scripts/test-check-engine-parity.mjs +++ b/scripts/test-check-engine-parity.mjs @@ -4,8 +4,8 @@ * divergence, stays quiet on a match, and lists what it does not compare. */ -import assert from 'node:assert/strict'; -import {findDrift, generatedPackageJson} from './check-engine-parity.mjs'; +import assert from 'node:assert/strict'; +import {findDrift, findOverrideDrift, generatedPackageJson} from './check-engine-parity.mjs'; // ── It reads the package.json the scaffold writes ────────────────────────────────────────────────── { @@ -13,6 +13,7 @@ import {findDrift, generatedPackageJson} from './check-engine-parity.mjs'; assert.match(packageJson.dependencies['neo.mjs'], /^\^\d+\.\d+\.\d+$/, 'the engine pin is read from the generator'); assert.ok(Object.keys(packageJson.devDependencies).length > 10, 'and so are the devDependencies'); + assert.ok(Object.keys(packageJson.overrides).length > 0, 'and the overrides'); } // ── A planted divergence is reported, a match is not ─────────────────────────────────────────────── @@ -36,4 +37,23 @@ import {findDrift, generatedPackageJson} from './check-engine-parity.mjs'; assert.deepEqual(scaffoldOnly, ['chromadb']) } +// ── Overrides compare in full, both ways: npm reads them only in the root project ────────────────── +{ + const engine = {'gray-matter': {'js-yaml': '^3.15.2'}, 'lodash-es': '^4.18.0'}; + + assert.deepEqual(findOverrideDrift({'gray-matter': {'kind-of': '^6.0.3', 'js-yaml': '^3.15.2'}}, + {'gray-matter': {'js-yaml': '^3.15.2', 'kind-of': '^6.0.3'}}), [], 'equal overrides pass in any key order'); + + assert.deepEqual(findOverrideDrift({'lodash-es': '^4.18.0'}, engine), + [{name: 'gray-matter', scaffold: undefined, engine: {'js-yaml': '^3.15.2'}}], 'an engine floor the scaffold lacks is drift'); + + assert.deepEqual(findOverrideDrift({...engine, 'gray-matter': {'js-yaml': '^3.14.0'}}, engine), + [{name: 'gray-matter', scaffold: {'js-yaml': '^3.14.0'}, engine: {'js-yaml': '^3.15.2'}}], 'a nested range that differs is drift'); + + assert.deepEqual(findOverrideDrift(engine, undefined).map(({name}) => name), ['gray-matter', 'lodash-es'], + 'overrides the release does not declare are drift, which also catches an answer without the field'); + + assert.deepEqual(findOverrideDrift(undefined, undefined), [], 'neither side declaring overrides is a match') +} + console.log('check-engine-parity: contract arms green.'); diff --git a/tasks/createGeminiSettings.mjs b/tasks/createGeminiSettings.mjs deleted file mode 100644 index 4636651..0000000 --- a/tasks/createGeminiSettings.mjs +++ /dev/null @@ -1,34 +0,0 @@ -export default { - init(folder, fs, os, path) { - const settingsJson = { - "context": { - "fileName": ["AGENTS.md", "GEMINI.md"] - }, - "mcpServers": { - "neo.mjs-github-workflow": { - "command": "npm", - "args" : ["run", "ai:mcp-server-github-workflow"] - }, - "neo.mjs-knowledge-base": { - "command": "npm", - "args" : ["run", "ai:mcp-server-knowledge-base"] - }, - "neo.mjs-memory-core": { - "command": "npm", - "args" : ["run", "ai:mcp-server-memory-core"] - }, - "neo.mjs-neural-link": { - "command": "npm", - "args" : ["run", "ai:mcp-server-neural-link"] - } - } - }; - - fs.mkdirpSync(path.join(folder, '.gemini')); - - fs.writeFileSync( - path.join(folder, '.gemini/settings.json'), - JSON.stringify(settingsJson, null, 4) + os.EOL - ); - } -}; diff --git a/tasks/createGitignore.mjs b/tasks/createGitignore.mjs index 4672c39..a257af7 100644 --- a/tasks/createGitignore.mjs +++ b/tasks/createGitignore.mjs @@ -26,10 +26,8 @@ export default { ".DS_Store", "Thumbs.db", "", - "# Local AI Knowledge Base", + "# Local environment", ".env", - "chroma-neo-knowledge-base/", - "chroma-neo-memory-core/", "", "# Playwright test results", "test/playwright/test-results/", diff --git a/tasks/createMcpConfigs.mjs b/tasks/createMcpConfigs.mjs deleted file mode 100644 index 68dc2c7..0000000 --- a/tasks/createMcpConfigs.mjs +++ /dev/null @@ -1,31 +0,0 @@ -export default { - init(workspace, fs, os, path) { - const mcpRoot = path.join(workspace, 'ai/mcp/server'); - const configs = [ - { - dir: 'github-workflow', - content: { - "owner": "ADD_GITHUB_ORGANIZATION_HERE", - "repo" : "ADD_GITHUB_REPOSITORY_HERE" - } - }, - { - dir: 'knowledge-base', - content: {} - }, - { - dir: 'memory-core', - content: {} - } - ]; - - configs.forEach(config => { - const dirPath = path.join(mcpRoot, config.dir); - fs.mkdirpSync(dirPath); - fs.writeFileSync( - path.join(dirPath, 'config.json'), - JSON.stringify(config.content, null, 4) + os.EOL - ); - }); - } -}; diff --git a/tasks/createPackageJson.mjs b/tasks/createPackageJson.mjs index 8f07b87..76a6c61 100644 --- a/tasks/createPackageJson.mjs +++ b/tasks/createPackageJson.mjs @@ -6,94 +6,80 @@ export default { private: true, type : 'module', scripts: { - "add-config" : "node ./node_modules/neo.mjs/buildScripts/create/addConfig.mjs", - "add-reactive-tags" : "node ./node_modules/neo.mjs/buildScripts/helpers/addReactiveTags.mjs", - "ai:defrag-kb" : "node ./node_modules/neo.mjs/buildScripts/ai/defragChromaDB.mjs --target knowledge-base", - "ai:defrag-memory" : "node ./node_modules/neo.mjs/buildScripts/ai/defragChromaDB.mjs --target memory-core", - "ai:download-kb" : "node ./node_modules/neo.mjs/buildScripts/ai/downloadKnowledgeBase.mjs", - "ai:mcp-client" : "node ./node_modules/neo.mjs/ai/mcp/client/mcp-cli.mjs", - "ai:mcp-server-github-workflow": "node ./node_modules/neo.mjs/ai/mcp/server/github-workflow/mcp-server.mjs", - "ai:mcp-server-knowledge-base" : "node ./node_modules/neo.mjs/ai/mcp/server/knowledge-base/mcp-server.mjs", - "ai:mcp-server-memory-core" : "node ./node_modules/neo.mjs/ai/mcp/server/memory-core/mcp-server.mjs", - "ai:mcp-server-neural-link" : "node ./node_modules/neo.mjs/ai/mcp/server/neural-link/mcp-server.mjs", - "ai:migrate-memory" : "node ./node_modules/neo.mjs/buildScripts/ai/migrateMemoryCore.mjs", - "ai:server" : "chroma run --path ./chroma-neo-knowledge-base", - "ai:server-memory" : "chroma run --path ./chroma-neo-memory-core --port 8001", - "ai:server-neural-link" : "node ./node_modules/neo.mjs/ai/mcp/server/neural-link/run-bridge.mjs", - "ai:sync-kb" : "node ./node_modules/neo.mjs/buildScripts/ai/syncKnowledgeBase.mjs", - "build-all" : "node ./node_modules/neo.mjs/buildScripts/build/all.mjs -n", - "build-all-questions" : "node ./node_modules/neo.mjs/buildScripts/build/all.mjs", - "build-dist-esm" : "node ./node_modules/neo.mjs/buildScripts/build/esmodules.mjs", - "build-highlightjs" : "node ./node_modules/neo.mjs/buildScripts/build/highlightJs.mjs", - "build-themes" : "node ./node_modules/neo.mjs/buildScripts/build/themes.mjs", - "build-threads" : "node ./node_modules/neo.mjs/buildScripts/webpack/buildThreads.mjs", - "bundle-browser-deps" : "npm run bundle-parse5 && npm run bundle-marked && npm run bundle-mermaid && npm run bundle-monaco && npm run build-highlightjs", - "bundle-marked" : "node ./node_modules/neo.mjs/buildScripts/build/marked.mjs", - "bundle-mermaid" : "node ./node_modules/neo.mjs/buildScripts/build/mermaid.mjs", - "bundle-monaco" : "node ./node_modules/neo.mjs/buildScripts/build/monaco.mjs", - "bundle-parse5" : "node ./node_modules/neo.mjs/buildScripts/build/parse5.mjs", - "check-reactive-tags" : "node ./node_modules/neo.mjs/buildScripts/helpers/checkReactiveTags.mjs", - "copy-examples" : "node ./buildScripts/copyExamples.mjs", - "create-app" : "node ./node_modules/neo.mjs/buildScripts/create/app.mjs", - "create-app-minimal" : "node ./node_modules/neo.mjs/buildScripts/create/appMinimal.mjs", - "create-class" : "node ./node_modules/neo.mjs/buildScripts/create/class.mjs", - "create-component" : "node ./node_modules/neo.mjs/buildScripts/create/component.mjs", - "generate-docs-json" : "node ./node_modules/neo.mjs/buildScripts/docs/jsdocx.mjs", - "postinstall" : "cd node_modules/neo.mjs && npm i", - "server-start" : "webpack serve -c ./buildScripts/webpack/webpack.server.config.mjs --open", - "test" : "playwright test -c node_modules/neo.mjs/test/playwright/playwright.config.mjs", - "test-components" : "playwright test -c node_modules/neo.mjs/test/playwright/playwright.config.component.mjs", - "test-e2e" : "playwright test -c node_modules/neo.mjs/test/playwright/playwright.config.e2e.mjs", - "test-unit" : "playwright test -c node_modules/neo.mjs/test/playwright/playwright.config.unit.mjs", - "watch-themes" : "node ./node_modules/neo.mjs/buildScripts/helpers/watchThemes.mjs" + "add-config" : "node ./node_modules/neo.mjs/buildScripts/create/addConfig.mjs", + "add-reactive-tags" : "node ./node_modules/neo.mjs/buildScripts/helpers/addReactiveTags.mjs", + "build-all" : "node ./node_modules/neo.mjs/buildScripts/build/all.mjs -n", + "build-all-questions": "node ./node_modules/neo.mjs/buildScripts/build/all.mjs", + "build-dist-esm" : "node ./node_modules/neo.mjs/buildScripts/build/esmodules.mjs", + "build-highlightjs" : "node ./node_modules/neo.mjs/buildScripts/build/highlightJs.mjs", + "build-themes" : "node ./node_modules/neo.mjs/buildScripts/build/themes.mjs", + "build-threads" : "node ./node_modules/neo.mjs/buildScripts/webpack/buildThreads.mjs", + "bundle-browser-deps": "npm run bundle-parse5 && npm run bundle-marked && npm run bundle-mermaid && npm run bundle-monaco && npm run build-highlightjs", + "bundle-marked" : "node ./node_modules/neo.mjs/buildScripts/build/marked.mjs", + "bundle-mermaid" : "node ./node_modules/neo.mjs/buildScripts/build/mermaid.mjs", + "bundle-monaco" : "node ./node_modules/neo.mjs/buildScripts/build/monaco.mjs", + "bundle-parse5" : "node ./node_modules/neo.mjs/buildScripts/build/parse5.mjs", + "check-reactive-tags": "node ./node_modules/neo.mjs/buildScripts/helpers/checkReactiveTags.mjs", + "copy-examples" : "node ./buildScripts/copyExamples.mjs", + "create-app" : "node ./node_modules/neo.mjs/buildScripts/create/app.mjs", + "create-app-minimal" : "node ./node_modules/neo.mjs/buildScripts/create/appMinimal.mjs", + "create-class" : "node ./node_modules/neo.mjs/buildScripts/create/class.mjs", + "create-component" : "node ./node_modules/neo.mjs/buildScripts/create/component.mjs", + "generate-docs-json" : "node ./node_modules/neo.mjs/buildScripts/docs/generateDocsJson.mjs", + // The engine package ships no generated bundles, and an install replaces node_modules/neo.mjs, so every + // install rebuilds the two the engine imports at module scope. The others load lazily: bundle-browser-deps. + "postinstall" : "cd node_modules/neo.mjs && npm i && npm run bundle-parse5 && npm run bundle-marked", + "server-start" : "webpack serve -c ./node_modules/neo.mjs/buildScripts/webpack/webpack.server.config.mjs --open", + "test" : "playwright test -c node_modules/neo.mjs/test/playwright/playwright.config.mjs", + "test-components" : "playwright test -c node_modules/neo.mjs/test/playwright/playwright.config.component.mjs", + "test-e2e" : "playwright test -c node_modules/neo.mjs/test/playwright/playwright.config.e2e.mjs", + "test-unit" : "playwright test -c node_modules/neo.mjs/test/playwright/playwright.config.unit.mjs", + "watch-themes" : "node ./node_modules/neo.mjs/buildScripts/helpers/watchThemes.mjs" }, dependencies: { - "neo.mjs": "^12.1.0" + "neo.mjs": "^13.2.0" }, devDependencies: { - "@chroma-core/default-embed" : "^0.1.9", - "@fortawesome/fontawesome-free": "^7.2.0", - "@google/generative-ai" : "^0.24.1", - "@modelcontextprotocol/sdk" : "^1.27.1", - "@playwright/test" : "^1.58.2", - "acorn" : "^8.16.0", + "@fortawesome/fontawesome-free": "^7.3.1", + "@playwright/test" : "^1.63.0", + "acorn" : "^8.19.0", "astring" : "^1.9.0", - "autoprefixer" : "^10.4.27", - "chalk" : "^5.6.2", - "chromadb" : "^3.3.1", - "clean-webpack-plugin" : "^4.0.0", - "commander" : "^14.0.3", - "cssnano" : "^7.1.3", - "dotenv" : "^17.3.1", + "autoprefixer" : "^10.6.1", + "chalk" : "^6.0.1", + "commander" : "^15.0.0", + "cssnano" : "^9.3.2", "envinfo" : "^7.21.0", - "esbuild" : "^0.27.3", + "esbuild" : "^0.28.2", "fast-glob" : "^3.3.3", - "fs-extra" : "^11.3.4", - "glob" : "^13.0.6", + "fs-extra" : "^11.4.1", "gray-matter" : "^4.0.3", "highlightjs-line-numbers.js" : "^2.9.1", "html-minifier-terser" : "^7.2.0", - "inquirer" : "^13.3.0", - "jsdoc-api" : "^9.3.5", - "js-yaml" : "^4.1.1", - "marked" : "^17.0.4", - "mermaid" : "^11.12.2", - "monaco-editor" : "0.50.0", - "parse5" : "^8.0.0", - "postcss" : "^8.5.8", - "sass" : "^1.97.3", - "semver" : "^7.7.4", - "terser" : "^5.46.0", + "inquirer" : "^14.2.3", + "jsdoc-api" : "^9.3.6", + "js-yaml" : "^5.4.3", + "marked" : "^18.1.0", + "mermaid" : "^12.1.0", + "monaco-editor" : "0.57.0", + "parse5" : "^8.0.1", + "postcss" : "^8.5.29", + "sass" : "^1.105.1", + "semver" : "^7.8.5", + "terser" : "^5.51.2", "url" : "^0.11.4", - "webpack" : "^5.105.4", - "webpack-cli" : "^6.0.1", - "webpack-dev-server" : "^5.2.3", + "webpack" : "^5.111.1", + "webpack-cli" : "^7.2.3", + "webpack-dev-server" : "^6.0.0", "webpack-hook-plugin" : "^1.0.7", - "webpack-node-externals" : "^3.0.0", - "ws" : "^8.19.0", - "yargs" : "^18.0.0", - "zod" : "^3.25.76", - "zod-to-json-schema" : "^3.25.1" + "ws" : "^8.22.0" + }, + // npm reads overrides only in the root project, so the engine's floors reach the app's own install + // through this copy alone. check-engine-parity.mjs keeps it equal to the pinned release's. + overrides: { + "dompurify" : "^3.4.16", + "gray-matter": {"js-yaml": "^3.15.2"}, + "katex" : "^0.18.2", + "lodash-es" : "^4.18.0" } }; diff --git a/tasks/neo-app.mjs b/tasks/neo-app.mjs index 7a2e2eb..76938a3 100755 --- a/tasks/neo-app.mjs +++ b/tasks/neo-app.mjs @@ -1,27 +1,25 @@ #!/usr/bin/env node -import chalk from 'chalk'; -import {spawnSync} from 'child_process'; -import {Command, Option} from 'commander/esm.mjs'; -import copyDocsApp from './copyDocsApp.mjs'; -import createApp from './createApp.mjs'; -import createGeminiSettings from './createGeminiSettings.mjs'; -import createMcpConfigs from './createMcpConfigs.mjs'; -import createGitignore from './createGitignore.mjs'; -import createIndexHtml from './createIndexHtml.mjs'; -import createMyAppsJson from './createMyAppsJson.mjs'; -import createNeoConfigJson from './createNeoConfigJson.mjs'; -import createPackageJson from './createPackageJson.mjs'; -import createScssResources from './createScssResources.mjs'; -import createSrcFolder from './createSrcFolder.mjs'; -import createServiceWorker from './createServiceWorker.mjs'; -import createViewport from './createViewport.mjs'; -import envinfo from 'envinfo'; -import fs from 'fs-extra'; -import inquirer from 'inquirer'; -import os from 'os'; -import path from 'path'; -import {fileURLToPath} from 'url'; +import chalk from 'chalk'; +import {spawnSync} from 'child_process'; +import {Command, Option} from 'commander/esm.mjs'; +import copyDocsApp from './copyDocsApp.mjs'; +import createApp from './createApp.mjs'; +import createGitignore from './createGitignore.mjs'; +import createIndexHtml from './createIndexHtml.mjs'; +import createMyAppsJson from './createMyAppsJson.mjs'; +import createNeoConfigJson from './createNeoConfigJson.mjs'; +import createPackageJson from './createPackageJson.mjs'; +import createScssResources from './createScssResources.mjs'; +import createSrcFolder from './createSrcFolder.mjs'; +import createServiceWorker from './createServiceWorker.mjs'; +import createViewport from './createViewport.mjs'; +import envinfo from 'envinfo'; +import fs from 'fs-extra'; +import inquirer from 'inquirer'; +import os from 'os'; +import path from 'path'; +import {fileURLToPath} from 'url'; const __dirname = fileURLToPath(path.dirname(import.meta.url)), @@ -160,18 +158,16 @@ if (programOpts.info) { throw err; } - createApp .init(appName, appPath, fs, os, path); - createGeminiSettings.init(path.join(cwd, workspace), fs, os, path); - createMcpConfigs .init(path.join(cwd, workspace), fs, os, path); - createGitignore .init(workspace, fs, os, path); - createIndexHtml .init(appName, appPath, fs, os, path); - createViewport .init(appName, appPath, fs, os, path); - createMyAppsJson .init(appName, workspace, fs, os, path); - createNeoConfigJson .init(appName, appPath, fs, mainThreadAddons, os, path, themes, useSharedWorkers, useServiceWorker); - createPackageJson .init(appName, workspace, fs, os, path); - createScssResources .init(appName, workspace, fs, os, path); - createServiceWorker .init(appName, workspace, fs, os, path); - createSrcFolder .init(path.join(cwd, workspace), fs, os, path, __dirname); + createApp .init(appName, appPath, fs, os, path); + createGitignore .init(workspace, fs, os, path); + createIndexHtml .init(appName, appPath, fs, os, path); + createViewport .init(appName, appPath, fs, os, path); + createMyAppsJson .init(appName, workspace, fs, os, path); + createNeoConfigJson.init(appName, appPath, fs, mainThreadAddons, os, path, themes, useSharedWorkers, useServiceWorker); + createPackageJson .init(appName, workspace, fs, os, path); + createScssResources.init(appName, workspace, fs, os, path); + createServiceWorker.init(appName, workspace, fs, os, path); + createSrcFolder .init(path.join(cwd, workspace), fs, os, path, __dirname); fs.copySync( path.join(__dirname, '../resources/copyExamples.mjs'), @@ -183,38 +179,8 @@ if (programOpts.info) { // npm install spawnSync(npmCmd, ['i'], cpOpts); - // Copy AI-related files after npm install - fs.copySync( - path.join(workspace, 'node_modules/neo.mjs/AGENTS.md'), - path.join(workspace, 'AGENTS.md') - ); - fs.copySync( - path.join(workspace, 'node_modules/neo.mjs/AGENTS_STARTUP.md'), - path.join(workspace, 'AGENTS_STARTUP.md') - ); - - fs.mkdirpSync(path.join(workspace, '.github')); // Create .github directory - - fs.copySync( - path.join(workspace, 'node_modules/neo.mjs/.github/AI_QUICK_START.md'), - path.join(workspace, '.github/AI_QUICK_START.md') - ); - fs.copySync( - path.join(workspace, 'node_modules/neo.mjs/.github/WORKING_WITH_AGENTS.md'), - path.join(workspace, '.github/WORKING_WITH_AGENTS.md') - ); - copyDocsApp.init(fs, os, path, workspace); - const webpackScriptFolder = path.join(workspace, 'buildScripts/webpack'); - - fs.mkdirpSync(webpackScriptFolder); - - fs.copySync( - path.join(workspace, 'node_modules/neo.mjs/buildScripts/webpack/webpack.server.config.mjs'), - path.join(webpackScriptFolder, 'webpack.server.config.mjs') - ); - spawnSync('node', ['./node_modules/neo.mjs/buildScripts/build/all.mjs', '-n', '-l', 'no', '-p', 'no'], { cwd : path.join(cwd, workspace), env : process.env,