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,