Skip to content
Closed
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
24 changes: 22 additions & 2 deletions scripts/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2885,7 +2885,16 @@ validate_station_deepseek_override() {
error "--station-deepseek cannot be combined with NEMOCLAW_NO_EXPRESS=1. Remove one override."
fi
if [ "${NON_INTERACTIVE:-}" = "1" ]; then
error "--station-deepseek selects the DGX Station express prompt and cannot be combined with --non-interactive."
# #7009: name what actually put the run in non-interactive mode so the user
# can act on it. NON_INTERACTIVE_SOURCE is recorded in main() where the
# origin is still known (main exports NON_INTERACTIVE into
# NEMOCLAW_NON_INTERACTIVE, erasing the distinction here). Omit the clause
# for direct callers that set NON_INTERACTIVE without going through main.
local trigger_note=""
if [ -n "${NON_INTERACTIVE_SOURCE:-}" ]; then
trigger_note=" (triggered by: ${NON_INTERACTIVE_SOURCE})"
fi
error "--station-deepseek selects the DGX Station express prompt and cannot be combined with non-interactive mode${trigger_note}."
fi
if [ -n "${NEMOCLAW_PROVIDER:-}" ]; then
error "--station-deepseek conflicts with NEMOCLAW_PROVIDER=${NEMOCLAW_PROVIDER}. Remove the provider override to use Station express install."
Expand Down Expand Up @@ -3099,12 +3108,20 @@ main() {

# Parse flags
NON_INTERACTIVE=""
# #7009: record what put the run in non-interactive mode so conflict errors
# (e.g. validate_station_deepseek_override) can name the trigger. main()
# exports NON_INTERACTIVE into NEMOCLAW_NON_INTERACTIVE below, so the origin
# cannot be recovered from the env at error time — track it here instead.
NON_INTERACTIVE_SOURCE=""
ACCEPT_THIRD_PARTY_SOFTWARE=""
FRESH=""
STATION_DEEPSEEK=""
for arg in "$@"; do
case "$arg" in
--non-interactive) NON_INTERACTIVE=1 ;;
--non-interactive)
NON_INTERACTIVE=1
NON_INTERACTIVE_SOURCE="the --non-interactive flag"
;;
--yes-i-accept-third-party-software) ACCEPT_THIRD_PARTY_SOFTWARE=1 ;;
--fresh) FRESH=1 ;;
--station-deepseek) STATION_DEEPSEEK=1 ;;
Expand All @@ -3126,6 +3143,9 @@ main() {
done
# Also honor env var
NON_INTERACTIVE="${NON_INTERACTIVE:-${NEMOCLAW_NON_INTERACTIVE:-}}"
if [ "${NON_INTERACTIVE:-}" = "1" ] && [ -z "${NON_INTERACTIVE_SOURCE:-}" ]; then
NON_INTERACTIVE_SOURCE="NEMOCLAW_NON_INTERACTIVE=1"
fi
ACCEPT_THIRD_PARTY_SOFTWARE="${ACCEPT_THIRD_PARTY_SOFTWARE:-${NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE:-}}"
FRESH="${FRESH:-${NEMOCLAW_FRESH:-}}"

Expand Down
14 changes: 11 additions & 3 deletions test/install-express-prompt.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -296,12 +296,20 @@ detect_express_platform
message: /--station-deepseek requires a detected DGX Station \(detected: DGX Spark\)/,
},
{
name: "a conflicting non-interactive flag",
name: "a conflicting non-interactive flag (names the flag as the trigger)",
args: ["--station-deepseek", "--non-interactive"],
platform: "DGX Station",
env: {},
message:
/--station-deepseek selects the DGX Station express prompt and cannot be combined with --non-interactive/,
/--station-deepseek selects the DGX Station express prompt and cannot be combined with non-interactive mode \(triggered by: the --non-interactive flag\)/,
},
{
name: "a conflicting NEMOCLAW_NON_INTERACTIVE env var (names the env var as the trigger)",
args: ["--station-deepseek"],
platform: "DGX Station",
env: { NEMOCLAW_NON_INTERACTIVE: "1" },
message:
/--station-deepseek selects the DGX Station express prompt and cannot be combined with non-interactive mode \(triggered by: NEMOCLAW_NON_INTERACTIVE=1\)/,
},
{
name: "a conflicting Station model",
Expand Down Expand Up @@ -358,7 +366,7 @@ main "$@"

it.each([
["NEMOCLAW_NO_EXPRESS", "1", /cannot be combined with NEMOCLAW_NO_EXPRESS=1/],
["NON_INTERACTIVE", "1", /cannot be combined with --non-interactive/],
["NON_INTERACTIVE", "1", /cannot be combined with non-interactive mode/],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Make the fallback assertion prove that no trigger is included.

The current unanchored regex matches both the generic message and a message containing (triggered by: ...). Anchor the expected ending or assert the complete message so this test protects the direct-caller fallback contract.

Suggested fix
-    ["NON_INTERACTIVE", "1", /cannot be combined with non-interactive mode/],
+    ["NON_INTERACTIVE", "1", /cannot be combined with non-interactive mode\.$/],
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
["NON_INTERACTIVE", "1", /cannot be combined with non-interactive mode/],
["NON_INTERACTIVE", "1", /cannot be combined with non-interactive mode\.$/],
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/install-express-prompt.test.ts` at line 369, Strengthen the fallback
assertion in the NON_INTERACTIVE case of the install-express prompt test by
anchoring the expected message ending or matching the complete message, ensuring
it cannot match text containing a “(triggered by: …)” suffix. Preserve the
test’s validation of the direct-caller fallback contract.

Source: Path instructions

["NEMOCLAW_PROVIDER", "install-vllm", /conflicts with NEMOCLAW_PROVIDER=install-vllm/],
])("rejects %s when the Station demo override would otherwise be ignored", (name, value, message) => {
const result = runExpressPromptWithTty("\n", "pipe", "DGX Station", {
Expand Down
Loading