@tbrandenburg/node-red-cli 0.2.15 → 0.2.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -4
- package/bin/node-red-cli-sandbox-entry.js +6 -0
- package/bin/node-red-cli.js +3 -1
- package/package.json +1 -1
- package/src/run-envelope.js +41 -5
package/README.md
CHANGED
|
@@ -290,6 +290,15 @@ deterministic **named Docker volume** (derived from the `--user-dir` value)
|
|
|
290
290
|
mounted inside the container, never a host bind mount — so "no stray host
|
|
291
291
|
files" holds even for persistent installs.
|
|
292
292
|
|
|
293
|
+
For images/derived images that pre-install Node-RED node packages into
|
|
294
|
+
their own conventional userDir, setting the `NODE_RED_CLI_DEFAULT_USERDIR`
|
|
295
|
+
environment variable (inside the image, e.g. via `ENV`) to that path lets
|
|
296
|
+
`--docker` discover it automatically whenever `--user-dir` isn't given —
|
|
297
|
+
that directory is used as `userDir` and, like an explicit `--user-dir`,
|
|
298
|
+
never deleted afterward. If the path doesn't exist or isn't a directory,
|
|
299
|
+
`--docker` logs a warning and falls back to the normal ephemeral `userDir`
|
|
300
|
+
rather than failing the invocation.
|
|
301
|
+
|
|
293
302
|
Fails fast with a clear `node-red-cli: docker unavailable: ...` error if
|
|
294
303
|
the Docker CLI/daemon isn't reachable, or `node-red-cli: docker build
|
|
295
304
|
failed: ...` if the image build fails (e.g. the local version isn't yet
|
|
@@ -320,10 +329,9 @@ already ships `opencode` + `node-red-agents`, e.g.
|
|
|
320
329
|
[`ghcr.io/tbrandenburg/agentic-workflow-dev-env`](https://github.com/tbrandenburg/agentic-workflow-dev-env)
|
|
321
330
|
(`--network` is required for network access, since the agent calls out to
|
|
322
331
|
its own API; `--node-modules`/`--user-dir` are still required too, since
|
|
323
|
-
Node-RED only discovers node types from a userDir it actually loaded
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
already ships the package):
|
|
332
|
+
Node-RED only discovers node types from a userDir it actually loaded, and
|
|
333
|
+
`--docker` doesn't yet reuse an image's own pre-populated default userDir —
|
|
334
|
+
see [#31](https://github.com/tbrandenburg/node-red-cli/issues/31)):
|
|
327
335
|
|
|
328
336
|
```bash
|
|
329
337
|
echo '{"payload":"Summarize this repo in one sentence.","cwd":"/repo"}' \
|
|
@@ -7,6 +7,12 @@
|
|
|
7
7
|
* envelope as JSON from stdin, runs it against a real Node-RED runtime via
|
|
8
8
|
* the shared `runFlowInvocation` (the exact same logic the host CLI uses
|
|
9
9
|
* for its non-Docker path), and writes the formatted result to stdout.
|
|
10
|
+
*
|
|
11
|
+
* The `NODE_RED_CLI_DEFAULT_USERDIR` env-var convention (see #31), which
|
|
12
|
+
* lets an image's own pre-populated default userDir be discovered when
|
|
13
|
+
* `--user-dir` isn't given, is resolved entirely inside the shared
|
|
14
|
+
* `runFlowInvocation` (`src/run-envelope.js`) -- nothing to do here beyond
|
|
15
|
+
* the existing pass-through of `envelope.options`.
|
|
10
16
|
*/
|
|
11
17
|
|
|
12
18
|
const { runFlowInvocation } = require("../src/run-envelope");
|
package/bin/node-red-cli.js
CHANGED
|
@@ -74,7 +74,9 @@ const HELP_TEXT = [
|
|
|
74
74
|
"network access independent of installing any package), --read-only",
|
|
75
75
|
"rootfs with a /tmp tmpfs, --cap-drop=ALL, --security-opt=no-new-privileges.",
|
|
76
76
|
"When combined with --user-dir, persistence uses a named Docker volume,",
|
|
77
|
-
"never a host bind mount.",
|
|
77
|
+
"never a host bind mount. Image authors can set",
|
|
78
|
+
"NODE_RED_CLI_DEFAULT_USERDIR=<path> so a pre-installed userDir is",
|
|
79
|
+
"discovered automatically when --user-dir isn't given.",
|
|
78
80
|
"",
|
|
79
81
|
"Example:",
|
|
80
82
|
' echo \'{"payload":{"x":4,"y":5}}\' | node-red-cli flows.json calculate',
|
package/package.json
CHANGED
package/src/run-envelope.js
CHANGED
|
@@ -132,6 +132,34 @@ function waitForFlowsSettled(RED) {
|
|
|
132
132
|
});
|
|
133
133
|
}
|
|
134
134
|
|
|
135
|
+
/**
|
|
136
|
+
* Resolves the image/host-provided default `userDir` from the
|
|
137
|
+
* `NODE_RED_CLI_DEFAULT_USERDIR` environment variable (see #31): community
|
|
138
|
+
* Docker images that pre-install Node-RED node packages into their own
|
|
139
|
+
* conventional userDir can set this variable so `--docker` (without an
|
|
140
|
+
* explicit `--user-dir`) discovers it automatically. Returns `undefined` if
|
|
141
|
+
* unset. Fails open, not closed: if the path doesn't exist, isn't a
|
|
142
|
+
* directory, or isn't accessible, logs a one-line stderr warning and returns
|
|
143
|
+
* `undefined` so the caller falls back to its normal ephemeral tmpdir,
|
|
144
|
+
* rather than aborting the invocation.
|
|
145
|
+
*/
|
|
146
|
+
function resolveDefaultUserDir() {
|
|
147
|
+
const configuredPath = process.env.NODE_RED_CLI_DEFAULT_USERDIR;
|
|
148
|
+
if (!configuredPath) return undefined;
|
|
149
|
+
|
|
150
|
+
try {
|
|
151
|
+
if (fs.statSync(configuredPath).isDirectory()) return configuredPath;
|
|
152
|
+
console.error(
|
|
153
|
+
`node-red-cli: NODE_RED_CLI_DEFAULT_USERDIR='${configuredPath}' is not usable (not a directory), falling back to an ephemeral userDir`
|
|
154
|
+
);
|
|
155
|
+
} catch (error) {
|
|
156
|
+
console.error(
|
|
157
|
+
`node-red-cli: NODE_RED_CLI_DEFAULT_USERDIR='${configuredPath}' is not usable (${error.message}), falling back to an ephemeral userDir`
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
return undefined;
|
|
161
|
+
}
|
|
162
|
+
|
|
135
163
|
/**
|
|
136
164
|
* Runs a single link-call invocation against a real, freshly booted
|
|
137
165
|
* Node-RED runtime: installs any missing `--node-modules`, boots RED with
|
|
@@ -146,8 +174,13 @@ function waitForFlowsSettled(RED) {
|
|
|
146
174
|
*
|
|
147
175
|
* `options.userDir`, when set, is treated as a persistent directory and is
|
|
148
176
|
* never removed afterward (host: an explicit `--user-dir`; container: the
|
|
149
|
-
* fixed mount path of a named Docker volume). When omitted,
|
|
150
|
-
*
|
|
177
|
+
* fixed mount path of a named Docker volume). When omitted, and the
|
|
178
|
+
* `NODE_RED_CLI_DEFAULT_USERDIR` environment variable points at an existing
|
|
179
|
+
* directory (see `resolveDefaultUserDir`), that directory is used instead —
|
|
180
|
+
* also treated as persistent and never removed afterward, letting a Docker
|
|
181
|
+
* image's own pre-populated default userDir be discovered automatically
|
|
182
|
+
* (see #31). Otherwise an ephemeral tmpdir is created and removed again
|
|
183
|
+
* after the call.
|
|
151
184
|
*/
|
|
152
185
|
async function runFlowInvocation({ flow, flowFile, msg, options }) {
|
|
153
186
|
const {
|
|
@@ -160,7 +193,10 @@ async function runFlowInvocation({ flow, flowFile, msg, options }) {
|
|
|
160
193
|
} = options;
|
|
161
194
|
|
|
162
195
|
const persistentUserDir = Boolean(fixedUserDir);
|
|
163
|
-
const
|
|
196
|
+
const imageDefaultUserDir = !persistentUserDir ? resolveDefaultUserDir() : undefined;
|
|
197
|
+
const userDir =
|
|
198
|
+
fixedUserDir || imageDefaultUserDir || fs.mkdtempSync(path.join(os.tmpdir(), "node-red-cli-"));
|
|
199
|
+
const managedUserDir = !persistentUserDir && !imageDefaultUserDir;
|
|
164
200
|
|
|
165
201
|
try {
|
|
166
202
|
if (nodeModules.length > 0) {
|
|
@@ -194,8 +230,8 @@ async function runFlowInvocation({ flow, flowFile, msg, options }) {
|
|
|
194
230
|
await RED.stop();
|
|
195
231
|
}
|
|
196
232
|
} finally {
|
|
197
|
-
if (
|
|
233
|
+
if (managedUserDir) fs.rmSync(userDir, { recursive: true, force: true });
|
|
198
234
|
}
|
|
199
235
|
}
|
|
200
236
|
|
|
201
|
-
module.exports = { runFlowInvocation, stderrLogHandler };
|
|
237
|
+
module.exports = { runFlowInvocation, stderrLogHandler, resolveDefaultUserDir };
|