@loopress/cli 0.28.0 → 0.30.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.
Files changed (190) hide show
  1. package/README.md +1460 -337
  2. package/bin/dev.js +0 -0
  3. package/dist/commands/acf/pull.d.ts +9 -1
  4. package/dist/commands/acf/pull.js +2 -0
  5. package/dist/commands/acf/push.d.ts +9 -1
  6. package/dist/commands/acf/push.js +3 -1
  7. package/dist/commands/api/publish.js +1 -1
  8. package/dist/commands/app/push.js +1 -1
  9. package/dist/commands/composer/push.js +3 -3
  10. package/dist/commands/cpt/diff.js +5 -0
  11. package/dist/commands/cpt/list.d.ts +2 -0
  12. package/dist/commands/cpt/list.js +4 -0
  13. package/dist/commands/cpt/pull.d.ts +2 -0
  14. package/dist/commands/cpt/pull.js +4 -0
  15. package/dist/commands/cpt/push.d.ts +2 -0
  16. package/dist/commands/cpt/push.js +4 -0
  17. package/dist/commands/cpt/rm.d.ts +2 -0
  18. package/dist/commands/cpt/rm.js +3 -0
  19. package/dist/commands/cpt/rollback.js +5 -0
  20. package/dist/commands/dev.js +14 -4
  21. package/dist/commands/diff.js +1 -1
  22. package/dist/commands/doctor.d.ts +1 -0
  23. package/dist/commands/doctor.js +30 -2
  24. package/dist/commands/form/pull.d.ts +9 -1
  25. package/dist/commands/form/pull.js +3 -1
  26. package/dist/commands/form/push.d.ts +7 -1
  27. package/dist/commands/form/push.js +3 -1
  28. package/dist/commands/init.js +6 -38
  29. package/dist/commands/menu/pull.d.ts +7 -1
  30. package/dist/commands/menu/pull.js +2 -0
  31. package/dist/commands/menu/push.d.ts +7 -1
  32. package/dist/commands/menu/push.js +3 -1
  33. package/dist/commands/meta/diff.d.ts +2 -0
  34. package/dist/commands/meta/diff.js +5 -0
  35. package/dist/commands/meta/list.d.ts +19 -0
  36. package/dist/commands/meta/list.js +21 -0
  37. package/dist/commands/meta/pull.d.ts +2 -0
  38. package/dist/commands/meta/pull.js +4 -0
  39. package/dist/commands/meta/push.d.ts +2 -0
  40. package/dist/commands/meta/push.js +4 -0
  41. package/dist/commands/meta/rm.d.ts +2 -0
  42. package/dist/commands/meta/rm.js +3 -0
  43. package/dist/commands/meta/rollback.d.ts +2 -0
  44. package/dist/commands/meta/rollback.js +5 -0
  45. package/dist/commands/option/list.js +2 -8
  46. package/dist/commands/option/pull.js +4 -4
  47. package/dist/commands/option/push.js +2 -0
  48. package/dist/commands/page/push.js +3 -0
  49. package/dist/commands/pattern/diff.d.ts +2 -0
  50. package/dist/commands/pattern/diff.js +5 -0
  51. package/dist/commands/pattern/list.d.ts +2 -0
  52. package/dist/commands/pattern/list.js +3 -0
  53. package/dist/commands/pattern/pull.d.ts +2 -0
  54. package/dist/commands/pattern/pull.js +4 -0
  55. package/dist/commands/pattern/push.d.ts +2 -0
  56. package/dist/commands/pattern/push.js +4 -0
  57. package/dist/commands/pattern/rm.d.ts +2 -0
  58. package/dist/commands/pattern/rm.js +3 -0
  59. package/dist/commands/pattern/rollback.d.ts +2 -0
  60. package/dist/commands/pattern/rollback.js +5 -0
  61. package/dist/commands/plugin/audit.js +2 -1
  62. package/dist/commands/plugin/pull.d.ts +4 -0
  63. package/dist/commands/plugin/pull.js +56 -10
  64. package/dist/commands/plugin/push.js +5 -4
  65. package/dist/commands/project/config.d.ts +1 -0
  66. package/dist/commands/project/config.js +20 -1
  67. package/dist/commands/project/list.d.ts +1 -1
  68. package/dist/commands/project/list.js +6 -6
  69. package/dist/commands/project/pull.js +11 -8
  70. package/dist/commands/project/push.js +23 -18
  71. package/dist/commands/project/remove.js +1 -1
  72. package/dist/commands/project/switch.d.ts +0 -1
  73. package/dist/commands/project/switch.js +16 -36
  74. package/dist/commands/pull.js +7 -2
  75. package/dist/commands/push.js +14 -6
  76. package/dist/commands/role/diff.d.ts +2 -0
  77. package/dist/commands/role/diff.js +5 -0
  78. package/dist/commands/role/list.d.ts +2 -0
  79. package/dist/commands/role/list.js +4 -0
  80. package/dist/commands/role/pull.d.ts +2 -0
  81. package/dist/commands/role/pull.js +4 -0
  82. package/dist/commands/role/push.d.ts +2 -0
  83. package/dist/commands/role/push.js +4 -0
  84. package/dist/commands/role/rm.d.ts +2 -0
  85. package/dist/commands/role/rm.js +3 -0
  86. package/dist/commands/role/rollback.d.ts +2 -0
  87. package/dist/commands/role/rollback.js +5 -0
  88. package/dist/commands/snippet/publish.js +1 -1
  89. package/dist/commands/snippet/pull.js +1 -1
  90. package/dist/commands/snippet/push.js +1 -1
  91. package/dist/commands/status.d.ts +3 -3
  92. package/dist/commands/status.js +21 -53
  93. package/dist/commands/taxonomy/diff.d.ts +2 -0
  94. package/dist/commands/taxonomy/diff.js +5 -0
  95. package/dist/commands/taxonomy/list.d.ts +2 -0
  96. package/dist/commands/taxonomy/list.js +5 -0
  97. package/dist/commands/taxonomy/pull.d.ts +2 -0
  98. package/dist/commands/taxonomy/pull.js +4 -0
  99. package/dist/commands/taxonomy/push.d.ts +2 -0
  100. package/dist/commands/taxonomy/push.js +4 -0
  101. package/dist/commands/taxonomy/rm.d.ts +2 -0
  102. package/dist/commands/taxonomy/rm.js +3 -0
  103. package/dist/commands/taxonomy/rollback.d.ts +2 -0
  104. package/dist/commands/taxonomy/rollback.js +5 -0
  105. package/dist/commands/theme/pull.d.ts +6 -10
  106. package/dist/commands/theme/pull.js +30 -32
  107. package/dist/commands/theme/push.d.ts +8 -9
  108. package/dist/commands/theme/push.js +54 -111
  109. package/dist/commands/theme/style/pull.d.ts +7 -1
  110. package/dist/commands/theme/style/pull.js +3 -1
  111. package/dist/commands/theme/style/push.d.ts +8 -1
  112. package/dist/commands/theme/style/push.js +4 -1
  113. package/dist/commands/{template → theme/template}/diff.d.ts +1 -1
  114. package/dist/commands/{template → theme/template}/diff.js +3 -3
  115. package/dist/commands/{template → theme/template}/list.d.ts +2 -2
  116. package/dist/commands/{template → theme/template}/list.js +5 -5
  117. package/dist/commands/{template → theme/template}/push.d.ts +3 -1
  118. package/dist/commands/theme/template/push.js +65 -0
  119. package/dist/commands/theme/version/pull.d.ts +23 -0
  120. package/dist/commands/theme/version/pull.js +43 -0
  121. package/dist/commands/theme/version/push.d.ts +22 -0
  122. package/dist/commands/theme/version/push.js +123 -0
  123. package/dist/config/project-config.manager.d.ts +3 -3
  124. package/dist/config/project-config.manager.js +22 -31
  125. package/dist/hooks/finally.d.ts +2 -1
  126. package/dist/hooks/finally.js +38 -7
  127. package/dist/lib/api-client.js +2 -1
  128. package/dist/lib/app-build.js +3 -1
  129. package/dist/lib/app-manifest.js +2 -2
  130. package/dist/lib/base.d.ts +2 -2
  131. package/dist/lib/base.js +33 -38
  132. package/dist/lib/declared-type-command.d.ts +35 -0
  133. package/dist/lib/declared-type-command.js +192 -0
  134. package/dist/lib/dev-watch.d.ts +1 -1
  135. package/dist/lib/dev-watch.js +7 -3
  136. package/dist/lib/diff-state.js +1 -0
  137. package/dist/lib/github-release.js +4 -1
  138. package/dist/lib/local-callback-server.d.ts +12 -6
  139. package/dist/lib/local-callback-server.js +24 -23
  140. package/dist/lib/php-files-command.js +3 -1
  141. package/dist/lib/push-command.d.ts +6 -0
  142. package/dist/lib/push-command.js +61 -18
  143. package/dist/lib/put-or-create.js +3 -4
  144. package/dist/lib/resource-state.js +40 -86
  145. package/dist/lib/rollback-materialize.js +13 -24
  146. package/dist/lib/snapshot-store.js +2 -2
  147. package/dist/lib/spinner.d.ts +2 -0
  148. package/dist/lib/spinner.js +72 -0
  149. package/dist/lib/temp-admin.d.ts +10 -1
  150. package/dist/lib/temp-admin.js +27 -2
  151. package/dist/lib/validate-local.js +31 -9
  152. package/dist/lib/wp-authorize-flow.d.ts +10 -17
  153. package/dist/lib/wp-authorize-flow.js +24 -28
  154. package/dist/lib/wp-client.d.ts +1 -0
  155. package/dist/lib/wp-client.js +7 -1
  156. package/dist/lib/wp-site-diagnostic.js +39 -1
  157. package/dist/types/global-config.generated.d.ts +1 -5
  158. package/dist/types/project-config.generated.d.ts +28 -4
  159. package/dist/utils/composer.d.ts +3 -1
  160. package/dist/utils/composer.js +16 -7
  161. package/dist/utils/declared-type-format.d.ts +52 -0
  162. package/dist/utils/declared-type-format.js +233 -0
  163. package/dist/utils/option-format.d.ts +3 -1
  164. package/dist/utils/option-format.js +14 -3
  165. package/dist/utils/page-format.d.ts +5 -1
  166. package/dist/utils/page-format.js +7 -3
  167. package/dist/utils/plugin-sync.js +1 -1
  168. package/dist/utils/resource-dirs.d.ts +9 -3
  169. package/dist/utils/resource-dirs.js +18 -6
  170. package/dist/utils/template-format.d.ts +3 -1
  171. package/dist/utils/template-format.js +10 -3
  172. package/dist/utils/theme-css.d.ts +19 -0
  173. package/dist/utils/theme-css.js +100 -0
  174. package/oclif.manifest.json +3542 -1087
  175. package/package.json +40 -21
  176. package/schemas/global-config.schema.json +2 -6
  177. package/schemas/project-config.schema.json +37 -7
  178. package/dist/commands/seo/diff.js +0 -5
  179. package/dist/commands/seo/list.d.ts +0 -18
  180. package/dist/commands/seo/list.js +0 -58
  181. package/dist/commands/seo/pull.d.ts +0 -17
  182. package/dist/commands/seo/pull.js +0 -87
  183. package/dist/commands/seo/push.d.ts +0 -23
  184. package/dist/commands/seo/push.js +0 -176
  185. package/dist/commands/seo/rollback.js +0 -5
  186. package/dist/commands/template/push.js +0 -42
  187. package/dist/utils/seo-format.d.ts +0 -29
  188. package/dist/utils/seo-format.js +0 -18
  189. /package/dist/commands/{seo → cpt}/diff.d.ts +0 -0
  190. /package/dist/commands/{seo → cpt}/rollback.d.ts +0 -0
@@ -7,17 +7,21 @@ import { pluralize } from '../utils/pluralize.js';
7
7
  const PULL_TARGETS = [
8
8
  { commandId: 'composer:pull', label: 'composer' },
9
9
  { commandId: 'plugin:pull', label: 'plugins' },
10
+ { commandId: 'cpt:pull', label: 'post types', supportsYes: true },
11
+ { commandId: 'taxonomy:pull', label: 'taxonomies', supportsYes: true },
12
+ { commandId: 'meta:pull', label: 'post meta', supportsYes: true },
13
+ { commandId: 'role:pull', label: 'roles', supportsYes: true },
10
14
  { commandId: 'acf:pull', label: 'ACF', supportsYes: true },
11
15
  { commandId: 'api:pull', label: 'API routes', supportsYes: true },
12
16
  { commandId: 'hook:pull', label: 'hooks', supportsYes: true },
13
17
  { commandId: 'form:pull', label: 'forms', supportsYes: true },
14
- { commandId: 'seo:pull', label: 'SEO', supportsYes: true },
18
+ { commandId: 'pattern:pull', label: 'patterns', supportsYes: true },
15
19
  { commandId: 'menu:pull', label: 'menus', supportsYes: true },
16
20
  { commandId: 'option:pull', label: 'options', supportsYes: true },
17
21
  { commandId: 'snippet:pull', label: 'snippets', supportsYes: true },
18
22
  ];
19
23
  export default class Pull extends LoopressCommand {
20
- static description = 'Pull all content, plugins, composer dependencies, ACF, API routes, hooks, forms, SEO, menus, options, and snippets, from WordPress';
24
+ static description = 'Pull all content, plugins, composer dependencies, post types, taxonomies, post meta, roles, ACF, API routes, hooks, forms, patterns, menus, options, and snippets, from WordPress';
21
25
  static enableJsonFlag = true;
22
26
  static examples = ['$ lps pull', '$ lps pull --env staging', '$ lps pull --dry-run'];
23
27
  static flags = {
@@ -27,6 +31,7 @@ export default class Pull extends LoopressCommand {
27
31
  failedCount = 0;
28
32
  async run() {
29
33
  const results = [];
34
+ this.warnRemovedSeoModule();
30
35
  for (const target of PULL_TARGETS) {
31
36
  this.log(`\n→ Pulling ${target.label}...`);
32
37
  try {
@@ -4,6 +4,7 @@ import { join } from 'node:path';
4
4
  import { LoopressCommand } from '../lib/base.js';
5
5
  import { guardProductionPush } from '../lib/guard-production-push.js';
6
6
  import { stdoutToStderr } from '../lib/json-delegation.js';
7
+ import { isLocalEnvironment } from '../lib/wp-client.js';
7
8
  import { wpackagistRequire } from '../utils/composer.js';
8
9
  import { pluralize } from '../utils/pluralize.js';
9
10
  // Dependency-ish order: code first (plugins, composer), then the ACF definitions content
@@ -11,20 +12,26 @@ import { pluralize } from '../utils/pluralize.js';
11
12
  const PUSH_TARGETS = [
12
13
  { commandId: 'plugin:push', label: 'plugins' },
13
14
  { commandId: 'composer:push', label: 'composer' },
15
+ // Before ACF: a field group's location rule can target a Loopress post type or taxonomy.
16
+ { commandId: 'cpt:push', label: 'post types' },
17
+ { commandId: 'taxonomy:push', label: 'taxonomies' },
18
+ { commandId: 'meta:push', label: 'post meta' },
19
+ { commandId: 'role:push', label: 'roles' },
14
20
  { commandId: 'acf:push', label: 'ACF' },
15
21
  { commandId: 'api:push', label: 'API routes' },
16
22
  { commandId: 'hook:push', label: 'hooks' },
17
23
  { commandId: 'form:push', label: 'forms' },
24
+ // Before templates and pages, which can reference them (`wp:pattern`).
25
+ { commandId: 'pattern:push', label: 'patterns' },
18
26
  // Before pages: WordPress refuses a page whose `template` it doesn't know yet.
19
- { commandId: 'template:push', label: 'templates and parts' },
27
+ { commandId: 'theme:template:push', label: 'templates and parts' },
20
28
  { commandId: 'page:push', label: 'pages' },
21
- { commandId: 'seo:push', label: 'SEO' },
22
29
  { commandId: 'menu:push', label: 'menus' },
23
30
  { commandId: 'option:push', label: 'options' },
24
31
  { commandId: 'snippet:push', label: 'snippets' },
25
32
  ];
26
33
  export default class Push extends LoopressCommand {
27
- static description = 'Push all local content, plugins, composer dependencies, ACF, API routes, hooks, forms, templates, pages, SEO, menus, options, and snippets, to WordPress';
34
+ static description = 'Push all local content, plugins, composer dependencies, post types, taxonomies, post meta, roles, ACF, API routes, hooks, forms, patterns, templates, pages, menus, options, and snippets, to WordPress';
28
35
  static enableJsonFlag = true;
29
36
  static examples = ['$ lps push', '$ lps push --env staging', '$ lps push --dry-run'];
30
37
  static flags = {
@@ -34,6 +41,7 @@ export default class Push extends LoopressCommand {
34
41
  failedCount = 0;
35
42
  async run() {
36
43
  await this.guardProductionPush();
44
+ this.warnRemovedSeoModule();
37
45
  const argv = this.buildArgv();
38
46
  const results = [];
39
47
  const composerPushedByPlugins = await this.composerDeclaresPlugins();
@@ -46,7 +54,7 @@ export default class Push extends LoopressCommand {
46
54
  this.log(`\n→ Pushing ${target.label}...`);
47
55
  try {
48
56
  await stdoutToStderr(this.jsonEnabled(), async () => this.config.runCommand(target.commandId, argv));
49
- this.log(`✓ ${target.label} pushed`);
57
+ this.log(this.dryRun ? `✓ ${target.label} would push` : `✓ ${target.label} pushed`);
50
58
  results.push({ label: target.label, status: 'pushed' });
51
59
  }
52
60
  catch (error) {
@@ -64,7 +72,7 @@ export default class Push extends LoopressCommand {
64
72
  .map((result) => `${result.label}: ${result.error}`);
65
73
  this.error(`${pluralize(this.failedCount, 'resource')} failed to push. ${failures.join('; ')}`);
66
74
  }
67
- this.log('\nAll resources pushed.');
75
+ this.log(this.dryRun ? '\nEvery resource would push.' : '\nAll resources pushed.');
68
76
  return { results };
69
77
  }
70
78
  // Every delegated push always gets --yes: either this command's own guard already confirmed
@@ -84,7 +92,7 @@ export default class Push extends LoopressCommand {
84
92
  return false;
85
93
  try {
86
94
  const composerJson = JSON.parse(await readFile(path, 'utf8'));
87
- return Object.keys(wpackagistRequire(composerJson, 'plugin')).length > 0;
95
+ return Object.keys(wpackagistRequire(composerJson, 'plugin', isLocalEnvironment(this.siteConfig.name))).length > 0;
88
96
  }
89
97
  catch {
90
98
  // Unreadable: let both commands run and report the parse error themselves.
@@ -0,0 +1,2 @@
1
+ declare const _default: typeof import("../../lib/diff-command.js").DiffCommand;
2
+ export default _default;
@@ -0,0 +1,5 @@
1
+ import { resourceDiffCommand } from '../../lib/diff-command.js';
2
+ export default resourceDiffCommand('role', {
3
+ description: 'Show what differs in roles between your local roles/ files and a WordPress environment, or between two environments',
4
+ pathNoun: 'roles directory',
5
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: import("../../lib/php-files-command.js").CommandClass<import("../../lib/declared-type-command.js").DeclaredListCommand>;
2
+ export default _default;
@@ -0,0 +1,4 @@
1
+ import { declaredListCommand } from '../../lib/declared-type-command.js';
2
+ import { ROLE_SPEC } from '../../utils/declared-type-format.js';
3
+ import { pluralize } from '../../utils/pluralize.js';
4
+ export default declaredListCommand(ROLE_SPEC, 'List the user roles on WordPress, where each comes from (Loopress, WordPress, a plugin) and how many users have it. Only Loopress ones are pulled and pushed.', (count) => pluralize(count, 'user'));
@@ -0,0 +1,2 @@
1
+ declare const _default: import("../../lib/php-files-command.js").CommandClass<import("../../lib/declared-type-command.js").DeclaredPullCommand>;
2
+ export default _default;
@@ -0,0 +1,4 @@
1
+ import { declaredPullCommand } from '../../lib/declared-type-command.js';
2
+ import { ROLE_SPEC } from '../../utils/declared-type-format.js';
3
+ export default declaredPullCommand(ROLE_SPEC, 'Pull the roles Loopress manages on WordPress into roles/<slug>.json files. ' +
4
+ 'Built-in roles and roles created by a plugin are never pulled, see `lps role list`.');
@@ -0,0 +1,2 @@
1
+ declare const _default: import("../../lib/php-files-command.js").CommandClass<import("../../lib/declared-type-command.js").DeclaredPushCommand>;
2
+ export default _default;
@@ -0,0 +1,4 @@
1
+ import { declaredPushCommand } from '../../lib/declared-type-command.js';
2
+ import { ROLE_SPEC } from '../../utils/declared-type-format.js';
3
+ export default declaredPushCommand(ROLE_SPEC, 'Push local roles (roles/<slug>.json, a "name" and its "capabilities") to WordPress. ' +
4
+ 'Create or update only, never deletes a role (use `lps role rm`), never changes which users have it.');
@@ -0,0 +1,2 @@
1
+ declare const _default: import("../../lib/php-files-command.js").CommandClass<import("../../lib/declared-type-command.js").DeclaredRmCommand>;
2
+ export default _default;
@@ -0,0 +1,3 @@
1
+ import { declaredRmCommand } from '../../lib/declared-type-command.js';
2
+ import { ROLE_SPEC } from '../../utils/declared-type-format.js';
3
+ export default declaredRmCommand(ROLE_SPEC, 'Stop registering a Loopress role on WordPress. Its users keep it in their profile, with no capability until the role is pushed again.', 'Its users keep it in their profile, with no capability until it is pushed again.');
@@ -0,0 +1,2 @@
1
+ declare const _default: typeof import("../../lib/base.js").LoopressCommand;
2
+ export default _default;
@@ -0,0 +1,5 @@
1
+ import { resourceRollbackCommand } from '../../lib/rollback-command.js';
2
+ export default resourceRollbackCommand('role', {
3
+ description: 'Restore roles to a snapshot taken automatically before an earlier `lps role push`',
4
+ pathNoun: 'roles directory',
5
+ });
@@ -14,7 +14,7 @@ export default class Publish extends Command {
14
14
  path: Args.string({ description: 'Path to snippets directory (overrides project config)' }),
15
15
  };
16
16
  static description = 'Publish snippets to your Loopress account so they can be deployed to other projects. Does not touch any WordPress site.';
17
- static examples = ['$ lps snippet publish', '$ lps snippet publish --path ./snippets'];
17
+ static examples = ['$ lps snippet publish', '$ lps snippet publish ./snippets'];
18
18
  async run() {
19
19
  const { args } = await this.parse(Publish);
20
20
  const { apiProjectId, localConfig, token } = await resolveLinkedProject((message) => this.error(message));
@@ -19,7 +19,7 @@ export default class Pull extends LoopressCommand {
19
19
  };
20
20
  static description = 'Pull snippets from WordPress';
21
21
  static enableJsonFlag = true;
22
- static examples = ['$ lps snippet pull', '$ lps snippet pull --path ./snippets'];
22
+ static examples = ['$ lps snippet pull', '$ lps snippet pull ./snippets'];
23
23
  static flags = {
24
24
  ...LoopressCommand.dryRunFlag,
25
25
  ...LoopressCommand.yesFlag,
@@ -15,7 +15,7 @@ export default class Push extends PushCommand {
15
15
  };
16
16
  static description = 'Push snippets to WordPress. Local snippet files created or updated remotely are renamed on disk to the `<id>-<slug>` convention.';
17
17
  static enableJsonFlag = true;
18
- static examples = ['$ lps snippet push', '$ lps snippet push --path ./snippets'];
18
+ static examples = ['$ lps snippet push', '$ lps snippet push ./snippets'];
19
19
  static flags = {
20
20
  ...PushCommand.dryRunFlag,
21
21
  ...PushCommand.yesFlag,
@@ -1,5 +1,6 @@
1
1
  import { Command } from '@oclif/core';
2
2
  type StatusInfo = {
3
+ environment?: string;
3
4
  environments?: string[];
4
5
  note?: string;
5
6
  project?: string;
@@ -17,8 +18,7 @@ export default class Status extends Command {
17
18
  env: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
18
19
  };
19
20
  run(): Promise<StatusResult>;
20
- private reportActiveProject;
21
- private reportEnvOverride;
22
- private reportPinnedProject;
21
+ private logTarget;
22
+ private report;
23
23
  }
24
24
  export {};
@@ -11,52 +11,26 @@ export default class Status extends Command {
11
11
  };
12
12
  async run() {
13
13
  const { flags } = await this.parse(Status);
14
- const localConfig = await readLocalConfig();
15
- let info;
16
- if (flags.env) {
17
- info = this.reportEnvOverride(localConfig.projectId, flags.env);
18
- }
19
- else if (localConfig.projectId) {
20
- info = this.reportPinnedProject(localConfig.projectId);
21
- }
22
- else {
23
- info = this.reportActiveProject();
24
- }
14
+ const { projectId } = await readLocalConfig();
15
+ const info = this.report(projectId, flags.env);
25
16
  this.log('');
26
17
  this.log(`Config dir: ${this.config.configDir}`);
27
18
  this.log(`Data dir: ${this.config.dataDir}`);
28
19
  return { ...info, configDir: this.config.configDir, dataDir: this.config.dataDir };
29
20
  }
30
- reportActiveProject() {
31
- const env = configManager.getCurrentEnv();
32
- const project = env ? configManager.getCurrentProject() : undefined;
33
- if (!env || !project) {
34
- const note = 'No project configured. Run `lps project config` first.';
35
- this.log(note);
36
- return { note };
37
- }
38
- this.log(`Project: ${project.name} (${env.name})`);
21
+ logTarget(label, env) {
22
+ this.log(`Project: ${label}`);
39
23
  this.log(`URL: ${env.url}`);
40
- return { project: `${project.name} (${env.name})`, url: env.url };
24
+ return { environment: env.name, project: label, url: env.url };
41
25
  }
42
- // Mirrors base.ts:resolveEnvironment with --env: the targeted project comes from
43
- // loopress.json when pinned, from the globally active project otherwise.
44
- reportEnvOverride(pinnedProjectId, envName) {
45
- const project = pinnedProjectId ? configManager.getProject(pinnedProjectId) : configManager.getCurrentProject();
46
- if (!project) {
26
+ // Mirrors base.ts:resolveEnvironment, reporting instead of failing where it can.
27
+ report(pinnedProjectId, envName) {
28
+ const projectId = pinnedProjectId ?? configManager.getCurrentProject()?.id;
29
+ if (!projectId) {
47
30
  const note = 'No project configured. Run `lps project config` first.';
48
31
  this.log(note);
49
32
  return { note };
50
33
  }
51
- const env = project.environments[envName];
52
- if (!env) {
53
- this.error(`Environment "${envName}" not found in project "${project.name}". Available: ${Object.keys(project.environments).join(', ')}`);
54
- }
55
- this.log(`Project: ${project.name} (${env.name}, via --env)`);
56
- this.log(`URL: ${env.url}`);
57
- return { project: `${project.name} (${env.name}, via --env)`, url: env.url };
58
- }
59
- reportPinnedProject(projectId) {
60
34
  const project = configManager.getProject(projectId);
61
35
  if (!project) {
62
36
  const note = `loopress.json pins project "${projectId}", but it no longer exists. Run \`lps project config\` to configure it.`;
@@ -71,28 +45,22 @@ export default class Status extends Command {
71
45
  this.log(note);
72
46
  return { note, project: project.name };
73
47
  }
74
- if (envNames.length === 1) {
75
- const env = project.environments[envNames[0]];
76
- this.log(`Project: ${project.name} (${env.name})`);
77
- this.log(`URL: ${env.url}`);
78
- return { project: `${project.name} (${env.name})`, url: env.url };
48
+ if (envName) {
49
+ const env = project.environments[envName];
50
+ if (!env) {
51
+ this.error(`Environment "${envName}" not found in project "${project.name}". Available: ${envNames.join(', ')}`);
52
+ }
53
+ return this.logTarget(`${project.name} (${env.name}, via --env)`, env);
79
54
  }
80
- const current = configManager.getCurrentProject();
81
- const currentEnv = current?.id === projectId ? configManager.getCurrentEnv() : null;
82
- if (!currentEnv) {
83
- const note = `"${project.name}" has multiple environments and isn't the globally active project. Run \`lps project switch\` to pick one.`;
84
- this.log(`Project: ${project.name} ${c('yellow', '(ambiguous)')}`);
55
+ const env = configManager.getDefaultEnvironment(projectId);
56
+ if (!env) {
57
+ const note = `"${project.name}" has no "local" environment, pass --env to pick one.`;
58
+ this.log(`Project: ${project.name} ${c('yellow', '(no default environment)')}`);
85
59
  this.log(`Environments: ${envNames.join(', ')}`);
86
60
  this.log('');
87
- this.warn(`"${project.name}" has multiple environments and isn't the globally active project.`);
88
- this.log('Run `lps project switch` to pick one before running commands here.');
89
- if (current) {
90
- this.log(`(Globally active project right now: "${current.name}")`);
91
- }
61
+ this.warn(note);
92
62
  return { environments: envNames, note, project: project.name };
93
63
  }
94
- this.log(`Project: ${project.name} (${currentEnv.name})`);
95
- this.log(`URL: ${currentEnv.url}`);
96
- return { project: `${project.name} (${currentEnv.name})`, url: currentEnv.url };
64
+ return this.logTarget(`${project.name} (${env.name})`, env);
97
65
  }
98
66
  }
@@ -0,0 +1,2 @@
1
+ declare const _default: typeof import("../../lib/diff-command.js").DiffCommand;
2
+ export default _default;
@@ -0,0 +1,5 @@
1
+ import { resourceDiffCommand } from '../../lib/diff-command.js';
2
+ export default resourceDiffCommand('taxonomy', {
3
+ description: 'Show what differs in taxonomies between your local taxonomies/ files and a WordPress environment, or between two environments',
4
+ pathNoun: 'taxonomies directory',
5
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: import("../../lib/php-files-command.js").CommandClass<import("../../lib/declared-type-command.js").DeclaredListCommand>;
2
+ export default _default;
@@ -0,0 +1,5 @@
1
+ import { declaredListCommand } from '../../lib/declared-type-command.js';
2
+ import { TAXONOMY_SPEC } from '../../utils/declared-type-format.js';
3
+ import { pluralize } from '../../utils/pluralize.js';
4
+ export default declaredListCommand(TAXONOMY_SPEC, 'List the taxonomies registered on WordPress, where each comes from (Loopress, WordPress, ACF, CPT UI, a theme or plugin) ' +
5
+ 'and the post types it attaches to. Only Loopress ones are pulled and pushed.', (count) => pluralize(count, 'term'));
@@ -0,0 +1,2 @@
1
+ declare const _default: import("../../lib/php-files-command.js").CommandClass<import("../../lib/declared-type-command.js").DeclaredPullCommand>;
2
+ export default _default;
@@ -0,0 +1,4 @@
1
+ import { declaredPullCommand } from '../../lib/declared-type-command.js';
2
+ import { TAXONOMY_SPEC } from '../../utils/declared-type-format.js';
3
+ export default declaredPullCommand(TAXONOMY_SPEC, 'Pull the taxonomies Loopress manages on WordPress into taxonomies/<slug>.json files, never their terms. ' +
4
+ 'Taxonomies registered by a theme or another plugin are never pulled, see `lps taxonomy list`.');
@@ -0,0 +1,2 @@
1
+ declare const _default: import("../../lib/php-files-command.js").CommandClass<import("../../lib/declared-type-command.js").DeclaredPushCommand>;
2
+ export default _default;
@@ -0,0 +1,4 @@
1
+ import { declaredPushCommand } from '../../lib/declared-type-command.js';
2
+ import { TAXONOMY_SPEC } from '../../utils/declared-type-format.js';
3
+ export default declaredPushCommand(TAXONOMY_SPEC, 'Push local taxonomies (taxonomies/<slug>.json, register_taxonomy() arguments plus "object_type") to WordPress. ' +
4
+ 'Create or update only, never deletes a taxonomy (use `lps taxonomy rm`), never touches its terms.');
@@ -0,0 +1,2 @@
1
+ declare const _default: import("../../lib/php-files-command.js").CommandClass<import("../../lib/declared-type-command.js").DeclaredRmCommand>;
2
+ export default _default;
@@ -0,0 +1,3 @@
1
+ import { declaredRmCommand } from '../../lib/declared-type-command.js';
2
+ import { TAXONOMY_SPEC } from '../../utils/declared-type-format.js';
3
+ export default declaredRmCommand(TAXONOMY_SPEC, 'Stop registering a Loopress taxonomy on WordPress. Its terms are kept in the database, hidden until the taxonomy is pushed again.', "Its terms are kept in the database, hidden until it's pushed again.");
@@ -0,0 +1,2 @@
1
+ declare const _default: typeof import("../../lib/base.js").LoopressCommand;
2
+ export default _default;
@@ -0,0 +1,5 @@
1
+ import { resourceRollbackCommand } from '../../lib/rollback-command.js';
2
+ export default resourceRollbackCommand('taxonomy', {
3
+ description: 'Restore taxonomies to a snapshot taken automatically before an earlier `lps taxonomy push`',
4
+ pathNoun: 'taxonomies directory',
5
+ });
@@ -1,15 +1,11 @@
1
1
  import { LoopressCommand } from '../../lib/base.js';
2
- import { type ComposerPullResult } from '../../utils/composer.js';
2
+ type PullTargetResult = {
3
+ error?: string;
4
+ label: string;
5
+ status: 'failed' | 'pulled';
6
+ };
3
7
  type PullResult = {
4
- added: string[];
5
- merged: Record<string, string>;
6
- skipped?: ComposerPullResult['skipped'];
7
- status: 'dry-run' | 'success';
8
- updated: Array<{
9
- from: string;
10
- slug: string;
11
- to: string;
12
- }>;
8
+ results: PullTargetResult[];
13
9
  };
14
10
  export default class Pull extends LoopressCommand {
15
11
  static description: string;
@@ -1,43 +1,41 @@
1
- import { existsSync } from 'node:fs';
2
- import { join } from 'node:path';
3
1
  import { LoopressCommand } from '../../lib/base.js';
4
- import { pullIntoComposerJson } from '../../utils/composer.js';
5
- import { writeLocalConfig } from '../../utils/loopress-config.js';
6
- import { mergePluginManifest } from '../../utils/plugins.js';
7
- import { parseInstalledThemes } from '../../utils/themes.js';
2
+ import { stdoutToStderr } from '../../lib/json-delegation.js';
3
+ import { pluralize } from '../../utils/pluralize.js';
4
+ // Templates and parts have no pull: the child theme is written from the project, never read back.
5
+ const PULL_TARGETS = [
6
+ { commandId: 'theme:version:pull', label: 'theme versions' },
7
+ { commandId: 'theme:style:pull', label: 'Global Styles' },
8
+ ];
8
9
  export default class Pull extends LoopressCommand {
9
- static description = 'Pull installed themes from WordPress into loopress.json, pinned to their live versions';
10
+ static description = 'Pull everything theme related from WordPress: theme versions and Global Styles';
10
11
  static enableJsonFlag = true;
11
- static examples = ['$ lps theme pull'];
12
+ static examples = ['$ lps theme pull', '$ lps theme pull --env staging', '$ lps theme pull --dry-run'];
12
13
  static flags = {
13
14
  ...LoopressCommand.dryRunFlag,
14
15
  };
15
16
  async run() {
16
- const { url } = this.siteConfig;
17
- this.log(`Pulling themes from ${url}`);
18
- const raw = await this.wp.get('wp/v2/themes');
19
- const installed = parseInstalledThemes(raw);
20
- const incoming = Object.fromEntries(installed.map((t) => [t.slug, t.version]));
21
- // A composer.json is authoritative over loopress.json: pin the live versions there instead.
22
- const composerJsonPath = join(process.cwd(), this.rootDir, 'composer.json');
23
- if (existsSync(composerJsonPath)) {
24
- const result = await pullIntoComposerJson(composerJsonPath, 'theme', incoming, {
25
- dryRun: this.dryRun,
26
- log: this.log.bind(this),
27
- });
28
- return { ...result, status: this.dryRun ? 'dry-run' : 'success' };
17
+ const argv = ['--env', this.siteConfig.name];
18
+ if (this.dryRun)
19
+ argv.push('--dry-run');
20
+ const results = [];
21
+ for (const target of PULL_TARGETS) {
22
+ this.log(`\n→ Pulling ${target.label}...`);
23
+ try {
24
+ await stdoutToStderr(this.jsonEnabled(), async () => this.config.runCommand(target.commandId, argv));
25
+ this.log(`✓ ${target.label} pulled`);
26
+ results.push({ label: target.label, status: 'pulled' });
27
+ }
28
+ catch (error) {
29
+ const { message } = error;
30
+ this.log(`✗ ${target.label} failed: ${message}`);
31
+ results.push({ error: message, label: target.label, status: 'failed' });
32
+ }
29
33
  }
30
- const { added, merged, updated } = mergePluginManifest(this.localConfig.themes ?? {}, incoming);
31
- if (this.dryRun) {
32
- this.log(`[dry-run] Would write ${Object.keys(merged).length} themes to loopress.json`);
33
- return { added, merged, status: 'dry-run', updated };
34
+ const failures = results.filter((result) => result.status === 'failed');
35
+ if (failures.length > 0) {
36
+ const reasons = failures.map((result) => `${result.label}: ${result.error}`);
37
+ this.error(`${pluralize(failures.length, 'theme resource')} failed to pull. ${reasons.join('; ')}`);
34
38
  }
35
- await writeLocalConfig({ ...this.localConfig, themes: merged });
36
- this.log(`Wrote ${Object.keys(merged).length} themes to loopress.json`);
37
- if (added.length > 0)
38
- this.log(` + Added: ${added.join(', ')}`);
39
- for (const u of updated)
40
- this.log(` ~ Updated: ${u.slug} ${u.from} → ${u.to}`);
41
- return { added, merged, status: 'success', updated };
39
+ return { results };
42
40
  }
43
41
  }
@@ -1,11 +1,13 @@
1
- import { PushCommand } from '../../lib/push-command.js';
1
+ import { LoopressCommand } from '../../lib/base.js';
2
+ type PushTargetResult = {
3
+ error?: string;
4
+ label: string;
5
+ status: 'failed' | 'pushed';
6
+ };
2
7
  type PushResult = {
3
- installed: string[];
4
- pinned: string[];
5
- removed: string[];
6
- status: 'composer-managed' | 'dry-run' | 'in-sync' | 'success';
8
+ results: PushTargetResult[];
7
9
  };
8
- export default class Push extends PushCommand {
10
+ export default class Push extends LoopressCommand {
9
11
  static description: string;
10
12
  static enableJsonFlag: boolean;
11
13
  static examples: string[];
@@ -15,8 +17,5 @@ export default class Push extends PushCommand {
15
17
  'dry-run': import("@oclif/core/interfaces").BooleanFlag<boolean>;
16
18
  };
17
19
  run(): Promise<PushResult>;
18
- private fetchInstanceLock;
19
- private guardForce;
20
- private sync;
21
20
  }
22
21
  export {};