nodepick-cli 0.1.1__tar.gz → 0.1.2__tar.gz
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.
- {nodepick_cli-0.1.1 → nodepick_cli-0.1.2}/PKG-INFO +5 -56
- {nodepick_cli-0.1.1 → nodepick_cli-0.1.2}/README.md +3 -54
- {nodepick_cli-0.1.1 → nodepick_cli-0.1.2}/install.sh +83 -21
- {nodepick_cli-0.1.1 → nodepick_cli-0.1.2}/pyproject.toml +2 -2
- {nodepick_cli-0.1.1 → nodepick_cli-0.1.2}/src/nodepick_cli/auth/login.py +30 -16
- {nodepick_cli-0.1.1 → nodepick_cli-0.1.2}/test_cli.py +23 -6
- {nodepick_cli-0.1.1 → nodepick_cli-0.1.2}/uv.lock +4 -4
- {nodepick_cli-0.1.1 → nodepick_cli-0.1.2}/.gitignore +0 -0
- {nodepick_cli-0.1.1 → nodepick_cli-0.1.2}/CHANGELOG.md +0 -0
- {nodepick_cli-0.1.1 → nodepick_cli-0.1.2}/src/nodepick_cli/__init__.py +0 -0
- {nodepick_cli-0.1.1 → nodepick_cli-0.1.2}/src/nodepick_cli/auth/__init__.py +0 -0
- {nodepick_cli-0.1.1 → nodepick_cli-0.1.2}/src/nodepick_cli/commands/__init__.py +0 -0
- {nodepick_cli-0.1.1 → nodepick_cli-0.1.2}/src/nodepick_cli/commands/ai.py +0 -0
- {nodepick_cli-0.1.1 → nodepick_cli-0.1.2}/src/nodepick_cli/commands/node.py +0 -0
- {nodepick_cli-0.1.1 → nodepick_cli-0.1.2}/src/nodepick_cli/commands/ssh.py +0 -0
- {nodepick_cli-0.1.1 → nodepick_cli-0.1.2}/src/nodepick_cli/core/__init__.py +0 -0
- {nodepick_cli-0.1.1 → nodepick_cli-0.1.2}/src/nodepick_cli/core/config.py +0 -0
- {nodepick_cli-0.1.1 → nodepick_cli-0.1.2}/src/nodepick_cli/core/exceptions.py +0 -0
- {nodepick_cli-0.1.1 → nodepick_cli-0.1.2}/src/nodepick_cli/core/formatters.py +0 -0
- {nodepick_cli-0.1.1 → nodepick_cli-0.1.2}/src/nodepick_cli/main.py +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: nodepick-cli
|
|
3
|
-
Version: 0.1.
|
|
4
|
-
Summary: CLI
|
|
3
|
+
Version: 0.1.2
|
|
4
|
+
Summary: Official Python CLI for nodepick.ai
|
|
5
5
|
Requires-Python: >=3.10
|
|
6
6
|
Requires-Dist: httpx>=0.24.0
|
|
7
7
|
Requires-Dist: keyring>=25.0.0
|
|
@@ -22,7 +22,7 @@ Description-Content-Type: text/markdown
|
|
|
22
22
|
# Install using auto-detection (uv -> pipx -> pip)
|
|
23
23
|
curl -sSL https://raw.githubusercontent.com/nodepick/developer/main/cli/install.sh | bash
|
|
24
24
|
|
|
25
|
-
# Install latest from Git repo
|
|
25
|
+
# Install latest from a local Git repo
|
|
26
26
|
curl -sSL https://raw.githubusercontent.com/nodepick/developer/main/cli/install.sh | bash -s -- --mode git
|
|
27
27
|
```
|
|
28
28
|
|
|
@@ -57,9 +57,9 @@ pip install -e ../sdk/python .
|
|
|
57
57
|
```
|
|
58
58
|
|
|
59
59
|
|
|
60
|
-
##
|
|
60
|
+
## Reference
|
|
61
61
|
|
|
62
|
-
[`
|
|
62
|
+
Check the official [`Documentation`](https://docs.nodepick.ai/cli-reference/overview) for the comprehensive reference guide.
|
|
63
63
|
|
|
64
64
|
|
|
65
65
|
### Basic Usage
|
|
@@ -81,54 +81,3 @@ np auth test
|
|
|
81
81
|
# Clear stored API key from OS keyring
|
|
82
82
|
np auth clear
|
|
83
83
|
```
|
|
84
|
-
|
|
85
|
-
### SSH Key Management
|
|
86
|
-
|
|
87
|
-
```bash
|
|
88
|
-
# Register an SSH public key from a file
|
|
89
|
-
np ssh add -n "MBA 2026" --file ~/.ssh/id_ed25519.pub
|
|
90
|
-
|
|
91
|
-
# Register an SSH public key directly
|
|
92
|
-
np ssh add -n "Desktop" --key "ssh-ed25519 AAAAC3... user@host"
|
|
93
|
-
|
|
94
|
-
# List registered SSH keys
|
|
95
|
-
np ssh list
|
|
96
|
-
|
|
97
|
-
# Delete an SSH key by ID
|
|
98
|
-
np ssh delete <key_id>
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
### Compute Nodes
|
|
102
|
-
|
|
103
|
-
```bash
|
|
104
|
-
# List all compute nodes
|
|
105
|
-
np node list
|
|
106
|
-
|
|
107
|
-
# Create a new compute node
|
|
108
|
-
np node create --name "my-sandbox" --cpu 2 --memory 2048
|
|
109
|
-
|
|
110
|
-
# Get details & connection info for a node
|
|
111
|
-
np node get <node_id>
|
|
112
|
-
|
|
113
|
-
# Reboot a node
|
|
114
|
-
np node reboot <node_id>
|
|
115
|
-
|
|
116
|
-
# Shutdown a node
|
|
117
|
-
np node shutdown <node_id>
|
|
118
|
-
|
|
119
|
-
# Delete a node
|
|
120
|
-
np node delete <node_id>
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
### [BETA] AI & Model Context Protocol (MCP)
|
|
124
|
-
|
|
125
|
-
```bash
|
|
126
|
-
# Configure Antigravity to connect to a specific node MCP server over HTTP Stream
|
|
127
|
-
np ai mcp configure antigravity dev
|
|
128
|
-
|
|
129
|
-
# Configure Antigravity to connect to multiple nodes
|
|
130
|
-
np ai mcp configure antigravity dev prod
|
|
131
|
-
|
|
132
|
-
# Configure Antigravity for all available compute nodes
|
|
133
|
-
np ai mcp configure antigravity
|
|
134
|
-
```
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
# Install using auto-detection (uv -> pipx -> pip)
|
|
11
11
|
curl -sSL https://raw.githubusercontent.com/nodepick/developer/main/cli/install.sh | bash
|
|
12
12
|
|
|
13
|
-
# Install latest from Git repo
|
|
13
|
+
# Install latest from a local Git repo
|
|
14
14
|
curl -sSL https://raw.githubusercontent.com/nodepick/developer/main/cli/install.sh | bash -s -- --mode git
|
|
15
15
|
```
|
|
16
16
|
|
|
@@ -45,9 +45,9 @@ pip install -e ../sdk/python .
|
|
|
45
45
|
```
|
|
46
46
|
|
|
47
47
|
|
|
48
|
-
##
|
|
48
|
+
## Reference
|
|
49
49
|
|
|
50
|
-
[`
|
|
50
|
+
Check the official [`Documentation`](https://docs.nodepick.ai/cli-reference/overview) for the comprehensive reference guide.
|
|
51
51
|
|
|
52
52
|
|
|
53
53
|
### Basic Usage
|
|
@@ -69,54 +69,3 @@ np auth test
|
|
|
69
69
|
# Clear stored API key from OS keyring
|
|
70
70
|
np auth clear
|
|
71
71
|
```
|
|
72
|
-
|
|
73
|
-
### SSH Key Management
|
|
74
|
-
|
|
75
|
-
```bash
|
|
76
|
-
# Register an SSH public key from a file
|
|
77
|
-
np ssh add -n "MBA 2026" --file ~/.ssh/id_ed25519.pub
|
|
78
|
-
|
|
79
|
-
# Register an SSH public key directly
|
|
80
|
-
np ssh add -n "Desktop" --key "ssh-ed25519 AAAAC3... user@host"
|
|
81
|
-
|
|
82
|
-
# List registered SSH keys
|
|
83
|
-
np ssh list
|
|
84
|
-
|
|
85
|
-
# Delete an SSH key by ID
|
|
86
|
-
np ssh delete <key_id>
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
### Compute Nodes
|
|
90
|
-
|
|
91
|
-
```bash
|
|
92
|
-
# List all compute nodes
|
|
93
|
-
np node list
|
|
94
|
-
|
|
95
|
-
# Create a new compute node
|
|
96
|
-
np node create --name "my-sandbox" --cpu 2 --memory 2048
|
|
97
|
-
|
|
98
|
-
# Get details & connection info for a node
|
|
99
|
-
np node get <node_id>
|
|
100
|
-
|
|
101
|
-
# Reboot a node
|
|
102
|
-
np node reboot <node_id>
|
|
103
|
-
|
|
104
|
-
# Shutdown a node
|
|
105
|
-
np node shutdown <node_id>
|
|
106
|
-
|
|
107
|
-
# Delete a node
|
|
108
|
-
np node delete <node_id>
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
### [BETA] AI & Model Context Protocol (MCP)
|
|
112
|
-
|
|
113
|
-
```bash
|
|
114
|
-
# Configure Antigravity to connect to a specific node MCP server over HTTP Stream
|
|
115
|
-
np ai mcp configure antigravity dev
|
|
116
|
-
|
|
117
|
-
# Configure Antigravity to connect to multiple nodes
|
|
118
|
-
np ai mcp configure antigravity dev prod
|
|
119
|
-
|
|
120
|
-
# Configure Antigravity for all available compute nodes
|
|
121
|
-
np ai mcp configure antigravity
|
|
122
|
-
```
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
set -eo pipefail
|
|
3
3
|
|
|
4
|
-
VERSION="0.
|
|
4
|
+
VERSION="0.1.1"
|
|
5
5
|
PACKAGE_NAME="nodepick-cli"
|
|
6
6
|
SDK_PACKAGE_NAME="nodepick"
|
|
7
7
|
GIT_URL="git+https://github.com/nodepick/developer#subdirectory=cli"
|
|
@@ -111,15 +111,26 @@ log_success() {
|
|
|
111
111
|
fi
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
+
log_warn() {
|
|
115
|
+
if [[ "$QUIET" == "false" ]]; then
|
|
116
|
+
echo -e "\033[33m!\033[0m $1" >&2
|
|
117
|
+
fi
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
log_error() {
|
|
121
|
+
echo -e "\033[31m✖\033[0m $1" >&2
|
|
122
|
+
}
|
|
123
|
+
|
|
114
124
|
run_cmd() {
|
|
115
125
|
if [[ "$DRY_RUN" == "true" ]]; then
|
|
116
126
|
log "[dry-run] Would execute: $*"
|
|
127
|
+
return 0
|
|
128
|
+
fi
|
|
129
|
+
|
|
130
|
+
if [[ "$QUIET" == "true" ]]; then
|
|
131
|
+
"$@" >/dev/null 2>&1
|
|
117
132
|
else
|
|
118
|
-
|
|
119
|
-
"$@" >/dev/null 2>&1
|
|
120
|
-
else
|
|
121
|
-
"$@"
|
|
122
|
-
fi
|
|
133
|
+
"$@"
|
|
123
134
|
fi
|
|
124
135
|
}
|
|
125
136
|
|
|
@@ -128,11 +139,19 @@ install_uv() {
|
|
|
128
139
|
if command -v uv >/dev/null 2>&1; then
|
|
129
140
|
log "Found uv: $(command -v uv)"
|
|
130
141
|
log_step "Installing ${PACKAGE_NAME} via 'uv tool'..."
|
|
131
|
-
run_cmd uv tool install "${PACKAGE_NAME}" --with "${SDK_PACKAGE_NAME}"
|
|
132
|
-
|
|
142
|
+
if run_cmd uv tool install "${PACKAGE_NAME}" --with "${SDK_PACKAGE_NAME}"; then
|
|
143
|
+
log_success "Successfully installed ${PACKAGE_NAME} using uv tool."
|
|
144
|
+
return 0
|
|
145
|
+
else
|
|
146
|
+
log_error "Failed to install ${PACKAGE_NAME} using uv tool."
|
|
147
|
+
if [[ "$MODE" == "uv" ]]; then
|
|
148
|
+
exit 1
|
|
149
|
+
fi
|
|
150
|
+
return 1
|
|
151
|
+
fi
|
|
133
152
|
else
|
|
134
153
|
if [[ "$MODE" == "uv" ]]; then
|
|
135
|
-
|
|
154
|
+
log_error "'uv' binary not found in PATH."
|
|
136
155
|
echo "Please install uv (https://github.com/astral-sh/uv) or run with '--mode auto'." >&2
|
|
137
156
|
exit 1
|
|
138
157
|
fi
|
|
@@ -145,11 +164,19 @@ install_pipx() {
|
|
|
145
164
|
if command -v pipx >/dev/null 2>&1; then
|
|
146
165
|
log "Found pipx: $(command -v pipx)"
|
|
147
166
|
log_step "Installing ${PACKAGE_NAME} via 'pipx'..."
|
|
148
|
-
run_cmd pipx install "${PACKAGE_NAME}"
|
|
149
|
-
|
|
167
|
+
if run_cmd pipx install "${PACKAGE_NAME}"; then
|
|
168
|
+
log_success "Successfully installed ${PACKAGE_NAME} using pipx."
|
|
169
|
+
return 0
|
|
170
|
+
else
|
|
171
|
+
log_error "Failed to install ${PACKAGE_NAME} using pipx."
|
|
172
|
+
if [[ "$MODE" == "pipx" ]]; then
|
|
173
|
+
exit 1
|
|
174
|
+
fi
|
|
175
|
+
return 1
|
|
176
|
+
fi
|
|
150
177
|
else
|
|
151
178
|
if [[ "$MODE" == "pipx" ]]; then
|
|
152
|
-
|
|
179
|
+
log_error "'pipx' binary not found in PATH."
|
|
153
180
|
echo "Please install pipx or run with '--mode auto'." >&2
|
|
154
181
|
exit 1
|
|
155
182
|
fi
|
|
@@ -166,36 +193,60 @@ install_pip() {
|
|
|
166
193
|
python_bin="python"
|
|
167
194
|
else
|
|
168
195
|
if [[ "$MODE" == "pip" ]]; then
|
|
169
|
-
|
|
196
|
+
log_error "Neither python3 nor python found in PATH."
|
|
170
197
|
exit 1
|
|
171
198
|
fi
|
|
172
199
|
return 1
|
|
173
200
|
fi
|
|
174
201
|
|
|
175
202
|
log "Using Python: $($python_bin --version 2>&1)"
|
|
203
|
+
|
|
204
|
+
if ! "$python_bin" -m pip --version >/dev/null 2>&1; then
|
|
205
|
+
if [[ "$MODE" == "pip" ]]; then
|
|
206
|
+
log_error "No module named pip found for $python_bin."
|
|
207
|
+
echo "Please install pip (e.g. 'sudo apt install python3-pip' or 'python3 -m ensurepip') or install uv." >&2
|
|
208
|
+
exit 1
|
|
209
|
+
fi
|
|
210
|
+
return 1
|
|
211
|
+
fi
|
|
212
|
+
|
|
176
213
|
log_step "Installing ${PACKAGE_NAME} via pip..."
|
|
177
|
-
run_cmd "$python_bin" -m pip install --upgrade "${PACKAGE_NAME}"
|
|
178
|
-
|
|
214
|
+
if run_cmd "$python_bin" -m pip install --upgrade "${PACKAGE_NAME}"; then
|
|
215
|
+
log_success "Successfully installed ${PACKAGE_NAME} using pip."
|
|
216
|
+
return 0
|
|
217
|
+
else
|
|
218
|
+
log_error "Failed to install ${PACKAGE_NAME} using pip."
|
|
219
|
+
if [[ "$MODE" == "pip" ]]; then
|
|
220
|
+
exit 1
|
|
221
|
+
fi
|
|
222
|
+
return 1
|
|
223
|
+
fi
|
|
179
224
|
}
|
|
180
225
|
|
|
181
226
|
install_git() {
|
|
182
227
|
log_step "Checking for 'uv' and 'git'..."
|
|
183
228
|
if ! command -v uv >/dev/null 2>&1; then
|
|
184
|
-
|
|
229
|
+
log_error "'uv' binary not found in PATH."
|
|
185
230
|
echo "Please install uv (https://github.com/astral-sh/uv)." >&2
|
|
186
231
|
exit 1
|
|
187
232
|
fi
|
|
188
233
|
|
|
189
234
|
if ! command -v git >/dev/null 2>&1; then
|
|
190
|
-
|
|
235
|
+
log_error "'git' binary not found in PATH."
|
|
236
|
+
echo "Please install git." >&2
|
|
191
237
|
exit 1
|
|
192
238
|
fi
|
|
193
239
|
|
|
194
240
|
log "Found uv: $(command -v uv)"
|
|
195
241
|
log "Found git: $(command -v git)"
|
|
196
242
|
log_step "Installing ${PACKAGE_NAME} from Git repository via uv tool (${GIT_URL})..."
|
|
197
|
-
run_cmd uv tool install "${GIT_URL}" --with "${GIT_URL_SDK}"
|
|
198
|
-
|
|
243
|
+
if run_cmd uv tool install "${GIT_URL}" --with "${GIT_URL_SDK}"; then
|
|
244
|
+
log_success "Successfully installed ${PACKAGE_NAME} from Git repository via uv tool."
|
|
245
|
+
return 0
|
|
246
|
+
else
|
|
247
|
+
log_error "Failed to install ${PACKAGE_NAME} from Git repository."
|
|
248
|
+
exit 1
|
|
249
|
+
fi
|
|
199
250
|
}
|
|
200
251
|
|
|
201
252
|
# Main execution
|
|
@@ -226,7 +277,12 @@ case "$MODE" in
|
|
|
226
277
|
elif install_pip; then
|
|
227
278
|
:
|
|
228
279
|
else
|
|
229
|
-
|
|
280
|
+
log_error "Could not install ${PACKAGE_NAME} via uv, pipx, or pip."
|
|
281
|
+
echo "" >&2
|
|
282
|
+
echo "No working package manager was found. Please do one of the following:" >&2
|
|
283
|
+
echo " 1. Install uv (recommended): curl -LsSf https://astral.sh/uv/install.sh | sh" >&2
|
|
284
|
+
echo " 2. Install pip (e.g. 'sudo apt install python3-pip')" >&2
|
|
285
|
+
echo " 3. Install pipx" >&2
|
|
230
286
|
exit 1
|
|
231
287
|
fi
|
|
232
288
|
;;
|
|
@@ -235,5 +291,11 @@ esac
|
|
|
235
291
|
if [[ "$DRY_RUN" == "false" ]]; then
|
|
236
292
|
log ""
|
|
237
293
|
log_success "nodepick.ai CLI installation process completed!"
|
|
238
|
-
|
|
294
|
+
if ! command -v np >/dev/null 2>&1; then
|
|
295
|
+
log_warn "'np' command was not found in your current PATH."
|
|
296
|
+
log_warn "You may need to add '~/.local/bin' to your PATH:"
|
|
297
|
+
log_warn " export PATH=\"\$HOME/.local/bin:\$PATH\""
|
|
298
|
+
else
|
|
299
|
+
log "Run 'np --help' to verify the installation."
|
|
300
|
+
fi
|
|
239
301
|
fi
|
|
@@ -4,8 +4,8 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "nodepick-cli"
|
|
7
|
-
version = "0.1.
|
|
8
|
-
description = "CLI
|
|
7
|
+
version = "0.1.2"
|
|
8
|
+
description = "Official Python CLI for nodepick.ai"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
11
11
|
dependencies = [
|
|
@@ -56,30 +56,30 @@ def auth_clear():
|
|
|
56
56
|
|
|
57
57
|
|
|
58
58
|
@app.command("configure")
|
|
59
|
-
@app.command("save")
|
|
60
59
|
def auth_configure(
|
|
61
|
-
api_key: Optional[str] = typer.Option(
|
|
62
|
-
None, "--api-key", "-k", help="Nodepick API key / bearer token"
|
|
63
|
-
),
|
|
64
60
|
base_url: Optional[str] = typer.Option(
|
|
65
61
|
None, "--base-url", "-u", help="API base URL (default: https://api.nodepick.ai)"
|
|
66
62
|
),
|
|
67
63
|
):
|
|
68
64
|
"""Configure API key (and optional base URL) securely in the OS keyring."""
|
|
69
65
|
try:
|
|
70
|
-
|
|
71
|
-
|
|
66
|
+
api_key = typer.prompt("API Key", default="", hide_input=True, show_default=False)
|
|
67
|
+
if not api_key or not api_key.strip():
|
|
68
|
+
console.print("[yellow]No API key entered. Aborting.[/yellow]")
|
|
69
|
+
raise typer.Exit(1)
|
|
72
70
|
|
|
73
71
|
resolved_url = (base_url or get_base_url()).rstrip("/")
|
|
74
72
|
|
|
75
|
-
_keyring_set(KEYRING_API_KEY, api_key)
|
|
73
|
+
_keyring_set(KEYRING_API_KEY, api_key.strip())
|
|
76
74
|
# Save base_url to config file; only the API key lives in the keyring.
|
|
77
75
|
save_config({"base_url": resolved_url})
|
|
78
76
|
|
|
79
77
|
console.print(
|
|
80
78
|
"[bold green]Credentials configured.[/bold green] "
|
|
81
|
-
f"API key stored in OS keyring. Base URL: {resolved_url}
|
|
79
|
+
f"API key stored in OS keyring. Base URL: {resolved_url}"
|
|
82
80
|
)
|
|
81
|
+
except typer.Exit:
|
|
82
|
+
raise
|
|
83
83
|
except Exception as e:
|
|
84
84
|
handle_error(e, "Failed to configure credentials")
|
|
85
85
|
|
|
@@ -99,14 +99,28 @@ def auth_test():
|
|
|
99
99
|
try:
|
|
100
100
|
client = nodepick.NodePickClient(api_key=key, base_url=url)
|
|
101
101
|
user_info = client.get_me()
|
|
102
|
-
user = user_info.get("user", {})
|
|
103
|
-
org = user_info.get("org", {})
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
102
|
+
user = user_info.get("user", {}) if isinstance(user_info.get("user"), dict) else {}
|
|
103
|
+
org = user_info.get("org", {}) if isinstance(user_info.get("org"), dict) else {}
|
|
104
|
+
|
|
105
|
+
user_id = (
|
|
106
|
+
user.get("id")
|
|
107
|
+
or user.get("userId")
|
|
108
|
+
or user_info.get("userId")
|
|
109
|
+
or user_info.get("user_id")
|
|
110
|
+
or user.get("email")
|
|
111
|
+
or "unknown"
|
|
110
112
|
)
|
|
113
|
+
org_id = (
|
|
114
|
+
org.get("id")
|
|
115
|
+
or org.get("orgId")
|
|
116
|
+
or user_info.get("orgId")
|
|
117
|
+
or user_info.get("org_id")
|
|
118
|
+
or "unknown"
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
console.print("[bold green]API access OK[/bold green]")
|
|
122
|
+
console.print(f"API URL: {url}")
|
|
123
|
+
console.print(f"User: {user_id}")
|
|
124
|
+
console.print(f"Organization: {org_id}")
|
|
111
125
|
except Exception as e:
|
|
112
126
|
handle_error(e, "API access test failed")
|
|
@@ -5,6 +5,7 @@ sys.path.insert(0, str(Path(__file__).parent / "src"))
|
|
|
5
5
|
|
|
6
6
|
from typer.testing import CliRunner
|
|
7
7
|
from nodepick_cli.main import app
|
|
8
|
+
from nodepick_cli import __version__
|
|
8
9
|
|
|
9
10
|
runner = CliRunner()
|
|
10
11
|
|
|
@@ -19,12 +20,12 @@ class TestCliCommands(unittest.TestCase):
|
|
|
19
20
|
def test_version(self):
|
|
20
21
|
result = runner.invoke(app, ["--version"])
|
|
21
22
|
self.assertEqual(result.exit_code, 0)
|
|
22
|
-
self.assertIn("nodepick CLI version
|
|
23
|
+
self.assertIn(f"nodepick CLI version {__version__}", result.output)
|
|
23
24
|
|
|
24
25
|
def test_version_short(self):
|
|
25
26
|
result = runner.invoke(app, ["-v"])
|
|
26
27
|
self.assertEqual(result.exit_code, 0)
|
|
27
|
-
self.assertIn("nodepick CLI version
|
|
28
|
+
self.assertIn(f"nodepick CLI version {__version__}", result.output)
|
|
28
29
|
|
|
29
30
|
def test_node_help(self):
|
|
30
31
|
result = runner.invoke(app, ["node", "--help"])
|
|
@@ -67,10 +68,26 @@ class TestCliCommands(unittest.TestCase):
|
|
|
67
68
|
self.assertEqual(result.exit_code, 0)
|
|
68
69
|
self.assertIn("Test API access", result.output)
|
|
69
70
|
|
|
70
|
-
def
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
71
|
+
def test_auth_test_success(self):
|
|
72
|
+
from unittest.mock import patch, MagicMock
|
|
73
|
+
mock_client = MagicMock()
|
|
74
|
+
mock_client.get_me.return_value = {
|
|
75
|
+
"user": {"id": "user-123", "email": "anil@nodepick.ai"},
|
|
76
|
+
"org": {"id": "org-456", "name": "anilj's Org"}
|
|
77
|
+
}
|
|
78
|
+
with patch("nodepick_cli.auth.login._get_api_key_with_source", return_value=("test-key", "env var")), \
|
|
79
|
+
patch("nodepick.NodePickClient", return_value=mock_client):
|
|
80
|
+
result = runner.invoke(app, ["auth", "test"])
|
|
81
|
+
self.assertEqual(result.exit_code, 0)
|
|
82
|
+
self.assertIn("API access OK", result.output)
|
|
83
|
+
self.assertIn("API URL: https://api.nodepick.ai", result.output)
|
|
84
|
+
self.assertIn("User: user-123", result.output)
|
|
85
|
+
self.assertIn("Organization: org-456", result.output)
|
|
86
|
+
|
|
87
|
+
def test_auth_configure_no_api_key_flag(self):
|
|
88
|
+
result = runner.invoke(app, ["auth", "configure", "--api-key", "secret123"])
|
|
89
|
+
self.assertNotEqual(result.exit_code, 0)
|
|
90
|
+
self.assertIn("No such option", result.output)
|
|
74
91
|
|
|
75
92
|
def test_ai_help(self):
|
|
76
93
|
result = runner.invoke(app, ["--help"])
|
|
@@ -259,7 +259,7 @@ name = "exceptiongroup"
|
|
|
259
259
|
version = "1.3.1"
|
|
260
260
|
source = { registry = "https://pypi.org/simple" }
|
|
261
261
|
dependencies = [
|
|
262
|
-
{ name = "typing-extensions", marker = "python_full_version < '3.
|
|
262
|
+
{ name = "typing-extensions", marker = "python_full_version < '3.11'" },
|
|
263
263
|
]
|
|
264
264
|
sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" }
|
|
265
265
|
wheels = [
|
|
@@ -346,7 +346,7 @@ name = "importlib-metadata"
|
|
|
346
346
|
version = "9.0.0"
|
|
347
347
|
source = { registry = "https://pypi.org/simple" }
|
|
348
348
|
dependencies = [
|
|
349
|
-
{ name = "zipp" },
|
|
349
|
+
{ name = "zipp", marker = "python_full_version < '3.14'" },
|
|
350
350
|
]
|
|
351
351
|
sdist = { url = "https://files.pythonhosted.org/packages/a9/01/15bb152d77b21318514a96f43af312635eb2500c96b55398d020c93d86ea/importlib_metadata-9.0.0.tar.gz", hash = "sha256:a4f57ab599e6a2e3016d7595cfd72eb4661a5106e787a95bcc90c7105b831efc", size = 56405, upload-time = "2026-03-20T06:42:56.999Z" }
|
|
352
352
|
wheels = [
|
|
@@ -514,7 +514,7 @@ wheels = [
|
|
|
514
514
|
|
|
515
515
|
[[package]]
|
|
516
516
|
name = "nodepick"
|
|
517
|
-
version = "0.1.
|
|
517
|
+
version = "0.1.1"
|
|
518
518
|
source = { directory = "../sdk/python" }
|
|
519
519
|
dependencies = [
|
|
520
520
|
{ name = "httpx" },
|
|
@@ -529,7 +529,7 @@ requires-dist = [
|
|
|
529
529
|
|
|
530
530
|
[[package]]
|
|
531
531
|
name = "nodepick-cli"
|
|
532
|
-
version = "0.1.
|
|
532
|
+
version = "0.1.2"
|
|
533
533
|
source = { editable = "." }
|
|
534
534
|
dependencies = [
|
|
535
535
|
{ name = "httpx" },
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|