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"]
Comment on lines +6 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

🌐 Web query:

For Codex .codex/config.toml, does writable_roots = ["~/.npmrc"]support tilde expansion, or must paths be absolute? Also, what is the recommended secure pattern to allow temporary npm auth for Nx local registry helpers without writing to user-home.npmrc?

💡 Result:

For Codex .codex/config.toml, writable_roots = ["~/.npmrc"] does not support tilde expansion; paths must be absolute. Official docs and examples consistently use absolute paths like ["/Users/YOU/.pyenv/shims"] or ["/additional/writable/path"]. A related GitHub issue confirms that Codex tools like Edit do not expand ~, treating it literally, which aligns with config path handling requiring explicit expansion or absolute paths. The recommended secure pattern for temporary npm auth with Nx local registry helpers, without writing to user-home .npmrc, is to use project-level .npmrc in the workspace root. Nx docs state this configures custom registries and auth tokens for publishing/installing, scoped by npm scopes (e.g., @my-scope:registry=... //my-custom-registry.com/:_authToken=). This avoids global user config, keeping auth local to the project. Environment variables like NPM_TOKEN can also inject auth temporarily via CI or shell_environment_policy in Codex config, but project .npmrc is the explicit Nx recommendation.

Citations:


Replace user-home .npmrc reference with workspace-local .npmrc and use absolute path if keeping this approach.

The writable_roots = ["~/.npmrc"] path will not work as intended: Codex does not expand tilde in writable_roots, so it will treat ~/.npmrc literally rather than resolving to the user's home directory. This is both a config bug and a security concern.

The recommended approach is to use a workspace-local .npmrc in the project root instead. This allows Nx's local registry helper to configure auth tokens scoped to the project without writing to user-home config, eliminating cross-run/cross-user persistence risks. If you must write to user-home ~/.npmrc, use an absolute path like /Users/USERNAME/.npmrc—but the workspace-local .npmrc pattern is safer and aligns with Nx documentation.

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

In @.codex/config.toml around lines 6 - 8, The config entry writable_roots =
["~/.npmrc"] uses an unexpanded tilde and will be treated literally by Codex;
replace it with a workspace-local .npmrc (e.g., writable_roots = ["./.npmrc"])
so Nx's startLocalRegistry helper writes auth tokens to the project root rather
than the user home, or if you intentionally must target the user home, change it
to an absolute home path (e.g., /Users/USERNAME/.npmrc) instead of "~/.npmrc";
update the writable_roots value accordingly and ensure any CI/dev docs reflect
the chosen pattern.

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';

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