@neopress/cli 4.0.0 → 4.1.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 +109 -0
- package/dist/bin.cjs +591 -63
- package/dist/index.js +130 -0
- package/package.json +12 -2
package/README.md
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# @neopress/cli
|
|
2
|
+
|
|
3
|
+
Manage your [Neopress](https://app.neopress.ai) site from the terminal — pages,
|
|
4
|
+
collections, entries, forms, assets, redirects, analytics, and publishing.
|
|
5
|
+
|
|
6
|
+
Designed to be driven by humans **and** by AI agents (Claude Code, Codex, etc.):
|
|
7
|
+
every command speaks JSON, and `neopress guide` prints the entire command
|
|
8
|
+
surface in one call.
|
|
9
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm i -g @neopress/cli
|
|
14
|
+
neopress --version
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Or run without installing:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npx @neopress/cli guide
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Authenticate
|
|
24
|
+
|
|
25
|
+
Log in once; the session is stored in `~/.config/neopress/tokens.json` and
|
|
26
|
+
refreshed automatically.
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
neopress login # OAuth in the browser
|
|
30
|
+
neopress whoami # confirm who you are
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
For CI or headless agents, skip the browser and pass a token instead:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
export NEOPRESS_ACCESS_TOKEN="<token>"
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Quickstart
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
neopress sites list # sites you can access
|
|
43
|
+
neopress sites use <id|handle> # pick the active site (persisted)
|
|
44
|
+
neopress pages list # list pages on the active site
|
|
45
|
+
neopress guide # full command reference
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Target a one-off site without changing the active one:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
neopress --site my-blog pages list
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Common tasks
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
# Create a page from a TSX file (created as a draft)
|
|
58
|
+
neopress pages create --path /about --title About --tsx ./about.tsx
|
|
59
|
+
|
|
60
|
+
# Localize a page — JSON options take inline JSON or @file
|
|
61
|
+
neopress pages create --path /about --i18n @i18n.json --public-locales en,ko
|
|
62
|
+
|
|
63
|
+
# Create and publish a collection entry
|
|
64
|
+
neopress entries create --collection 12 --data @entry.json --title Hello
|
|
65
|
+
neopress entries publish <entryId>
|
|
66
|
+
|
|
67
|
+
# Preview, then publish the whole site
|
|
68
|
+
neopress publish preview
|
|
69
|
+
neopress publish
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Run `neopress <command> --help` for the flags and examples of any command.
|
|
73
|
+
|
|
74
|
+
## JSON / AI mode
|
|
75
|
+
|
|
76
|
+
Output is human-readable in a terminal and **automatically switches to JSON when
|
|
77
|
+
piped or redirected**, so it composes with `jq` and tools out of the box:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
neopress pages list | jq '.data[].path'
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Force JSON in a terminal with `--json`. For agents that want the whole CLI in a
|
|
84
|
+
single introspectable payload:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
neopress guide --json
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
`neopress guide` is generated from the live command tree, so it never drifts from
|
|
91
|
+
the installed version — treat it as the source of truth for what the CLI can do.
|
|
92
|
+
|
|
93
|
+
## Configuration
|
|
94
|
+
|
|
95
|
+
Resolution order for the active site: `--site` flag → `NEOPRESS_SITE_ID` →
|
|
96
|
+
project config file → the site saved by `neopress sites use`.
|
|
97
|
+
|
|
98
|
+
| Variable | Default | Purpose |
|
|
99
|
+
| --- | --- | --- |
|
|
100
|
+
| `NEOPRESS_ACCESS_TOKEN` | — | Auth token (skips `neopress login`) |
|
|
101
|
+
| `NEOPRESS_SITE_ID` | — | Default site id (overrides the active site) |
|
|
102
|
+
| `NEOPRESS_BASE_URL` | `https://app.neopress.ai` | API base URL (staging/local targets) |
|
|
103
|
+
|
|
104
|
+
Per-project defaults can also live in `.neopressrc.json` (or
|
|
105
|
+
`.neopress/config.json`):
|
|
106
|
+
|
|
107
|
+
```json
|
|
108
|
+
{ "siteId": 42, "baseUrl": "https://app.neopress.ai" }
|
|
109
|
+
```
|
package/dist/bin.cjs
CHANGED
|
@@ -3652,7 +3652,12 @@ function parseImplicitCallbackTokens(callbackUrl) {
|
|
|
3652
3652
|
};
|
|
3653
3653
|
}
|
|
3654
3654
|
function registerAuthCommands(program3) {
|
|
3655
|
-
program3.command("login").description("Authenticate with Neopress").
|
|
3655
|
+
program3.command("login").description("Authenticate with Neopress").addHelpText("after", `
|
|
3656
|
+
Examples:
|
|
3657
|
+
$ neopress login
|
|
3658
|
+
$ neopress login --manual
|
|
3659
|
+
$ neopress login --provider google
|
|
3660
|
+
Default flow opens a browser and listens on a local callback port; use --manual on a headless host to paste the callback URL by hand. After login, run \`neopress sites use <siteId>\` to select a site.`).option("--provider <provider>", "OAuth provider (google)", "google").option("--manual", "Paste the OAuth callback URL manually instead of running a local callback server").action(async (options) => {
|
|
3656
3661
|
console.log(options.manual ? "Starting manual browser login..." : "Opening browser for login...");
|
|
3657
3662
|
const codeVerifier = generateCodeVerifier();
|
|
3658
3663
|
const codeChallenge = generateCodeChallenge(codeVerifier);
|
|
@@ -24882,6 +24887,27 @@ function serializeTemplate(t) {
|
|
|
24882
24887
|
createdAt: t.created_at
|
|
24883
24888
|
};
|
|
24884
24889
|
}
|
|
24890
|
+
function serializeHeadshot(h) {
|
|
24891
|
+
return {
|
|
24892
|
+
id: h.id,
|
|
24893
|
+
imageUrl: h.image_url,
|
|
24894
|
+
width: h.width,
|
|
24895
|
+
height: h.height,
|
|
24896
|
+
aspectRatio: h.aspect_ratio,
|
|
24897
|
+
mimeType: h.mime_type,
|
|
24898
|
+
byteSize: h.byte_size,
|
|
24899
|
+
ageBand: h.age_band,
|
|
24900
|
+
gender: h.gender,
|
|
24901
|
+
ethnicity: h.ethnicity,
|
|
24902
|
+
attire: h.attire,
|
|
24903
|
+
variationIndex: h.variation_index,
|
|
24904
|
+
gptPrompt: h.gpt_prompt,
|
|
24905
|
+
tags: h.tags ?? [],
|
|
24906
|
+
isActive: h.is_active,
|
|
24907
|
+
createdAt: h.created_at,
|
|
24908
|
+
updatedAt: h.updated_at
|
|
24909
|
+
};
|
|
24910
|
+
}
|
|
24885
24911
|
function serializeSite(site) {
|
|
24886
24912
|
return {
|
|
24887
24913
|
id: site.id,
|
|
@@ -40564,6 +40590,113 @@ var TemplatesEndpoint = class {
|
|
|
40564
40590
|
}
|
|
40565
40591
|
};
|
|
40566
40592
|
|
|
40593
|
+
// ../sdk/dist/endpoints/headshots.js
|
|
40594
|
+
var HeadshotsEndpoint = class {
|
|
40595
|
+
client;
|
|
40596
|
+
constructor(client) {
|
|
40597
|
+
this.client = client;
|
|
40598
|
+
}
|
|
40599
|
+
async list(params) {
|
|
40600
|
+
const { page, limit, offset } = this.client.resolvePagination(params);
|
|
40601
|
+
let query = this.client.db.from("headshot_pool").select("*", { count: "exact" });
|
|
40602
|
+
if (params?.ageBand)
|
|
40603
|
+
query = query.eq("age_band", params.ageBand);
|
|
40604
|
+
if (params?.gender)
|
|
40605
|
+
query = query.eq("gender", params.gender);
|
|
40606
|
+
if (params?.ethnicity)
|
|
40607
|
+
query = query.eq("ethnicity", params.ethnicity);
|
|
40608
|
+
if (params?.attire)
|
|
40609
|
+
query = query.eq("attire", params.attire);
|
|
40610
|
+
if (params?.isActive !== void 0)
|
|
40611
|
+
query = query.eq("is_active", params.isActive);
|
|
40612
|
+
const { data, error: error48, count } = await query.order("age_band", { ascending: true }).order("gender", { ascending: true }).order("ethnicity", { ascending: true }).order("variation_index", { ascending: true }).range(offset, offset + limit - 1);
|
|
40613
|
+
if (error48)
|
|
40614
|
+
throw new NeopressApiError("DB_ERROR", error48.message, 0, error48);
|
|
40615
|
+
return {
|
|
40616
|
+
data: (data ?? []).map((r) => serializeHeadshot(r)),
|
|
40617
|
+
pagination: this.client.paginationMeta(page, limit, offset, count ?? 0)
|
|
40618
|
+
};
|
|
40619
|
+
}
|
|
40620
|
+
async get(id) {
|
|
40621
|
+
const { data, error: error48 } = await this.client.db.from("headshot_pool").select("*").eq("id", id).single();
|
|
40622
|
+
if (error48)
|
|
40623
|
+
throw new NeopressApiError("DB_ERROR", error48.message, 0, error48);
|
|
40624
|
+
return serializeHeadshot(data);
|
|
40625
|
+
}
|
|
40626
|
+
async create(params) {
|
|
40627
|
+
const values = {
|
|
40628
|
+
image_url: params.imageUrl,
|
|
40629
|
+
age_band: params.ageBand,
|
|
40630
|
+
gender: params.gender,
|
|
40631
|
+
ethnicity: params.ethnicity,
|
|
40632
|
+
variation_index: params.variationIndex
|
|
40633
|
+
};
|
|
40634
|
+
if (params.attire !== void 0)
|
|
40635
|
+
values.attire = params.attire;
|
|
40636
|
+
if (params.width !== void 0)
|
|
40637
|
+
values.width = params.width;
|
|
40638
|
+
if (params.height !== void 0)
|
|
40639
|
+
values.height = params.height;
|
|
40640
|
+
if (params.aspectRatio !== void 0)
|
|
40641
|
+
values.aspect_ratio = params.aspectRatio;
|
|
40642
|
+
if (params.mimeType !== void 0)
|
|
40643
|
+
values.mime_type = params.mimeType;
|
|
40644
|
+
if (params.byteSize !== void 0)
|
|
40645
|
+
values.byte_size = params.byteSize;
|
|
40646
|
+
if (params.gptPrompt !== void 0)
|
|
40647
|
+
values.gpt_prompt = params.gptPrompt;
|
|
40648
|
+
if (params.tags !== void 0)
|
|
40649
|
+
values.tags = params.tags;
|
|
40650
|
+
if (params.isActive !== void 0)
|
|
40651
|
+
values.is_active = params.isActive;
|
|
40652
|
+
const { data, error: error48 } = await this.client.db.from("headshot_pool").insert(values).select().single();
|
|
40653
|
+
if (error48)
|
|
40654
|
+
throw new NeopressApiError("DB_ERROR", error48.message, 0, error48);
|
|
40655
|
+
return serializeHeadshot(data);
|
|
40656
|
+
}
|
|
40657
|
+
async update(id, params) {
|
|
40658
|
+
const values = {};
|
|
40659
|
+
if (params.imageUrl !== void 0)
|
|
40660
|
+
values.image_url = params.imageUrl;
|
|
40661
|
+
if (params.ageBand !== void 0)
|
|
40662
|
+
values.age_band = params.ageBand;
|
|
40663
|
+
if (params.gender !== void 0)
|
|
40664
|
+
values.gender = params.gender;
|
|
40665
|
+
if (params.ethnicity !== void 0)
|
|
40666
|
+
values.ethnicity = params.ethnicity;
|
|
40667
|
+
if (params.attire !== void 0)
|
|
40668
|
+
values.attire = params.attire;
|
|
40669
|
+
if (params.variationIndex !== void 0)
|
|
40670
|
+
values.variation_index = params.variationIndex;
|
|
40671
|
+
if (params.width !== void 0)
|
|
40672
|
+
values.width = params.width;
|
|
40673
|
+
if (params.height !== void 0)
|
|
40674
|
+
values.height = params.height;
|
|
40675
|
+
if (params.aspectRatio !== void 0)
|
|
40676
|
+
values.aspect_ratio = params.aspectRatio;
|
|
40677
|
+
if (params.mimeType !== void 0)
|
|
40678
|
+
values.mime_type = params.mimeType;
|
|
40679
|
+
if (params.byteSize !== void 0)
|
|
40680
|
+
values.byte_size = params.byteSize;
|
|
40681
|
+
if (params.gptPrompt !== void 0)
|
|
40682
|
+
values.gpt_prompt = params.gptPrompt;
|
|
40683
|
+
if (params.tags !== void 0)
|
|
40684
|
+
values.tags = params.tags;
|
|
40685
|
+
if (params.isActive !== void 0)
|
|
40686
|
+
values.is_active = params.isActive;
|
|
40687
|
+
const { data, error: error48 } = await this.client.db.from("headshot_pool").update(values).eq("id", id).select().single();
|
|
40688
|
+
if (error48)
|
|
40689
|
+
throw new NeopressApiError("DB_ERROR", error48.message, 0, error48);
|
|
40690
|
+
return serializeHeadshot(data);
|
|
40691
|
+
}
|
|
40692
|
+
async delete(id) {
|
|
40693
|
+
const { error: error48 } = await this.client.db.from("headshot_pool").delete().eq("id", id);
|
|
40694
|
+
if (error48)
|
|
40695
|
+
throw new NeopressApiError("DB_ERROR", error48.message, 0, error48);
|
|
40696
|
+
return { id, deleted: true };
|
|
40697
|
+
}
|
|
40698
|
+
};
|
|
40699
|
+
|
|
40567
40700
|
// ../sdk/dist/client.js
|
|
40568
40701
|
var NeopressClient = class {
|
|
40569
40702
|
baseUrl;
|
|
@@ -40584,6 +40717,7 @@ var NeopressClient = class {
|
|
|
40584
40717
|
entryReferences;
|
|
40585
40718
|
analytics;
|
|
40586
40719
|
templates;
|
|
40720
|
+
headshots;
|
|
40587
40721
|
constructor(options) {
|
|
40588
40722
|
this.baseUrl = (options.baseUrl || "https://app.neopress.ai").replace(/\/$/, "");
|
|
40589
40723
|
this.accessToken = options.accessToken || "";
|
|
@@ -40602,6 +40736,7 @@ var NeopressClient = class {
|
|
|
40602
40736
|
this.entryReferences = new EntryReferencesEndpoint(this);
|
|
40603
40737
|
this.analytics = new AnalyticsEndpoint(this);
|
|
40604
40738
|
this.templates = new TemplatesEndpoint(this);
|
|
40739
|
+
this.headshots = new HeadshotsEndpoint(this);
|
|
40605
40740
|
}
|
|
40606
40741
|
get siteBasePath() {
|
|
40607
40742
|
return `/api/v1/sites/${this.siteId}`;
|
|
@@ -40731,39 +40866,40 @@ async function getClientAsync(siteIdOverride) {
|
|
|
40731
40866
|
const sb = getSupabaseConfig();
|
|
40732
40867
|
return new NeopressClient({ accessToken, siteId, baseUrl: getBaseUrl(), supabaseUrl: sb.url, supabaseAnonKey: sb.anonKey });
|
|
40733
40868
|
}
|
|
40869
|
+
async function getGlobalClientAsync() {
|
|
40870
|
+
const token = process.env.NEOPRESS_ACCESS_TOKEN || await getValidAccessToken();
|
|
40871
|
+
if (!token) {
|
|
40872
|
+
fail("Not authenticated. Run `neopress login` or set NEOPRESS_ACCESS_TOKEN.");
|
|
40873
|
+
}
|
|
40874
|
+
const sb = getSupabaseConfig();
|
|
40875
|
+
return new NeopressClient({ accessToken: token, siteId: 0, baseUrl: getBaseUrl(), supabaseUrl: sb.url, supabaseAnonKey: sb.anonKey });
|
|
40876
|
+
}
|
|
40734
40877
|
|
|
40735
40878
|
// src/commands/sites.ts
|
|
40736
40879
|
function registerSiteCommands(program3) {
|
|
40737
|
-
const sites = program3.command("sites").description("Manage sites")
|
|
40880
|
+
const sites = program3.command("sites").description("Manage sites").addHelpText("after", `
|
|
40881
|
+
Examples:
|
|
40882
|
+
$ neopress sites list
|
|
40883
|
+
$ neopress sites create --name "My Site" --handle my-site --use
|
|
40884
|
+
$ neopress sites use my-site
|
|
40885
|
+
Run \`sites use <id|handle>\` to set the active site for all other commands.`);
|
|
40738
40886
|
sites.command("list").description("List accessible sites").action(async () => {
|
|
40739
|
-
const
|
|
40740
|
-
if (!token) {
|
|
40741
|
-
fail("Not authenticated. Run `neopress login`.");
|
|
40742
|
-
}
|
|
40743
|
-
const client = new NeopressClient({
|
|
40744
|
-
accessToken: token,
|
|
40745
|
-
siteId: 0,
|
|
40746
|
-
baseUrl: getBaseUrl()
|
|
40747
|
-
});
|
|
40887
|
+
const client = await getGlobalClientAsync();
|
|
40748
40888
|
const sitesList = await client.site.list();
|
|
40749
40889
|
output(sitesList);
|
|
40750
40890
|
});
|
|
40751
|
-
sites.command("use <siteIdOrHandle>").description("Set active site (ID or handle)").
|
|
40891
|
+
sites.command("use <siteIdOrHandle>").description("Set active site (ID or handle)").addHelpText("after", `
|
|
40892
|
+
Examples:
|
|
40893
|
+
$ neopress sites use 12
|
|
40894
|
+
$ neopress sites use my-site
|
|
40895
|
+
Accepts a numeric site ID or a handle (resolved via \`sites list\`). Sets the active site used by all other commands.`).action(async (siteIdOrHandle) => {
|
|
40752
40896
|
const id = parseInt(siteIdOrHandle, 10);
|
|
40753
40897
|
if (!isNaN(id)) {
|
|
40754
40898
|
setActiveSiteId(id);
|
|
40755
40899
|
ok(`Active site set to ${id}`);
|
|
40756
40900
|
return;
|
|
40757
40901
|
}
|
|
40758
|
-
const
|
|
40759
|
-
if (!token) {
|
|
40760
|
-
fail("Not authenticated. Run `neopress login`.");
|
|
40761
|
-
}
|
|
40762
|
-
const client = new NeopressClient({
|
|
40763
|
-
accessToken: token,
|
|
40764
|
-
siteId: 0,
|
|
40765
|
-
baseUrl: getBaseUrl()
|
|
40766
|
-
});
|
|
40902
|
+
const client = await getGlobalClientAsync();
|
|
40767
40903
|
const sitesList = await client.site.list();
|
|
40768
40904
|
const match = sitesList.find((s) => s.handle === siteIdOrHandle);
|
|
40769
40905
|
if (!match) {
|
|
@@ -40772,19 +40908,16 @@ function registerSiteCommands(program3) {
|
|
|
40772
40908
|
setActiveSiteId(match.id);
|
|
40773
40909
|
ok(`Active site set to ${match.id} (${match.handle})`);
|
|
40774
40910
|
});
|
|
40775
|
-
sites.command("create").description("Create a new site").
|
|
40911
|
+
sites.command("create").description("Create a new site").addHelpText("after", `
|
|
40912
|
+
Examples:
|
|
40913
|
+
$ neopress sites create --name "My Site" --handle my-site
|
|
40914
|
+
$ neopress sites create --prompt "a portfolio for a freelance photographer" --use
|
|
40915
|
+
$ neopress sites create --name Acme --handle acme --language en
|
|
40916
|
+
Pass --prompt to auto-generate name/handle, or supply both --name and --handle. --language sets the default content locale (default en). --use sets the new site as active.`).option("--name <name>", "Site name").option("--handle <handle>", "Site handle").option("--prompt <prompt>", "Prompt to generate site name/handle").option("--language <locale>", "Default content locale", "en").option("--use", "Set the created site as active").action(async (options) => {
|
|
40776
40917
|
if (!options.prompt && !(options.name && options.handle)) {
|
|
40777
40918
|
fail("Provide --prompt or both --name and --handle.");
|
|
40778
40919
|
}
|
|
40779
|
-
const
|
|
40780
|
-
if (!token) {
|
|
40781
|
-
fail("Not authenticated. Run `neopress login`.");
|
|
40782
|
-
}
|
|
40783
|
-
const client = new NeopressClient({
|
|
40784
|
-
accessToken: token,
|
|
40785
|
-
siteId: 0,
|
|
40786
|
-
baseUrl: getBaseUrl()
|
|
40787
|
-
});
|
|
40920
|
+
const client = await getGlobalClientAsync();
|
|
40788
40921
|
const site = await client.site.create({
|
|
40789
40922
|
siteName: options.name,
|
|
40790
40923
|
siteHandle: options.handle,
|
|
@@ -40802,7 +40935,11 @@ function registerSiteCommands(program3) {
|
|
|
40802
40935
|
const site = await client.site.get();
|
|
40803
40936
|
output(site);
|
|
40804
40937
|
});
|
|
40805
|
-
sites.command("update").description("Update site settings").
|
|
40938
|
+
sites.command("update").description("Update site settings").addHelpText("after", `
|
|
40939
|
+
Examples:
|
|
40940
|
+
$ neopress sites update --name "New Name"
|
|
40941
|
+
$ neopress sites update --locale-config '{"locales":["en","ko"],"defaultLocale":"en"}'
|
|
40942
|
+
Updates the active site. --locale-config takes inline JSON. Pass at least one of --name or --locale-config.`).option("--name <name>", "Site name").option("--locale-config <json>", "Locale config JSON").action(async (options) => {
|
|
40806
40943
|
const client = await getClientAsync();
|
|
40807
40944
|
const data = {};
|
|
40808
40945
|
if (options.name) data.name = options.name;
|
|
@@ -40819,7 +40956,11 @@ function registerSiteCommands(program3) {
|
|
|
40819
40956
|
const site = await client.site.update(data);
|
|
40820
40957
|
output(site);
|
|
40821
40958
|
});
|
|
40822
|
-
sites.command("delete <siteIdOrHandle>").description("Delete a site and all its content (workspace admin only)").
|
|
40959
|
+
sites.command("delete <siteIdOrHandle>").description("Delete a site and all its content (workspace admin only)").addHelpText("after", `
|
|
40960
|
+
Examples:
|
|
40961
|
+
$ neopress sites delete my-site
|
|
40962
|
+
$ neopress sites delete 12 --yes
|
|
40963
|
+
Permanently deletes the site and all its content (workspace admin only) \u2014 this is a hard delete, not recoverable. Interactive runs prompt for the id/handle to confirm; --yes is required in non-interactive mode.`).option("--yes", "Skip confirmation (required in non-interactive mode)").action(async (siteIdOrHandle, options) => {
|
|
40823
40964
|
const interactive = process.stdout.isTTY && process.stdin.isTTY;
|
|
40824
40965
|
if (!options.yes && !interactive) {
|
|
40825
40966
|
fail("Refusing to delete without --yes in non-interactive mode.");
|
|
@@ -40878,7 +41019,13 @@ function mergeQueryConfigIntoDraftMeta(draftMetaInput, queryConfigInput) {
|
|
|
40878
41019
|
};
|
|
40879
41020
|
}
|
|
40880
41021
|
function registerPageCommands(program3) {
|
|
40881
|
-
const pages = program3.command("pages").description("Manage pages")
|
|
41022
|
+
const pages = program3.command("pages").description("Manage pages").addHelpText("after", `
|
|
41023
|
+
Examples:
|
|
41024
|
+
$ neopress pages create --path /about --title About --tsx ./about.tsx
|
|
41025
|
+
$ neopress pages update <pageId> --tsx ./about.tsx
|
|
41026
|
+
$ neopress pages compile <pageId>
|
|
41027
|
+
|
|
41028
|
+
Draft content fields (--tsx/--i18n/--draft-meta) need \`neopress publish\` to go live. \`pages delete\` is a soft delete.`);
|
|
40882
41029
|
pages.command("list").description("List pages").option("--status <status>", "Filter by status (draft/published)").option("--page <n>", "Page number", "1").option("--limit <n>", "Results per page", "20").action(async (options) => {
|
|
40883
41030
|
const client = await getClientAsync();
|
|
40884
41031
|
const res = await client.pages.list({
|
|
@@ -40893,7 +41040,17 @@ function registerPageCommands(program3) {
|
|
|
40893
41040
|
const page = await client.pages.get(parseInt(pageId, 10));
|
|
40894
41041
|
output(page);
|
|
40895
41042
|
});
|
|
40896
|
-
pages.command("create").description("Create a new page").requiredOption("--path <path>", "Page path (e.g., /about)").option("--title <title>", "Page title").option("--tsx <file>", "TSX file path").option("--i18n <json>", "Page i18n JSON string or @file path").option("--public-locales <locales>", "Comma-separated locale list or JSON string array").option("--metadata <json>", "Page metadata JSON string or @file path").option("--draft-meta <json>", "Draft runtime metadata JSON string or @file path").option("--query-config <json>", "Query config JSON string or @file path; stored as draftMeta.queryConfig").option("--collection <id>", "Collection ID for dynamic pages").option("--type <type>", "Page type (static/dynamic)", "static").
|
|
41043
|
+
pages.command("create").description("Create a new page").requiredOption("--path <path>", "Page path (e.g., /about)").option("--title <title>", "Page title").option("--tsx <file>", "TSX file path").option("--i18n <json>", "Page i18n JSON string or @file path").option("--public-locales <locales>", "Comma-separated locale list or JSON string array").option("--metadata <json>", "Page metadata JSON string or @file path").option("--draft-meta <json>", "Draft runtime metadata JSON string or @file path").option("--query-config <json>", "Query config JSON string or @file path; stored as draftMeta.queryConfig").option("--collection <id>", "Collection ID for dynamic pages").option("--type <type>", "Page type (static/dynamic)", "static").addHelpText(
|
|
41044
|
+
"after",
|
|
41045
|
+
`
|
|
41046
|
+
Examples:
|
|
41047
|
+
$ neopress pages create --path /about --title About --tsx ./about.tsx
|
|
41048
|
+
$ neopress pages create --path /blog --type dynamic --collection 12 --tsx ./blog.tsx
|
|
41049
|
+
$ neopress pages create --path /about --i18n @i18n.json --public-locales en,ko
|
|
41050
|
+
|
|
41051
|
+
--tsx reads the component from a file. JSON options take inline JSON or @file (e.g. --i18n @i18n.json).
|
|
41052
|
+
Pages are created as drafts \u2014 run \`neopress publish\` to make them live.`
|
|
41053
|
+
).action(async (options) => {
|
|
40897
41054
|
const client = await getClientAsync();
|
|
40898
41055
|
const draftTsx = options.tsx ? (0, import_node_fs3.readFileSync)(options.tsx, "utf-8") : void 0;
|
|
40899
41056
|
const draftI18n = parseJsonInput(options.i18n);
|
|
@@ -40914,7 +41071,13 @@ function registerPageCommands(program3) {
|
|
|
40914
41071
|
});
|
|
40915
41072
|
output(page);
|
|
40916
41073
|
});
|
|
40917
|
-
pages.command("update <pageId>").description("Update a page").
|
|
41074
|
+
pages.command("update <pageId>").description("Update a page").addHelpText("after", `
|
|
41075
|
+
Examples:
|
|
41076
|
+
$ neopress pages update 12 --tsx ./about.tsx
|
|
41077
|
+
$ neopress pages update 12 --title About --path /about-us
|
|
41078
|
+
$ neopress pages update 12 --collection 12 --query-config @query.json
|
|
41079
|
+
|
|
41080
|
+
Pass at least one field flag. --tsx reads the component from a file; JSON options take inline JSON or @file. Draft content (--tsx/--i18n/--draft-meta/--query-config) needs \`neopress publish\` to go live; --title/--path/--collection apply immediately.`).option("--path <path>", "New page path").option("--title <title>", "New title").option("--tsx <file>", "TSX file path").option("--i18n <json>", "Page i18n JSON string or @file path").option("--public-locales <locales>", "Comma-separated locale list or JSON string array").option("--metadata <json>", "Page metadata JSON string or @file path").option("--draft-meta <json>", "Draft runtime metadata JSON string or @file path").option("--query-config <json>", "Query config JSON string or @file path; stored as draftMeta.queryConfig").option("--collection <id>", "Collection ID for dynamic pages").action(async (pageId, options) => {
|
|
40918
41081
|
const client = await getClientAsync();
|
|
40919
41082
|
const data = {};
|
|
40920
41083
|
if (options.path) data.path = options.path;
|
|
@@ -40938,7 +41101,11 @@ function registerPageCommands(program3) {
|
|
|
40938
41101
|
await client.pages.delete(parseInt(pageId, 10));
|
|
40939
41102
|
ok(`Page ${pageId} deleted`);
|
|
40940
41103
|
});
|
|
40941
|
-
pages.command("compile <pageId>").description("Validate TSX compilation").
|
|
41104
|
+
pages.command("compile <pageId>").description("Validate TSX compilation").addHelpText("after", `
|
|
41105
|
+
Examples:
|
|
41106
|
+
$ neopress pages compile 12
|
|
41107
|
+
|
|
41108
|
+
Validates the page's draft TSX and reports compile status \u2014 it does not save or publish.`).action(async (pageId) => {
|
|
40942
41109
|
const client = await getClientAsync();
|
|
40943
41110
|
const result = await client.pages.compile(parseInt(pageId, 10));
|
|
40944
41111
|
output(result);
|
|
@@ -40952,7 +41119,13 @@ function parseJsonInput2(input) {
|
|
|
40952
41119
|
return input.startsWith("@") ? JSON.parse((0, import_node_fs4.readFileSync)(input.slice(1), "utf-8")) : JSON.parse(input);
|
|
40953
41120
|
}
|
|
40954
41121
|
function registerCollectionCommands(program3) {
|
|
40955
|
-
const collections = program3.command("collections").description("Manage collections")
|
|
41122
|
+
const collections = program3.command("collections").description("Manage collections").addHelpText("after", `
|
|
41123
|
+
Examples:
|
|
41124
|
+
$ neopress collections create --name Posts --schema @schema.json
|
|
41125
|
+
$ neopress collections list
|
|
41126
|
+
$ neopress collections update 12 --schema @schema.json
|
|
41127
|
+
|
|
41128
|
+
Collections are identified by numeric id, never name. delete is a soft delete \u2014 the collection is hidden from list/get but its row is retained.`);
|
|
40956
41129
|
collections.command("list").description("List collections").action(async () => {
|
|
40957
41130
|
const client = await getClientAsync();
|
|
40958
41131
|
const data = await client.collections.list();
|
|
@@ -40963,7 +41136,13 @@ function registerCollectionCommands(program3) {
|
|
|
40963
41136
|
const data = await client.collections.get(parseInt(collectionId, 10));
|
|
40964
41137
|
output(data);
|
|
40965
41138
|
});
|
|
40966
|
-
collections.command("create").description("Create a collection").
|
|
41139
|
+
collections.command("create").description("Create a collection").addHelpText("after", `
|
|
41140
|
+
Examples:
|
|
41141
|
+
$ neopress collections create --name Posts
|
|
41142
|
+
$ neopress collections create --name Posts --schema @schema.json
|
|
41143
|
+
$ neopress collections create --name Posts --schema '{"title":{"type":"text"}}'
|
|
41144
|
+
|
|
41145
|
+
--schema takes inline JSON or @file and is keyed by field id. It is written to the draft schema \u2014 publish the site to make it live.`).requiredOption("--name <name>", "Collection name").option("--schema <json>", "Draft schema as JSON string or @file path").action(async (options) => {
|
|
40967
41146
|
const client = await getClientAsync();
|
|
40968
41147
|
const data = await client.collections.create({
|
|
40969
41148
|
name: options.name,
|
|
@@ -40971,7 +41150,12 @@ function registerCollectionCommands(program3) {
|
|
|
40971
41150
|
});
|
|
40972
41151
|
output(data);
|
|
40973
41152
|
});
|
|
40974
|
-
collections.command("update <collectionId>").description("Update a collection").
|
|
41153
|
+
collections.command("update <collectionId>").description("Update a collection").addHelpText("after", `
|
|
41154
|
+
Examples:
|
|
41155
|
+
$ neopress collections update 12 --name Articles
|
|
41156
|
+
$ neopress collections update 12 --schema @schema.json
|
|
41157
|
+
|
|
41158
|
+
Identify the collection by numeric id. Pass at least one of --name or --schema. --schema (inline JSON or @file, field-id keyed) replaces the draft schema; publish the site to make it live.`).option("--name <name>", "Collection name").option("--schema <json>", "Draft schema as JSON string or @file path").action(async (collectionId, options) => {
|
|
40975
41159
|
const client = await getClientAsync();
|
|
40976
41160
|
const data = {};
|
|
40977
41161
|
if (options.name) data.name = options.name;
|
|
@@ -40995,7 +41179,13 @@ function registerCollectionCommands(program3) {
|
|
|
40995
41179
|
// src/commands/entries.ts
|
|
40996
41180
|
var import_node_fs5 = require("fs");
|
|
40997
41181
|
function registerEntryCommands(program3) {
|
|
40998
|
-
const entries = program3.command("entries").description("Manage entries")
|
|
41182
|
+
const entries = program3.command("entries").description("Manage entries").addHelpText("after", `
|
|
41183
|
+
Examples:
|
|
41184
|
+
$ neopress entries list --collection 12 --status published --locale en
|
|
41185
|
+
$ neopress entries create --collection 12 --data @entry.json --title Hello
|
|
41186
|
+
$ neopress entries publish <entryId>
|
|
41187
|
+
|
|
41188
|
+
Entries are created as drafts \u2014 run \`neopress entries publish <entryId>\` to make them live. create/update/delete revalidate the reader cache; delete is a soft delete.`);
|
|
40999
41189
|
entries.command("list").description("List entries in a collection").requiredOption("--collection <id>", "Collection ID").option("--status <status>", "Filter by status").option("--locale <locale>", "Filter by locale").option("--page <n>", "Page number", "1").option("--limit <n>", "Results per page", "20").action(async (options) => {
|
|
41000
41190
|
const client = await getClientAsync();
|
|
41001
41191
|
const res = await client.entries.list(parseInt(options.collection, 10), {
|
|
@@ -41011,7 +41201,15 @@ function registerEntryCommands(program3) {
|
|
|
41011
41201
|
const data = await client.entries.get(parseInt(entryId, 10));
|
|
41012
41202
|
output(data);
|
|
41013
41203
|
});
|
|
41014
|
-
entries.command("create").description("Create an entry").requiredOption("--collection <id>", "Collection ID").option("--data <json>", "Entry data as JSON string or @file path").option("--title <title>", "Entry title").option("--slug <slug>", "Entry slug").option("--locale <locale>", "Entry locale").
|
|
41204
|
+
entries.command("create").description("Create an entry").requiredOption("--collection <id>", "Collection ID").option("--data <json>", "Entry data as JSON string or @file path").option("--title <title>", "Entry title").option("--slug <slug>", "Entry slug").option("--locale <locale>", "Entry locale").addHelpText(
|
|
41205
|
+
"after",
|
|
41206
|
+
`
|
|
41207
|
+
Examples:
|
|
41208
|
+
$ neopress entries create --collection 12 --data '{"body":"Hello"}' --title Hello
|
|
41209
|
+
$ neopress entries create --collection 12 --data @entry.json --locale ko
|
|
41210
|
+
|
|
41211
|
+
--data takes inline JSON or @file. After creating, run \`neopress entries publish <entryId>\` to publish it.`
|
|
41212
|
+
).action(async (options) => {
|
|
41015
41213
|
const client = await getClientAsync();
|
|
41016
41214
|
let data;
|
|
41017
41215
|
if (options.data?.startsWith("@")) {
|
|
@@ -41030,7 +41228,12 @@ function registerEntryCommands(program3) {
|
|
|
41030
41228
|
await client.entries.revalidateReaderCache(entry.id);
|
|
41031
41229
|
output(entry);
|
|
41032
41230
|
});
|
|
41033
|
-
entries.command("update <entryId>").description("Update an entry").
|
|
41231
|
+
entries.command("update <entryId>").description("Update an entry").addHelpText("after", `
|
|
41232
|
+
Examples:
|
|
41233
|
+
$ neopress entries update <entryId> --title "New title"
|
|
41234
|
+
$ neopress entries update <entryId> --data @entry.json --locale ko
|
|
41235
|
+
|
|
41236
|
+
--data takes inline JSON or @file and replaces the entry data. At least one field is required. Updating revalidates the reader cache; publish state is unchanged.`).option("--data <json>", "Entry data as JSON string or @file path").option("--title <title>", "Entry title").option("--slug <slug>", "Entry slug").option("--locale <locale>", "Entry locale").action(async (entryId, options) => {
|
|
41034
41237
|
const client = await getClientAsync();
|
|
41035
41238
|
const updateData = {};
|
|
41036
41239
|
if (options.data) {
|
|
@@ -41071,7 +41274,12 @@ function parseJsonInput3(input) {
|
|
|
41071
41274
|
return input.startsWith("@") ? JSON.parse((0, import_node_fs6.readFileSync)(input.slice(1), "utf-8")) : JSON.parse(input);
|
|
41072
41275
|
}
|
|
41073
41276
|
function registerFormCommands(program3) {
|
|
41074
|
-
const forms = program3.command("forms").description("Manage forms")
|
|
41277
|
+
const forms = program3.command("forms").description("Manage forms").addHelpText("after", `
|
|
41278
|
+
Examples:
|
|
41279
|
+
$ neopress forms create --name Contact --schema @schema.json --layout @layout.json
|
|
41280
|
+
$ neopress forms publish <formId>
|
|
41281
|
+
$ neopress forms responses <formId> --limit 50
|
|
41282
|
+
Forms are created as drafts \u2014 run \`neopress forms publish <formId>\` to make them live. JSON options take inline JSON or @file.`);
|
|
41075
41283
|
forms.command("list").description("List forms").action(async () => {
|
|
41076
41284
|
const client = await getClientAsync();
|
|
41077
41285
|
const data = await client.forms.list();
|
|
@@ -41082,7 +41290,12 @@ function registerFormCommands(program3) {
|
|
|
41082
41290
|
const data = await client.forms.get(parseInt(formId, 10));
|
|
41083
41291
|
output(data);
|
|
41084
41292
|
});
|
|
41085
|
-
forms.command("create").description("Create a form").
|
|
41293
|
+
forms.command("create").description("Create a form").addHelpText("after", `
|
|
41294
|
+
Examples:
|
|
41295
|
+
$ neopress forms create --name Contact
|
|
41296
|
+
$ neopress forms create --name Contact --schema @schema.json --layout @layout.json --i18n @i18n.json
|
|
41297
|
+
$ neopress forms create --name Signup --settings '{"redirectUrl":"/thanks"}'
|
|
41298
|
+
Only --name is required. --schema/--layout/--style/--i18n/--settings each take inline JSON or @file and write the draft state. The form is created as a draft \u2014 run \`neopress forms publish\` to make it live.`).requiredOption("--name <name>", "Form name").option("--schema <json>", "Draft form schema JSON string or @file path").option("--layout <json>", "Draft form layout JSON string or @file path").option("--style <json>", "Draft form style JSON string or @file path").option("--i18n <json>", "Draft form i18n JSON string or @file path").option("--settings <json>", "Form settings JSON string or @file path").action(async (options) => {
|
|
41086
41299
|
const client = await getClientAsync();
|
|
41087
41300
|
const data = await client.forms.create({
|
|
41088
41301
|
name: options.name,
|
|
@@ -41094,7 +41307,11 @@ function registerFormCommands(program3) {
|
|
|
41094
41307
|
});
|
|
41095
41308
|
output(data);
|
|
41096
41309
|
});
|
|
41097
|
-
forms.command("update <formId>").description("Update a form").
|
|
41310
|
+
forms.command("update <formId>").description("Update a form").addHelpText("after", `
|
|
41311
|
+
Examples:
|
|
41312
|
+
$ neopress forms update <formId> --name Contact
|
|
41313
|
+
$ neopress forms update <formId> --schema @schema.json --layout @layout.json
|
|
41314
|
+
Only the supplied fields change; pass at least one of --name/--schema/--layout/--style/--i18n/--settings. JSON options take inline JSON or @file and update the draft state \u2014 run \`neopress forms publish\` to push changes live.`).option("--name <name>", "Form name").option("--schema <json>", "Draft form schema JSON string or @file path").option("--layout <json>", "Draft form layout JSON string or @file path").option("--style <json>", "Draft form style JSON string or @file path").option("--i18n <json>", "Draft form i18n JSON string or @file path").option("--settings <json>", "Form settings JSON string or @file path").action(async (formId, options) => {
|
|
41098
41315
|
const client = await getClientAsync();
|
|
41099
41316
|
const data = {};
|
|
41100
41317
|
if (options.name) data.name = options.name;
|
|
@@ -41109,12 +41326,19 @@ function registerFormCommands(program3) {
|
|
|
41109
41326
|
const updated = await client.forms.update(parseInt(formId, 10), data);
|
|
41110
41327
|
output(updated);
|
|
41111
41328
|
});
|
|
41112
|
-
forms.command("publish <formId>").description("Publish a form").
|
|
41329
|
+
forms.command("publish <formId>").description("Publish a form").addHelpText("after", `
|
|
41330
|
+
Examples:
|
|
41331
|
+
$ neopress forms publish <formId>
|
|
41332
|
+
Copies the form's draft state (schema/layout/style/i18n) to its live state. Required after create/update before the form renders publicly.`).action(async (formId) => {
|
|
41113
41333
|
const client = await getClientAsync();
|
|
41114
41334
|
const result = await client.forms.publish(parseInt(formId, 10));
|
|
41115
41335
|
output(result);
|
|
41116
41336
|
});
|
|
41117
|
-
forms.command("responses <formId>").description("List form responses").
|
|
41337
|
+
forms.command("responses <formId>").description("List form responses").addHelpText("after", `
|
|
41338
|
+
Examples:
|
|
41339
|
+
$ neopress forms responses <formId>
|
|
41340
|
+
$ neopress forms responses <formId> --page 2 --limit 50
|
|
41341
|
+
Returns submitted responses newest-first, paginated (--page/--limit, default page 1, limit 20).`).option("--page <n>", "Page number", "1").option("--limit <n>", "Results per page", "20").action(async (formId, options) => {
|
|
41118
41342
|
const client = await getClientAsync();
|
|
41119
41343
|
const res = await client.forms.listResponses(parseInt(formId, 10), {
|
|
41120
41344
|
page: parseInt(options.page, 10),
|
|
@@ -41133,7 +41357,11 @@ function registerFormCommands(program3) {
|
|
|
41133
41357
|
var import_node_fs7 = require("fs");
|
|
41134
41358
|
var import_node_path3 = require("path");
|
|
41135
41359
|
function registerAssetCommands(program3) {
|
|
41136
|
-
const assets = program3.command("assets").description("Manage assets")
|
|
41360
|
+
const assets = program3.command("assets").description("Manage assets").addHelpText("after", `
|
|
41361
|
+
Examples:
|
|
41362
|
+
$ neopress assets upload ./hero.png --folder images
|
|
41363
|
+
$ neopress assets list --limit 50
|
|
41364
|
+
Upload runs presign \u2192 PUT to storage \u2192 register in one step; content type is inferred from the file extension.`);
|
|
41137
41365
|
assets.command("list").description("List assets").option("--page <n>", "Page number", "1").option("--limit <n>", "Results per page", "20").action(async (options) => {
|
|
41138
41366
|
const client = await getClientAsync();
|
|
41139
41367
|
const res = await client.assets.list({
|
|
@@ -41142,7 +41370,11 @@ function registerAssetCommands(program3) {
|
|
|
41142
41370
|
});
|
|
41143
41371
|
output(res);
|
|
41144
41372
|
});
|
|
41145
|
-
assets.command("upload <filePath>").description("Upload a file (presign \u2192 upload \u2192 register)").
|
|
41373
|
+
assets.command("upload <filePath>").description("Upload a file (presign \u2192 upload \u2192 register)").addHelpText("after", `
|
|
41374
|
+
Examples:
|
|
41375
|
+
$ neopress assets upload ./hero.png
|
|
41376
|
+
$ neopress assets upload ./docs/guide.pdf --folder downloads
|
|
41377
|
+
<filePath> is a local file path; its extension sets the content type. --folder is the storage subfolder (defaults to uploads/); omit it and the asset record's folder is left unset. Prints the registered asset and its public URL.`).option("--folder <folder>", "Target folder path").action(async (filePath, options) => {
|
|
41146
41378
|
const client = await getClientAsync();
|
|
41147
41379
|
const fileName = (0, import_node_path3.basename)(filePath);
|
|
41148
41380
|
const stats = (0, import_node_fs7.statSync)(filePath);
|
|
@@ -41188,7 +41420,13 @@ function registerAssetCommands(program3) {
|
|
|
41188
41420
|
|
|
41189
41421
|
// src/commands/publish.ts
|
|
41190
41422
|
function registerPublishCommands(program3) {
|
|
41191
|
-
const publish = program3.command("publish").description("Publish site or preview changes").
|
|
41423
|
+
const publish = program3.command("publish").description("Publish site or preview changes").addHelpText(
|
|
41424
|
+
"after",
|
|
41425
|
+
`
|
|
41426
|
+
Examples:
|
|
41427
|
+
$ neopress publish preview Show what would change
|
|
41428
|
+
$ neopress publish Publish all pending changes live`
|
|
41429
|
+
).action(async () => {
|
|
41192
41430
|
const client = await getClientAsync();
|
|
41193
41431
|
const result = await client.publish.site();
|
|
41194
41432
|
output(result);
|
|
@@ -41203,13 +41441,22 @@ function registerPublishCommands(program3) {
|
|
|
41203
41441
|
|
|
41204
41442
|
// src/commands/redirects.ts
|
|
41205
41443
|
function registerRedirectCommands(program3) {
|
|
41206
|
-
const redirects = program3.command("redirects").description("Manage redirect rules")
|
|
41444
|
+
const redirects = program3.command("redirects").description("Manage redirect rules").addHelpText("after", `
|
|
41445
|
+
Examples:
|
|
41446
|
+
$ neopress redirects create --source /old --dest /about
|
|
41447
|
+
$ neopress redirects create --source /docs --dest /guide --type 308
|
|
41448
|
+
$ neopress redirects list
|
|
41449
|
+
Rules are created enabled. delete <ruleId> removes a rule permanently.`);
|
|
41207
41450
|
redirects.command("list").description("List redirect rules").action(async () => {
|
|
41208
41451
|
const client = await getClientAsync();
|
|
41209
41452
|
const data = await client.redirects.list();
|
|
41210
41453
|
output(data);
|
|
41211
41454
|
});
|
|
41212
|
-
redirects.command("create").description("Create a redirect rule").
|
|
41455
|
+
redirects.command("create").description("Create a redirect rule").addHelpText("after", `
|
|
41456
|
+
Examples:
|
|
41457
|
+
$ neopress redirects create --source /old --dest /about
|
|
41458
|
+
$ neopress redirects create --source /docs --dest /guide --type 308
|
|
41459
|
+
--source and --dest are both required. --type is 307 (temporary, default) or 308 (permanent). The rule is created enabled.`).requiredOption("--source <path>", "Source path").requiredOption("--dest <path>", "Destination path").option("--type <type>", "Redirect type (307/308)", "307").action(async (options) => {
|
|
41213
41460
|
const client = await getClientAsync();
|
|
41214
41461
|
const rule = await client.redirects.create({
|
|
41215
41462
|
source: options.source,
|
|
@@ -41228,13 +41475,22 @@ function registerRedirectCommands(program3) {
|
|
|
41228
41475
|
// src/commands/layout.ts
|
|
41229
41476
|
var import_node_fs8 = require("fs");
|
|
41230
41477
|
function registerLayoutCommands(program3) {
|
|
41231
|
-
const layout = program3.command("layout").description("Manage site layout")
|
|
41478
|
+
const layout = program3.command("layout").description("Manage site layout").addHelpText("after", `
|
|
41479
|
+
Examples:
|
|
41480
|
+
$ neopress layout get
|
|
41481
|
+
$ neopress layout update --tsx ./layout.tsx --global-css ./globals.css
|
|
41482
|
+
$ neopress layout update --not-found-tsx ./not-found.tsx
|
|
41483
|
+
Layout edits land in draft state \u2014 run \`neopress publish\` to make them live.`);
|
|
41232
41484
|
layout.command("get").description("Get current site layout").action(async () => {
|
|
41233
41485
|
const client = await getClientAsync();
|
|
41234
41486
|
const data = await client.site.getLayout();
|
|
41235
41487
|
output(data);
|
|
41236
41488
|
});
|
|
41237
|
-
layout.command("update").description("Update site layout").
|
|
41489
|
+
layout.command("update").description("Update site layout").addHelpText("after", `
|
|
41490
|
+
Examples:
|
|
41491
|
+
$ neopress layout update --tsx ./layout.tsx
|
|
41492
|
+
$ neopress layout update --tsx ./layout.tsx --not-found-tsx ./not-found.tsx --global-css ./globals.css
|
|
41493
|
+
Each flag reads its content from a file path. Pass at least one of --tsx, --not-found-tsx, or --global-css. Updates write to the draft layout only \u2014 run \`neopress publish\` to make them live.`).option("--tsx <file>", "Layout TSX file path").option("--not-found-tsx <file>", "Not-found page TSX file path").option("--global-css <file>", "Global CSS file path").action(async (options) => {
|
|
41238
41494
|
const client = await getClientAsync();
|
|
41239
41495
|
const data = {};
|
|
41240
41496
|
if (options.tsx) data.draftTsx = (0, import_node_fs8.readFileSync)(options.tsx, "utf-8");
|
|
@@ -41250,7 +41506,12 @@ function registerLayoutCommands(program3) {
|
|
|
41250
41506
|
|
|
41251
41507
|
// src/commands/entry-references.ts
|
|
41252
41508
|
function registerEntryReferenceCommands(program3) {
|
|
41253
|
-
const refs = program3.command("entry-references").description("Manage entry reference relations")
|
|
41509
|
+
const refs = program3.command("entry-references").description("Manage entry reference relations").addHelpText("after", `
|
|
41510
|
+
Examples:
|
|
41511
|
+
$ neopress entry-references create --from-entry 12 --to-entry 34 --field author
|
|
41512
|
+
$ neopress entry-references list --from-entry 12
|
|
41513
|
+
$ neopress entry-references delete <referenceId>
|
|
41514
|
+
--field is a reference field key from the source entry's collection schema. delete is a hard delete and removes the relation immediately.`);
|
|
41254
41515
|
refs.command("list").description("List entry references").option("--from-entry <id>", "Filter by source entry ID").option("--to-entry <id>", "Filter by target entry ID").action(async (options) => {
|
|
41255
41516
|
const client = await getClientAsync();
|
|
41256
41517
|
const data = await client.entryReferences.list({
|
|
@@ -41259,7 +41520,11 @@ function registerEntryReferenceCommands(program3) {
|
|
|
41259
41520
|
});
|
|
41260
41521
|
output(data);
|
|
41261
41522
|
});
|
|
41262
|
-
refs.command("create").description("Create an entry reference").
|
|
41523
|
+
refs.command("create").description("Create an entry reference").addHelpText("after", `
|
|
41524
|
+
Examples:
|
|
41525
|
+
$ neopress entry-references create --from-entry 12 --to-entry 34 --field author
|
|
41526
|
+
$ neopress entry-references create --from-entry 100 --to-entry 7 --field relatedPosts
|
|
41527
|
+
All three flags are required. --field is a reference field key defined in the source entry's collection schema; --from-entry and --to-entry must be numeric entry IDs.`).requiredOption("--from-entry <id>", "Source entry ID").requiredOption("--to-entry <id>", "Target entry ID").requiredOption("--field <key>", "Reference field key from the source collection schema").action(async (options) => {
|
|
41263
41528
|
const client = await getClientAsync();
|
|
41264
41529
|
const fromEntryId = parseInt(options.fromEntry, 10);
|
|
41265
41530
|
const toEntryId = parseInt(options.toEntry, 10);
|
|
@@ -41326,9 +41591,19 @@ function parseSearchConsoleDimensions(raw) {
|
|
|
41326
41591
|
return dimensions;
|
|
41327
41592
|
}
|
|
41328
41593
|
function registerAnalyticsCommands(program3) {
|
|
41329
|
-
const analytics = program3.command("analytics").description("Read site analytics and Search Console data")
|
|
41594
|
+
const analytics = program3.command("analytics").description("Read site analytics and Search Console data").addHelpText("after", `
|
|
41595
|
+
Examples:
|
|
41596
|
+
$ neopress analytics summary --date-from 2026-01-01 --date-to 2026-01-31
|
|
41597
|
+
$ neopress analytics pages --date-from 2026-01-01 --date-to 2026-01-31 --limit 20
|
|
41598
|
+
$ neopress analytics search-console --date-from 2026-01-01 --date-to 2026-01-31 --dimensions query,page
|
|
41599
|
+
All analytics commands are read-only. Convenience commands (summary, pages, sources, forms, crawlers, pageviews) share --date-from/--date-to/--timezone/--limit.`);
|
|
41330
41600
|
addDateOptions(
|
|
41331
|
-
analytics.command("query").description("Run an allowed analytics pipe").
|
|
41601
|
+
analytics.command("query").description("Run an allowed analytics pipe").addHelpText("after", `
|
|
41602
|
+
Examples:
|
|
41603
|
+
$ neopress analytics query --pipe get_top_pages --date-from 2026-01-01 --date-to 2026-01-31
|
|
41604
|
+
$ neopress analytics query --pipe get_pageviews --params '{"device":"mobile"}'
|
|
41605
|
+
$ neopress analytics query --pipe get_top_pages --params @params.json --limit 50
|
|
41606
|
+
--pipe is required. --params takes inline JSON or @file and adds extra pipe params; reserved keys (pipe, site, site_id, timezone, token, q) are ignored.`).requiredOption("--pipe <pipe>", "Analytics pipe name")
|
|
41332
41607
|
).action(async (options) => {
|
|
41333
41608
|
const client = await getClientAsync();
|
|
41334
41609
|
const data = await client.analytics.query({
|
|
@@ -41373,7 +41648,12 @@ function registerAnalyticsCommands(program3) {
|
|
|
41373
41648
|
const client = await getClientAsync();
|
|
41374
41649
|
output(await client.analytics.crawlerSummary(readDateOptions(options)));
|
|
41375
41650
|
});
|
|
41376
|
-
analytics.command("search-console").description("Query Google Search Console performance data").
|
|
41651
|
+
analytics.command("search-console").description("Query Google Search Console performance data").addHelpText("after", `
|
|
41652
|
+
Examples:
|
|
41653
|
+
$ neopress analytics search-console --date-from 2026-01-01 --date-to 2026-01-31
|
|
41654
|
+
$ neopress analytics search-console --date-from 2026-01-01 --date-to 2026-01-31 --dimensions query,page --row-limit 50
|
|
41655
|
+
$ neopress analytics search-console --date-from 2026-01-01 --date-to 2026-01-31 --page-filter https://example.com/about
|
|
41656
|
+
--date-from and --date-to are required. --dimensions is a CSV of query,page,country,device (defaults to query).`).requiredOption("--date-from <date>", "Start date in YYYY-MM-DD").requiredOption("--date-to <date>", "End date in YYYY-MM-DD").option("--dimensions <csv>", "CSV dimensions: query,page,country,device", "query").option("--query-filter <query>", "Exact query filter").option("--page-filter <url>", "Exact page URL filter").option("--row-limit <n>", "Maximum rows to return", "100").action(async (options) => {
|
|
41377
41657
|
const client = await getClientAsync();
|
|
41378
41658
|
const data = await client.analytics.searchConsole({
|
|
41379
41659
|
dateFrom: options.dateFrom,
|
|
@@ -41392,7 +41672,12 @@ function collectPreviewImgUrl(value, previous = []) {
|
|
|
41392
41672
|
return previous.concat(value);
|
|
41393
41673
|
}
|
|
41394
41674
|
function registerTemplateCommands(program3) {
|
|
41395
|
-
const templates = program3.command("templates").description("Manage template metadata for the active site")
|
|
41675
|
+
const templates = program3.command("templates").description("Manage template metadata for the active site").addHelpText("after", `
|
|
41676
|
+
Examples:
|
|
41677
|
+
$ neopress templates mark --name "SaaS Landing" --industry saas --reference-url https://example.com --preview-img-url https://cdn.example.com/1.png
|
|
41678
|
+
$ neopress templates list --industry saas --limit 50
|
|
41679
|
+
$ neopress templates delete
|
|
41680
|
+
\`templates mark\` operates on the active site. \`templates delete\` permanently removes the template metadata AND the connected site \u2014 it is destructive and not recoverable.`);
|
|
41396
41681
|
templates.command("list").description("List templates across sites you can access").option("--name-prefix <prefix>", "Filter by template name prefix").option("--industry <industry>", "Filter by industry key").option("--limit <n>", "Max results (default 100, max 500)").action(async (options) => {
|
|
41397
41682
|
const token = process.env.NEOPRESS_ACCESS_TOKEN || await getValidAccessToken() || void 0;
|
|
41398
41683
|
if (!token) {
|
|
@@ -41411,7 +41696,11 @@ function registerTemplateCommands(program3) {
|
|
|
41411
41696
|
const template = await client.templates.get();
|
|
41412
41697
|
output(template);
|
|
41413
41698
|
});
|
|
41414
|
-
templates.command("mark").description("Mark or update the active site as a template").
|
|
41699
|
+
templates.command("mark").description("Mark or update the active site as a template").addHelpText("after", `
|
|
41700
|
+
Examples:
|
|
41701
|
+
$ neopress templates mark --name "SaaS Landing" --industry saas --reference-url https://example.com --preview-img-url https://cdn.example.com/1.png
|
|
41702
|
+
$ neopress templates mark --name Portfolio --industry creative --reference-url https://example.com --preview-img-url https://cdn.example.com/a.png --preview-img-url https://cdn.example.com/b.png --description "Minimal portfolio"
|
|
41703
|
+
--name, --industry, and --reference-url are all required, and at least one --preview-img-url must be given (repeat the flag for multiple images). Upserts the template metadata for the active site and sets the site status to active; running it again updates the existing template.`).requiredOption("--name <name>", "Template display name").option("--description <description>", "Template description, up to 150 characters").requiredOption("--industry <industry>", "Template industry key").requiredOption(
|
|
41415
41704
|
"--reference-url <url>",
|
|
41416
41705
|
"Reference URL for template provenance"
|
|
41417
41706
|
).option(
|
|
@@ -41437,9 +41726,226 @@ function registerTemplateCommands(program3) {
|
|
|
41437
41726
|
});
|
|
41438
41727
|
}
|
|
41439
41728
|
|
|
41729
|
+
// src/commands/headshots.ts
|
|
41730
|
+
var AGE_BANDS = ["young", "middle"];
|
|
41731
|
+
var GENDERS = ["male", "female"];
|
|
41732
|
+
var ETHNICITIES = ["asian", "white", "black", "latino"];
|
|
41733
|
+
var ATTIRES = ["formal"];
|
|
41734
|
+
function validateEnum(value, allowed, flag) {
|
|
41735
|
+
if (value !== void 0 && !allowed.includes(value)) {
|
|
41736
|
+
fail(`${flag} must be one of: ${allowed.join(", ")}`);
|
|
41737
|
+
}
|
|
41738
|
+
}
|
|
41739
|
+
function parseNonNegativeInt(raw, flag) {
|
|
41740
|
+
if (raw === void 0) return void 0;
|
|
41741
|
+
const value = Number(raw);
|
|
41742
|
+
if (!Number.isInteger(value) || value < 0) {
|
|
41743
|
+
fail(`${flag} must be a non-negative integer`);
|
|
41744
|
+
}
|
|
41745
|
+
return value;
|
|
41746
|
+
}
|
|
41747
|
+
function registerHeadshotCommands(program3) {
|
|
41748
|
+
const headshots = program3.command("headshots").description("Manage the shared headshot pool (super-admin only)").addHelpText("after", `
|
|
41749
|
+
Examples:
|
|
41750
|
+
$ neopress headshots list --gender female --ethnicity asian
|
|
41751
|
+
$ neopress headshots create --image-url https://cdn/x.webp --age-band young --gender male --ethnicity white --variation-index 0
|
|
41752
|
+
$ neopress headshots update 12 --inactive
|
|
41753
|
+
The pool is global and RLS-gated: only the super-admin account can read or write it. No active site is needed.`);
|
|
41754
|
+
headshots.command("list").description("List headshot pool entries").option("--age-band <band>", `Filter by age band (${AGE_BANDS.join("/")})`).option("--gender <gender>", `Filter by gender (${GENDERS.join("/")})`).option("--ethnicity <ethnicity>", `Filter by ethnicity (${ETHNICITIES.join("/")})`).option("--attire <attire>", `Filter by attire (${ATTIRES.join("/")})`).option("--active", "Only active entries").option("--inactive", "Only inactive entries").option("--page <n>", "Page number", "1").option("--limit <n>", "Results per page", "20").addHelpText("after", `
|
|
41755
|
+
Examples:
|
|
41756
|
+
$ neopress headshots list
|
|
41757
|
+
$ neopress headshots list --gender female --age-band middle --active
|
|
41758
|
+
Filters are equality matches on the pool's demographic columns; results are paginated.`).action(async (options) => {
|
|
41759
|
+
validateEnum(options.ageBand, AGE_BANDS, "--age-band");
|
|
41760
|
+
validateEnum(options.gender, GENDERS, "--gender");
|
|
41761
|
+
validateEnum(options.ethnicity, ETHNICITIES, "--ethnicity");
|
|
41762
|
+
validateEnum(options.attire, ATTIRES, "--attire");
|
|
41763
|
+
if (options.active && options.inactive) {
|
|
41764
|
+
fail("Use only one of --active or --inactive.");
|
|
41765
|
+
}
|
|
41766
|
+
const params = {
|
|
41767
|
+
page: parseInt(options.page, 10),
|
|
41768
|
+
limit: parseInt(options.limit, 10),
|
|
41769
|
+
ageBand: options.ageBand,
|
|
41770
|
+
gender: options.gender,
|
|
41771
|
+
ethnicity: options.ethnicity,
|
|
41772
|
+
attire: options.attire
|
|
41773
|
+
};
|
|
41774
|
+
if (options.active) params.isActive = true;
|
|
41775
|
+
else if (options.inactive) params.isActive = false;
|
|
41776
|
+
const client = await getGlobalClientAsync();
|
|
41777
|
+
const res = await client.headshots.list(params);
|
|
41778
|
+
output(res);
|
|
41779
|
+
});
|
|
41780
|
+
headshots.command("get <id>").description("Get a headshot pool entry").action(async (id) => {
|
|
41781
|
+
const client = await getGlobalClientAsync();
|
|
41782
|
+
const data = await client.headshots.get(parseInt(id, 10));
|
|
41783
|
+
output(data);
|
|
41784
|
+
});
|
|
41785
|
+
headshots.command("create").description("Add a headshot to the pool").requiredOption("--image-url <url>", "Public image URL").requiredOption("--age-band <band>", `Age band (${AGE_BANDS.join("/")})`).requiredOption("--gender <gender>", `Gender (${GENDERS.join("/")})`).requiredOption("--ethnicity <ethnicity>", `Ethnicity (${ETHNICITIES.join("/")})`).requiredOption("--variation-index <n>", "Variation index within the demographic cell (>= 0)").option("--attire <attire>", `Attire (${ATTIRES.join("/")}; default formal)`).option("--width <n>", "Image width in px").option("--height <n>", "Image height in px").option("--aspect-ratio <ratio>", "Aspect ratio, e.g. 2:3").option("--mime-type <type>", "MIME type, e.g. image/webp").option("--byte-size <n>", "File size in bytes").option("--gpt-prompt <prompt>", "Generation prompt (for provenance)").option("--tags <csv>", "Comma-separated tags").option("--inactive", "Create as inactive (default active)").addHelpText("after", `
|
|
41786
|
+
Examples:
|
|
41787
|
+
$ neopress headshots create --image-url https://cdn/a.webp --age-band young --gender female --ethnicity asian --variation-index 0
|
|
41788
|
+
$ neopress headshots create --image-url https://cdn/b.webp --age-band middle --gender male --ethnicity black --variation-index 1 --tags suit,studio
|
|
41789
|
+
(age-band, gender, ethnicity, attire, variation-index) must be unique. The DB rejects out-of-range enum values.`).action(async (options) => {
|
|
41790
|
+
validateEnum(options.ageBand, AGE_BANDS, "--age-band");
|
|
41791
|
+
validateEnum(options.gender, GENDERS, "--gender");
|
|
41792
|
+
validateEnum(options.ethnicity, ETHNICITIES, "--ethnicity");
|
|
41793
|
+
validateEnum(options.attire, ATTIRES, "--attire");
|
|
41794
|
+
const variationIndex = parseNonNegativeInt(options.variationIndex, "--variation-index");
|
|
41795
|
+
const params = {
|
|
41796
|
+
imageUrl: options.imageUrl,
|
|
41797
|
+
ageBand: options.ageBand,
|
|
41798
|
+
gender: options.gender,
|
|
41799
|
+
ethnicity: options.ethnicity,
|
|
41800
|
+
variationIndex
|
|
41801
|
+
};
|
|
41802
|
+
if (options.attire) params.attire = options.attire;
|
|
41803
|
+
const width = parseNonNegativeInt(options.width, "--width");
|
|
41804
|
+
if (width !== void 0) params.width = width;
|
|
41805
|
+
const height = parseNonNegativeInt(options.height, "--height");
|
|
41806
|
+
if (height !== void 0) params.height = height;
|
|
41807
|
+
if (options.aspectRatio) params.aspectRatio = options.aspectRatio;
|
|
41808
|
+
if (options.mimeType) params.mimeType = options.mimeType;
|
|
41809
|
+
const byteSize = parseNonNegativeInt(options.byteSize, "--byte-size");
|
|
41810
|
+
if (byteSize !== void 0) params.byteSize = byteSize;
|
|
41811
|
+
if (options.gptPrompt) params.gptPrompt = options.gptPrompt;
|
|
41812
|
+
if (options.tags) params.tags = String(options.tags).split(",").map((t) => t.trim()).filter(Boolean);
|
|
41813
|
+
if (options.inactive) params.isActive = false;
|
|
41814
|
+
const client = await getGlobalClientAsync();
|
|
41815
|
+
const data = await client.headshots.create(params);
|
|
41816
|
+
output(data);
|
|
41817
|
+
});
|
|
41818
|
+
headshots.command("update <id>").description("Update a headshot pool entry").option("--image-url <url>", "Public image URL").option("--age-band <band>", `Age band (${AGE_BANDS.join("/")})`).option("--gender <gender>", `Gender (${GENDERS.join("/")})`).option("--ethnicity <ethnicity>", `Ethnicity (${ETHNICITIES.join("/")})`).option("--attire <attire>", `Attire (${ATTIRES.join("/")})`).option("--variation-index <n>", "Variation index (>= 0)").option("--width <n>", "Image width in px").option("--height <n>", "Image height in px").option("--aspect-ratio <ratio>", "Aspect ratio, e.g. 2:3").option("--mime-type <type>", "MIME type, e.g. image/webp").option("--byte-size <n>", "File size in bytes").option("--gpt-prompt <prompt>", "Generation prompt").option("--tags <csv>", "Comma-separated tags (replaces existing)").option("--active", "Mark active").option("--inactive", "Mark inactive").addHelpText("after", `
|
|
41819
|
+
Examples:
|
|
41820
|
+
$ neopress headshots update 12 --inactive
|
|
41821
|
+
$ neopress headshots update 12 --image-url https://cdn/new.webp --tags suit,studio
|
|
41822
|
+
Pass at least one field. --active/--inactive toggle is_active; --tags replaces the tag list.`).action(async (id, options) => {
|
|
41823
|
+
validateEnum(options.ageBand, AGE_BANDS, "--age-band");
|
|
41824
|
+
validateEnum(options.gender, GENDERS, "--gender");
|
|
41825
|
+
validateEnum(options.ethnicity, ETHNICITIES, "--ethnicity");
|
|
41826
|
+
validateEnum(options.attire, ATTIRES, "--attire");
|
|
41827
|
+
if (options.active && options.inactive) {
|
|
41828
|
+
fail("Use only one of --active or --inactive.");
|
|
41829
|
+
}
|
|
41830
|
+
const params = {};
|
|
41831
|
+
if (options.imageUrl) params.imageUrl = options.imageUrl;
|
|
41832
|
+
if (options.ageBand) params.ageBand = options.ageBand;
|
|
41833
|
+
if (options.gender) params.gender = options.gender;
|
|
41834
|
+
if (options.ethnicity) params.ethnicity = options.ethnicity;
|
|
41835
|
+
if (options.attire) params.attire = options.attire;
|
|
41836
|
+
const variationIndex = parseNonNegativeInt(options.variationIndex, "--variation-index");
|
|
41837
|
+
if (variationIndex !== void 0) params.variationIndex = variationIndex;
|
|
41838
|
+
const width = parseNonNegativeInt(options.width, "--width");
|
|
41839
|
+
if (width !== void 0) params.width = width;
|
|
41840
|
+
const height = parseNonNegativeInt(options.height, "--height");
|
|
41841
|
+
if (height !== void 0) params.height = height;
|
|
41842
|
+
if (options.aspectRatio) params.aspectRatio = options.aspectRatio;
|
|
41843
|
+
if (options.mimeType) params.mimeType = options.mimeType;
|
|
41844
|
+
const byteSize = parseNonNegativeInt(options.byteSize, "--byte-size");
|
|
41845
|
+
if (byteSize !== void 0) params.byteSize = byteSize;
|
|
41846
|
+
if (options.gptPrompt) params.gptPrompt = options.gptPrompt;
|
|
41847
|
+
if (options.tags) params.tags = String(options.tags).split(",").map((t) => t.trim()).filter(Boolean);
|
|
41848
|
+
if (options.active) params.isActive = true;
|
|
41849
|
+
else if (options.inactive) params.isActive = false;
|
|
41850
|
+
if (Object.keys(params).length === 0) {
|
|
41851
|
+
fail("No fields to update.");
|
|
41852
|
+
}
|
|
41853
|
+
const client = await getGlobalClientAsync();
|
|
41854
|
+
const data = await client.headshots.update(parseInt(id, 10), params);
|
|
41855
|
+
output(data);
|
|
41856
|
+
});
|
|
41857
|
+
headshots.command("delete <id>").description("Delete a headshot pool entry (hard delete)").action(async (id) => {
|
|
41858
|
+
const client = await getGlobalClientAsync();
|
|
41859
|
+
await client.headshots.delete(parseInt(id, 10));
|
|
41860
|
+
ok(`Headshot ${id} deleted`);
|
|
41861
|
+
});
|
|
41862
|
+
}
|
|
41863
|
+
|
|
41864
|
+
// src/commands/guide.ts
|
|
41865
|
+
function describeOption(opt) {
|
|
41866
|
+
const info = { flags: opt.flags, description: opt.description || "" };
|
|
41867
|
+
if (opt.defaultValue !== void 0) info.default = opt.defaultValue;
|
|
41868
|
+
return info;
|
|
41869
|
+
}
|
|
41870
|
+
function describeArgument(arg) {
|
|
41871
|
+
return {
|
|
41872
|
+
name: arg.name(),
|
|
41873
|
+
required: arg.required,
|
|
41874
|
+
variadic: arg.variadic,
|
|
41875
|
+
description: arg.description || ""
|
|
41876
|
+
};
|
|
41877
|
+
}
|
|
41878
|
+
function describeCommand(cmd, prefix) {
|
|
41879
|
+
const path = `${prefix} ${cmd.name()}`;
|
|
41880
|
+
return {
|
|
41881
|
+
path,
|
|
41882
|
+
aliases: cmd.aliases(),
|
|
41883
|
+
description: cmd.description(),
|
|
41884
|
+
arguments: cmd.registeredArguments.map(describeArgument),
|
|
41885
|
+
options: cmd.options.map(describeOption),
|
|
41886
|
+
subcommands: cmd.commands.filter((c) => c.name() !== "help").map((c) => describeCommand(c, path))
|
|
41887
|
+
};
|
|
41888
|
+
}
|
|
41889
|
+
function buildGuide(program3) {
|
|
41890
|
+
return {
|
|
41891
|
+
name: program3.name(),
|
|
41892
|
+
version: program3.version() ?? "",
|
|
41893
|
+
description: program3.description(),
|
|
41894
|
+
globalOptions: program3.options.map(describeOption),
|
|
41895
|
+
commands: program3.commands.filter((c) => c.name() !== "help").map((c) => describeCommand(c, program3.name()))
|
|
41896
|
+
};
|
|
41897
|
+
}
|
|
41898
|
+
function pad(s, width) {
|
|
41899
|
+
return s.length >= width ? `${s} ` : s + " ".repeat(width - s.length);
|
|
41900
|
+
}
|
|
41901
|
+
function argSignature(args) {
|
|
41902
|
+
return args.map((a) => {
|
|
41903
|
+
const inner = a.variadic ? `${a.name}...` : a.name;
|
|
41904
|
+
return a.required ? `<${inner}>` : `[${inner}]`;
|
|
41905
|
+
}).join(" ");
|
|
41906
|
+
}
|
|
41907
|
+
function printCommandNode(node, lines, depth) {
|
|
41908
|
+
const indent = " ".repeat(depth * 2);
|
|
41909
|
+
const sig = argSignature(node.arguments);
|
|
41910
|
+
const head2 = `${indent}${node.path}${sig ? ` ${sig}` : ""}`;
|
|
41911
|
+
lines.push(`${pad(head2, 46)}${node.description}`);
|
|
41912
|
+
if (node.subcommands.length === 0) {
|
|
41913
|
+
for (const o of node.options) {
|
|
41914
|
+
const def = o.default !== void 0 ? ` (default: ${JSON.stringify(o.default)})` : "";
|
|
41915
|
+
lines.push(`${pad(`${indent} ${o.flags}`, 46)}${o.description}${def}`);
|
|
41916
|
+
}
|
|
41917
|
+
}
|
|
41918
|
+
for (const sub of node.subcommands) printCommandNode(sub, lines, depth + 1);
|
|
41919
|
+
}
|
|
41920
|
+
function printHuman(guide) {
|
|
41921
|
+
const lines = [];
|
|
41922
|
+
lines.push(`${guide.name} ${guide.version} \u2014 ${guide.description}`);
|
|
41923
|
+
lines.push("");
|
|
41924
|
+
if (guide.globalOptions.length) {
|
|
41925
|
+
lines.push("GLOBAL OPTIONS");
|
|
41926
|
+
for (const o of guide.globalOptions) lines.push(`${pad(` ${o.flags}`, 46)}${o.description}`);
|
|
41927
|
+
lines.push("");
|
|
41928
|
+
}
|
|
41929
|
+
lines.push("COMMANDS");
|
|
41930
|
+
for (const c of guide.commands) printCommandNode(c, lines, 1);
|
|
41931
|
+
lines.push("");
|
|
41932
|
+
lines.push("Run `neopress <command> --help` for details, or `neopress guide --json` for the full surface.");
|
|
41933
|
+
console.log(lines.join("\n"));
|
|
41934
|
+
}
|
|
41935
|
+
function registerGuideCommands(program3) {
|
|
41936
|
+
program3.command("guide").description("Print the full command reference (human tree, or --json for AI tools)").option("--json", "Output the command surface as JSON").action(() => {
|
|
41937
|
+
const guide = buildGuide(program3);
|
|
41938
|
+
if (isJsonMode()) {
|
|
41939
|
+
console.log(JSON.stringify(guide, null, 2));
|
|
41940
|
+
} else {
|
|
41941
|
+
printHuman(guide);
|
|
41942
|
+
}
|
|
41943
|
+
});
|
|
41944
|
+
}
|
|
41945
|
+
|
|
41440
41946
|
// src/bin.ts
|
|
41441
41947
|
var program2 = new Command();
|
|
41442
|
-
program2.name("neopress").description("Neopress CLI \u2014 manage your site from the terminal").version("4.
|
|
41948
|
+
program2.name("neopress").description("Neopress CLI \u2014 manage your site from the terminal").version("4.1.0").option("--json", "Output in JSON format (for AI tools and pipes)").option("--site <idOrHandle>", "Target a specific site (overrides active site; not persisted)").option("--no-input", "Non-interactive mode").hook("preAction", (thisCommand) => {
|
|
41443
41949
|
const opts = thisCommand.optsWithGlobals();
|
|
41444
41950
|
if (opts.site) setSiteOverride(String(opts.site));
|
|
41445
41951
|
if (opts.json || !process.stdout.isTTY) setJsonMode(true);
|
|
@@ -41457,6 +41963,28 @@ registerLayoutCommands(program2);
|
|
|
41457
41963
|
registerEntryReferenceCommands(program2);
|
|
41458
41964
|
registerAnalyticsCommands(program2);
|
|
41459
41965
|
registerTemplateCommands(program2);
|
|
41966
|
+
registerHeadshotCommands(program2);
|
|
41967
|
+
registerGuideCommands(program2);
|
|
41968
|
+
program2.addHelpText(
|
|
41969
|
+
"after",
|
|
41970
|
+
`
|
|
41971
|
+
Quickstart:
|
|
41972
|
+
$ neopress login Authenticate (or set NEOPRESS_ACCESS_TOKEN)
|
|
41973
|
+
$ neopress sites list See sites you can access
|
|
41974
|
+
$ neopress sites use <id|handle> Pick the active site
|
|
41975
|
+
$ neopress pages list List pages on the active site
|
|
41976
|
+
$ neopress guide Full command reference (add --json for AI tools)
|
|
41977
|
+
|
|
41978
|
+
AI / scripting:
|
|
41979
|
+
Output is JSON automatically when piped or redirected; force it with --json.
|
|
41980
|
+
Run \`neopress guide --json\` to get the entire command surface in one call.
|
|
41981
|
+
|
|
41982
|
+
Env vars:
|
|
41983
|
+
NEOPRESS_ACCESS_TOKEN Auth token (skips \`neopress login\`)
|
|
41984
|
+
NEOPRESS_SITE_ID Default site id (overrides the active site)
|
|
41985
|
+
NEOPRESS_BASE_URL API base URL (defaults to the hosted Neopress app)
|
|
41986
|
+
`
|
|
41987
|
+
);
|
|
41460
41988
|
program2.parseAsync(process.argv).catch((err) => {
|
|
41461
41989
|
if (err?.code) {
|
|
41462
41990
|
console.error(JSON.stringify({ ok: false, error: err.message, code: err.code }));
|
package/dist/index.js
CHANGED
|
@@ -21146,6 +21146,27 @@ function serializeTemplate(t) {
|
|
|
21146
21146
|
createdAt: t.created_at
|
|
21147
21147
|
};
|
|
21148
21148
|
}
|
|
21149
|
+
function serializeHeadshot(h) {
|
|
21150
|
+
return {
|
|
21151
|
+
id: h.id,
|
|
21152
|
+
imageUrl: h.image_url,
|
|
21153
|
+
width: h.width,
|
|
21154
|
+
height: h.height,
|
|
21155
|
+
aspectRatio: h.aspect_ratio,
|
|
21156
|
+
mimeType: h.mime_type,
|
|
21157
|
+
byteSize: h.byte_size,
|
|
21158
|
+
ageBand: h.age_band,
|
|
21159
|
+
gender: h.gender,
|
|
21160
|
+
ethnicity: h.ethnicity,
|
|
21161
|
+
attire: h.attire,
|
|
21162
|
+
variationIndex: h.variation_index,
|
|
21163
|
+
gptPrompt: h.gpt_prompt,
|
|
21164
|
+
tags: h.tags ?? [],
|
|
21165
|
+
isActive: h.is_active,
|
|
21166
|
+
createdAt: h.created_at,
|
|
21167
|
+
updatedAt: h.updated_at
|
|
21168
|
+
};
|
|
21169
|
+
}
|
|
21149
21170
|
function serializeSite(site) {
|
|
21150
21171
|
return {
|
|
21151
21172
|
id: site.id,
|
|
@@ -36828,6 +36849,113 @@ var TemplatesEndpoint = class {
|
|
|
36828
36849
|
}
|
|
36829
36850
|
};
|
|
36830
36851
|
|
|
36852
|
+
// ../sdk/dist/endpoints/headshots.js
|
|
36853
|
+
var HeadshotsEndpoint = class {
|
|
36854
|
+
client;
|
|
36855
|
+
constructor(client) {
|
|
36856
|
+
this.client = client;
|
|
36857
|
+
}
|
|
36858
|
+
async list(params) {
|
|
36859
|
+
const { page, limit, offset } = this.client.resolvePagination(params);
|
|
36860
|
+
let query = this.client.db.from("headshot_pool").select("*", { count: "exact" });
|
|
36861
|
+
if (params?.ageBand)
|
|
36862
|
+
query = query.eq("age_band", params.ageBand);
|
|
36863
|
+
if (params?.gender)
|
|
36864
|
+
query = query.eq("gender", params.gender);
|
|
36865
|
+
if (params?.ethnicity)
|
|
36866
|
+
query = query.eq("ethnicity", params.ethnicity);
|
|
36867
|
+
if (params?.attire)
|
|
36868
|
+
query = query.eq("attire", params.attire);
|
|
36869
|
+
if (params?.isActive !== void 0)
|
|
36870
|
+
query = query.eq("is_active", params.isActive);
|
|
36871
|
+
const { data, error: error48, count } = await query.order("age_band", { ascending: true }).order("gender", { ascending: true }).order("ethnicity", { ascending: true }).order("variation_index", { ascending: true }).range(offset, offset + limit - 1);
|
|
36872
|
+
if (error48)
|
|
36873
|
+
throw new NeopressApiError("DB_ERROR", error48.message, 0, error48);
|
|
36874
|
+
return {
|
|
36875
|
+
data: (data ?? []).map((r) => serializeHeadshot(r)),
|
|
36876
|
+
pagination: this.client.paginationMeta(page, limit, offset, count ?? 0)
|
|
36877
|
+
};
|
|
36878
|
+
}
|
|
36879
|
+
async get(id) {
|
|
36880
|
+
const { data, error: error48 } = await this.client.db.from("headshot_pool").select("*").eq("id", id).single();
|
|
36881
|
+
if (error48)
|
|
36882
|
+
throw new NeopressApiError("DB_ERROR", error48.message, 0, error48);
|
|
36883
|
+
return serializeHeadshot(data);
|
|
36884
|
+
}
|
|
36885
|
+
async create(params) {
|
|
36886
|
+
const values = {
|
|
36887
|
+
image_url: params.imageUrl,
|
|
36888
|
+
age_band: params.ageBand,
|
|
36889
|
+
gender: params.gender,
|
|
36890
|
+
ethnicity: params.ethnicity,
|
|
36891
|
+
variation_index: params.variationIndex
|
|
36892
|
+
};
|
|
36893
|
+
if (params.attire !== void 0)
|
|
36894
|
+
values.attire = params.attire;
|
|
36895
|
+
if (params.width !== void 0)
|
|
36896
|
+
values.width = params.width;
|
|
36897
|
+
if (params.height !== void 0)
|
|
36898
|
+
values.height = params.height;
|
|
36899
|
+
if (params.aspectRatio !== void 0)
|
|
36900
|
+
values.aspect_ratio = params.aspectRatio;
|
|
36901
|
+
if (params.mimeType !== void 0)
|
|
36902
|
+
values.mime_type = params.mimeType;
|
|
36903
|
+
if (params.byteSize !== void 0)
|
|
36904
|
+
values.byte_size = params.byteSize;
|
|
36905
|
+
if (params.gptPrompt !== void 0)
|
|
36906
|
+
values.gpt_prompt = params.gptPrompt;
|
|
36907
|
+
if (params.tags !== void 0)
|
|
36908
|
+
values.tags = params.tags;
|
|
36909
|
+
if (params.isActive !== void 0)
|
|
36910
|
+
values.is_active = params.isActive;
|
|
36911
|
+
const { data, error: error48 } = await this.client.db.from("headshot_pool").insert(values).select().single();
|
|
36912
|
+
if (error48)
|
|
36913
|
+
throw new NeopressApiError("DB_ERROR", error48.message, 0, error48);
|
|
36914
|
+
return serializeHeadshot(data);
|
|
36915
|
+
}
|
|
36916
|
+
async update(id, params) {
|
|
36917
|
+
const values = {};
|
|
36918
|
+
if (params.imageUrl !== void 0)
|
|
36919
|
+
values.image_url = params.imageUrl;
|
|
36920
|
+
if (params.ageBand !== void 0)
|
|
36921
|
+
values.age_band = params.ageBand;
|
|
36922
|
+
if (params.gender !== void 0)
|
|
36923
|
+
values.gender = params.gender;
|
|
36924
|
+
if (params.ethnicity !== void 0)
|
|
36925
|
+
values.ethnicity = params.ethnicity;
|
|
36926
|
+
if (params.attire !== void 0)
|
|
36927
|
+
values.attire = params.attire;
|
|
36928
|
+
if (params.variationIndex !== void 0)
|
|
36929
|
+
values.variation_index = params.variationIndex;
|
|
36930
|
+
if (params.width !== void 0)
|
|
36931
|
+
values.width = params.width;
|
|
36932
|
+
if (params.height !== void 0)
|
|
36933
|
+
values.height = params.height;
|
|
36934
|
+
if (params.aspectRatio !== void 0)
|
|
36935
|
+
values.aspect_ratio = params.aspectRatio;
|
|
36936
|
+
if (params.mimeType !== void 0)
|
|
36937
|
+
values.mime_type = params.mimeType;
|
|
36938
|
+
if (params.byteSize !== void 0)
|
|
36939
|
+
values.byte_size = params.byteSize;
|
|
36940
|
+
if (params.gptPrompt !== void 0)
|
|
36941
|
+
values.gpt_prompt = params.gptPrompt;
|
|
36942
|
+
if (params.tags !== void 0)
|
|
36943
|
+
values.tags = params.tags;
|
|
36944
|
+
if (params.isActive !== void 0)
|
|
36945
|
+
values.is_active = params.isActive;
|
|
36946
|
+
const { data, error: error48 } = await this.client.db.from("headshot_pool").update(values).eq("id", id).select().single();
|
|
36947
|
+
if (error48)
|
|
36948
|
+
throw new NeopressApiError("DB_ERROR", error48.message, 0, error48);
|
|
36949
|
+
return serializeHeadshot(data);
|
|
36950
|
+
}
|
|
36951
|
+
async delete(id) {
|
|
36952
|
+
const { error: error48 } = await this.client.db.from("headshot_pool").delete().eq("id", id);
|
|
36953
|
+
if (error48)
|
|
36954
|
+
throw new NeopressApiError("DB_ERROR", error48.message, 0, error48);
|
|
36955
|
+
return { id, deleted: true };
|
|
36956
|
+
}
|
|
36957
|
+
};
|
|
36958
|
+
|
|
36831
36959
|
// ../sdk/dist/client.js
|
|
36832
36960
|
var NeopressClient = class {
|
|
36833
36961
|
baseUrl;
|
|
@@ -36848,6 +36976,7 @@ var NeopressClient = class {
|
|
|
36848
36976
|
entryReferences;
|
|
36849
36977
|
analytics;
|
|
36850
36978
|
templates;
|
|
36979
|
+
headshots;
|
|
36851
36980
|
constructor(options) {
|
|
36852
36981
|
this.baseUrl = (options.baseUrl || "https://app.neopress.ai").replace(/\/$/, "");
|
|
36853
36982
|
this.accessToken = options.accessToken || "";
|
|
@@ -36866,6 +36995,7 @@ var NeopressClient = class {
|
|
|
36866
36995
|
this.entryReferences = new EntryReferencesEndpoint(this);
|
|
36867
36996
|
this.analytics = new AnalyticsEndpoint(this);
|
|
36868
36997
|
this.templates = new TemplatesEndpoint(this);
|
|
36998
|
+
this.headshots = new HeadshotsEndpoint(this);
|
|
36869
36999
|
}
|
|
36870
37000
|
get siteBasePath() {
|
|
36871
37001
|
return `/api/v1/sites/${this.siteId}`;
|
package/package.json
CHANGED
|
@@ -1,15 +1,25 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neopress/cli",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.1.0",
|
|
4
4
|
"description": "Neopress CLI — manage your Neopress site from the terminal",
|
|
5
5
|
"type": "module",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"neopress",
|
|
8
|
+
"cli",
|
|
9
|
+
"cms",
|
|
10
|
+
"headless-cms",
|
|
11
|
+
"website-builder",
|
|
12
|
+
"content-management",
|
|
13
|
+
"ai-agent"
|
|
14
|
+
],
|
|
6
15
|
"bin": {
|
|
7
16
|
"neopress": "./dist/bin.cjs"
|
|
8
17
|
},
|
|
9
18
|
"main": "./dist/index.js",
|
|
10
19
|
"types": "./dist/index.d.ts",
|
|
11
20
|
"files": [
|
|
12
|
-
"dist"
|
|
21
|
+
"dist",
|
|
22
|
+
"README.md"
|
|
13
23
|
],
|
|
14
24
|
"publishConfig": {
|
|
15
25
|
"access": "public"
|