@solidactions/cli 1.17.0 → 1.18.0

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/README.md CHANGED
@@ -97,6 +97,7 @@ Use `solidactions <command> --help` for full flag details on any command.
97
97
 
98
98
  | Command | Key Flags | Description |
99
99
  |---------|-----------|-------------|
100
+ | `project create <name>` | `-e` | Create an empty project (no source/build); `-e` defaults to `production` |
100
101
  | `project deploy <name> [path]` | `-e`, `--create`, `--config-only` | Deploy or sync config only |
101
102
  | `project pull <name> [path]` | `-y` | Pull source (warns before overwriting) |
102
103
  | `project logs <name>` | | View build logs |
@@ -14,6 +14,7 @@ const js_yaml_1 = __importDefault(require("js-yaml"));
14
14
  const env_1 = require("../utils/env");
15
15
  const api_1 = require("../utils/api");
16
16
  const deploy_ignore_1 = require("../utils/deploy-ignore");
17
+ const slug_1 = require("../utils/slug");
17
18
  /**
18
19
  * Validate project structure before deployment.
19
20
  * Checks for required files and SDK dependency.
@@ -243,7 +244,7 @@ async function deploy(projectName, sourcePath, options = {}) {
243
244
  process.exit(1);
244
245
  }
245
246
  console.log(chalk_1.default.yellow(`Project "${projectName}"${envLabel} not found. Creating...`));
246
- const requestedSlug = projectName.toLowerCase().replace(/[^a-z0-9-]/g, '-') + (environment !== 'production' ? `-${environment}` : '');
247
+ const requestedSlug = (0, slug_1.buildProjectSlug)(projectName, environment);
247
248
  try {
248
249
  const createResponse = await axios_1.default.post(`${config.host}/api/v1/projects`, {
249
250
  name: projectName,
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ /**
3
+ * solidactions project create <name> [-e <environment>]
4
+ *
5
+ * Creates a project + environment via POST /api/v1/projects WITHOUT uploading
6
+ * any source or triggering a build. This is the empty-project path that the web
7
+ * UI already offers; `project deploy` creates-on-demand but always builds.
8
+ *
9
+ * When -e is omitted we default to `production`: a project needs a production
10
+ * root before dev/staging children can attach to it, so creating the root is
11
+ * the sensible default (mirrors the guidance in `project deploy`).
12
+ */
13
+ var __importDefault = (this && this.__importDefault) || function (mod) {
14
+ return (mod && mod.__esModule) ? mod : { "default": mod };
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.projectCreateWithConfig = projectCreateWithConfig;
18
+ exports.projectCreate = projectCreate;
19
+ const axios_1 = __importDefault(require("axios"));
20
+ const chalk_1 = __importDefault(require("chalk"));
21
+ const api_1 = require("../utils/api");
22
+ const slug_1 = require("../utils/slug");
23
+ /**
24
+ * Core implementation — accepts an injected config so tests can point at a
25
+ * stub server without touching the filesystem config.
26
+ */
27
+ async function projectCreateWithConfig(name, options, config) {
28
+ const environment = options.env ?? 'production';
29
+ // Reject names that produce no usable slug (e.g. "!!!" or non-Latin scripts)
30
+ // up front, with a clear client-side message instead of an opaque 422.
31
+ // Name/slug length is left to the server, which owns those limits.
32
+ if ((0, slug_1.slugifyName)(name) === '') {
33
+ console.error(chalk_1.default.red(`Invalid project name "${name}": it must contain letters or numbers (a-z, 0-9).`));
34
+ process.exit(1);
35
+ }
36
+ const slug = (0, slug_1.buildProjectSlug)(name, environment);
37
+ const envLabel = environment !== 'production' ? ` (${environment})` : '';
38
+ console.log(chalk_1.default.blue(`Creating project "${name}"${envLabel}...`));
39
+ try {
40
+ const response = await axios_1.default.post(`${config.host}/api/v1/projects`, { name, slug, environment }, { headers: (0, api_1.getApiHeaders)(config, 'application/json') });
41
+ const createdSlug = response.data?.slug || slug;
42
+ console.log(chalk_1.default.green(`✓ Project "${name}"${envLabel} created.`));
43
+ console.log(chalk_1.default.gray(` slug: ${createdSlug}`));
44
+ }
45
+ catch (error) {
46
+ if (error.response) {
47
+ if (error.response.status === 401) {
48
+ console.error(chalk_1.default.red('Authentication failed. Run "solidactions login <api-key>" to re-configure.'));
49
+ }
50
+ else {
51
+ console.error(chalk_1.default.red('Failed to create project:'), error.response.data?.message || error.message);
52
+ }
53
+ }
54
+ else {
55
+ console.error(chalk_1.default.red('Connection failed:'), error.message);
56
+ }
57
+ process.exit(1);
58
+ }
59
+ }
60
+ /** Entry point wired into the CLI — resolves config, then delegates. */
61
+ async function projectCreate(name, options) {
62
+ const config = await (0, api_1.requireConfigWithWorkspace)();
63
+ await projectCreateWithConfig(name, options, config);
64
+ }
package/dist/index.js CHANGED
@@ -11,6 +11,7 @@ const login_1 = require("./commands/login");
11
11
  const init_1 = require("./commands/init");
12
12
  const pull_1 = require("./commands/pull");
13
13
  const project_list_1 = require("./commands/project-list");
14
+ const project_create_1 = require("./commands/project-create");
14
15
  const project_logs_1 = require("./commands/project-logs");
15
16
  const run_start_1 = require("./commands/run-start");
16
17
  const run_list_1 = require("./commands/run-list");
@@ -141,6 +142,14 @@ program
141
142
  // project <subcommand>
142
143
  // =============================================================================
143
144
  const project = program.command('project').description('Manage projects');
145
+ project
146
+ .command('create')
147
+ .description('Create an empty project (and environment) without deploying source')
148
+ .argument('<name>', 'Project name')
149
+ .option('-e, --env <environment>', 'Target environment (production/staging/dev). Defaults to production.')
150
+ .action(async (name, options) => {
151
+ await (0, project_create_1.projectCreate)(name, options);
152
+ });
144
153
  project
145
154
  .command('deploy')
146
155
  .description('Deploy a project to SolidActions')
@@ -14,12 +14,19 @@ const ignore_1 = __importDefault(require("ignore"));
14
14
  /**
15
15
  * Layer-2 matcher defaults (gitignore syntax). These are excluded unless a later
16
16
  * pattern (deploy.exclude or .gitignore) re-includes them via a `!` negation.
17
+ *
18
+ * `dist/` and `vendor/` are anchored to the project root (`/dist/`, `/vendor/`)
19
+ * so they only strip the project's own build output. An unanchored `dist/` /
20
+ * `vendor/` matches at any depth and wrongly excludes a vendored dependency's
21
+ * own build output — e.g. a `"@solidactions/sdk": "file:./sdk"` dep whose code
22
+ * lives in `sdk/dist/`, which then fails to resolve at build time.
23
+ * `node_modules/` and `.git/` stay unanchored: those are never wanted at any depth.
17
24
  */
18
25
  exports.DEFAULT_DEPLOY_IGNORES = [
19
26
  'node_modules/',
20
27
  '.git/',
21
- 'dist/',
22
- 'vendor/',
28
+ '/dist/',
29
+ '/vendor/',
23
30
  ];
24
31
  /**
25
32
  * Layer-1 hard deny — matched against the *basename* of a path. Never
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ /**
3
+ * Project slug generation — shared by `project create` and `project deploy`
4
+ * so the two commands always produce identical slugs for the same input.
5
+ *
6
+ * The server is the authority on slugs (it re-derives/validates on write); this
7
+ * client-side slug is what we send in the POST body and use for follow-up
8
+ * lookups. Keeping it normalized avoids odd values like `foo--bar` or `-foo-`.
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.slugifyName = slugifyName;
12
+ exports.buildProjectSlug = buildProjectSlug;
13
+ /**
14
+ * Normalize a free-text project name into a slug fragment:
15
+ * lowercase, collapse every run of non-alphanumerics to a single hyphen, and
16
+ * trim leading/trailing hyphens. Returns '' when the name has no usable
17
+ * alphanumeric characters (e.g. "!!!" or "你好") — callers should treat an
18
+ * empty result as invalid input.
19
+ */
20
+ function slugifyName(name) {
21
+ return name
22
+ .toLowerCase()
23
+ .replace(/[^a-z0-9]+/g, '-')
24
+ .replace(/^-+|-+$/g, '');
25
+ }
26
+ /**
27
+ * Build the full project slug for an environment. Non-production environments
28
+ * get a `-<environment>` suffix (matching the deploy create flow); production
29
+ * is the bare root slug.
30
+ */
31
+ function buildProjectSlug(name, environment) {
32
+ const base = slugifyName(name);
33
+ return environment !== 'production' ? `${base}-${environment}` : base;
34
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solidactions/cli",
3
- "version": "1.17.0",
3
+ "version": "1.18.0",
4
4
  "description": "SolidActions CLI - Deploy and manage workflow automation",
5
5
  "main": "dist/index.js",
6
6
  "bin": {