jac-client 0.2.8__py3-none-any.whl → 0.2.10__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.
- jac_client/examples/all-in-one/{app.jac → main.jac} +5 -5
- jac_client/examples/all-in-one/pages/BudgetPlanner.jac +8 -1
- jac_client/examples/all-in-one/pages/FeaturesTest.jac +16 -1
- jac_client/examples/all-in-one/pages/{FeaturesTest.cl.jac → features_test_ui.cl.jac} +11 -0
- jac_client/examples/all-in-one/pages/nestedDemo.jac +1 -1
- jac_client/examples/all-in-one/pages/notFound.jac +2 -7
- jac_client/plugin/cli.jac +491 -411
- jac_client/plugin/client.jac +25 -0
- jac_client/plugin/client_runtime.cl.jac +5 -1
- jac_client/plugin/impl/client.impl.jac +96 -55
- jac_client/plugin/impl/client_runtime.impl.jac +154 -0
- jac_client/plugin/plugin_config.jac +243 -15
- jac_client/plugin/src/config_loader.jac +1 -0
- jac_client/plugin/src/desktop_config.jac +31 -0
- jac_client/plugin/src/impl/compiler.impl.jac +1 -1
- jac_client/plugin/src/impl/config_loader.impl.jac +8 -0
- jac_client/plugin/src/impl/desktop_config.impl.jac +191 -0
- jac_client/plugin/src/impl/vite_bundler.impl.jac +97 -16
- jac_client/plugin/src/targets/desktop/sidecar/main.py +144 -0
- jac_client/plugin/src/targets/desktop_target.jac +37 -0
- jac_client/plugin/src/targets/impl/desktop_target.impl.jac +2334 -0
- jac_client/plugin/src/targets/impl/registry.impl.jac +64 -0
- jac_client/plugin/src/targets/impl/web_target.impl.jac +157 -0
- jac_client/plugin/src/targets/register.jac +21 -0
- jac_client/plugin/src/targets/registry.jac +87 -0
- jac_client/plugin/src/targets/web_target.jac +35 -0
- jac_client/plugin/src/vite_bundler.jac +6 -0
- jac_client/plugin/utils/__init__.jac +1 -0
- jac_client/plugin/utils/impl/node_installer.impl.jac +249 -0
- jac_client/plugin/utils/node_installer.jac +41 -0
- jac_client/templates/client.jacpack +72 -0
- jac_client/templates/fullstack.jacpack +61 -0
- jac_client/tests/conftest.py +48 -7
- jac_client/tests/test_cli.py +184 -70
- jac_client/tests/test_e2e.py +232 -0
- jac_client/tests/test_helpers.py +65 -0
- jac_client/tests/test_it.py +91 -135
- jac_client/tests/test_it_desktop.py +891 -0
- {jac_client-0.2.8.dist-info → jac_client-0.2.10.dist-info}/METADATA +4 -4
- jac_client-0.2.10.dist-info/RECORD +115 -0
- {jac_client-0.2.8.dist-info → jac_client-0.2.10.dist-info}/WHEEL +1 -1
- jac_client-0.2.8.dist-info/RECORD +0 -97
- /jac_client/examples/all-in-one/pages/{BudgetPlanner.cl.jac → budget_planner_ui.cl.jac} +0 -0
- /jac_client/examples/asset-serving/css-with-image/{src/app.jac → main.jac} +0 -0
- /jac_client/examples/asset-serving/image-asset/{src/app.jac → main.jac} +0 -0
- /jac_client/examples/asset-serving/import-alias/{src/app.jac → main.jac} +0 -0
- /jac_client/examples/basic/{src/app.jac → main.jac} +0 -0
- /jac_client/examples/basic-auth/{src/app.jac → main.jac} +0 -0
- /jac_client/examples/basic-auth-with-router/{src/app.jac → main.jac} +0 -0
- /jac_client/examples/basic-full-stack/{src/app.jac → main.jac} +0 -0
- /jac_client/examples/css-styling/js-styling/{src/app.jac → main.jac} +0 -0
- /jac_client/examples/css-styling/material-ui/{src/app.jac → main.jac} +0 -0
- /jac_client/examples/css-styling/pure-css/{src/app.jac → main.jac} +0 -0
- /jac_client/examples/css-styling/sass-example/{src/app.jac → main.jac} +0 -0
- /jac_client/examples/css-styling/styled-components/{src/app.jac → main.jac} +0 -0
- /jac_client/examples/css-styling/tailwind-example/{src/app.jac → main.jac} +0 -0
- /jac_client/examples/full-stack-with-auth/{src/app.jac → main.jac} +0 -0
- /jac_client/examples/little-x/{src/app.jac → main.jac} +0 -0
- /jac_client/examples/nested-folders/nested-advance/{src/app.jac → main.jac} +0 -0
- /jac_client/examples/nested-folders/nested-basic/{src/app.jac → main.jac} +0 -0
- /jac_client/examples/ts-support/{src/app.jac → main.jac} +0 -0
- /jac_client/examples/with-router/{src/app.jac → main.jac} +0 -0
- {jac_client-0.2.8.dist-info → jac_client-0.2.10.dist-info}/entry_points.txt +0 -0
- {jac_client-0.2.8.dist-info → jac_client-0.2.10.dist-info}/top_level.txt +0 -0
jac_client/plugin/cli.jac
CHANGED
|
@@ -1,504 +1,584 @@
|
|
|
1
1
|
"""Command line interface tool for the Jac Client.
|
|
2
2
|
|
|
3
|
-
This module extends
|
|
4
|
-
|
|
3
|
+
This module extends core CLI commands to add the --npm flag for
|
|
4
|
+
client-side (frontend) package management:
|
|
5
|
+
- `jac add --npm`: Add npm dependencies
|
|
6
|
+
- `jac remove --npm`: Remove npm dependencies
|
|
7
|
+
|
|
8
|
+
For creating client projects, use: `jac create --use client`
|
|
5
9
|
"""
|
|
6
10
|
|
|
7
|
-
import os;
|
|
8
|
-
import re;
|
|
9
|
-
import sys;
|
|
10
|
-
import pathlib;
|
|
11
|
-
import subprocess;
|
|
12
|
-
import shutil;
|
|
13
11
|
import from jaclang.cli.registry { get_registry }
|
|
14
12
|
import from jaclang.cli.command { Arg, ArgKind, HookContext }
|
|
15
13
|
import from jaclang.pycore.runtime { hookimpl }
|
|
16
|
-
import
|
|
14
|
+
import os;
|
|
15
|
+
|
|
16
|
+
glob registry = get_registry();
|
|
17
|
+
|
|
18
|
+
# Register targets when module loads
|
|
19
|
+
# Import base target classes - this should trigger annex pass to auto-discover .impl.jac files
|
|
20
|
+
import from jac_client.plugin.src.targets.desktop_target {
|
|
21
|
+
DesktopTarget
|
|
22
|
+
}
|
|
23
|
+
import from jac_client.plugin.src.targets.web_target { WebTarget }
|
|
24
|
+
import from jac_client.plugin.src.targets.register { register_targets }
|
|
25
|
+
|
|
26
|
+
with entry {
|
|
27
|
+
register_targets();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
"""Register 'build' command at module level."""
|
|
31
|
+
@registry.command(
|
|
32
|
+
name="build",
|
|
33
|
+
help="Build a Jac application for a specific target",
|
|
34
|
+
args=[
|
|
35
|
+
Arg.create(
|
|
36
|
+
"filename",
|
|
37
|
+
kind=ArgKind.POSITIONAL,
|
|
38
|
+
default="main.jac",
|
|
39
|
+
help="Path to .jac file (default: main.jac)"
|
|
40
|
+
),
|
|
41
|
+
Arg.create(
|
|
42
|
+
"client",
|
|
43
|
+
typ=str,
|
|
44
|
+
default="web",
|
|
45
|
+
help="Build client (web, desktop)",
|
|
46
|
+
choices=["web", "desktop"],
|
|
47
|
+
short="" # Disable auto-generated -t (may conflict with other plugins)
|
|
48
|
+
),
|
|
49
|
+
Arg.create(
|
|
50
|
+
"platform",
|
|
51
|
+
typ=str,
|
|
52
|
+
default=None,
|
|
53
|
+
help="Platform for desktop builds (windows, macos, linux, all)",
|
|
54
|
+
choices=["windows", "macos", "linux", "all"],
|
|
55
|
+
short="p" # Use -p for platform
|
|
56
|
+
),
|
|
57
|
+
|
|
58
|
+
],
|
|
59
|
+
examples=[
|
|
60
|
+
("jac build", "Build web target (default)"),
|
|
61
|
+
("jac build main.jac", "Build specific file"),
|
|
62
|
+
("jac build --client desktop", "Build desktop app"),
|
|
63
|
+
("jac build --client desktop --platform windows", "Build for Windows"),
|
|
64
|
+
|
|
65
|
+
],
|
|
66
|
+
group="build",
|
|
67
|
+
source="jac-client"
|
|
68
|
+
)
|
|
69
|
+
def build(
|
|
70
|
+
filename: str = "main.jac", target: str = "web", platform: str | None = None
|
|
71
|
+
) -> int {
|
|
72
|
+
# This will be handled by the pre_hook
|
|
73
|
+
return 0;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
"""Register 'setup' command at module level."""
|
|
77
|
+
@registry.command(
|
|
78
|
+
name="setup",
|
|
79
|
+
help="Setup a build target (one-time initialization)",
|
|
80
|
+
args=[
|
|
81
|
+
Arg.create(
|
|
82
|
+
"target", kind=ArgKind.POSITIONAL, help="Target to setup (e.g., desktop)"
|
|
83
|
+
),
|
|
84
|
+
|
|
85
|
+
],
|
|
86
|
+
examples=[("jac setup desktop", "Setup desktop target (Tauri)"), ],
|
|
87
|
+
group="project",
|
|
88
|
+
source="jac-client"
|
|
89
|
+
)
|
|
90
|
+
def setup(target: str) -> int {
|
|
91
|
+
# This will be handled by the pre_hook
|
|
92
|
+
return 0;
|
|
93
|
+
}
|
|
17
94
|
|
|
18
95
|
"""Jac CLI extensions for client-side development."""
|
|
19
96
|
class JacCmd {
|
|
20
97
|
"""Create Jac CLI cmds."""
|
|
21
98
|
@hookimpl
|
|
22
99
|
static def create_cmd -> None {
|
|
23
|
-
"""Extend core
|
|
100
|
+
"""Extend core commands to add --npm flag for npm package management.""";
|
|
24
101
|
registry = get_registry();
|
|
25
102
|
|
|
26
|
-
# Extend the core 'create' command with client
|
|
103
|
+
# Extend the core 'create' command with --skip flag for client template
|
|
27
104
|
registry.extend_command(
|
|
28
105
|
command_name="create",
|
|
29
106
|
args=[
|
|
30
107
|
Arg.create(
|
|
31
|
-
"
|
|
108
|
+
"skip",
|
|
32
109
|
typ=bool,
|
|
33
110
|
default=False,
|
|
34
|
-
help="
|
|
35
|
-
short="c"
|
|
111
|
+
help="Skip npm package installation (for --use client)"
|
|
36
112
|
),
|
|
113
|
+
|
|
114
|
+
],
|
|
115
|
+
pre_hook=_handle_create_skip,
|
|
116
|
+
source="jac-client"
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
# Extend the core 'add' command with --npm flag
|
|
120
|
+
registry.extend_command(
|
|
121
|
+
command_name="add",
|
|
122
|
+
args=[
|
|
37
123
|
Arg.create(
|
|
38
|
-
"
|
|
124
|
+
"npm",
|
|
39
125
|
typ=bool,
|
|
40
126
|
default=False,
|
|
41
|
-
help="
|
|
42
|
-
short="s"
|
|
127
|
+
help="Add as npm (client-side) dependency"
|
|
43
128
|
),
|
|
129
|
+
|
|
130
|
+
],
|
|
131
|
+
pre_hook=_handle_npm_add,
|
|
132
|
+
source="jac-client"
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
# Extend the core 'remove' command with --npm flag
|
|
136
|
+
registry.extend_command(
|
|
137
|
+
command_name="remove",
|
|
138
|
+
args=[
|
|
44
139
|
Arg.create(
|
|
45
|
-
"
|
|
140
|
+
"npm",
|
|
46
141
|
typ=bool,
|
|
47
142
|
default=False,
|
|
48
|
-
help="
|
|
49
|
-
short="v"
|
|
143
|
+
help="Remove npm (client-side) dependency"
|
|
50
144
|
),
|
|
51
145
|
|
|
52
146
|
],
|
|
53
|
-
pre_hook=
|
|
147
|
+
pre_hook=_handle_npm_remove,
|
|
54
148
|
source="jac-client"
|
|
55
149
|
);
|
|
150
|
+
|
|
151
|
+
# Add pre-hook to build command (command is registered at module level)
|
|
152
|
+
registry.extend_command(
|
|
153
|
+
command_name="build", pre_hook=_handle_build_target, source="jac-client"
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
# Add pre-hook to setup command (command is registered at module level)
|
|
157
|
+
registry.extend_command(
|
|
158
|
+
command_name="setup", pre_hook=_handle_setup_target, source="jac-client"
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
# Extend 'start' command with --client flag
|
|
162
|
+
# Note: jac-scale also uses --client, so we use --client to avoid conflict
|
|
163
|
+
if registry.has_command("start") {
|
|
164
|
+
registry.extend_command(
|
|
165
|
+
command_name="start",
|
|
166
|
+
args=[
|
|
167
|
+
Arg.create(
|
|
168
|
+
"client", # Use client to avoid conflict with jac-scale's --client
|
|
169
|
+
typ=str,
|
|
170
|
+
default="web",
|
|
171
|
+
help="Client build target for dev server (web, desktop)",
|
|
172
|
+
choices=["web", "desktop"],
|
|
173
|
+
short="" # Disable auto-generated short flag
|
|
174
|
+
),
|
|
175
|
+
|
|
176
|
+
],
|
|
177
|
+
pre_hook=_handle_start_target,
|
|
178
|
+
source="jac-client"
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
"""Pre-hook to handle --skip flag for create command."""
|
|
185
|
+
def _handle_create_skip(ctx: HookContext) -> None {
|
|
186
|
+
# Check if --skip flag is set
|
|
187
|
+
skip_flag = ctx.get_arg("skip", False);
|
|
188
|
+
if skip_flag {
|
|
189
|
+
# Set environment variable to skip npm installation
|
|
190
|
+
os.environ["JAC_CLIENT_SKIP_NPM_INSTALL"] = "1";
|
|
56
191
|
}
|
|
192
|
+
# Let core create command run normally
|
|
57
193
|
}
|
|
58
194
|
|
|
59
|
-
"""Pre-hook to handle --
|
|
60
|
-
def
|
|
61
|
-
# Check if --
|
|
62
|
-
|
|
63
|
-
if not
|
|
64
|
-
# Let core
|
|
195
|
+
"""Pre-hook to handle --npm flag for adding npm dependencies."""
|
|
196
|
+
def _handle_npm_add(ctx: HookContext) -> None {
|
|
197
|
+
# Check if --npm flag is set
|
|
198
|
+
npm_flag = ctx.get_arg("npm", False);
|
|
199
|
+
if not npm_flag {
|
|
200
|
+
# Let core add command run normally
|
|
65
201
|
return;
|
|
66
202
|
}
|
|
67
203
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
skip_install = ctx.get_arg("skip", False);
|
|
73
|
-
verbose = ctx.get_arg("verbose", False);
|
|
204
|
+
import from jaclang.project.config { get_config }
|
|
205
|
+
import from jaclang.project.dep_registry { get_dependency_registry }
|
|
206
|
+
import from jaclang.project.dependencies { DependencyResolver }
|
|
207
|
+
import from jaclang.cli.console { console }
|
|
74
208
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
} except SystemExit as e {
|
|
81
|
-
# Preserve exit code from sys.exit() calls
|
|
82
|
-
ctx.set_data("cancel_execution", True);
|
|
83
|
-
ctx.set_data("cancel_return_code", e.code if e.code is not None else 1);
|
|
84
|
-
} except Exception as e {
|
|
85
|
-
print(f"Error creating client project: {e}", file=sys.stderr);
|
|
209
|
+
config = get_config();
|
|
210
|
+
if config is None {
|
|
211
|
+
console.error(
|
|
212
|
+
"No jac.toml found", hint="Run 'jac create' to create a project."
|
|
213
|
+
);
|
|
86
214
|
ctx.set_data("cancel_execution", True);
|
|
87
215
|
ctx.set_data("cancel_return_code", 1);
|
|
216
|
+
return;
|
|
88
217
|
}
|
|
89
|
-
}
|
|
90
218
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
verbose: bool = False
|
|
98
|
-
) -> None {
|
|
99
|
-
project_name = name or cwd.name;
|
|
100
|
-
|
|
101
|
-
if not project_name or project_name == 'main' {
|
|
102
|
-
print(
|
|
103
|
-
"Error: Project name is required for client projects. Use: jac create --cl <name>",
|
|
104
|
-
file=sys.stderr
|
|
219
|
+
registry = get_dependency_registry();
|
|
220
|
+
dep_type = registry.get_by_flag("--npm");
|
|
221
|
+
if dep_type is None {
|
|
222
|
+
console.error(
|
|
223
|
+
"--npm flag requires jac-client plugin",
|
|
224
|
+
hint="Install with: pip install jac-client"
|
|
105
225
|
);
|
|
106
|
-
|
|
226
|
+
ctx.set_data("cancel_execution", True);
|
|
227
|
+
ctx.set_data("cancel_return_code", 1);
|
|
228
|
+
return;
|
|
107
229
|
}
|
|
108
230
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
"Error: Project name must contain only letters, numbers, hyphens, and underscores",
|
|
112
|
-
file=sys.stderr
|
|
113
|
-
);
|
|
114
|
-
<>exit(1);
|
|
115
|
-
}
|
|
231
|
+
packages = ctx.get_arg("packages", []);
|
|
232
|
+
dev = ctx.get_arg("dev", False);
|
|
116
233
|
|
|
117
|
-
|
|
118
|
-
if
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
234
|
+
# If no packages specified, install all npm packages from jac.toml
|
|
235
|
+
if not packages {
|
|
236
|
+
if dep_type.install_all_handler is None {
|
|
237
|
+
console.error(f"No install_all handler registered for {dep_type.name}");
|
|
238
|
+
ctx.set_data("cancel_execution", True);
|
|
239
|
+
ctx.set_data("cancel_return_code", 1);
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
try {
|
|
243
|
+
console.print(
|
|
244
|
+
f"\n📦 Installing all {dep_type.name} packages from jac.toml",
|
|
245
|
+
style="bold"
|
|
246
|
+
);
|
|
247
|
+
with console.status(
|
|
248
|
+
f"[cyan]Installing {dep_type.name} packages...[/cyan]", spinner="dots"
|
|
249
|
+
) as status {
|
|
250
|
+
dep_type.install_all_handler(config);
|
|
251
|
+
}
|
|
252
|
+
console.success(f"Installed all {dep_type.name} packages");
|
|
253
|
+
ctx.set_data("cancel_execution", True);
|
|
254
|
+
ctx.set_data("cancel_return_code", 0);
|
|
255
|
+
} except Exception as e {
|
|
256
|
+
console.error(f"Failed to install packages: {e}");
|
|
257
|
+
ctx.set_data("cancel_execution", True);
|
|
258
|
+
ctx.set_data("cancel_return_code", 1);
|
|
259
|
+
}
|
|
260
|
+
return;
|
|
123
261
|
}
|
|
124
262
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
263
|
+
# Install specific packages
|
|
264
|
+
try {
|
|
265
|
+
resolver = DependencyResolver(config=config);
|
|
266
|
+
console.print(
|
|
267
|
+
f"\n📦 Adding {len(packages)} {dep_type.name} package(s)", style="bold"
|
|
268
|
+
);
|
|
269
|
+
for pkg_spec in packages {
|
|
270
|
+
(name, version) = resolver.parse_spec(pkg_spec);
|
|
271
|
+
with console.status(f"[cyan]Installing {name}...[/cyan]", spinner="dots") as status {
|
|
272
|
+
dep_type.install_handler(config, name, version, dev);
|
|
273
|
+
}
|
|
274
|
+
console.print(f" ✔ {name}", style="success");
|
|
131
275
|
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
276
|
+
section = f"dependencies.{dep_type.dev_name if dev else dep_type.name}";
|
|
277
|
+
console.print(f"\n ✔ Updated jac.toml [{section}]", style="muted");
|
|
278
|
+
ctx.set_data("cancel_execution", True);
|
|
279
|
+
ctx.set_data("cancel_return_code", 0);
|
|
280
|
+
} except Exception as e {
|
|
281
|
+
console.error(f"Failed to install packages: {e}");
|
|
282
|
+
ctx.set_data("cancel_execution", True);
|
|
283
|
+
ctx.set_data("cancel_return_code", 1);
|
|
135
284
|
}
|
|
285
|
+
}
|
|
136
286
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
287
|
+
"""Pre-hook to handle --client flag for build command."""
|
|
288
|
+
def _handle_build_target(ctx: HookContext) -> None {
|
|
289
|
+
import from jaclang.cli.console { console }
|
|
290
|
+
import from jac_client.plugin.src.targets.registry { get_target_registry }
|
|
291
|
+
import from pathlib { Path }
|
|
292
|
+
import from jaclang.project.config { get_config }
|
|
293
|
+
|
|
294
|
+
target_name = ctx.get_arg("client", "web");
|
|
295
|
+
platform = ctx.get_arg("platform", None);
|
|
296
|
+
|
|
297
|
+
registry = get_target_registry();
|
|
298
|
+
target = registry.get(target_name);
|
|
299
|
+
|
|
300
|
+
if not target {
|
|
301
|
+
console.error(f"Unknown client target: {target_name}");
|
|
302
|
+
console.print(
|
|
303
|
+
f"Available client targets: {', '.join(
|
|
304
|
+
[t.name for t in registry.get_all()]
|
|
305
|
+
)}",
|
|
306
|
+
style="muted"
|
|
307
|
+
);
|
|
308
|
+
ctx.set_data("cancel_execution", True);
|
|
309
|
+
ctx.set_data("cancel_return_code", 1);
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
153
312
|
|
|
154
|
-
|
|
313
|
+
# Store target info in context for use by build handler
|
|
314
|
+
ctx.set_data("build_target", target);
|
|
315
|
+
ctx.set_data("build_platform", platform);
|
|
155
316
|
|
|
156
|
-
|
|
157
|
-
|
|
317
|
+
# If target requires setup, warn user
|
|
318
|
+
if target.requires_setup {
|
|
319
|
+
console.warning(
|
|
320
|
+
f"Client target '{target_name}' requires setup. Run 'jac setup {target_name}' first."
|
|
321
|
+
);
|
|
322
|
+
}
|
|
158
323
|
|
|
159
|
-
|
|
160
|
-
|
|
324
|
+
# Build using target's build method
|
|
325
|
+
try {
|
|
326
|
+
config = get_config();
|
|
327
|
+
if not config {
|
|
328
|
+
console.error("No jac.toml found. Run 'jac create' to create a project.");
|
|
329
|
+
ctx.set_data("cancel_execution", True);
|
|
330
|
+
ctx.set_data("cancel_return_code", 1);
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
161
333
|
|
|
162
|
-
|
|
163
|
-
|
|
334
|
+
entry_file = ctx.get_arg("filename", None);
|
|
335
|
+
if not entry_file {
|
|
336
|
+
entry_file = config.entry_point;
|
|
337
|
+
}
|
|
338
|
+
if not entry_file {
|
|
339
|
+
console.error("No entry file specified. Use: jac build <file>");
|
|
340
|
+
ctx.set_data("cancel_execution", True);
|
|
341
|
+
ctx.set_data("cancel_return_code", 1);
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
164
344
|
|
|
165
|
-
|
|
166
|
-
|
|
345
|
+
entry_path = Path(entry_file);
|
|
346
|
+
project_dir = config.project_root or Path.cwd();
|
|
347
|
+
if not entry_path.is_absolute() {
|
|
348
|
+
entry_path = project_dir / entry_path;
|
|
349
|
+
}
|
|
350
|
+
bundle_path = target.build(entry_path, project_dir, platform);
|
|
167
351
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
cl import from react { useEffect }
|
|
182
|
-
cl import from .components.Button { Button }
|
|
183
|
-
|
|
184
|
-
# Client-side component
|
|
185
|
-
cl {
|
|
186
|
-
def:pub app() -> any {
|
|
187
|
-
has count: int = 0;
|
|
188
|
-
|
|
189
|
-
useEffect(lambda -> None {
|
|
190
|
-
console.log("Count updated:", count);
|
|
191
|
-
}, [count]);
|
|
192
|
-
|
|
193
|
-
return <div style={{padding: "2rem", fontFamily: "Arial, sans-serif"}}>
|
|
194
|
-
<h1>Hello, World!</h1>
|
|
195
|
-
<p>Count: {count}</p>
|
|
196
|
-
<div style={{display: "flex", gap: "1rem", marginTop: "1rem"}}>
|
|
197
|
-
<Button
|
|
198
|
-
label="Increment"
|
|
199
|
-
onClick={lambda -> None { count = count + 1; }}
|
|
200
|
-
variant="primary"
|
|
201
|
-
/>
|
|
202
|
-
<Button
|
|
203
|
-
label="Reset"
|
|
204
|
-
onClick={lambda -> None { count = 0; }}
|
|
205
|
-
variant="secondary"
|
|
206
|
-
/>
|
|
207
|
-
</div>
|
|
208
|
-
</div>;
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
''';
|
|
212
|
-
with open(project_path / "main.jac", 'w') as f {
|
|
213
|
-
f.write(main_jac_content);
|
|
352
|
+
console.success(f"Build complete: {bundle_path}");
|
|
353
|
+
ctx.set_data("cancel_execution", True);
|
|
354
|
+
ctx.set_data("cancel_return_code", 0);
|
|
355
|
+
} except NotImplementedError as e {
|
|
356
|
+
console.error(
|
|
357
|
+
f"Target '{target_name}' is not yet implemented. Coming in Phase 2!"
|
|
358
|
+
);
|
|
359
|
+
ctx.set_data("cancel_execution", True);
|
|
360
|
+
ctx.set_data("cancel_return_code", 1);
|
|
361
|
+
} except Exception as e {
|
|
362
|
+
console.error(f"Build failed: {e}");
|
|
363
|
+
ctx.set_data("cancel_execution", True);
|
|
364
|
+
ctx.set_data("cancel_return_code", 1);
|
|
214
365
|
}
|
|
215
|
-
print("Created main.jac");
|
|
216
|
-
|
|
217
|
-
button_cl_jac_content = '''"""Button component for the Jac client application."""
|
|
218
|
-
|
|
219
|
-
def:pub Button(label: str, onClick: any, variant: str = "primary", disabled: bool = False) -> any {
|
|
220
|
-
base_styles = {
|
|
221
|
-
"padding": "0.75rem 1.5rem",
|
|
222
|
-
"fontSize": "1rem",
|
|
223
|
-
"fontWeight": "600",
|
|
224
|
-
"borderRadius": "0.5rem",
|
|
225
|
-
"border": "none",
|
|
226
|
-
"cursor": "not-allowed" if disabled else "pointer",
|
|
227
|
-
"transition": "all 0.2s ease"
|
|
228
|
-
};
|
|
229
|
-
|
|
230
|
-
variant_styles = {
|
|
231
|
-
"primary": {
|
|
232
|
-
"backgroundColor": "#9ca3af" if disabled else "#3b82f6",
|
|
233
|
-
"color": "#ffffff"
|
|
234
|
-
},
|
|
235
|
-
"secondary": {
|
|
236
|
-
"backgroundColor": "#e5e7eb" if disabled else "#6b7280",
|
|
237
|
-
"color": "#ffffff"
|
|
238
|
-
}
|
|
239
|
-
};
|
|
240
|
-
|
|
241
|
-
return <button
|
|
242
|
-
style={{**base_styles, **variant_styles[variant]}}
|
|
243
|
-
onClick={onClick}
|
|
244
|
-
disabled={disabled}
|
|
245
|
-
>
|
|
246
|
-
{label}
|
|
247
|
-
</button>;
|
|
248
366
|
}
|
|
249
|
-
''';
|
|
250
|
-
with open(components_dir / "Button.cl.jac", 'w') as f {
|
|
251
|
-
f.write(button_cl_jac_content);
|
|
252
|
-
}
|
|
253
|
-
print("Created components/Button.cl.jac");
|
|
254
|
-
|
|
255
|
-
readme_content = f''' # {project_name}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
A Jac client-side application with React support.
|
|
259
|
-
|
|
260
|
-
## Project Structure
|
|
261
|
-
|
|
262
|
-
```
|
|
263
|
-
{project_name}/
|
|
264
|
-
├── jac.toml # Project configuration
|
|
265
|
-
├── main.jac # Main application entry
|
|
266
|
-
├── components/ # Reusable components
|
|
267
|
-
│ └── Button.cl.jac # Example Jac component
|
|
268
|
-
├── assets/ # Static assets (images, fonts, etc.)
|
|
269
|
-
└── build/ # Build output (generated)
|
|
270
|
-
```
|
|
271
|
-
|
|
272
|
-
## Getting Started
|
|
273
|
-
|
|
274
|
-
Start the development server:
|
|
275
|
-
|
|
276
|
-
```bash
|
|
277
|
-
jac start main.jac
|
|
278
|
-
```
|
|
279
367
|
|
|
280
|
-
|
|
368
|
+
"""Pre-hook to handle --client flag for start command."""
|
|
369
|
+
def _handle_start_target(ctx: HookContext) -> None {
|
|
370
|
+
import from jaclang.cli.console { console }
|
|
371
|
+
import from jac_client.plugin.src.targets.registry { get_target_registry }
|
|
281
372
|
|
|
282
|
-
|
|
373
|
+
target_name = ctx.get_arg("client", "web");
|
|
283
374
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
```
|
|
375
|
+
registry = get_target_registry();
|
|
376
|
+
target = registry.get(target_name);
|
|
287
377
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
print("Created README.md");
|
|
300
|
-
|
|
301
|
-
_create_gitignore(project_path);
|
|
302
|
-
|
|
303
|
-
# Install default packages unless --skip is specified
|
|
304
|
-
if not skip {
|
|
305
|
-
print("\nInstalling default packages...");
|
|
306
|
-
_install_default_packages(project_path, verbose);
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
print(f"\nProject '{project_name}' created successfully!");
|
|
310
|
-
if name and name != cwd.name {
|
|
311
|
-
print("\nNext steps:");
|
|
312
|
-
print(f" cd {name}");
|
|
313
|
-
print(" jac start main.jac");
|
|
314
|
-
} else {
|
|
315
|
-
print("\nNext steps:");
|
|
316
|
-
print(" jac start main.jac");
|
|
378
|
+
if not target {
|
|
379
|
+
console.error(f"Unknown client target: {target_name}");
|
|
380
|
+
console.print(
|
|
381
|
+
f"Available client targets: {', '.join(
|
|
382
|
+
[t.name for t in registry.get_all()]
|
|
383
|
+
)}",
|
|
384
|
+
style="muted"
|
|
385
|
+
);
|
|
386
|
+
ctx.set_data("cancel_execution", True);
|
|
387
|
+
ctx.set_data("cancel_return_code", 1);
|
|
388
|
+
return;
|
|
317
389
|
}
|
|
318
|
-
}
|
|
319
390
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
".venv/",
|
|
334
|
-
"venv/",
|
|
335
|
-
"",
|
|
336
|
-
"# IDE",
|
|
337
|
-
".idea/",
|
|
338
|
-
".vscode/",
|
|
339
|
-
"*.swp",
|
|
340
|
-
"",
|
|
341
|
-
"# Node.js",
|
|
342
|
-
"node_modules/",
|
|
343
|
-
"",
|
|
344
|
-
"# Jac build artifacts",
|
|
345
|
-
".jac/",
|
|
346
|
-
"*.session",
|
|
347
|
-
"*.session.*"
|
|
348
|
-
];
|
|
349
|
-
|
|
350
|
-
gitignore_path = project_path / ".gitignore";
|
|
351
|
-
if gitignore_path.exists() {
|
|
352
|
-
with open(gitignore_path, "r") as f {
|
|
353
|
-
existing_content = f.read();
|
|
391
|
+
# Store target info in context
|
|
392
|
+
ctx.set_data("start_client_target", target);
|
|
393
|
+
|
|
394
|
+
# Handle desktop target
|
|
395
|
+
if target_name == "desktop" {
|
|
396
|
+
import from pathlib { Path }
|
|
397
|
+
import from jaclang.project.config { get_config }
|
|
398
|
+
config = get_config();
|
|
399
|
+
if not config {
|
|
400
|
+
console.error("No jac.toml found. Run 'jac create' to create a project.");
|
|
401
|
+
ctx.set_data("cancel_execution", True);
|
|
402
|
+
ctx.set_data("cancel_return_code", 1);
|
|
403
|
+
return;
|
|
354
404
|
}
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
}
|
|
405
|
+
# Get entry file
|
|
406
|
+
entry_file = ctx.get_arg("filename", None);
|
|
407
|
+
if not entry_file {
|
|
408
|
+
entry_file = config.entry_point;
|
|
360
409
|
}
|
|
361
|
-
if
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
410
|
+
if not entry_file {
|
|
411
|
+
console.error("No entry file specified. Use: jac start <file>");
|
|
412
|
+
ctx.set_data("cancel_execution", True);
|
|
413
|
+
ctx.set_data("cancel_return_code", 1);
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
entry_path = Path(entry_file);
|
|
417
|
+
project_dir = config.project_root or Path.cwd();
|
|
418
|
+
if not entry_path.is_absolute() {
|
|
419
|
+
entry_path = project_dir / entry_path;
|
|
420
|
+
}
|
|
421
|
+
# Check if setup has been run
|
|
422
|
+
tauri_dir = project_dir / "src-tauri";
|
|
423
|
+
if not tauri_dir.exists() {
|
|
424
|
+
console.error("Desktop target not set up. Run 'jac setup desktop' first.");
|
|
425
|
+
ctx.set_data("cancel_execution", True);
|
|
426
|
+
ctx.set_data("cancel_return_code", 1);
|
|
427
|
+
return;
|
|
366
428
|
}
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
429
|
+
# Check if --dev flag is set
|
|
430
|
+
dev_mode = ctx.get_arg("dev", False);
|
|
431
|
+
try {
|
|
432
|
+
if dev_mode {
|
|
433
|
+
# Desktop target with --dev: launch Tauri dev mode (hot reload)
|
|
434
|
+
target.dev(entry_path, project_dir);
|
|
435
|
+
} else {
|
|
436
|
+
# Desktop target without --dev: build web bundle and launch Tauri with built bundle
|
|
437
|
+
target.start(entry_path, project_dir);
|
|
438
|
+
}
|
|
439
|
+
ctx.set_data("cancel_execution", True);
|
|
440
|
+
ctx.set_data("cancel_return_code", 0);
|
|
441
|
+
} except Exception as e {
|
|
442
|
+
import traceback;
|
|
443
|
+
console.error(f"Desktop start failed: {e}");
|
|
444
|
+
console.print(traceback.format_exc(), style="muted");
|
|
445
|
+
ctx.set_data("cancel_execution", True);
|
|
446
|
+
ctx.set_data("cancel_return_code", 1);
|
|
370
447
|
}
|
|
371
|
-
|
|
448
|
+
return;
|
|
372
449
|
}
|
|
450
|
+
# Web target: let existing start command handle it
|
|
451
|
+
# (no cancellation, let it run normally)
|
|
373
452
|
}
|
|
374
453
|
|
|
375
|
-
"""
|
|
376
|
-
def
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
import from
|
|
454
|
+
"""Pre-hook to handle setup command."""
|
|
455
|
+
def _handle_setup_target(ctx: HookContext) -> None {
|
|
456
|
+
import from jaclang.cli.console { console }
|
|
457
|
+
import from jac_client.plugin.src.targets.registry { get_target_registry }
|
|
458
|
+
import from pathlib { Path }
|
|
459
|
+
import from jaclang.project.config { get_config }
|
|
460
|
+
|
|
461
|
+
target_name = ctx.get_arg("target", None);
|
|
462
|
+
if not target_name {
|
|
463
|
+
console.error("No target specified. Use: jac setup <target>");
|
|
464
|
+
console.print("Available targets: desktop", style="muted");
|
|
465
|
+
ctx.set_data("cancel_execution", True);
|
|
466
|
+
ctx.set_data("cancel_return_code", 1);
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
registry = get_target_registry();
|
|
471
|
+
target = registry.get(target_name);
|
|
472
|
+
|
|
473
|
+
if not target {
|
|
474
|
+
console.error(f"Unknown client target: {target_name}");
|
|
475
|
+
console.print(
|
|
476
|
+
f"Available targets: {', '.join([t.name for t in registry.get_all()])}",
|
|
477
|
+
style="muted"
|
|
478
|
+
);
|
|
479
|
+
ctx.set_data("cancel_execution", True);
|
|
480
|
+
ctx.set_data("cancel_return_code", 1);
|
|
481
|
+
return;
|
|
482
|
+
}
|
|
380
483
|
|
|
484
|
+
# Setup using target's setup method
|
|
381
485
|
try {
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
file=sys.stderr
|
|
388
|
-
);
|
|
486
|
+
config = get_config();
|
|
487
|
+
if not config {
|
|
488
|
+
console.error("No jac.toml found. Run 'jac create' to create a project.");
|
|
489
|
+
ctx.set_data("cancel_execution", True);
|
|
490
|
+
ctx.set_data("cancel_return_code", 1);
|
|
389
491
|
return;
|
|
390
492
|
}
|
|
391
493
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
# Generate package.json with default packages (defaults are added automatically)
|
|
399
|
-
bundler.create_package_json(project_name=project_name);
|
|
400
|
-
|
|
401
|
-
# Ensure .jac/client directory exists
|
|
402
|
-
client_dir = bundler._get_client_dir();
|
|
403
|
-
client_dir.mkdir(parents=True, exist_ok=True);
|
|
404
|
-
|
|
405
|
-
# Copy package.json to .jac/client/ for npm install
|
|
406
|
-
configs_package_json = client_dir / 'configs' / 'package.json';
|
|
407
|
-
build_package_json = client_dir / 'package.json';
|
|
494
|
+
project_dir = config.project_root or Path.cwd();
|
|
495
|
+
console.print(
|
|
496
|
+
f"Setting up target '{target_name}' in: {project_dir}", style="muted"
|
|
497
|
+
);
|
|
498
|
+
target.setup(project_dir);
|
|
408
499
|
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
500
|
+
# Verify setup completed successfully
|
|
501
|
+
tauri_dir = project_dir / "src-tauri";
|
|
502
|
+
if not tauri_dir.exists() {
|
|
503
|
+
console.error(
|
|
504
|
+
f"Setup completed but src-tauri directory not found at: {tauri_dir}"
|
|
505
|
+
);
|
|
506
|
+
console.print(
|
|
507
|
+
"This may indicate the setup function failed silently.", style="muted"
|
|
413
508
|
);
|
|
509
|
+
ctx.set_data("cancel_execution", True);
|
|
510
|
+
ctx.set_data("cancel_return_code", 1);
|
|
414
511
|
return;
|
|
415
512
|
}
|
|
416
513
|
|
|
417
|
-
|
|
418
|
-
|
|
514
|
+
console.success(f"Target '{target_name}' setup complete!");
|
|
515
|
+
ctx.set_data("cancel_execution", True);
|
|
516
|
+
ctx.set_data("cancel_return_code", 0);
|
|
517
|
+
} except NotImplementedError as e {
|
|
518
|
+
console.error(f"Target '{target_name}' setup is not yet implemented.");
|
|
519
|
+
ctx.set_data("cancel_execution", True);
|
|
520
|
+
ctx.set_data("cancel_return_code", 1);
|
|
521
|
+
} except Exception as e {
|
|
522
|
+
import traceback;
|
|
523
|
+
console.error(f"Setup failed: {e}");
|
|
524
|
+
console.print(traceback.format_exc(), style="muted");
|
|
525
|
+
ctx.set_data("cancel_execution", True);
|
|
526
|
+
ctx.set_data("cancel_return_code", 1);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
419
529
|
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
if verbose {
|
|
429
|
-
# Verbose mode: show detailed package list and stream npm output
|
|
430
|
-
if deps {
|
|
431
|
-
print(" Dependencies:");
|
|
432
|
-
for (name, version) in deps.items() {
|
|
433
|
-
print(f" - {name}@{version}");
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
if dev_deps {
|
|
437
|
-
print(" Dev dependencies:");
|
|
438
|
-
for (name, version) in dev_deps.items() {
|
|
439
|
-
print(f" - {name}@{version}");
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
print("\nRunning npm install...");
|
|
443
|
-
}
|
|
530
|
+
"""Pre-hook to handle --npm flag for removing npm dependencies."""
|
|
531
|
+
def _handle_npm_remove(ctx: HookContext) -> None {
|
|
532
|
+
# Check if --npm flag is set
|
|
533
|
+
npm_flag = ctx.get_arg("npm", False);
|
|
534
|
+
if not npm_flag {
|
|
535
|
+
# Let core remove command run normally
|
|
536
|
+
return;
|
|
537
|
+
}
|
|
444
538
|
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
# Stream output for visibility in verbose mode
|
|
449
|
-
subprocess.run(
|
|
450
|
-
['npm', 'install', '--progress'], cwd=client_dir, check=True
|
|
451
|
-
);
|
|
452
|
-
} else {
|
|
453
|
-
# Quiet mode: capture output
|
|
454
|
-
subprocess.run(
|
|
455
|
-
['npm', 'install'],
|
|
456
|
-
cwd=client_dir,
|
|
457
|
-
check=True,
|
|
458
|
-
capture_output=True,
|
|
459
|
-
text=True
|
|
460
|
-
);
|
|
461
|
-
}
|
|
539
|
+
import from jaclang.project.config { get_config }
|
|
540
|
+
import from jaclang.project.dep_registry { get_dependency_registry }
|
|
541
|
+
import from jaclang.cli.console { console }
|
|
462
542
|
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
configs_package_lock.unlink();
|
|
471
|
-
}
|
|
472
|
-
shutil.move(str(build_package_lock), str(configs_package_lock));
|
|
473
|
-
}
|
|
543
|
+
config = get_config();
|
|
544
|
+
if config is None {
|
|
545
|
+
console.error("No jac.toml found. Run 'jac create' to create a project.");
|
|
546
|
+
ctx.set_data("cancel_execution", True);
|
|
547
|
+
ctx.set_data("cancel_return_code", 1);
|
|
548
|
+
return;
|
|
549
|
+
}
|
|
474
550
|
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
551
|
+
packages = ctx.get_arg("packages", []);
|
|
552
|
+
if not packages {
|
|
553
|
+
console.error("No packages specified.");
|
|
554
|
+
ctx.set_data("cancel_execution", True);
|
|
555
|
+
ctx.set_data("cancel_return_code", 1);
|
|
556
|
+
return;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
registry = get_dependency_registry();
|
|
560
|
+
dep_type = registry.get_by_flag("--npm");
|
|
561
|
+
if dep_type is None {
|
|
562
|
+
console.error("--npm flag requires jac-client plugin to be installed.");
|
|
563
|
+
console.print("Install with: pip install jac-client", style="muted");
|
|
564
|
+
ctx.set_data("cancel_execution", True);
|
|
565
|
+
ctx.set_data("cancel_return_code", 1);
|
|
566
|
+
return;
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
dev = ctx.get_arg("dev", False);
|
|
570
|
+
|
|
571
|
+
try {
|
|
572
|
+
for name in packages {
|
|
573
|
+
console.info(f"Removing {name} ({dep_type.name})...");
|
|
574
|
+
dep_type.remove_handler(config, name, dev);
|
|
499
575
|
}
|
|
576
|
+
console.success(f"Removed {len(packages)} package(s)");
|
|
577
|
+
ctx.set_data("cancel_execution", True);
|
|
578
|
+
ctx.set_data("cancel_return_code", 0);
|
|
500
579
|
} except Exception as e {
|
|
501
|
-
|
|
502
|
-
|
|
580
|
+
console.error(f"Error removing packages: {e}");
|
|
581
|
+
ctx.set_data("cancel_execution", True);
|
|
582
|
+
ctx.set_data("cancel_return_code", 1);
|
|
503
583
|
}
|
|
504
584
|
}
|