exb-community-cli 1.0.2 → 1.0.3

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/LICENSE.md ADDED
@@ -0,0 +1,7 @@
1
+ Copyright 2026 Lucius Creamer
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md CHANGED
@@ -4,9 +4,9 @@ A simple, lightweight command line interface to make using Experience Builder De
4
4
 
5
5
  ## Using this CLI
6
6
 
7
- The ExB Community CLI has a few tools to make it easy to install, update, remove, and search for Experience Builder widgets that have been posted on NPM. Installing the CLI is as simple as running `npm i exb-community-cli` in your client directory of your Experience Builder application. To then run commands, the format is `npx exb-cli [command]`. If you don't want to prefix every command with npx, you can install the exb-community-cli globally, by running `npm i -g exb-community-cli` (Recommended). For information on the commands that exist, run `npx exb-cli help`, and commands, arguments, and descriptions will be listed.
7
+ The ExB Community CLI has a few tools to make it easy to install, update, remove, and search for Experience Builder widgets that have been posted on NPM. Installing the CLI is as simple as running `npm install exb-community-cli` in your client directory of your Experience Builder application. To then run commands, the format is `npx exb [command]`. If you don't want to prefix every command with npx, you can install the exb-community-cli globally, by running `npm install -g exb-community-cli` (Recommended). For information on the commands that exist, run `npx exb help`, and commands, arguments, and descriptions will be listed.
8
8
 
9
- Additionally, this CLI makes it easy to get up and running with Experience Builder, requiring a single command to install and run Experience Builder Developer Edition, making it easier than ever to get started. Just install the CLI globally `npm-i -g exb-community-cli` and then run `exb-cli dev-setup`. The tool will give you a few prompts to get started, and you'll end up with a fully functional install.
9
+ Additionally, this CLI makes it easy to get up and running with Experience Builder, requiring a single command to install and run Experience Builder Developer Edition, making it easier than ever to get started. Just install the CLI globally `npm install -g exb-community-cli` and then run `exb dev-setup`. The tool will give you a few prompts to get started, and you'll end up with a fully functional install.
10
10
 
11
11
  When using any of the ExB Community CLI commands, the command needs to be run in the client directory of your Experience builder application (excluding dev-setup). If you don't, you will get the error `Error: Run this from the ExB client folder.`.
12
12
 
@@ -25,4 +25,4 @@ To prepare your widget to be easily ingested by the ExB Community CLI, there are
25
25
 
26
26
  If you're like me, you probably don't want to re-publish your widget manually on NPM every time that you have an update. That'd be a pain right? Well, as long as you're using GitHub, I have a solution for you. _**GitHub Actions**_. You can use GitHub Actions to automate deployment to NPM using a fairly simple process, outlined in this [Esri Community Post](TBD).
27
27
 
28
- If you are using automated deployment YAML for your Experience Builder installs, you might also want to make sure that the widgets you're using come along for the ride. This CLI has that in mind! To inline install a widget into your build pipeline, use `npx exb-community-cli i widgetname`. This will install the widget into your project. If you want to ensure that you always use the same version of the widget, simply add the version suffix ex `@1.5.3`.
28
+ If you are using automated deployment YAML for your Experience Builder installs, you might also want to make sure that the widgets you're using come along for the ride. This CLI has that in mind! To inline install a widget into your build pipeline, use `npx exb-community-cli install widgetname`. This will install the widget into your project. If you want to ensure that you always use the same version of the widget, simply add the version suffix ex `@1.5.3`.
@@ -1,4 +1,37 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
37
  };
@@ -46,9 +79,10 @@ async function devSetup(options) {
46
79
  }
47
80
  const clientDir = path_1.default.join(process.cwd(), `arcgis-experience-builder-${version}`, "client");
48
81
  const serverDir = path_1.default.join(process.cwd(), `arcgis-experience-builder-${version}`, "server");
49
- console.log("Starting development servers in new terminal windows...");
50
- openInNewTerminal(clientDir, "client");
51
- openInNewTerminal(serverDir, "server");
82
+ console.log("Starting client and server development servers...");
83
+ // Start dev servers using util
84
+ const { startDevServer } = await Promise.resolve().then(() => __importStar(require("../utils/startDevServer")));
85
+ startDevServer(clientDir, serverDir);
52
86
  }
53
87
  const ciWithSpinner = (message, cwd) => {
54
88
  const spinnerFrames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
@@ -77,64 +111,7 @@ const ciWithSpinner = (message, cwd) => {
77
111
  });
78
112
  });
79
113
  };
80
- const openInNewTerminal = (cwd, label) => {
81
- const cmd = `cd "${cwd}" && npm start`;
82
- if (process.platform === "darwin") {
83
- const script = `tell application "Terminal"\nactivate\ndo script "${cmd.replace(/"/g, '\\"')}"\nend tell`;
84
- (0, child_process_1.spawn)("osascript", ["-e", script], {
85
- stdio: "ignore",
86
- detached: true
87
- }).unref();
88
- }
89
- else if (process.platform === "win32") {
90
- (0, child_process_1.spawn)("cmd.exe", ["/c", "start", "cmd.exe", "/k", cmd], {
91
- cwd,
92
- stdio: "ignore",
93
- detached: true,
94
- shell: true
95
- }).unref();
96
- }
97
- else {
98
- // Linux: try common terminal emulators in order
99
- const terminals = [
100
- {
101
- bin: "x-terminal-emulator",
102
- args: ["-e", `bash -c '${cmd}; exec bash'`]
103
- },
104
- {
105
- bin: "gnome-terminal",
106
- args: ["--", "bash", "-c", `${cmd}; exec bash`]
107
- },
108
- { bin: "konsole", args: ["-e", "bash", "-c", `${cmd}; exec bash`] },
109
- {
110
- bin: "xfce4-terminal",
111
- args: ["-e", `bash -c '${cmd}; exec bash'`]
112
- },
113
- { bin: "xterm", args: ["-e", `bash -c '${cmd}; exec bash'`] }
114
- ];
115
- let launched = false;
116
- for (const t of terminals) {
117
- try {
118
- (0, child_process_1.execSync)(`which ${t.bin}`, { stdio: "pipe" });
119
- (0, child_process_1.spawn)(t.bin, t.args, {
120
- cwd,
121
- stdio: "ignore",
122
- detached: true
123
- }).unref();
124
- launched = true;
125
- break;
126
- }
127
- catch {
128
- // not found, try next
129
- }
130
- }
131
- if (!launched) {
132
- console.log(` ⚠ No supported terminal found. Run manually: cd "${cwd}" && npm start`);
133
- return;
134
- }
135
- }
136
- console.log(` ✔ Opened ${label} in a new terminal window.`);
137
- };
114
+ // ...existing code...
138
115
  const installExperienceBuilder = async (version) => {
139
116
  const url = `https://downloads.arcgis.com/dms/rest/download/secured/arcgis-experience-builder-${version}.zip?f=json&folder=software%2FExperienceBuilder%2F${version}`;
140
117
  const res = await fetch(url);
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.start = start;
7
+ const fs_extra_1 = __importDefault(require("fs-extra"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const startDevServer_1 = require("../utils/startDevServer");
10
+ function start() {
11
+ const clientDir = process.cwd();
12
+ const serverDir = path_1.default.join(process.cwd(), "..", "server");
13
+ if (!fs_extra_1.default.existsSync(path_1.default.join(clientDir, "your-extensions"))) {
14
+ console.error("Error: Run this from the ExB client folder.");
15
+ return;
16
+ }
17
+ (0, startDevServer_1.startDevServer)(clientDir, serverDir);
18
+ }
package/dist/index.js CHANGED
@@ -43,22 +43,23 @@ const search_1 = require("./commands/search");
43
43
  const remove_1 = require("./commands/remove");
44
44
  const format_1 = require("./commands/format");
45
45
  const scaffold_1 = require("./commands/scaffold");
46
+ const dev_setup_1 = require("./commands/dev-setup");
47
+ const start_1 = require("./commands/start");
46
48
  const fs = __importStar(require("fs-extra"));
47
49
  const path = __importStar(require("path"));
48
- const dev_setup_1 = require("./commands/dev-setup");
49
50
  const packageJsonPath = path.join(__dirname, "../package.json");
50
51
  const packageJson = fs.readJsonSync(packageJsonPath, { throws: false }) || {
51
52
  version: "1.0.0"
52
53
  };
53
54
  const program = new commander_1.Command();
54
55
  program
55
- .name("exb-cli")
56
- .description("The community-led widget manager for ArcGIS Experience Builder")
56
+ .name("exb")
57
+ .description("The community-led widget manager for ArcGIS Experience Builder.")
57
58
  .version(packageJson.version);
58
59
  // --- COMMAND: INSTALL ---
59
60
  program
60
61
  .command("install <package>")
61
- .alias("i") // Allows users to type `exb-cli i widget-name`
62
+ .alias("i") // Allows users to type `exb i widget-name`
62
63
  .description("Install a widget from NPM into your Experience Builder project")
63
64
  .option("--widget-only", "Skip running npm ci in the installed widget directory")
64
65
  .action(async (pkg, options) => {
@@ -67,7 +68,6 @@ program
67
68
  // --- COMMAND: UPDATE ---
68
69
  program
69
70
  .command("update <package>")
70
- .alias("u")
71
71
  .description("Update an installed widget to the latest version (or a specified version)")
72
72
  .option("--widget-only", "Skip running npm ci in the updated widget directory")
73
73
  .option("--version <version>", "Specify a version or dist-tag to update to")
@@ -80,7 +80,6 @@ program
80
80
  // --- COMMAND: REMOVE ---
81
81
  program
82
82
  .command("remove <package>")
83
- .alias("rm")
84
83
  .description("Remove an installed widget from your Experience Builder project")
85
84
  .option("-f, --force", "Skip confirmation prompt")
86
85
  .action(async (pkg, options) => {
@@ -89,7 +88,6 @@ program
89
88
  // --- COMMAND: SEARCH ---
90
89
  program
91
90
  .command("search")
92
- .alias("s")
93
91
  .description("Search npm for Experience Builder widgets (by keyword)")
94
92
  .option("-k, --keyword <keyword>", "Additional keyword to include in search")
95
93
  .option("-n, --size <size>", "Maximum number of npm results to fetch (default: 15)")
@@ -105,7 +103,6 @@ program
105
103
  // --- COMMAND: FORMAT ---
106
104
  program
107
105
  .command("format <widget>")
108
- .alias("fmt")
109
106
  .description("Format a widget package according to community standards, based on the manifest.json configuration.")
110
107
  .option("-f, --force", "Skip prompts and overwrite package.json if present")
111
108
  .action(async (widget, options) => {
@@ -114,7 +111,6 @@ program
114
111
  // --- COMMAND: SCAFFOLD ---
115
112
  program
116
113
  .command("scaffold <name>")
117
- .alias("new")
118
114
  .description("Scaffold a new widget package with a manifest.json, using an esri template")
119
115
  .action(async (name, options) => {
120
116
  await (0, scaffold_1.scaffoldWidget)(name);
@@ -129,6 +125,10 @@ program
129
125
  (0, dev_setup_1.devSetup)({ version });
130
126
  //await scaffoldWidget('dev-environment', { version });
131
127
  });
128
+ program
129
+ .command("start")
130
+ .description("Start the client and server development servers for the current Experience Builder Developer Edition environment")
131
+ .action(start_1.start);
132
132
  // Parse the arguments passed by the user in the terminal
133
133
  program.parse(process.argv);
134
134
  // If the user runs the CLI with no arguments, show the help menu
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.startDevServer = startDevServer;
4
+ const child_process_1 = require("child_process");
5
+ function startDevServer(clientDir, serverDir) {
6
+ console.log("Starting client and server development servers...");
7
+ // Save terminal settings before spawning child processes (Unix/macOS only)
8
+ let savedTermSettings = null;
9
+ if (process.platform !== "win32" && process.stdin.isTTY) {
10
+ try {
11
+ savedTermSettings = (0, child_process_1.execSync)("stty -g", {
12
+ stdio: ["inherit", "pipe", "pipe"]
13
+ })
14
+ .toString()
15
+ .trim();
16
+ }
17
+ catch { }
18
+ }
19
+ const restoreTerminal = () => {
20
+ if (savedTermSettings) {
21
+ try {
22
+ (0, child_process_1.execSync)(`stty ${savedTermSettings}`, { stdio: "inherit" });
23
+ }
24
+ catch { }
25
+ }
26
+ };
27
+ const serverProc = (0, child_process_1.spawn)("npm", ["start"], {
28
+ cwd: serverDir,
29
+ stdio: "ignore",
30
+ detached: true
31
+ });
32
+ serverProc.unref();
33
+ const clientProc = (0, child_process_1.spawn)("npm", ["start"], {
34
+ cwd: clientDir,
35
+ stdio: "inherit"
36
+ });
37
+ let isShuttingDown = false;
38
+ const shutdown = () => {
39
+ if (isShuttingDown)
40
+ return;
41
+ isShuttingDown = true;
42
+ if (serverProc && !serverProc.killed && serverProc.pid) {
43
+ try {
44
+ process.kill(-serverProc.pid);
45
+ }
46
+ catch { }
47
+ }
48
+ if (clientProc && !clientProc.killed) {
49
+ try {
50
+ clientProc.kill();
51
+ }
52
+ catch { }
53
+ }
54
+ restoreTerminal();
55
+ process.exit();
56
+ };
57
+ process.on("SIGINT", shutdown);
58
+ process.on("SIGTERM", shutdown);
59
+ clientProc.on("exit", shutdown);
60
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "exb-community-cli",
3
- "version": "1.0.2",
4
- "description": "A lightweight command line interface to allow Experience Builder developers to quickly import widgets published as NPM pacakges.",
3
+ "version": "1.0.3",
4
+ "description": "A lightweight command line interface to allow Experience Builder developers to quickly import widgets published as NPM pacakges. Developed by the Esri Community.",
5
5
  "keywords": [
6
6
  "exb-community",
7
7
  "cli",
@@ -9,7 +9,11 @@
9
9
  "widget"
10
10
  ],
11
11
  "bin": {
12
- "exb-cli": "dist/index.js"
12
+ "exb": "dist/index.js"
13
+ },
14
+ "homepage": "https://github.com/SunshineLuke90/exb-community-cli#readme",
15
+ "bugs": {
16
+ "url": "https://github.com/SunshineLuke90/exb-community-cli/issues"
13
17
  },
14
18
  "preferGlobal": true,
15
19
  "license": "MIT",
@@ -41,5 +45,9 @@
41
45
  "jest": "^29.7.0",
42
46
  "ts-jest": "^29.1.0",
43
47
  "typescript": "^5.9.3"
48
+ },
49
+ "repository": {
50
+ "type": "git",
51
+ "url": "git+https://github.com/SunshineLuke90/exb-community-cli.git"
44
52
  }
45
53
  }