@swell/cli 2.2.1 → 2.3.1

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.
Files changed (61) hide show
  1. package/dist/app-command.js +1 -1
  2. package/dist/commands/api/delete.js +4 -1
  3. package/dist/commands/api/get.js +1 -0
  4. package/dist/commands/api/index.js +4 -1
  5. package/dist/commands/api/post.js +1 -0
  6. package/dist/commands/api/put.js +1 -0
  7. package/dist/commands/app/frontend/dev.js +1 -1
  8. package/dist/commands/app/init.d.ts +8 -7
  9. package/dist/commands/app/init.js +36 -18
  10. package/dist/commands/app/pull.js +2 -2
  11. package/dist/commands/app/push.js +2 -2
  12. package/dist/commands/app/version.d.ts +1 -0
  13. package/dist/commands/app/version.js +15 -5
  14. package/dist/commands/create/app.d.ts +8 -4
  15. package/dist/commands/create/app.js +68 -51
  16. package/dist/commands/create/content.d.ts +5 -6
  17. package/dist/commands/create/content.js +21 -37
  18. package/dist/commands/create/function.d.ts +6 -7
  19. package/dist/commands/create/function.js +94 -31
  20. package/dist/commands/create/index.js +8 -0
  21. package/dist/commands/create/model.d.ts +5 -6
  22. package/dist/commands/create/model.js +21 -33
  23. package/dist/commands/create/notification.d.ts +9 -9
  24. package/dist/commands/create/notification.js +117 -95
  25. package/dist/commands/create/setting.d.ts +21 -0
  26. package/dist/commands/create/setting.js +120 -0
  27. package/dist/commands/create/tests.d.ts +4 -5
  28. package/dist/commands/create/tests.js +8 -11
  29. package/dist/commands/create/webhook.d.ts +22 -0
  30. package/dist/commands/create/webhook.js +176 -0
  31. package/dist/commands/schema.d.ts +1 -0
  32. package/dist/commands/schema.js +51 -5
  33. package/dist/commands/theme/init.d.ts +8 -4
  34. package/dist/commands/theme/init.js +21 -8
  35. package/dist/create-app-command.d.ts +1 -0
  36. package/dist/create-app-command.js +15 -10
  37. package/dist/create-config-command.js +2 -2
  38. package/dist/help/custom-help.d.ts +89 -0
  39. package/dist/help/custom-help.js +337 -0
  40. package/dist/help/types.d.ts +75 -0
  41. package/dist/help/types.js +1 -0
  42. package/dist/lib/apps/app-config.js +2 -2
  43. package/dist/lib/apps/index.d.ts +2 -1
  44. package/dist/lib/apps/index.js +21 -5
  45. package/dist/lib/apps/paths.js +7 -6
  46. package/dist/lib/create/notification.d.ts +1 -0
  47. package/dist/lib/create/schemas.d.ts +1 -0
  48. package/dist/lib/create/schemas.js +1 -0
  49. package/dist/lib/create/setting.d.ts +15 -0
  50. package/dist/lib/create/setting.js +27 -0
  51. package/dist/lib/create/tests/templates/env-dts.js +1 -0
  52. package/dist/lib/create/tests/templates/swell-client.js +2 -0
  53. package/dist/lib/create/tests/templates/tsconfig.js +2 -0
  54. package/dist/lib/create/tests/templates/vitest-config.js +1 -0
  55. package/dist/lib/create/webhook.d.ts +32 -0
  56. package/dist/lib/create/webhook.js +52 -0
  57. package/dist/lib/proxy.js +62 -5
  58. package/dist/swell-api-command.d.ts +14 -0
  59. package/dist/swell-api-command.js +113 -7
  60. package/oclif.manifest.json +609 -259
  61. package/package.json +3 -1
@@ -17,7 +17,7 @@ export class AppCommand extends SwellCommand {
17
17
  // needs to be in a ES2021 format: https://github.com/oclif/oclif/issues/1100
18
18
  static baseFlags = {
19
19
  'app-path': Flags.string({
20
- description: 'path to your app directory',
20
+ description: 'Path to your app directory',
21
21
  }),
22
22
  };
23
23
  // the local path to the app directory
@@ -16,7 +16,10 @@ export default class ApiDelete extends SwellApiCommand {
16
16
  default: false,
17
17
  }),
18
18
  };
19
- static examples = ['swell api delete /products/abc123'];
19
+ static examples = [
20
+ 'swell api delete /products/abc123',
21
+ 'swell api delete /functions/my-app/clear-cache',
22
+ ];
20
23
  get method() {
21
24
  return HttpMethod.DELETE;
22
25
  }
@@ -21,6 +21,7 @@ export default class ApiGet extends SwellApiCommand {
21
21
  'swell api get /products',
22
22
  'swell api get "/products?limit=10&category=shoes"',
23
23
  'swell api get /products/abc123',
24
+ 'swell api get /functions/my-app/get-inventory',
24
25
  ];
25
26
  get method() {
26
27
  return HttpMethod.GET;
@@ -2,12 +2,15 @@ import { Command } from '@oclif/core';
2
2
  export default class Api extends Command {
3
3
  static summary = 'Send requests directly to the Swell Backend API.';
4
4
  static description = `Run Swell API requests directly from the command line.
5
- Supports GET, POST, PUT, and DELETE methods with optional test/live environments.`;
5
+ Supports GET, POST, PUT, and DELETE methods with optional test/live environments.
6
+ Call app functions via /functions/<app_id>/<function_name> paths.`;
6
7
  static examples = [
7
8
  'swell api get /products',
8
9
  'swell api post /products --body \'{"name":"New product"}\'',
9
10
  'swell api put /products/abc123 --body ./update.json',
10
11
  'swell api delete /products/abc123',
12
+ 'swell api get /functions/my-app/get-inventory',
13
+ 'swell api post /functions/my-app/create-order --body \'{"items":["sku-1"]}\'',
11
14
  ];
12
15
  async run() {
13
16
  this.log('Use "swell api get|post|put|delete" to interact with the Swell API.');
@@ -23,6 +23,7 @@ export default class ApiPost extends SwellApiCommand {
23
23
  static examples = [
24
24
  'swell api post /products --body \'{"name": "Product", "price": 100}\'',
25
25
  'swell api post /products --body ./product.json',
26
+ 'swell api post /functions/my-app/create-order --body \'{"items":["sku-1"]}\'',
26
27
  ];
27
28
  get method() {
28
29
  return HttpMethod.POST;
@@ -23,6 +23,7 @@ export default class ApiPut extends SwellApiCommand {
23
23
  static examples = [
24
24
  'swell api put /products/{id} --body \'{"id": "abc123", "name": "Updated"}\'',
25
25
  'swell api put /products/abc123 --body ./product.json',
26
+ 'swell api put /functions/my-app/update-stock --body \'{"sku":"abc","qty":10}\'',
26
27
  ];
27
28
  get method() {
28
29
  return HttpMethod.PUT;
@@ -83,7 +83,7 @@ export default class AppFrontendDev extends PushAppCommand {
83
83
  }
84
84
  // 3. READY DETECTION: Detect server ready, show our message
85
85
  if (!serverReadyDetected &&
86
- (/✓ ready in \d+/.test(string) || /✓ starting/.test(string))) {
86
+ (/✓ ready in \d+/i.test(string) || /✓ starting/i.test(string))) {
87
87
  serverReadyDetected = true;
88
88
  this.log(`Started ${projectType.name} dev server on port ${serverPort}.\n`);
89
89
  const sessionId = localConfig.getSessionId(currentStore);
@@ -1,12 +1,13 @@
1
+ import { HelpMeta } from '../../help/types.js';
1
2
  import CreateApp from '../create/app.js';
2
3
  export default class InitApp extends CreateApp {
3
- static description: string;
4
- static examples: {
5
- command: string;
6
- description: string;
7
- }[];
8
- static flags: {
9
- yes: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
4
+ protected commandExample: string;
5
+ static args: {
6
+ id: import("@oclif/core/lib/interfaces/parser.js").Arg<string, Record<string, unknown>>;
10
7
  };
8
+ static description: string;
9
+ static examples: string[];
10
+ static helpMeta: HelpMeta;
11
+ static flags: any;
11
12
  run(): Promise<void>;
12
13
  }
@@ -1,32 +1,50 @@
1
- import { Flags } from '@oclif/core';
1
+ import { Args } from '@oclif/core';
2
2
  import path from 'node:path';
3
- import CreateApp from '../create/app.js';
3
+ import CreateApp, { appHelpMetaBase } from '../create/app.js';
4
4
  export default class InitApp extends CreateApp {
5
+ // Override command example for error messages
6
+ commandExample = 'swell app init';
7
+ static args = {
8
+ id: Args.string({
9
+ default: '',
10
+ description: 'App identifier (defaults to current directory name)',
11
+ }),
12
+ };
5
13
  static description = 'Initialize app swell.json in the current directory.';
6
14
  static examples = [
7
- {
8
- command: 'swell app init',
9
- description: 'Initialize app following command prompts.',
10
- },
11
- {
12
- command: 'swell app init -y',
13
- description: 'Initialize app and accept all default values.',
14
- },
15
+ '$ swell app init',
16
+ '$ swell app init my-app',
17
+ '$ swell app init -t admin -y',
18
+ '$ swell app init my-app -t admin -y',
19
+ '$ swell app init my-app -t admin --frontend astro -y',
20
+ '$ swell app init my_theme -t theme --storefront-app proxima -y',
15
21
  ];
22
+ static helpMeta = {
23
+ ...appHelpMetaBase,
24
+ usageDirect: '[id] -t <type> [...] -y',
25
+ };
26
+ // Inherit all flags from CreateApp (includes -p, -t, -n, -v, -d)
27
+ // baseFlags from CreateAppCommand (-y, --frontend, etc.) are merged automatically by oclif
16
28
  static flags = {
17
- yes: Flags.boolean({
18
- char: 'y',
19
- description: `accept all default values`,
20
- }),
29
+ ...CreateApp.flags,
21
30
  };
22
31
  async run() {
23
- const { flags } = await this.parse(InitApp);
24
- const { yes: confirmYes } = flags;
25
- const id = process.cwd().split(path.sep).pop() || 'Swell App';
32
+ const { args, flags } = await this.parse(InitApp);
33
+ const { id: argId } = args;
34
+ const { yes: confirmYes, type, name, version, description, frontend, } = flags;
35
+ // Use provided id argument, or fall back to current directory name
36
+ const id = argId || process.cwd().split(path.sep).pop() || 'Swell App';
26
37
  await this.createSwellConfig({
27
38
  allowOverwrite: false,
28
39
  inputId: id,
29
- inputType: this.appType,
40
+ inputType: type || this.appType,
41
+ inputName: name,
42
+ inputVersion: version,
43
+ inputDescription: description,
44
+ inputFrontend: frontend,
45
+ inputStorefrontApp: flags['storefront-app'],
46
+ inputIntegrationType: flags['integration-type'],
47
+ inputIntegrationId: flags['integration-id'],
30
48
  inputYes: confirmYes,
31
49
  nestedPath: false,
32
50
  });
@@ -1,6 +1,6 @@
1
1
  import { Args, Flags } from '@oclif/core';
2
2
  import * as path from 'node:path';
3
- import { ConfigPaths } from '../../lib/apps/index.js';
3
+ import { AllConfigPaths } from '../../lib/apps/index.js';
4
4
  import style from '../../lib/style.js';
5
5
  import { PushAppCommand } from '../../push-app-command.js';
6
6
  export default class AppPull extends PushAppCommand {
@@ -17,7 +17,7 @@ type from an app in your store's test environment to your local machine.
17
17
  If APPID is not specified, you will be prompted with a list of apps to choose from.
18
18
 
19
19
  App file directories:
20
- ${Object.values(ConfigPaths)
20
+ ${Object.values(AllConfigPaths)
21
21
  .map((dir) => style.path(`${dir}/`))
22
22
  .join('\n')}\n${style.path(`frontend/`)}`;
23
23
  static examples = [
@@ -1,6 +1,6 @@
1
1
  import { Args, Flags } from '@oclif/core';
2
2
  import * as path from 'node:path';
3
- import { ConfigPaths, filePathExists, isPathDirectory, } from '../../lib/apps/index.js';
3
+ import { AllConfigPaths, filePathExists, isPathDirectory, } from '../../lib/apps/index.js';
4
4
  import style from '../../lib/style.js';
5
5
  import { PushAppCommand } from '../../push-app-command.js';
6
6
  export default class AppPush extends PushAppCommand {
@@ -22,7 +22,7 @@ If the app does not exist, it will be created and its global ID saved to a .swel
22
22
  - If a directory is specified, only files in that directory will be pushed.
23
23
 
24
24
  App file directories:
25
- ${Object.values(ConfigPaths)
25
+ ${Object.values(AllConfigPaths)
26
26
  .map((dir) => style.path(`${dir}/`))
27
27
  .join('\n')}`;
28
28
  static examples = [
@@ -7,6 +7,7 @@ export default class AppVersion extends PushAppCommand {
7
7
  static examples: string[];
8
8
  static flags: {
9
9
  amend: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
10
+ 'force-create-files': import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
10
11
  message: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
11
12
  'no-git-tag': import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
12
13
  yes: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
@@ -55,6 +55,9 @@ behavior by using the --no-git-tag option.`;
55
55
  amend: Flags.boolean({
56
56
  description: 'amend the description an existing version',
57
57
  }),
58
+ 'force-create-files': Flags.boolean({
59
+ description: 'do not use files from previous versions',
60
+ }),
58
61
  message: Flags.string({
59
62
  char: 'm',
60
63
  description: 'description of the changes in this version for internal use',
@@ -73,7 +76,7 @@ behavior by using the --no-git-tag option.`;
73
76
  static summary = 'Increment the version of your Swell app.';
74
77
  async run() {
75
78
  const { args, flags } = await this.parse(AppVersion);
76
- const { amend, 'no-git-tag': noGitTag, yes } = flags;
79
+ const { amend, 'no-git-tag': noGitTag, yes, 'force-create-files': forceCreateFiles = false, } = flags;
77
80
  let { message } = flags;
78
81
  let { nextVersion } = args;
79
82
  if (!(await this.ensureAppExists(undefined, false))) {
@@ -137,7 +140,7 @@ behavior by using the --no-git-tag option.`;
137
140
  const spinner = ora();
138
141
  spinner.start('Creating version');
139
142
  try {
140
- await this.createRemoteVersion(nextVersion, message, spinner);
143
+ await this.createRemoteVersion(nextVersion, message, spinner, forceCreateFiles);
141
144
  await this.gitCommit(message);
142
145
  if (!noGitTag)
143
146
  await this.gitTag(nextVersion);
@@ -148,17 +151,24 @@ behavior by using the --no-git-tag option.`;
148
151
  }
149
152
  spinner.succeed(`${style.appConfigValue(this.app.name)} version ${nextVersion} created.`);
150
153
  }
151
- async createRemoteVersion(nextVersion, message, spinner) {
154
+ async createRemoteVersion(nextVersion, message, spinner, forceCreateFiles = false) {
155
+ const body = {
156
+ description: message,
157
+ version: nextVersion,
158
+ };
159
+ if (forceCreateFiles) {
160
+ body.$force_create_files = true;
161
+ }
152
162
  // update the version on the remote
153
163
  const versionResponse = await this.api.post({ adminPath: `/apps/${this.app.id}/versions` }, {
154
- body: { description: message, version: nextVersion },
164
+ body,
155
165
  onAsyncGetPath: (response) => ({
156
166
  adminPath: `/apps/${this.app.id}/versions/${response.id}`,
157
167
  }),
158
168
  spinner,
159
169
  });
160
170
  if (!versionResponse || !versionResponse.version) {
161
- spinner.fail('Something went wrong.');
171
+ throw new Error('Something went wrong. Server could not create version.');
162
172
  }
163
173
  // update the local app config file since remote was successful
164
174
  this.swellConfig.set('version', nextVersion);
@@ -1,13 +1,17 @@
1
1
  import { CreateAppCommand } from '../../create-app-command.js';
2
+ import { HelpMeta } from '../../help/types.js';
3
+ /**
4
+ * Shared helpMeta for app creation commands (create app, app init).
5
+ * Defines the APP TYPES section and type-specific flags.
6
+ */
7
+ export declare const appHelpMetaBase: Omit<HelpMeta, 'usageDirect'>;
2
8
  export default class CreateApp extends CreateAppCommand {
3
9
  static args: {
4
10
  id: import("@oclif/core/lib/interfaces/parser.js").Arg<string, Record<string, unknown>>;
5
11
  };
6
12
  static description: string;
7
- static examples: {
8
- command: string;
9
- description: string;
10
- }[];
13
+ static examples: string[];
14
+ static helpMeta: HelpMeta;
11
15
  static flags: any;
12
16
  appType: string;
13
17
  createSwellConfig({ allowOverwrite, inputId, inputStorefrontApp, inputType, inputName, inputVersion, inputDescription, inputFrontend, inputIntegrationType, inputIntegrationId, inputYes, nestedPath, }: {
@@ -6,75 +6,89 @@ import { CreateAppCommand } from '../../create-app-command.js';
6
6
  import { newConfig, swellConfigFileExists } from '../../lib/app-config.js';
7
7
  import { toAppId, toAppName } from '../../lib/create/index.js';
8
8
  import style from '../../lib/style.js';
9
+ /**
10
+ * Shared helpMeta for app creation commands (create app, app init).
11
+ * Defines the APP TYPES section and type-specific flags.
12
+ */
13
+ export const appHelpMetaBase = {
14
+ typeSection: {
15
+ title: 'APP TYPES',
16
+ types: [
17
+ {
18
+ name: 'admin',
19
+ description: 'Dashboard extension',
20
+ optional: ['--frontend'],
21
+ },
22
+ {
23
+ name: 'storefront',
24
+ description: 'Hosted storefront',
25
+ optional: ['--frontend'],
26
+ },
27
+ {
28
+ name: 'theme',
29
+ description: 'Theme for existing storefront',
30
+ requires: ['--storefront-app'],
31
+ },
32
+ {
33
+ name: 'integration',
34
+ description: 'Third-party service',
35
+ requires: [
36
+ '--integration-type',
37
+ '--integration-id (for payment | shipping | tax)',
38
+ ],
39
+ },
40
+ ],
41
+ },
42
+ typeFlags: [
43
+ 'frontend',
44
+ 'storefront-app',
45
+ 'integration-type',
46
+ 'integration-id',
47
+ ],
48
+ };
9
49
  export default class CreateApp extends CreateAppCommand {
10
50
  static args = {
11
51
  id: Args.string({
12
52
  default: '',
13
- description: `id of the app to create (required in -y)`,
53
+ description: 'App identifier (e.g., my-app)',
14
54
  }),
15
55
  };
16
56
  static description = 'Create an app.';
17
57
  static examples = [
18
- {
19
- command: 'swell create app',
20
- description: 'Interactive: follow prompts to create an app.',
21
- },
22
- {
23
- command: 'swell create app my_app -t admin -y',
24
- description: 'Non-interactive: minimal with defaults.',
25
- },
26
- {
27
- command: 'swell create app my_app --type admin --name "My App" --version 1.0.1 --description "" -y',
28
- description: 'Non-interactive: explicit name, version, description.',
29
- },
30
- {
31
- command: 'swell create app my_app --type admin --frontend astro -y',
32
- description: 'Non-interactive: initialize an Astro frontend.',
33
- },
34
- {
35
- command: 'swell create app my_theme --type theme --storefront-app proxima -y',
36
- description: 'Non-interactive: theme targeting a specific storefront app.',
37
- },
38
- {
39
- command: 'swell create app my_payment --type integration --integration-type payment --integration-id card -y',
40
- description: 'Non-interactive: payment integration for credit cards.',
41
- },
42
- {
43
- command: 'swell create app my_shipping --type integration --integration-type shipping --integration-id fedex -y',
44
- description: 'Non-interactive: shipping integration for FedEx.',
45
- },
46
- {
47
- command: 'swell create app -p yarn',
48
- description: 'Package manager: use Yarn instead of npm.',
49
- },
50
- {
51
- command: 'swell create app -p none',
52
- description: 'Package manager: skip installing default dependencies.',
53
- },
58
+ '$ swell create app',
59
+ '$ swell create app my_app -t admin -y',
60
+ '$ swell create app my_app -t admin --frontend astro -y',
61
+ '$ swell create app my_theme -t theme --storefront-app proxima -y',
62
+ '$ swell create app my_payment -t integration --integration-type payment --integration-id card -y',
63
+ '$ swell create app my_shipping -t integration --integration-type shipping --integration-id fedex -y',
54
64
  ];
65
+ static helpMeta = {
66
+ ...appHelpMetaBase,
67
+ usageDirect: '<id> -t <type> [...] -y',
68
+ };
55
69
  static flags = {
56
70
  pkg: Flags.string({
57
71
  char: 'p',
58
72
  default: 'npm',
59
- description: `use npm or yarn to install default dependencies, or none to disable`,
73
+ description: 'Package manager: npm | yarn | none',
60
74
  options: ['npm', 'yarn', 'none'],
61
75
  }),
62
76
  type: Flags.string({
63
77
  char: 't',
64
- description: `create a specific app type (required in -y)`,
78
+ description: 'App type: admin | storefront | theme | integration',
65
79
  options: ['admin', 'integration', 'storefront', 'theme'],
66
80
  }),
67
81
  name: Flags.string({
68
82
  char: 'n',
69
- description: `application name (default: capitalized ID)`,
83
+ description: 'Display name (default: capitalized ID)',
70
84
  }),
71
85
  version: Flags.string({
72
86
  char: 'v',
73
- description: `application version (default: 1.0.0)`,
87
+ description: 'Version (default: 1.0.0)',
74
88
  }),
75
89
  description: Flags.string({
76
90
  char: 'd',
77
- description: `application description`,
91
+ description: 'Description',
78
92
  }),
79
93
  };
80
94
  appType = '';
@@ -87,12 +101,12 @@ export default class CreateApp extends CreateAppCommand {
87
101
  // check missed parameters
88
102
  if (confirmYes) {
89
103
  if (!appId) {
90
- this.error('Missing application id for non-interactive mode\n\nYou need to provide an app id value for non-interactive mode\n\nExample: swell create app reviews --type admin -y', {
104
+ this.error(`Missing application id for non-interactive mode\n\nYou need to provide an app id value for non-interactive mode\n\nExample: ${this.commandExample} reviews --type admin -y`, {
91
105
  exit: 1,
92
106
  });
93
107
  }
94
108
  if (!inputType) {
95
- this.error('Missing required flag for non-interactive mode: --type\n\nValid types: admin, integration, storefront, theme\n\nExample: swell create app reviews --type admin -y', {
109
+ this.error(`Missing required flag for non-interactive mode: --type\n\nValid types: admin, integration, storefront, theme\n\nExample: ${this.commandExample} reviews --type admin -y`, {
96
110
  exit: 1,
97
111
  });
98
112
  }
@@ -145,7 +159,7 @@ export default class CreateApp extends CreateAppCommand {
145
159
  let extensions;
146
160
  if (type === 'integration') {
147
161
  if (confirmYes && !inputIntegrationType) {
148
- this.error('Missing required flag for non-interactive mode for integration app: --integration-type\n\nValid types: generic, payment, shipping, tax\n\nExample: swell create app reviews --type integration --integration-type generic -y', {
162
+ this.error(`Missing required flag for non-interactive mode for integration app: --integration-type\n\nValid types: generic, payment, shipping, tax\n\nExample: ${this.commandExample} reviews --type integration --integration-type generic -y`, {
149
163
  exit: 1,
150
164
  });
151
165
  }
@@ -174,7 +188,7 @@ export default class CreateApp extends CreateAppCommand {
174
188
  const validValues = integrationType === 'payment'
175
189
  ? "use 'card' for credit card integration or unique custom ID for other payment integrations"
176
190
  : 'unique custom ID';
177
- this.error(`Missing required flag for non-interactive mode for ${integrationType} integration: --integration-id\n\nValid values: ${validValues}\n\nExample: swell create app my_app --type integration --integration-type ${integrationType} --integration-id ${integrationType === 'payment' ? 'card' : 'myid'} -y`, {
191
+ this.error(`Missing required flag for non-interactive mode for ${integrationType} integration: --integration-id\n\nValid values: ${validValues}\n\nExample: ${this.commandExample} my_app --type integration --integration-type ${integrationType} --integration-id ${integrationType === 'payment' ? 'card' : 'myid'} -y`, {
178
192
  exit: 1,
179
193
  });
180
194
  }
@@ -210,7 +224,7 @@ export default class CreateApp extends CreateAppCommand {
210
224
  }
211
225
  // Unified validation
212
226
  if (integrationId.length < 3) {
213
- this.error(`--integration-id must contain at least 3 characters\n\nValid value is a custom ID containing at least 3 characters\n\nExample: swell create app my_app --type integration --integration-type ${integrationType} --integration-id ${integrationType === 'payment' ? 'card' : 'myid'} -y`, {
227
+ this.error(`--integration-id must contain at least 3 characters\n\nValid value is a custom ID containing at least 3 characters\n\nExample: ${this.commandExample} my_app --type integration --integration-type ${integrationType} --integration-id ${integrationType === 'payment' ? 'card' : 'myid'} -y`, {
214
228
  exit: 1,
215
229
  });
216
230
  }
@@ -224,7 +238,7 @@ export default class CreateApp extends CreateAppCommand {
224
238
  break;
225
239
  }
226
240
  default: {
227
- this.error('Incorrect value for --integration-type\n\nValid types: generic, payment, shipping, tax\n\nExample: swell create app reviews --type integration --integration-type generic -y', {
241
+ this.error(`Incorrect value for --integration-type\n\nValid types: generic, payment, shipping, tax\n\nExample: ${this.commandExample} reviews --type integration --integration-type generic -y`, {
228
242
  exit: 1,
229
243
  });
230
244
  }
@@ -244,7 +258,7 @@ export default class CreateApp extends CreateAppCommand {
244
258
  }
245
259
  else {
246
260
  if (confirmYes) {
247
- this.error('There are several installed storefront apps to choose from\n\nYou should select a specific storefront app in the non-interactive mode using --storefront-app appid\n\nExample: swell create app reviews --type theme --storefront-app proxima -y', {
261
+ this.error(`There are several installed storefront apps to choose from\n\nYou should select a specific storefront app in the non-interactive mode using --storefront-app appid\n\nExample: ${this.commandExample} reviews --type theme --storefront-app proxima -y`, {
248
262
  exit: 1,
249
263
  });
250
264
  }
@@ -299,8 +313,11 @@ export default class CreateApp extends CreateAppCommand {
299
313
  }),
300
314
  ...(extensions && { extensions }),
301
315
  };
302
- const appPath = path.join(process.cwd(), inputId || appId);
303
- if (swellConfigFileExists(appPath)) {
316
+ const appPath = nestedPath
317
+ ? path.join(process.cwd(), inputId || appId)
318
+ : process.cwd();
319
+ const swellConfigPath = path.join(appPath, 'swell.json');
320
+ if (swellConfigFileExists(swellConfigPath)) {
304
321
  if (allowOverwrite) {
305
322
  if (!confirmYes) {
306
323
  const continueCreateApp = await confirm({
@@ -1,20 +1,19 @@
1
1
  import { CreateCollectionCommand } from '../../create-collection-command.js';
2
+ import { HelpMeta } from '../../help/types.js';
2
3
  import { ConfigType } from '../../lib/apps/index.js';
3
4
  export default class CreateContent extends CreateCollectionCommand {
4
5
  static args: {
5
6
  collection: import("@oclif/core/lib/interfaces/parser.js").Arg<string, Record<string, unknown>>;
6
7
  };
7
8
  static description: string;
8
- static examples: {
9
- command: string;
10
- description: string;
11
- }[];
9
+ static examples: string[];
10
+ static helpMeta: HelpMeta;
12
11
  static flags: {
12
+ label: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
13
13
  description: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
14
14
  fields: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
15
- label: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
16
- overwrite: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
17
15
  views: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
16
+ overwrite: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
18
17
  yes: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
19
18
  };
20
19
  static summary: string;
@@ -9,65 +9,49 @@ export default class CreateContent extends CreateCollectionCommand {
9
9
  static args = {
10
10
  collection: Args.string({
11
11
  default: '',
12
- description: 'collection ID to create or apply to, e.g., products (required with -y)',
12
+ description: 'Collection ID to create or extend (e.g., products)',
13
13
  }),
14
14
  };
15
- static description = `Interactive mode: choose to create a new collection or extend an existing standard collection. The CLI will propose a list of standard collections you can extend.
16
-
17
- Non-interactive (-y): provide COLLECTION explicitly. To discover standard collections first, run: swell models.`;
15
+ static description = 'Interactive mode lets you choose to create a new collection or extend a standard one.\nTo discover standard collections: swell inspect models';
18
16
  static examples = [
19
- {
20
- command: 'swell create content',
21
- description: 'Create content model interactively.',
22
- },
23
- {
24
- command: 'swell create content products -y',
25
- description: 'Apply configuration to a standard collection (non-interactive)',
26
- },
27
- {
28
- command: 'swell create content visitors -v list,edit,new -f name:short_text,verified:boolean -l "Visitors" -d "" -y',
29
- description: 'Create custom collection with explicit fields and views (non-interactive)',
30
- },
31
- {
32
- command: 'swell create content visitors --overwrite -y',
33
- description: 'Non-interactive: force overwrite existing config file',
34
- },
35
- {
36
- command: 'swell create content visitors -f name:short_text,description:long_text,verified:boolean,visitor_count:integer,photo:image,orders:collection',
37
- description: 'Specify fields with types delimited by commas (interactive mode)',
38
- },
17
+ '$ swell create content',
18
+ '$ swell create content products -y',
19
+ '$ swell create content visitors -v list,edit,new -f name:short_text,verified:boolean -y',
39
20
  ];
21
+ static helpMeta = {
22
+ usageDirect: '<collection> [...] -y',
23
+ };
40
24
  static flags = {
25
+ label: Flags.string({
26
+ char: 'l',
27
+ default: '',
28
+ description: 'Display label (default: capitalized collection)',
29
+ }),
41
30
  description: Flags.string({
42
31
  char: 'd',
43
32
  default: '',
44
- description: 'content model description',
33
+ description: 'Description',
45
34
  }),
46
35
  fields: Flags.string({
47
36
  char: 'f',
48
37
  default: '',
49
- description: 'comma-separated id:type pairs (e.g., name:short_text, verified:boolean)',
38
+ description: 'Fields as id:type pairs (e.g., name:short_text,verified:boolean)',
50
39
  }),
51
- label: Flags.string({
52
- char: 'l',
40
+ views: Flags.string({
41
+ char: 'v',
53
42
  default: '',
54
- description: 'display label for the content model (defaults to capitalized collection name)',
43
+ description: 'Views to enable: list | edit | new',
55
44
  }),
56
45
  overwrite: Flags.boolean({
57
46
  default: false,
58
- description: 'overwrite existing content model configuration file (use with -y to force overwrite)',
59
- }),
60
- views: Flags.string({
61
- char: 'v',
62
- default: '',
63
- description: 'comma-separated views - valid: list, edit, new',
47
+ description: 'Overwrite existing file',
64
48
  }),
65
49
  yes: Flags.boolean({
66
50
  char: 'y',
67
- description: 'accept all default values; non-interactive, never prompts; errors if required values are missing',
51
+ description: 'Skip prompts, require all arguments',
68
52
  }),
69
53
  };
70
- static summary = 'Initialize a content UI model config file with properties in the content folder.';
54
+ static summary = 'Create a content UI model configuration in the content folder.';
71
55
  createType = ConfigType.CONTENT;
72
56
  async run() {
73
57
  const { args, flags } = await this.parse(CreateContent);