Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .codex/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
approval_policy = "on-request"
sandbox_mode = "workspace-write"

[sandbox_workspace_write]
network_access = true
# Nx's startLocalRegistry helper shells out to `npm config set/delete ... --ws=false`,
# which temporarily writes the local registry auth token to the user npm config at ~/.npmrc.
writable_roots = ["~/.npmrc"]
1 change: 0 additions & 1 deletion .eslintignore

This file was deleted.

44 changes: 0 additions & 44 deletions .eslintrc.json

This file was deleted.

4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,6 @@ Thumbs.db
.env

.nx/cache
.nx/workspace-data
.nx/workspace-data
.claude/worktrees
.claude/settings.local.json
4 changes: 4 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,7 @@ If a tradeoff is required, choose correctness and robustness over short-term con
## Maintainability

Long-term maintainability is a core priority. If you add new functionality, first check if there is shared logic that can be extracted to a separate module. Duplicate logic across multiple files is a code smell and should be avoided. Don't be afraid to change existing code. Don't take shortcuts by just adding local logic to solve a problem. If you are not sure, research to find a good solution.

## Technology Stack

- Use npm
25 changes: 22 additions & 3 deletions docs/.vitepress/config.mts
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
import { readFileSync } from 'fs';
import { fileURLToPath } from 'url';
import { readFileSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { resolve } from 'node:path';
import { defineConfig } from 'vitepress';
import {
injectReferenceOptions,
validateReferenceDocs,
} from '../../tools/docs/src/lib/reference-docs';
} from '../../tools/docs';
Comment on lines 5 to +8
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "docs config import:"
sed -n '1,12p' docs/.vitepress/config.mts

echo
echo "tools/docs package entry:"
sed -n '1,40p' tools/docs/package.json

echo
echo "available source entry files:"
find tools/docs/src -maxdepth 1 \( -name 'index.ts' -o -name 'index.js' \) -print | sort

Repository: toolsplus/nx-forge

Length of output: 723


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== All files in tools/docs/src ==="
ls -la tools/docs/src/ 2>/dev/null || echo "Directory listing failed"

echo
echo "=== Check for compiled index.js anywhere in tools/docs ==="
find tools/docs -name 'index.js' -type f 2>/dev/null || echo "No index.js found"

echo
echo "=== Check build/package scripts ==="
grep -A 5 '"scripts"' tools/docs/package.json || echo "No scripts section"

echo
echo "=== Check if there's a build config (tsconfig, esbuild, etc) ==="
ls -la tools/docs/ | grep -E '\.(tsconfig|esbuild|rollup|webpack)' || echo "No obvious build configs at root"

echo
echo "=== Check tsconfig in tools directory ==="
if [ -f tools/tsconfig.json ]; then
  echo "Found tools/tsconfig.json - first 30 lines:"
  head -30 tools/tsconfig.json
fi

echo
echo "=== Check if tools/docs has its own tsconfig ==="
if [ -f tools/docs/tsconfig.json ]; then
  echo "Found tools/docs/tsconfig.json:"
  cat tools/docs/tsconfig.json
else
  echo "No tsconfig.json in tools/docs"
fi

Repository: toolsplus/nx-forge

Length of output: 905


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Content of tools/docs/src/index.ts ==="
cat tools/docs/src/index.ts

echo
echo "=== Root vite/build config ==="
ls -la | grep -E '(vite|build)' || echo "No vite/build files at root"

echo
echo "=== Check if docs has its own vite config ==="
find docs -name 'vite.config.*' -o -name 'vitest.config.*' 2>/dev/null | head -5

echo
echo "=== Check package.json to see if it defines exports field (modern resolution) ==="
grep -E '"(exports|browser|module)"' tools/docs/package.json || echo "No exports/browser/module fields"

echo
echo "=== Check nx.json or project.json for build setup ==="
if [ -f tools/docs/project.json ]; then
  echo "Found tools/docs/project.json - showing first 50 lines:"
  head -50 tools/docs/project.json
else
  echo "No project.json in tools/docs"
fi

Repository: toolsplus/nx-forge

Length of output: 1743


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Check docs/project.json for build configuration ==="
if [ -f docs/project.json ]; then
  cat docs/project.json
else
  echo "No docs/project.json found"
fi

echo
echo "=== Check root tsconfig for path mapping ==="
if [ -f tsconfig.base.json ]; then
  cat tsconfig.base.json | head -100
fi

echo
echo "=== Check if docs has dependency on tools-docs build ==="
grep -r 'tools.docs\|tools/docs' nx.json 2>/dev/null | head -20 || echo "No references found"

Repository: toolsplus/nx-forge

Length of output: 853


🏁 Script executed:

#!/bin/bash
set -euo pipefamerikansk

echo "=== Check VitePress version and config ==="
grep -i 'vitepress' docs/.vitepress/config.mts package.json pnpm-lock.yaml 2>/dev/null | head -20 || echo "Checking package files..."

if [ -f package.json ]; then
  echo "VitePress in package.json:"
  grep 'vitepress' package.json || echo "Not found in package.json"
fi

echo
echo "=== Check if there's a build script or dev script that handles this ==="
grep -A 5 '"scripts"' package.json | head -20

echo
echo "=== Verify what the relative import actually resolves to ==="
echo "Import path: ../../tools/docs from docs/.vitepress/config.mts"
echo "This resolves to: tools/docs (directory)"
echo "Node would then check: tools/docs/package.json#main = ./src/index.js"
echo "Which would resolve to: tools/docs/src/index.js"
echo
echo "File existence check:"
[ -f tools/docs/src/index.js ] && echo "✓ index.js EXISTS" || echo "✗ index.js DOES NOT EXIST"
[ -f tools/docs/src/index.ts ] && echo "✓ index.ts EXISTS" || echo "✗ index.ts DOES NOT EXIST"

Repository: toolsplus/nx-forge

Length of output: 122


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Check VitePress version and config ==="
if [ -f package.json ]; then
  echo "VitePress in package.json:"
  grep 'vitepress' package.json || echo "Not found in package.json"
fi

echo
echo "=== Check if there's a build script or dev script that handles this ==="
grep -A 5 '"scripts"' package.json | head -20

echo
echo "=== Verify what the relative import actually resolves to ==="
echo "Import path: ../../tools/docs from docs/.vitepress/config.mts"
echo "This resolves to: tools/docs (directory)"
echo "Node would then check: tools/docs/package.json#main = ./src/index.js"
echo "Which would resolve to: tools/docs/src/index.js"
echo
echo "File existence check:"
[ -f tools/docs/src/index.js ] && echo "✓ index.js EXISTS" || echo "✗ index.js DOES NOT EXIST"
[ -f tools/docs/src/index.ts ] && echo "✓ index.ts EXISTS" || echo "✗ index.ts DOES NOT EXIST"

Repository: toolsplus/nx-forge

Length of output: 722


Update tools/docs/package.json to correctly reference the source entry point.

The import in docs/.vitepress/config.mts resolves to tools/docs as a directory. Node module resolution then checks tools/docs/package.json#main, which points to ./src/index.js. However, this file does not exist—only tools/docs/src/index.ts is checked in, and the Nx build outputs to dist/tools/docs. Change the "main" field to "./src/index.ts" to match the actual source entry point, or update it to point to the compiled output path if the package should be consumed post-build.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/.vitepress/config.mts` around lines 5 - 8, The package.json for the
tools/docs package is pointing its "main" field at a non-existent
./src/index.js; update tools/docs/package.json's "main" field so imports used in
docs/.vitepress/config.mts (e.g., injectReferenceOptions and
validateReferenceDocs) resolve correctly — either set "main" to the actual
source entry "./src/index.ts" if you want to import the TS source directly, or
change it to the built output (e.g., the compiled dist path such as
"./dist/tools/docs/index.js") depending on whether consumers should use the
built package.


const jsonataGrammar = JSON.parse(
readFileSync(
fileURLToPath(
new URL('./grammars/jsonata.tmLanguage.json', import.meta.url)
),
'utf-8'
)
);

const base = '/nx-forge/';
const workspaceRoot = fileURLToPath(new URL('../..', import.meta.url));
Expand Down Expand Up @@ -37,6 +47,15 @@ export default defineConfig({
],
],
cleanUrls: true,
markdown: {
languages: [
{
name: 'jsonata',
scopeName: 'source.jsonata',
...jsonataGrammar,
},
],
},
vite: {
plugins: [
{
Expand Down
224 changes: 224 additions & 0 deletions docs/.vitepress/grammars/jsonata.tmLanguage.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
{
"$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json",
"scopeName": "source.jsonata",
"foldingStartMarker": "\\{\\s*$",
"foldingStopMarker": "^\\s*\\}",
"patterns": [
{
"include": "#value"
}
],
"repository": {
"expression": {
"name": "meta.selector.jsonata",
"patterns": [
{
"match": "(\\$|\\.)",
"name": "keyword.other.selector.jsonata"
},
{
"match": "(\\+|-|\\*|/|&)",
"name": "keyword.other.math.jsonata"
}
]
},
"array": {
"begin": "\\[",
"beginCaptures": {
"0": {
"name": "punctuation.definition.array.begin.jsonata"
}
},
"end": "\\]",
"endCaptures": {
"0": {
"name": "punctuation.definition.array.end.jsonata"
}
},
"name": "meta.structure.array.jsonata",
"patterns": [
{
"include": "#value"
},
{
"match": ",",
"name": "punctuation.separator.array.jsonata"
},
{
"match": "[^\\s\\]]",
"name": "invalid.illegal.expected-array-separator.jsonata"
}
]
},
"comments": {
"patterns": [
{
"begin": "/\\*\\*(?!/)",
"captures": {
"0": {
"name": "punctuation.definition.comment.jsonata"
}
},
"end": "\\*/",
"name": "comment.block.documentation.jsonata"
},
{
"begin": "/\\*",
"captures": {
"0": {
"name": "punctuation.definition.comment.jsonata"
}
},
"end": "\\*/",
"name": "comment.block.jsonata"
},
{
"captures": {
"1": {
"name": "punctuation.definition.comment.jsonata"
}
},
"match": "(//).*$\\n?",
"name": "comment.line.double-slash.js"
}
]
},
"constant": {
"match": "\\b(?:true|false|null)\\b",
"name": "constant.language.jsonata"
},
"number": {
"match": "(?x) # turn on extended mode\n -? # an optional minus\n (?:\n 0 # a zero\n | # ...or...\n [1-9] # a 1-9 character\n \\d* # followed by zero or more digits\n )\n (?:\n (?:\n \\. # a period\n \\d+ # followed by one or more digits\n )?\n (?:\n [eE] # an e character\n [+-]? # followed by an option +/-\n \\d+ # followed by one or more digits\n )? # make exponent optional\n )? # make decimal portion optional",
"name": "constant.numeric.jsonata"
},
"object": {
"begin": "\\{",
"beginCaptures": {
"0": {
"name": "punctuation.definition.dictionary.begin.jsonata"
}
},
"end": "\\}",
"endCaptures": {
"0": {
"name": "punctuation.definition.dictionary.end.jsonata"
}
},
"name": "meta.structure.dictionary.jsonata",
"patterns": [
{
"comment": "the JSON object key",
"include": "#objectkey"
},
{
"include": "#comments"
},
{
"begin": ":",
"beginCaptures": {
"0": {
"name": "punctuation.separator.dictionary.key-value.jsonata"
}
},
"end": "(,)|(?=\\})",
"endCaptures": {
"1": {
"name": "punctuation.separator.dictionary.pair.jsonata"
}
},
"name": "meta.structure.dictionary.value.jsonata",
"patterns": [
{
"comment": "the JSON object value",
"include": "#value"
}
]
},
{
"match": "[^\\s\\}]",
"name": "invalid.illegal.expected-dictionary-separator.jsonata"
}
]
},
"string": {
"begin": "\"",
"beginCaptures": {
"0": {
"name": "punctuation.definition.string.begin.jsonata"
}
},
"end": "\"",
"endCaptures": {
"0": {
"name": "punctuation.definition.string.end.jsonata"
}
},
"name": "string.quoted.double.jsonata",
"patterns": [
{
"include": "#stringcontent"
}
]
},
"objectkey": {
"begin": "\"",
"beginCaptures": {
"0": {
"name": "punctuation.support.type.property-name.begin.jsonata"
}
},
"end": "\"",
"endCaptures": {
"0": {
"name": "punctuation.support.type.property-name.end.jsonata"
}
},
"name": "string.jsonata support.type.property-name.jsonata",
"patterns": [
{
"include": "#stringcontent"
},
{
"include": "#expression"
}
]
},
"stringcontent": {
"patterns": [
{
"match": "(?x) # turn on extended mode\n \\\\ # a literal backslash\n (?: # ...followed by...\n [\"\\\\/bfnrt] # one of these characters\n | # ...or...\n u # a u\n [0-9a-fA-F]{4}) # and four hex digits",
"name": "constant.character.escape.jsonata"
},
{
"match": "\\\\.",
"name": "invalid.illegal.unrecognized-string-escape.jsonata"
}
]
},
"value": {
"patterns": [
{
"include": "#comments"
},
{
"include": "#constant"
},
{
"include": "#number"
},
{
"include": "#string"
},
{
"include": "#array"
},
{
"include": "#object"
},
{
"include": "#expression"
}
]
}
}
}
6 changes: 3 additions & 3 deletions docs/concepts/plugin-concepts.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ This page summarizes the main Nx Forge plugin concepts and ideas.

## Building Forge apps

When using [the app generator](../guides/generating-a-forge-app.md) to scaffold a Forge app, you will get a Nx project with a build target and a collection of inferred targets provided by the Nx Forge plugin.
When using [the app generator](../guides/generating-a-forge-app.md) to scaffold a Forge app, you will get an Nx project with a build target and a collection of inferred targets provided by the Nx Forge plugin.

The most important thing to know is that to deploy a Forge app, you need to run the following executors to get an artifact that can be deployed to the Forge platform:
The most important thing to know is that to deploy a Forge app, you need to run the following targets to get an artifact that can be deployed to the Forge platform:

::: tip Executors to get a deployable Forge app artifact
::: tip Targets to get a deployable Forge app artifact

build -> package

Expand Down
2 changes: 1 addition & 1 deletion docs/guides/adding-a-ui-kit-module.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ UI Kit support is experimental. Please try it out and let us know if you face an

## Enabling UI Kit packaging

Unfortunately, UI Kit and Custom UI packaging do not work the same way. To avoid breaking any existing builds, the default packaging mechanism is currently only compatible with Custom UI. However, you can enable UI Kit compatible packaging by setting the `uiKit2Packaging` option on the [`build`](../reference/executors.md#build) or [`package`](../reference/executors.md#package) executor.
Unfortunately, UI Kit and Custom UI packaging do not work the same way. To avoid breaking any existing builds, the default packaging mechanism is currently only compatible with Custom UI. However, you can enable UI Kit-compatible packaging by setting the `uiKit2Packaging` option on the [`package`](../reference/executors.md#package) target.

## Installing UI Kit dependencies

Expand Down
8 changes: 4 additions & 4 deletions docs/guides/generating-a-forge-app.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ nx g @toolsplus/nx-forge:app <nx-forge-app-name>

Refer to [the generator reference documentation](../reference/generators#application) for details on the available generator options.

When the generator completes, you have a blank Forge app project. To register the new app with the Forge platform, run the following [build](../reference/executors#build), [package](../reference/executors#package), and [register](../reference/executors#register) commands in this order:
When the generator completes, you have a blank Forge app project. To register the new app with the Forge platform, run the `build` target, then the [`package`](../reference/executors#package) and [`register`](../reference/executors#register) targets in this order:

```shell
nx build <nx-forge-app-name>
nx package <nx-forge-app-name>
nx register <nx-forge-app-name> --appName="My Forge App"
nx run <nx-forge-app-name>:build
nx run <nx-forge-app-name>:package
nx run <nx-forge-app-name>:register --appName="My Forge App"
```

The register command updates the `app.id` in the manifest file to the value returned from the registration.
Loading
Loading