griptape_nodes 0.26.4__py3-none-any.whl
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.
- griptape_nodes/__init__.py +446 -0
- griptape_nodes/app/.python-version +1 -0
- griptape_nodes/app/__init__.py +5 -0
- griptape_nodes/app/app.py +400 -0
- griptape_nodes/app/nodes_api_socket_manager.py +115 -0
- griptape_nodes/exe_types/__init__.py +1 -0
- griptape_nodes/exe_types/connections.py +214 -0
- griptape_nodes/exe_types/core_types.py +1304 -0
- griptape_nodes/exe_types/flow.py +443 -0
- griptape_nodes/exe_types/node_types.py +609 -0
- griptape_nodes/exe_types/type_validator.py +35 -0
- griptape_nodes/machines/__init__.py +1 -0
- griptape_nodes/machines/control_flow.py +209 -0
- griptape_nodes/machines/fsm.py +55 -0
- griptape_nodes/machines/node_resolution.py +453 -0
- griptape_nodes/node_library/__init__.py +1 -0
- griptape_nodes/node_library/library_registry.py +222 -0
- griptape_nodes/node_library/workflow_registry.py +111 -0
- griptape_nodes/py.typed +0 -0
- griptape_nodes/retained_mode/__init__.py +1 -0
- griptape_nodes/retained_mode/events/__init__.py +1 -0
- griptape_nodes/retained_mode/events/app_events.py +72 -0
- griptape_nodes/retained_mode/events/arbitrary_python_events.py +30 -0
- griptape_nodes/retained_mode/events/base_events.py +559 -0
- griptape_nodes/retained_mode/events/config_events.py +120 -0
- griptape_nodes/retained_mode/events/connection_events.py +90 -0
- griptape_nodes/retained_mode/events/execution_events.py +274 -0
- griptape_nodes/retained_mode/events/flow_events.py +223 -0
- griptape_nodes/retained_mode/events/generate_request_payload_schemas.py +30 -0
- griptape_nodes/retained_mode/events/library_events.py +178 -0
- griptape_nodes/retained_mode/events/logger_events.py +14 -0
- griptape_nodes/retained_mode/events/node_events.py +262 -0
- griptape_nodes/retained_mode/events/object_events.py +47 -0
- griptape_nodes/retained_mode/events/os_events.py +27 -0
- griptape_nodes/retained_mode/events/parameter_events.py +292 -0
- griptape_nodes/retained_mode/events/payload_registry.py +60 -0
- griptape_nodes/retained_mode/events/secrets_events.py +83 -0
- griptape_nodes/retained_mode/events/static_file_events.py +35 -0
- griptape_nodes/retained_mode/events/validation_events.py +53 -0
- griptape_nodes/retained_mode/events/workflow_events.py +176 -0
- griptape_nodes/retained_mode/griptape_nodes.py +538 -0
- griptape_nodes/retained_mode/managers/__init__.py +1 -0
- griptape_nodes/retained_mode/managers/arbitrary_code_exec_manager.py +36 -0
- griptape_nodes/retained_mode/managers/config_manager.py +446 -0
- griptape_nodes/retained_mode/managers/context_manager.py +401 -0
- griptape_nodes/retained_mode/managers/event_manager.py +123 -0
- griptape_nodes/retained_mode/managers/flow_manager.py +1278 -0
- griptape_nodes/retained_mode/managers/library_manager.py +872 -0
- griptape_nodes/retained_mode/managers/node_manager.py +1749 -0
- griptape_nodes/retained_mode/managers/object_manager.py +258 -0
- griptape_nodes/retained_mode/managers/operation_manager.py +463 -0
- griptape_nodes/retained_mode/managers/os_manager.py +107 -0
- griptape_nodes/retained_mode/managers/secrets_manager.py +142 -0
- griptape_nodes/retained_mode/managers/settings.py +98 -0
- griptape_nodes/retained_mode/managers/static_files_manager.py +89 -0
- griptape_nodes/retained_mode/managers/workflow_manager.py +924 -0
- griptape_nodes/retained_mode/retained_mode.py +835 -0
- griptape_nodes/traits/__init__.py +1 -0
- griptape_nodes/traits/add_param_button.py +21 -0
- griptape_nodes/traits/button.py +21 -0
- griptape_nodes/traits/clamp.py +36 -0
- griptape_nodes/traits/compare.py +20 -0
- griptape_nodes/traits/compare_images.py +41 -0
- griptape_nodes/traits/minmax.py +43 -0
- griptape_nodes/traits/options.py +34 -0
- griptape_nodes/traits/slider.py +37 -0
- griptape_nodes/traits/trait_registry.py +35 -0
- griptape_nodes/traits/traits.json +4 -0
- griptape_nodes/updater/__init__.py +69 -0
- griptape_nodes/updater/__main__.py +4 -0
- griptape_nodes/utils/__init__.py +1 -0
- griptape_nodes/utils/dict_utils.py +215 -0
- griptape_nodes-0.26.4.dist-info/METADATA +73 -0
- griptape_nodes-0.26.4.dist-info/RECORD +77 -0
- griptape_nodes-0.26.4.dist-info/WHEEL +4 -0
- griptape_nodes-0.26.4.dist-info/entry_points.txt +3 -0
- griptape_nodes-0.26.4.dist-info/licenses/LICENSE +201 -0
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
"""Griptape Nodes package."""
|
|
2
|
+
|
|
3
|
+
# ruff: noqa: S603, S607
|
|
4
|
+
import argparse
|
|
5
|
+
import importlib.metadata
|
|
6
|
+
import json
|
|
7
|
+
import shutil
|
|
8
|
+
import subprocess
|
|
9
|
+
import sys
|
|
10
|
+
import tarfile
|
|
11
|
+
import tempfile
|
|
12
|
+
import webbrowser
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
|
|
15
|
+
import httpx
|
|
16
|
+
from dotenv import load_dotenv
|
|
17
|
+
from rich.console import Console
|
|
18
|
+
from rich.panel import Panel
|
|
19
|
+
from rich.progress import Progress
|
|
20
|
+
from rich.prompt import Confirm, Prompt
|
|
21
|
+
from xdg_base_dirs import xdg_config_home, xdg_data_home
|
|
22
|
+
|
|
23
|
+
from griptape_nodes.app import start_app
|
|
24
|
+
from griptape_nodes.retained_mode.managers.config_manager import ConfigManager
|
|
25
|
+
from griptape_nodes.retained_mode.managers.os_manager import OSManager
|
|
26
|
+
from griptape_nodes.retained_mode.managers.secrets_manager import SecretsManager
|
|
27
|
+
|
|
28
|
+
CONFIG_DIR = xdg_config_home() / "griptape_nodes"
|
|
29
|
+
DATA_DIR = xdg_data_home() / "griptape_nodes"
|
|
30
|
+
ENV_FILE = CONFIG_DIR / ".env"
|
|
31
|
+
CONFIG_FILE = CONFIG_DIR / "griptape_nodes_config.json"
|
|
32
|
+
REPO_NAME = "griptape-ai/griptape-nodes"
|
|
33
|
+
NODES_APP_URL = "https://nodes.griptape.ai"
|
|
34
|
+
NODES_TARBALL_URL = "https://github.com/griptape-ai/griptape-nodes/archive/refs/tags/{tag}.tar.gz"
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
console = Console()
|
|
38
|
+
config_manager = ConfigManager()
|
|
39
|
+
secrets_manager = SecretsManager(config_manager)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def main() -> None:
|
|
43
|
+
"""Main entry point for the Griptape Nodes CLI."""
|
|
44
|
+
load_dotenv(ENV_FILE, override=True)
|
|
45
|
+
|
|
46
|
+
# Hack to make paths "just work". # noqa: FIX004
|
|
47
|
+
# Without this, packages like `nodes` don't properly import.
|
|
48
|
+
# Long term solution could be to make `nodes` a proper src-layout package
|
|
49
|
+
# but current engine relies on importing files rather than packages.
|
|
50
|
+
sys.path.append(str(Path.cwd()))
|
|
51
|
+
|
|
52
|
+
args = _get_args()
|
|
53
|
+
_process_args(args)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def _run_init(api_key: str | None = None, workspace_directory: str | None = None) -> None:
|
|
57
|
+
"""Runs through the engine init steps, optionally skipping prompts if the user provided `--api-key`."""
|
|
58
|
+
__init_system_config()
|
|
59
|
+
_prompt_for_workspace(workspace_directory)
|
|
60
|
+
_prompt_for_api_key(api_key)
|
|
61
|
+
_update_assets()
|
|
62
|
+
console.print("Initialization complete! You can now run the engine with 'griptape-nodes' (or just 'gtn').")
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _start_engine(*, no_update: bool) -> None:
|
|
66
|
+
"""Starts the Griptape Nodes engine.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
no_update: If True, skips the auto-update check.
|
|
70
|
+
"""
|
|
71
|
+
if not CONFIG_DIR.exists():
|
|
72
|
+
# Default init flow if there is no config directory
|
|
73
|
+
_run_init()
|
|
74
|
+
webbrowser.open(NODES_APP_URL)
|
|
75
|
+
|
|
76
|
+
# Confusing double negation -- If `no_update` is set, we want to skip the update
|
|
77
|
+
if not no_update:
|
|
78
|
+
_auto_update_self()
|
|
79
|
+
|
|
80
|
+
start_app()
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _get_args() -> argparse.Namespace:
|
|
84
|
+
"""Parse CLI arguments for the *griptape-nodes* entry-point."""
|
|
85
|
+
parser = argparse.ArgumentParser(
|
|
86
|
+
prog="griptape-nodes",
|
|
87
|
+
description="Griptape Nodes Engine.",
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
# Global options (apply to every command)
|
|
91
|
+
parser.add_argument(
|
|
92
|
+
"--no-update",
|
|
93
|
+
action="store_true",
|
|
94
|
+
help="Skip the auto-update check.",
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
subparsers = parser.add_subparsers(
|
|
98
|
+
dest="command",
|
|
99
|
+
metavar="COMMAND",
|
|
100
|
+
required=False,
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
init_parser = subparsers.add_parser("init", help="Initialize a workspace.")
|
|
104
|
+
init_parser.add_argument(
|
|
105
|
+
"--api-key",
|
|
106
|
+
help="Override the Griptape Nodes API key.",
|
|
107
|
+
)
|
|
108
|
+
init_parser.add_argument(
|
|
109
|
+
"--workspace-directory",
|
|
110
|
+
help="Override the Griptape Nodes workspace directory.",
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
# engine
|
|
114
|
+
subparsers.add_parser("engine", help="Run the Griptape Nodes engine.")
|
|
115
|
+
|
|
116
|
+
# config
|
|
117
|
+
config_parser = subparsers.add_parser("config", help="Manage configuration.")
|
|
118
|
+
config_subparsers = config_parser.add_subparsers(
|
|
119
|
+
dest="subcommand",
|
|
120
|
+
metavar="SUBCOMMAND",
|
|
121
|
+
required=True,
|
|
122
|
+
)
|
|
123
|
+
config_subparsers.add_parser("show", help="Show configuration values.")
|
|
124
|
+
config_subparsers.add_parser("list", help="List configuration values.")
|
|
125
|
+
config_subparsers.add_parser("reset", help="Reset configuration to defaults.")
|
|
126
|
+
|
|
127
|
+
# self
|
|
128
|
+
self_parser = subparsers.add_parser("self", help="Manage this CLI installation.")
|
|
129
|
+
self_subparsers = self_parser.add_subparsers(
|
|
130
|
+
dest="subcommand",
|
|
131
|
+
metavar="SUBCOMMAND",
|
|
132
|
+
required=True,
|
|
133
|
+
)
|
|
134
|
+
self_subparsers.add_parser("update", help="Update the CLI.")
|
|
135
|
+
self_subparsers.add_parser("uninstall", help="Uninstall the CLI.")
|
|
136
|
+
self_subparsers.add_parser("version", help="Print the CLI version.")
|
|
137
|
+
|
|
138
|
+
# assets
|
|
139
|
+
assets_parser = subparsers.add_parser("assets", help="Manage local assets (libraries, workflows, etc.).")
|
|
140
|
+
assets_subparsers = assets_parser.add_subparsers(
|
|
141
|
+
dest="subcommand",
|
|
142
|
+
metavar="SUBCOMMAND",
|
|
143
|
+
required=True,
|
|
144
|
+
)
|
|
145
|
+
assets_subparsers.add_parser("update", help="Update bundled assets.")
|
|
146
|
+
|
|
147
|
+
args = parser.parse_args()
|
|
148
|
+
|
|
149
|
+
# Default to the `engine` command when none is given.
|
|
150
|
+
if args.command is None:
|
|
151
|
+
args.command = "engine"
|
|
152
|
+
|
|
153
|
+
return args
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def _prompt_for_api_key(api_key: str | None = None) -> None:
|
|
157
|
+
"""Prompts the user for their GT_CLOUD_API_KEY unless it's provided."""
|
|
158
|
+
if api_key is None:
|
|
159
|
+
explainer = f"""[bold cyan]Griptape API Key[/bold cyan]
|
|
160
|
+
A Griptape API Key is needed to proceed.
|
|
161
|
+
This key allows the Griptape Nodes Engine to communicate with the Griptape Nodes Editor.
|
|
162
|
+
In order to get your key, return to the [link={NODES_APP_URL}]{NODES_APP_URL}[/link] tab in your browser and click the button
|
|
163
|
+
"Generate API Key".
|
|
164
|
+
Once the key is generated, copy and paste its value here to proceed."""
|
|
165
|
+
console.print(Panel(explainer, expand=False))
|
|
166
|
+
|
|
167
|
+
default_key = api_key or secrets_manager.get_secret("GT_CLOUD_API_KEY", should_error_on_not_found=False)
|
|
168
|
+
# If api_key is provided via --api-key, we don't want to prompt for it
|
|
169
|
+
current_key = api_key
|
|
170
|
+
while current_key is None:
|
|
171
|
+
current_key = Prompt.ask(
|
|
172
|
+
"Griptape API Key",
|
|
173
|
+
default=default_key,
|
|
174
|
+
show_default=True,
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
secrets_manager.set_secret("GT_CLOUD_API_KEY", current_key)
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def _prompt_for_workspace(workspace_directory_arg: str | None) -> None:
|
|
181
|
+
"""Prompts the user for their workspace directory and stores it in config directory."""
|
|
182
|
+
explainer = """[bold cyan]Workspace Directory[/bold cyan]
|
|
183
|
+
Select the workspace directory. This is the location where Griptape Nodes will store your saved workflows.
|
|
184
|
+
You may enter a custom directory or press Return to accept the default workspace directory"""
|
|
185
|
+
console.print(Panel(explainer, expand=False))
|
|
186
|
+
|
|
187
|
+
valid_workspace = False
|
|
188
|
+
default_workspace_directory = workspace_directory_arg or config_manager.get_config_value("workspace_directory")
|
|
189
|
+
while not valid_workspace:
|
|
190
|
+
try:
|
|
191
|
+
workspace_directory = Prompt.ask(
|
|
192
|
+
"Workspace Directory",
|
|
193
|
+
default=default_workspace_directory,
|
|
194
|
+
show_default=True,
|
|
195
|
+
)
|
|
196
|
+
workspace_path = Path(workspace_directory).expanduser().resolve()
|
|
197
|
+
|
|
198
|
+
config_manager.workspace_path = workspace_path
|
|
199
|
+
config_manager.set_config_value("workspace_directory", str(workspace_path))
|
|
200
|
+
|
|
201
|
+
valid_workspace = True
|
|
202
|
+
except OSError as e:
|
|
203
|
+
console.print(f"[bold red]Invalid workspace directory: {e}[/bold red]")
|
|
204
|
+
except json.JSONDecodeError as e:
|
|
205
|
+
console.print(f"[bold red]Error reading config file: {e}[/bold red]")
|
|
206
|
+
console.print(f"[bold green]Workspace directory set to: {config_manager.workspace_path}[/bold green]")
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def _get_latest_version(repo: str) -> str:
|
|
210
|
+
"""Fetches the latest release tag from a GitHub repository using httpx.
|
|
211
|
+
|
|
212
|
+
Args:
|
|
213
|
+
repo (str): Repository name in the format "owner/repo"
|
|
214
|
+
|
|
215
|
+
Returns:
|
|
216
|
+
str: Latest release tag (e.g., "v0.31.4")
|
|
217
|
+
"""
|
|
218
|
+
url = f"https://api.github.com/repos/{repo}/releases/latest"
|
|
219
|
+
with httpx.Client() as client:
|
|
220
|
+
response = client.get(url)
|
|
221
|
+
response.raise_for_status()
|
|
222
|
+
return response.json()["tag_name"]
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def _auto_update_self() -> None:
|
|
226
|
+
"""Automatically updates the script to the latest version if the user confirms."""
|
|
227
|
+
current_version = __get_current_version()
|
|
228
|
+
latest_version = _get_latest_version(REPO_NAME)
|
|
229
|
+
|
|
230
|
+
if current_version < latest_version:
|
|
231
|
+
update = Confirm.ask(
|
|
232
|
+
f"Your current engine version, {current_version}, is behind the latest release, {latest_version}. Update now?",
|
|
233
|
+
default=True,
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
_update_assets()
|
|
237
|
+
|
|
238
|
+
if update:
|
|
239
|
+
_update_self(restart_after_update=True)
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def _update_self(*, restart_after_update: bool = False) -> None:
|
|
243
|
+
"""Installs the latest release of the CLI *and* refreshes bundled assets."""
|
|
244
|
+
console.print("[bold green]Starting updater...[/bold green]")
|
|
245
|
+
|
|
246
|
+
args = ["--restart"] if restart_after_update else []
|
|
247
|
+
subprocess.Popen([sys.executable, "-m", "griptape_nodes.updater", *args], start_new_session=True)
|
|
248
|
+
|
|
249
|
+
sys.exit(0)
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
def _update_assets() -> None:
|
|
253
|
+
"""Download the release tarball identified."""
|
|
254
|
+
tag = _get_latest_version(REPO_NAME)
|
|
255
|
+
|
|
256
|
+
console.print(f"[bold cyan]Fetching Griptape Nodes assets ({tag})…[/bold cyan]")
|
|
257
|
+
|
|
258
|
+
tar_url = NODES_TARBALL_URL.format(tag=tag)
|
|
259
|
+
dest_nodes = DATA_DIR / "nodes"
|
|
260
|
+
dest_workflows = DATA_DIR / "workflows"
|
|
261
|
+
|
|
262
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
263
|
+
tar_path = Path(tmp) / "nodes.tar.gz"
|
|
264
|
+
|
|
265
|
+
# Streaming download with a tiny progress bar
|
|
266
|
+
with httpx.stream("GET", tar_url, follow_redirects=True) as r, Progress() as progress:
|
|
267
|
+
r.raise_for_status()
|
|
268
|
+
task = progress.add_task("[green]downloading…", total=int(r.headers.get("Content-Length", 0)))
|
|
269
|
+
with tar_path.open("wb") as f:
|
|
270
|
+
for chunk in r.iter_bytes():
|
|
271
|
+
f.write(chunk)
|
|
272
|
+
progress.update(task, advance=len(chunk))
|
|
273
|
+
|
|
274
|
+
# Extract and copy
|
|
275
|
+
with tarfile.open(tar_path) as tar:
|
|
276
|
+
tar.extractall(tmp, filter="data")
|
|
277
|
+
|
|
278
|
+
extracted_root = next(Path(tmp).glob("griptape-nodes-*"))
|
|
279
|
+
|
|
280
|
+
console.print("[yellow]Copying nodes directory…[/yellow]")
|
|
281
|
+
shutil.copytree(extracted_root / "nodes", dest_nodes, dirs_exist_ok=True)
|
|
282
|
+
console.print("[yellow]Copying workflows directory…[/yellow]")
|
|
283
|
+
shutil.copytree(extracted_root / "workflows", dest_workflows, dirs_exist_ok=True)
|
|
284
|
+
|
|
285
|
+
console.print("[bold green]Nodes + Workflows updated.[/bold green]")
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
def _print_current_version() -> None:
|
|
289
|
+
"""Prints the current version of the script."""
|
|
290
|
+
version = __get_current_version()
|
|
291
|
+
console.print(f"[bold green]{version}[/bold green]")
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
def _print_user_config() -> None:
|
|
295
|
+
"""Prints the user configuration from the config file."""
|
|
296
|
+
config = config_manager.user_config
|
|
297
|
+
sys.stdout.write(json.dumps(config, indent=2))
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
def _list_user_configs() -> None:
|
|
301
|
+
"""Lists user configuration files in ascending precedence."""
|
|
302
|
+
num_config_files = len(config_manager.config_files)
|
|
303
|
+
console.print(
|
|
304
|
+
f"[bold]User Configuration Files (lowest precedence (1.) ⟶ highest precedence ({num_config_files}.)):[/bold]"
|
|
305
|
+
)
|
|
306
|
+
for idx, config in enumerate(config_manager.config_files):
|
|
307
|
+
console.print(f"[green]{idx + 1}. {config}[/green]")
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
def _reset_user_config() -> None:
|
|
311
|
+
"""Resets the user configuration to the default values."""
|
|
312
|
+
console.print("[bold]Resetting user configuration to default values...[/bold]")
|
|
313
|
+
config_manager.reset_user_config()
|
|
314
|
+
console.print("[bold green]User configuration reset complete![/bold green]")
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
def _uninstall_self() -> None:
|
|
318
|
+
"""Uninstalls itself by removing config/data directories and the executable."""
|
|
319
|
+
console.print("[bold]Uninstalling Griptape Nodes...[/bold]")
|
|
320
|
+
|
|
321
|
+
# Remove config and data directories
|
|
322
|
+
dirs = [(CONFIG_DIR, "Config Dir"), (DATA_DIR, "Data Dir")]
|
|
323
|
+
for dir_path, dir_name in dirs:
|
|
324
|
+
if dir_path.exists():
|
|
325
|
+
console.print(f"[bold]Removing {dir_name} '{dir_path}'...[/bold]")
|
|
326
|
+
try:
|
|
327
|
+
shutil.rmtree(dir_path)
|
|
328
|
+
except OSError as exc:
|
|
329
|
+
console.print(f"[red]Error removing {dir_name} '{dir_path}': {exc}[/red]")
|
|
330
|
+
else:
|
|
331
|
+
console.print(f"[yellow]{dir_name} '{dir_path}' does not exist; skipping.[/yellow]")
|
|
332
|
+
|
|
333
|
+
# Remove the executable/tool
|
|
334
|
+
executable_removed = __uninstall_executable()
|
|
335
|
+
|
|
336
|
+
caveats = []
|
|
337
|
+
# Handle any remaining config files not removed by design
|
|
338
|
+
remaining_config_files = config_manager.config_files
|
|
339
|
+
if remaining_config_files:
|
|
340
|
+
caveats.append("- Some config files were intentionally not removed:")
|
|
341
|
+
caveats.extend(f"\t[yellow]- {file}[/yellow]" for file in remaining_config_files)
|
|
342
|
+
|
|
343
|
+
if not executable_removed:
|
|
344
|
+
caveats.append(
|
|
345
|
+
"- The uninstaller was not able to remove the Griptape Nodes executable. "
|
|
346
|
+
"Please remove the executable manually by running '[bold]uv tool uninstall griptape-nodes[/bold]'."
|
|
347
|
+
)
|
|
348
|
+
|
|
349
|
+
# If there were any caveats to the uninstallation process, print them
|
|
350
|
+
if caveats:
|
|
351
|
+
console.print("[bold]Caveats:[/bold]")
|
|
352
|
+
for line in caveats:
|
|
353
|
+
console.print(line)
|
|
354
|
+
|
|
355
|
+
# Exit the process
|
|
356
|
+
sys.exit(0)
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
def _process_args(args: argparse.Namespace) -> None: # noqa: C901, PLR0912
|
|
360
|
+
if args.command == "init":
|
|
361
|
+
_run_init(api_key=args.api_key, workspace_directory=args.workspace_directory)
|
|
362
|
+
elif args.command == "engine":
|
|
363
|
+
_start_engine(no_update=args.no_update)
|
|
364
|
+
elif args.command == "config":
|
|
365
|
+
if args.subcommand == "list":
|
|
366
|
+
_list_user_configs()
|
|
367
|
+
elif args.subcommand == "reset":
|
|
368
|
+
_reset_user_config()
|
|
369
|
+
elif args.subcommand == "show":
|
|
370
|
+
_print_user_config()
|
|
371
|
+
elif args.command == "self":
|
|
372
|
+
if args.subcommand == "update":
|
|
373
|
+
_update_self()
|
|
374
|
+
elif args.subcommand == "uninstall":
|
|
375
|
+
_uninstall_self()
|
|
376
|
+
elif args.subcommand == "version":
|
|
377
|
+
_print_current_version()
|
|
378
|
+
elif args.command == "assets":
|
|
379
|
+
if args.subcommand == "update":
|
|
380
|
+
_update_assets()
|
|
381
|
+
else:
|
|
382
|
+
msg = f"Unknown command: {args.command}"
|
|
383
|
+
raise ValueError(msg)
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
def __uninstall_executable() -> bool:
|
|
387
|
+
"""Uninstalls the Griptape Nodes executable.
|
|
388
|
+
|
|
389
|
+
This is skipped on Windows due to OS limitations.
|
|
390
|
+
|
|
391
|
+
Returns:
|
|
392
|
+
bool: True if the executable was removed, False otherwise.
|
|
393
|
+
|
|
394
|
+
"""
|
|
395
|
+
executable_path = shutil.which("griptape-nodes")
|
|
396
|
+
executable_removed = False
|
|
397
|
+
if executable_path:
|
|
398
|
+
if OSManager.is_windows():
|
|
399
|
+
console.print(
|
|
400
|
+
"[bold]Windows does not allow for uninstalling executables while they are running. Please review uninstallation caveats for manual steps.[/bold]"
|
|
401
|
+
)
|
|
402
|
+
else:
|
|
403
|
+
console.print(f"[bold]Removing Griptape Nodes executable ({executable_path})...[/bold]")
|
|
404
|
+
try:
|
|
405
|
+
subprocess.run(
|
|
406
|
+
["uv", "tool", "uninstall", "griptape-nodes"],
|
|
407
|
+
check=True,
|
|
408
|
+
text=True,
|
|
409
|
+
)
|
|
410
|
+
executable_removed = True
|
|
411
|
+
except subprocess.CalledProcessError:
|
|
412
|
+
executable_removed = False
|
|
413
|
+
else:
|
|
414
|
+
console.print("[yellow]Griptape Nodes executable not found; skipping removal.[/yellow]")
|
|
415
|
+
|
|
416
|
+
console.print("[bold green]Uninstall complete![/bold green]")
|
|
417
|
+
|
|
418
|
+
return executable_removed
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
def __get_current_version() -> str:
|
|
422
|
+
"""Returns the current version of the Griptape Nodes package."""
|
|
423
|
+
version = importlib.metadata.version("griptape_nodes")
|
|
424
|
+
|
|
425
|
+
return f"v{version}"
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
def __init_system_config() -> None:
|
|
429
|
+
"""Initializes the system config directory if it doesn't exist."""
|
|
430
|
+
if not CONFIG_DIR.exists():
|
|
431
|
+
CONFIG_DIR.mkdir(parents=True, exist_ok=True)
|
|
432
|
+
|
|
433
|
+
files_to_create = [
|
|
434
|
+
(ENV_FILE, ""),
|
|
435
|
+
(CONFIG_FILE, "{}"),
|
|
436
|
+
]
|
|
437
|
+
|
|
438
|
+
for file_name in files_to_create:
|
|
439
|
+
file_path = CONFIG_DIR / file_name[0]
|
|
440
|
+
if not file_path.exists():
|
|
441
|
+
with Path.open(file_path, "w") as file:
|
|
442
|
+
file.write(file_name[1])
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
if __name__ == "__main__":
|
|
446
|
+
main()
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.12
|