fedincms-cli 0.0.1 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -23,13 +23,13 @@ npm install -g @your-scope/fedin-cms-cli
23
23
  cd /path/to/your-project
24
24
  ```
25
25
 
26
- 2. 初始化并配置站点 ID(必填)与可选 API 地址、密钥:
26
+ 2. 初始化:只需传入**站点密钥**(格式 `cms_<base64>`),会解密得到 websiteId 与 userId 并写入脚本:
27
27
  ```bash
28
- fedincms init website=你的站点ID
29
- # 或带可选参数
30
- fedincms init website=你的站点ID apiUrl=https://... anonKey=你的密钥
31
- # 或长选项
32
- fedincms init --website=你的站点ID --api-url=https://... --anon-key=你的密钥
28
+ fedincms init cms_website_key=你的站点密钥
29
+ # 或带可选 API 地址、密钥
30
+ fedincms init cms_website_key=你的站点密钥 apiUrl=https://... anonKey=你的密钥
31
+ # 长选项
32
+ fedincms init --cms-website-key=你的站点密钥 --api-url=... --anon-key=...
33
33
  ```
34
34
 
35
35
  3. 在 Cursor 中打开该项目,AI 将根据 `.cursor/skills/fedin-cms/SKILL.md` 在需要时执行:
package/dist/cli.js CHANGED
@@ -8,6 +8,27 @@ const TEMPLATE_DIR = path.join(__dirname, '..', 'templates', 'skill');
8
8
  const SKILL_DIR = '.cursor/skills/fedin-cms';
9
9
  const SKILL_SCRIPTS_DIR = '.cursor/skills/fedin-cms/scripts';
10
10
 
11
+ /**
12
+ * 解密站点密钥,得到 websiteId 和 userId
13
+ * @param {string} key - 格式为 cms_<base64url>
14
+ * @returns {{ websiteId: string, userId: string }}
15
+ */
16
+ function decodeWebsiteKey(key) {
17
+ const PREFIX = 'cms_';
18
+ if (!key || typeof key !== 'string' || !key.startsWith(PREFIX)) {
19
+ throw new Error('Invalid website key format');
20
+ }
21
+ const base64 = key.slice(PREFIX.length).replace(/-/g, '+').replace(/_/g, '/');
22
+ const pad = base64.length % 4;
23
+ const padded = pad ? base64 + '='.repeat(4 - pad) : base64;
24
+ const json = Buffer.from(padded, 'base64').toString('utf8');
25
+ const out = JSON.parse(json);
26
+ if (typeof out?.userId !== 'string' || typeof out?.websiteId !== 'string') {
27
+ throw new Error('Invalid website key payload');
28
+ }
29
+ return { userId: out.userId, websiteId: out.websiteId };
30
+ }
31
+
11
32
  function parseArgs(argv) {
12
33
  const args = { _: [] };
13
34
  for (let i = 0; i < argv.length; i++) {
@@ -25,17 +46,13 @@ function parseArgs(argv) {
25
46
  if (eq > 0) {
26
47
  const k = arg.slice(2, eq).replace(/-/g, '');
27
48
  const v = arg.slice(eq + 1);
28
- if (k === 'website') args.website = v;
29
- else if (k === 'apiurl') args.apiUrl = v;
30
- else if (k === 'anonkey') args.anonKey = v;
49
+ if (k === 'cmswebsitekey' || k === 'cms_website_key') args.cmsWebsiteKey = v;
31
50
  }
32
51
  continue;
33
52
  }
34
53
  if (arg.includes('=')) {
35
54
  const [k, v] = arg.split('=').map(s => s.trim());
36
- if (k === 'website') args.website = v;
37
- else if (k === 'apiUrl') args.apiUrl = v;
38
- else if (k === 'anonKey') args.anonKey = v;
55
+ if (k === 'cms_website_key' || k === 'cmsWebsiteKey') args.cmsWebsiteKey = v;
39
56
  continue;
40
57
  }
41
58
  args._.push(arg);
@@ -57,24 +74,16 @@ function copyFile(src, dest, force) {
57
74
  return true;
58
75
  }
59
76
 
60
- function readOrCreateEnv() {
61
- const envPath = path.join(process.cwd(), '.env');
62
- let content = '';
63
- if (fs.existsSync(envPath)) {
64
- content = fs.readFileSync(envPath, 'utf8');
65
- if (!content.endsWith('\n')) content += '\n';
66
- }
67
- return { envPath, content };
68
- }
69
-
70
- function appendEnv(lines) {
71
- const { envPath, content } = readOrCreateEnv();
72
- const toAdd = lines.filter(line => {
73
- const key = line.split('=')[0].trim();
74
- return !content.includes(key + '=');
75
- });
76
- if (toAdd.length === 0) return;
77
- fs.writeFileSync(envPath, content + '\n# Fedin CMS (fedincms init)\n' + toAdd.join('\n') + '\n', 'utf8');
77
+ // 复制脚本并替换占位符 __FEDINCMS_WEBSITE_ID__、__FEDINCMS_USER_ID__
78
+ function copyScriptWithPlaceholders(srcPath, destRel, placeholders, force) {
79
+ const destFull = path.join(process.cwd(), destRel);
80
+ if (!force && fs.existsSync(destFull)) return false;
81
+ ensureDir(path.dirname(destFull));
82
+ let content = fs.readFileSync(srcPath, 'utf8');
83
+ content = content.replace(/__FEDINCMS_WEBSITE_ID__/g, placeholders.websiteId || '');
84
+ content = content.replace(/__FEDINCMS_USER_ID__/g, placeholders.userId || '');
85
+ fs.writeFileSync(destFull, content, 'utf8');
86
+ return true;
78
87
  }
79
88
 
80
89
  function runInit(options) {
@@ -85,9 +94,20 @@ function runInit(options) {
85
94
  process.exit(1);
86
95
  }
87
96
 
88
- const website = options.website;
89
- if (!website) {
90
- console.error('fedincms init: 缺少必填参数 website。用法: fedincms init website=xxxxx [apiUrl=...] [anonKey=...]');
97
+ const key = options.cmsWebsiteKey;
98
+ if (!key) {
99
+ console.error('fedincms init: 缺少必填参数 cms_website_key。用法: fedincms init cms_website_key=xxxxx [apiUrl=...] [anonKey=...]');
100
+ process.exit(1);
101
+ }
102
+
103
+ let websiteId;
104
+ let userId;
105
+ try {
106
+ const decoded = decodeWebsiteKey(key);
107
+ websiteId = decoded.websiteId;
108
+ userId = decoded.userId;
109
+ } catch (e) {
110
+ console.error('fedincms init: 站点密钥解密失败:', e.message);
91
111
  process.exit(1);
92
112
  }
93
113
 
@@ -102,23 +122,11 @@ function runInit(options) {
102
122
  const scriptJs = path.join(templateBase, 'scripts', 'fedin-cms-cli.js');
103
123
  if (fs.existsSync(skillMd)) copyFile(skillMd, path.join(SKILL_DIR, 'SKILL.md'), options.force);
104
124
  if (fs.existsSync(refMd)) copyFile(refMd, path.join(SKILL_DIR, 'reference.md'), options.force);
105
- if (fs.existsSync(scriptJs)) copyFile(scriptJs, path.join(SKILL_DIR, 'scripts', 'fedin-cms-cli.js'), options.force);
125
+ if (fs.existsSync(scriptJs)) copyScriptWithPlaceholders(scriptJs, path.join(SKILL_DIR, 'scripts', 'fedin-cms-cli.js'), { websiteId, userId }, options.force);
106
126
  }
107
127
 
108
- const defaultContentTypeUrl = 'https://database.fedin.cn/functions/v1/cms_content-type-manager';
109
- const defaultContentUrl = 'https://database.fedin.cn/functions/v1/cms_content-manager';
110
- const envLines = [
111
- `WEBSITE_ID=${website}`,
112
- options.apiUrl ? `SUPABASE_CMS_API_URL=${options.apiUrl}` : `SUPABASE_CMS_API_URL=${defaultContentTypeUrl}`,
113
- `SUPABASE_CONTENT_API_URL=${defaultContentUrl}`,
114
- options.anonKey ? `SUPABASE_ANON_KEY=${options.anonKey}` : 'SUPABASE_ANON_KEY=',
115
- ].filter(Boolean);
116
- appendEnv(envLines);
117
-
118
128
  console.log('Skill 已安装到 .cursor/skills/fedin-cms/');
119
- if (!options.apiUrl || !options.anonKey) {
120
- console.log('如未配置 API 地址或密钥,请在项目根 .env 中设置 SUPABASE_CMS_API_URL、SUPABASE_CONTENT_API_URL、SUPABASE_ANON_KEY。');
121
- }
129
+ console.log('站点 ID 与用户 ID 已从密钥解密并写入脚本。');
122
130
  console.log('脚本为单文件打包,无需在 scripts/ 下安装依赖。');
123
131
  }
124
132
 
@@ -127,28 +135,27 @@ function printHelp() {
127
135
  fedincms init - 将 Fedin CMS Skill 安装到当前项目
128
136
 
129
137
  用法:
130
- fedincms init website=<站点ID> [apiUrl=<API地址>] [anonKey=<密钥>]
131
- fedincms init --website=<站点ID> [--api-url=<API地址>] [--anon-key=<密钥>]
138
+ fedincms init cms_website_key=<站点密钥>
139
+ fedincms init --cms-website-key=<站点密钥>
132
140
 
133
141
  参数:
134
- website 必填。站点 ID,对应环境变量 WEBSITE_ID。
135
- apiUrl 可选。Fedin CMS API 根地址,对应 SUPABASE_CMS_API_URL。
136
- anonKey 可选。API 密钥,对应 SUPABASE_ANON_KEY。
142
+ cms_website_key 必填。站点密钥(格式 cms_<base64>),解密后得到 websiteId 与 userId,并写入脚本占位符。
137
143
 
138
144
  选项:
139
- --force, -f 已存在 .cursor/skills/fedin-cms/ 时覆盖复制。
145
+ --force, -f 已存在 .cursor/skills/fedin-cms/ 时覆盖复制并重新替换占位符。
140
146
  --help, -h 显示此帮助。
141
147
 
142
148
  行为:
143
- - 创建 .cursor/skills/fedin-cms/ 并复制 SKILL.md 与 scripts/fedin-cms-cli.js
144
- - 在项目根写入或追加 .env(WEBSITE_IDSUPABASE_CMS_API_URL、SUPABASE_ANON_KEY)
149
+ - 解密 cms_website_key 得到 websiteId、userId
150
+ - 创建 .cursor/skills/fedin-cms/ 并复制 SKILL.mdreference.md
151
+ - 复制 scripts/fedin-cms-cli.js 并将占位符 __FEDINCMS_WEBSITE_ID__、__FEDINCMS_USER_ID__ 替换为解密后的值
145
152
  `);
146
153
  }
147
154
 
148
155
  function main() {
149
156
  const argv = process.argv.slice(2);
150
157
  if (argv.length === 0) {
151
- console.log('用法: fedincms init website=xxxxx [apiUrl=...] [anonKey=...]');
158
+ console.log('用法: fedincms init cms_website_key=xxxxx');
152
159
  console.log('查看帮助: fedincms init --help');
153
160
  process.exit(0);
154
161
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fedincms-cli",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
4
4
  "description": "Fedin CMS Skill CLI",
5
5
  "main": "dist/cli.js",
6
6
  "bin": {
@@ -7,8 +7,8 @@ description: 通过 Fedin CMS 脚本管理内容类型与条目:列出/获取/
7
7
 
8
8
  ## 前提
9
9
 
10
- - 项目已通过 `fedincms init website=xxxxx` 初始化。
11
- - 项目根 `.env` 中已配置 `WEBSITE_ID`;若需调用 API,请配置 `SUPABASE_CMS_API_URL`(内容类型)、`SUPABASE_CONTENT_API_URL`(条目,可选)、`SUPABASE_ANON_KEY`。
10
+ - 项目已通过 `fedincms init cms_website_key=xxxxx` 初始化,站点 ID 与用户 ID 已从密钥解密并写入脚本,无需再从环境变量读取。
11
+ - 若需调用 API,请在项目根 `.env` 中配置 `SUPABASE_CMS_API_URL`、`SUPABASE_CONTENT_API_URL`、`SUPABASE_ANON_KEY`。
12
12
  - 脚本为单文件打包(依赖已内联),**无需**在 `scripts/` 下执行 `npm install`。
13
13
 
14
14
  ## 执行约定
@@ -5,11 +5,11 @@
5
5
 
6
6
  ## 环境
7
7
 
8
- - 脚本从项目根加载 `.env`,与 Fedin CMS MCP 一致:
9
- - `WEBSITE_ID`(必填)
10
- - `SUPABASE_CMS_API_URL`(内容类型 API,默认 `cms_content-type-manager`)
11
- - `SUPABASE_CONTENT_API_URL`(条目 API,默认 `cms_content-manager`,可选,未设时与 MCP 一致使用 content-manager 默认)
12
- - `SUPABASE_ANON_KEY`、`USER_ID`(可选)
8
+ - **站点 ID 与用户 ID**:由 `fedincms init cms_website_key=xxx` 解密密钥后写入脚本,**不从环境变量读取**。
9
+ - 脚本从项目根加载 `.env`,仅用于:
10
+ - `SUPABASE_CMS_API_URL`(内容类型 API
11
+ - `SUPABASE_CONTENT_API_URL`(条目 API
12
+ - `SUPABASE_ANON_KEY`(API 密钥)
13
13
  - 成功时结果 JSON 输出到 stdout;失败时错误信息输出到 stderr 并以非 0 退出码退出。
14
14
 
15
15
  ---
@@ -1,5 +1,4 @@
1
1
  #!/usr/bin/env node
2
- #!/usr/bin/env node
3
2
  "use strict";
4
3
  var __getOwnPropNames = Object.getOwnPropertyNames;
5
4
  var __commonJS = (cb, mod) => function __require() {
@@ -15397,11 +15396,11 @@ var fs = require("fs");
15397
15396
  var dotenv = require_main();
15398
15397
  var axios = require_axios();
15399
15398
  dotenv.config({ path: path.join(process.cwd(), ".env") });
15400
- var WEBSITE_ID = process.env.WEBSITE_ID;
15399
+ var WEBSITE_ID = "__FEDINCMS_WEBSITE_ID__";
15400
+ var USER_ID = "__FEDINCMS_USER_ID__";
15401
15401
  var CONTENT_TYPE_BASE_URL = process.env.SUPABASE_CMS_API_URL || "https://database.fedin.cn/functions/v1/cms_content-type-manager";
15402
15402
  var CONTENT_BASE_URL = process.env.SUPABASE_CONTENT_API_URL || "https://database.fedin.cn/functions/v1/cms_content-manager";
15403
15403
  var ANON_KEY = process.env.SUPABASE_ANON_KEY || "";
15404
- var USER_ID = process.env.USER_ID || "";
15405
15404
  function err(msg) {
15406
15405
  process.stderr.write(msg + "\n");
15407
15406
  process.exit(1);