@loopress/cli 0.34.0 → 0.35.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 +190 -174
- package/dist/commands/doctor.js +2 -2
- package/dist/commands/form/push.js +3 -2
- package/dist/commands/option/list.js +6 -1
- package/dist/commands/plugin/audit.d.ts +1 -1
- package/dist/commands/plugin/audit.js +45 -23
- package/dist/commands/plugin/outdated.d.ts +22 -0
- package/dist/commands/plugin/outdated.js +67 -0
- package/dist/commands/plugin/push.d.ts +2 -1
- package/dist/commands/plugin/push.js +70 -19
- package/dist/commands/plugin/update.d.ts +36 -0
- package/dist/commands/plugin/update.js +121 -0
- package/dist/commands/push.js +12 -1
- package/dist/commands/snippet/push.js +3 -2
- package/dist/lib/base.d.ts +1 -0
- package/dist/lib/base.js +22 -1
- package/dist/lib/capabilities.d.ts +5 -0
- package/dist/lib/capabilities.js +16 -0
- package/dist/lib/load-snippets.js +1 -4
- package/dist/lib/push-command.d.ts +22 -0
- package/dist/lib/push-command.js +41 -11
- package/dist/lib/validate-local.js +4 -4
- package/dist/lib/wp-client.d.ts +1 -0
- package/dist/lib/wp-client.js +30 -10
- package/dist/types/plugin.d.ts +2 -1
- package/dist/types/plugin.js +32 -1
- package/dist/utils/option-format.d.ts +1 -0
- package/dist/utils/option-format.js +14 -1
- package/dist/utils/plugins.d.ts +3 -0
- package/dist/utils/plugins.js +6 -1
- package/dist/utils/rename-retry.d.ts +1 -0
- package/dist/utils/rename-retry.js +20 -0
- package/dist/utils/version.d.ts +2 -0
- package/dist/utils/version.js +21 -0
- package/dist/utils/wporg.d.ts +5 -0
- package/dist/utils/wporg.js +41 -0
- package/oclif.manifest.json +1401 -1301
- package/package.json +10 -10
- package/dist/commands/api/publish.d.ts +0 -9
- package/dist/commands/api/publish.js +0 -45
- package/dist/commands/snippet/publish.d.ts +0 -10
- package/dist/commands/snippet/publish.js +0 -62
- package/dist/lib/resolve-linked-project.d.ts +0 -8
- package/dist/lib/resolve-linked-project.js +0 -27
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@loopress/cli",
|
|
3
3
|
"description": "Build, review and ship WordPress, in one loop: pull, diff, push and roll back a site's code and config from git",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.35.0",
|
|
5
5
|
"author": "jean-smaug",
|
|
6
6
|
"bin": {
|
|
7
7
|
"loopress": "bin/run.js",
|
|
@@ -12,21 +12,21 @@
|
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
14
|
"@inquirer/prompts": "^8.7.5",
|
|
15
|
-
"@oclif/core": "^5.1.
|
|
15
|
+
"@oclif/core": "^5.1.11",
|
|
16
16
|
"@oclif/plugin-help": "^7.0.6",
|
|
17
17
|
"@oclif/plugin-warn-if-update-available": "^4.0.5",
|
|
18
|
-
"@sentry/node": "^11.
|
|
18
|
+
"@sentry/node": "^11.11.0",
|
|
19
19
|
"chokidar": "^6.0.0",
|
|
20
20
|
"compare-versions": "^6.1.1",
|
|
21
21
|
"diff": "^9.0.0",
|
|
22
22
|
"esbuild": "0.28.2",
|
|
23
|
-
"got": "^16.
|
|
23
|
+
"got": "^16.2.0",
|
|
24
24
|
"listr2": "^11.4.0",
|
|
25
25
|
"microdiff": "^1.6.0",
|
|
26
26
|
"open": "^11.0.4",
|
|
27
27
|
"playwright-core": "^1.64.1",
|
|
28
28
|
"slugify": "^1.6.9",
|
|
29
|
-
"tty-table": "^
|
|
29
|
+
"tty-table": "^7.2.1",
|
|
30
30
|
"write-file-atomic": "^8.0.0",
|
|
31
31
|
"zod": "^4.6.7"
|
|
32
32
|
},
|
|
@@ -34,14 +34,14 @@
|
|
|
34
34
|
"@oclif/prettier-config": "^0.2.2",
|
|
35
35
|
"@stryker-mutator/core": "^10.1.1",
|
|
36
36
|
"@stryker-mutator/vitest-runner": "^10.1.1",
|
|
37
|
-
"@types/node": "26.6.
|
|
37
|
+
"@types/node": "26.6.6",
|
|
38
38
|
"@types/write-file-atomic": "^4.0.3",
|
|
39
|
-
"@vitest/coverage-v8": "^5.0
|
|
39
|
+
"@vitest/coverage-v8": "^5.1.0",
|
|
40
40
|
"@vitest/eslint-plugin": "^1.6.28",
|
|
41
|
-
"eslint": "^10.
|
|
41
|
+
"eslint": "^10.14.0",
|
|
42
42
|
"eslint-config-oclif": "^7.1.10",
|
|
43
43
|
"eslint-config-prettier": "^10",
|
|
44
|
-
"eslint-plugin-regexp": "^3.3.
|
|
44
|
+
"eslint-plugin-regexp": "^3.3.3",
|
|
45
45
|
"eslint-plugin-sonarjs": "^4.2.2",
|
|
46
46
|
"json-schema-to-typescript": "^16.0.0",
|
|
47
47
|
"oclif": "^6.0.15",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"ts-node": "10.9.2",
|
|
51
51
|
"tsx": "4.23.15",
|
|
52
52
|
"typescript": "^6.0.3",
|
|
53
|
-
"vitest": "^5.0
|
|
53
|
+
"vitest": "^5.1.0"
|
|
54
54
|
},
|
|
55
55
|
"engines": {
|
|
56
56
|
"node": ">=22.0.0"
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { Command } from '@oclif/core';
|
|
2
|
-
export default class Publish extends Command {
|
|
3
|
-
static args: {
|
|
4
|
-
path: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
|
|
5
|
-
};
|
|
6
|
-
static description: string;
|
|
7
|
-
static examples: string[];
|
|
8
|
-
run(): Promise<void>;
|
|
9
|
-
}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { Args, Command } from '@oclif/core';
|
|
2
|
-
import { basename, join } from 'node:path';
|
|
3
|
-
import { ApiClient } from '../../lib/api-client.js';
|
|
4
|
-
import { loadFiles } from '../../lib/load-files.js';
|
|
5
|
-
import { errorMessage } from '../../lib/narrow.js';
|
|
6
|
-
import { resolveLinkedProject } from '../../lib/resolve-linked-project.js';
|
|
7
|
-
import { pluralize } from '../../utils/pluralize.js';
|
|
8
|
-
// Publishes to the Loopress api (not a WordPress site), so this does not extend
|
|
9
|
-
// `LoopressCommand`/`PushCommand`: those force an environment to be resolved, but publishing
|
|
10
|
-
// for cross-project sharing doesn't need one, same reasoning as `snippet publish`. An API route
|
|
11
|
-
// is a special case of the same publish/deploy rules as snippets and ACF (see
|
|
12
|
-
// obsidian/Product/API and Console Backlog.md, US-18): a `push` (direct to WordPress, this
|
|
13
|
-
// project's own site) and a `publish` (to the cloud, deployable to other projects) are two
|
|
14
|
-
// separate, coexisting paths.
|
|
15
|
-
export default class Publish extends Command {
|
|
16
|
-
static args = {
|
|
17
|
-
path: Args.string({ description: 'Path to api directory (overrides project config)' }),
|
|
18
|
-
};
|
|
19
|
-
static description = 'Publish custom API routes to your Loopress account so they can be deployed to other projects. Does not touch any WordPress site.';
|
|
20
|
-
static examples = ['$ lps api publish', '$ lps api publish ./api'];
|
|
21
|
-
async run() {
|
|
22
|
-
const { args } = await this.parse(Publish);
|
|
23
|
-
const { apiProjectId, localConfig, token } = await resolveLinkedProject((message) => this.error(message));
|
|
24
|
-
const path = args.path ?? join(localConfig.rootDir ?? '.', localConfig.apiDir ?? 'api');
|
|
25
|
-
this.log(`Publishing API routes from ${path}`);
|
|
26
|
-
const files = await loadFiles(path, {
|
|
27
|
-
extension: '.php',
|
|
28
|
-
onSkip: (message) => { this.warn(message); },
|
|
29
|
-
parse: (raw, filePath) => ({ code: raw, filename: basename(filePath, '.php') }),
|
|
30
|
-
});
|
|
31
|
-
const api = new ApiClient(token);
|
|
32
|
-
try {
|
|
33
|
-
await api.post(`projects/${apiProjectId}/api-routes/publish/upsert`, {
|
|
34
|
-
routes: files,
|
|
35
|
-
});
|
|
36
|
-
await api.post(`projects/${apiProjectId}/api-routes/publish/prune`, {
|
|
37
|
-
filenames: files.map((file) => file.filename),
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
catch (error) {
|
|
41
|
-
this.error(errorMessage(error));
|
|
42
|
-
}
|
|
43
|
-
this.log(`Published ${pluralize(files.length, 'route')} to your Loopress account.`);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { Command } from '@oclif/core';
|
|
2
|
-
export default class Publish extends Command {
|
|
3
|
-
static args: {
|
|
4
|
-
path: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
|
|
5
|
-
};
|
|
6
|
-
static description: string;
|
|
7
|
-
static examples: string[];
|
|
8
|
-
run(): Promise<void>;
|
|
9
|
-
private toPayload;
|
|
10
|
-
}
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import { Args, Command } from '@oclif/core';
|
|
2
|
-
import { ApiClient } from '../../lib/api-client.js';
|
|
3
|
-
import { loadSnippets } from '../../lib/load-snippets.js';
|
|
4
|
-
import { errorMessage } from '../../lib/narrow.js';
|
|
5
|
-
import { resolveLinkedProject } from '../../lib/resolve-linked-project.js';
|
|
6
|
-
import {} from '../../types/snippet.js';
|
|
7
|
-
import { pluralize } from '../../utils/pluralize.js';
|
|
8
|
-
import { resolveResourceDir } from '../../utils/resource-dirs.js';
|
|
9
|
-
import { toSlug } from '../../utils/to-slug.js';
|
|
10
|
-
// Publishes to the Loopress api (not a WordPress site), so this does not extend
|
|
11
|
-
// `LoopressCommand`/`PushCommand`: those force an environment to be resolved, but a project
|
|
12
|
-
// publishing its snippets for sharing doesn't need one, a pure "library" project
|
|
13
|
-
// may have zero environments configured at all.
|
|
14
|
-
export default class Publish extends Command {
|
|
15
|
-
static args = {
|
|
16
|
-
path: Args.string({ description: 'Path to snippets directory (overrides project config)' }),
|
|
17
|
-
};
|
|
18
|
-
static description = 'Publish snippets to your Loopress account so they can be deployed to other projects. Does not touch any WordPress site.';
|
|
19
|
-
static examples = ['$ lps snippet publish', '$ lps snippet publish ./snippets'];
|
|
20
|
-
async run() {
|
|
21
|
-
const { args } = await this.parse(Publish);
|
|
22
|
-
const { apiProjectId, localConfig, token } = await resolveLinkedProject((message) => this.error(message));
|
|
23
|
-
const path = resolveResourceDir('snippets', localConfig, args.path);
|
|
24
|
-
this.log(`Publishing snippets from ${path}`);
|
|
25
|
-
let snippets;
|
|
26
|
-
try {
|
|
27
|
-
snippets = await loadSnippets(path, (message) => {
|
|
28
|
-
this.warn(message);
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
catch (error) {
|
|
32
|
-
this.error(errorMessage(error));
|
|
33
|
-
}
|
|
34
|
-
const api = new ApiClient(token);
|
|
35
|
-
try {
|
|
36
|
-
await api.post(`projects/${apiProjectId}/snippets/publish`, {
|
|
37
|
-
snippets: snippets.map((snippet) => this.toPayload(snippet)),
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
catch (error) {
|
|
41
|
-
this.error(errorMessage(error));
|
|
42
|
-
}
|
|
43
|
-
this.log(`Published ${pluralize(snippets.length, 'snippet')} to your Loopress account.`);
|
|
44
|
-
}
|
|
45
|
-
toPayload(snippet) {
|
|
46
|
-
return {
|
|
47
|
-
active: snippet.active,
|
|
48
|
-
code: snippet.code,
|
|
49
|
-
insertMethod: snippet.insertMethod,
|
|
50
|
-
location: snippet.location,
|
|
51
|
-
name: snippet.name,
|
|
52
|
-
priority: snippet.priority,
|
|
53
|
-
shortcodeAttributes: snippet.shortcodeAttributes,
|
|
54
|
-
// Derived from the snippet's name rather than its on-disk filename: the same
|
|
55
|
-
// slugification `push`/`pull` already use for the canonical `<id>-<slug>` filename
|
|
56
|
-
// convention, so it stays stable even for a not-yet-pushed file with an arbitrary name.
|
|
57
|
-
slug: toSlug(snippet.name),
|
|
58
|
-
tags: snippet.tags,
|
|
59
|
-
type: snippet.type,
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { type LoopressLocalConfig } from '../utils/loopress-config.js';
|
|
2
|
-
type LinkedProject = {
|
|
3
|
-
apiProjectId: string;
|
|
4
|
-
localConfig: LoopressLocalConfig;
|
|
5
|
-
token: string;
|
|
6
|
-
};
|
|
7
|
-
export declare function resolveLinkedProject(fail: (message: string) => never): Promise<LinkedProject>;
|
|
8
|
-
export {};
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { authManager } from '../config/auth.manager.js';
|
|
2
|
-
import { configManager } from '../config/project-config.manager.js';
|
|
3
|
-
import { readLocalConfig } from '../utils/loopress-config.js';
|
|
4
|
-
// Shared preamble for `api publish` and `snippet publish`. Both target the Loopress cloud (never
|
|
5
|
-
// a WordPress site), so neither extends `LoopressCommand`/`PushCommand` and neither needs an
|
|
6
|
-
// environment resolved, but both need a logged-in user and a project already linked to the
|
|
7
|
-
// account (`lps project push`). `fail` is the caller's `this.error`, so its messages keep
|
|
8
|
-
// oclif's formatting and exit code; typed `=> never` so callers still narrow after the guards.
|
|
9
|
-
export async function resolveLinkedProject(fail) {
|
|
10
|
-
const token = process.env.LOOPRESS_TOKEN ?? authManager.getAuth()?.token;
|
|
11
|
-
if (!token) {
|
|
12
|
-
fail('Not logged in. Run `lps login` first.');
|
|
13
|
-
}
|
|
14
|
-
const localConfig = await readLocalConfig();
|
|
15
|
-
const projectId = localConfig.projectId ?? configManager.getCurrentProject()?.id;
|
|
16
|
-
if (!projectId) {
|
|
17
|
-
fail('No project configured. Run `lps project config` first.');
|
|
18
|
-
}
|
|
19
|
-
const project = configManager.getProject(projectId);
|
|
20
|
-
if (!project) {
|
|
21
|
-
fail(`Project "${projectId}" (from loopress.json) not found. Run \`lps project config\` to configure it.`);
|
|
22
|
-
}
|
|
23
|
-
if (!project.apiProjectId) {
|
|
24
|
-
fail(`Project "${project.name}" is not linked to your Loopress account yet. Run \`lps project push\` first.`);
|
|
25
|
-
}
|
|
26
|
-
return { apiProjectId: project.apiProjectId, localConfig, token };
|
|
27
|
-
}
|