exflower-license-server 1.0.7 → 1.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +33 -34
  2. package/package.json +1 -1
  3. package/routes.js +22 -10
package/README.md CHANGED
@@ -12,7 +12,7 @@ npm install -g exflower-license-server
12
12
 
13
13
  # 查看版本
14
14
  exflower-license-server --version
15
- # 输出: 1.0.2
15
+ # 输出: 1.0.7
16
16
 
17
17
  # 运行
18
18
  exflower-license-server
@@ -145,9 +145,9 @@ sudo systemctl enable --now exflower-license-server
145
145
  启动后访问 `http://localhost:4001/admin`,使用 `ADMIN_TOKEN` 登录。
146
146
 
147
147
  管理后台功能:
148
- - **企业管理**:创建/编辑/禁用/删除公司,设置授权配额
148
+ - **企业管理**:创建公司时可选择有效期(1/3/6 个月、1 年、2 年、永久);列表显示剩余天数(<30 天标黄、过期标红);支持编辑(改有效期/配额)、暂停/恢复、删除
149
149
  - **实例管理**:查看已激活的实例列表
150
- - **模板管理**:上传/编辑/删除模板(agent/crew/excard/workflow),支持按公司分发,查看导入统计(次数/公司/实例)
150
+ - **模板管理**:按类型选择上传方式(见下方"模板系统"),支持按公司分发,查看导入统计(次数/公司/实例)
151
151
 
152
152
  ## API 端点
153
153
 
@@ -177,17 +177,26 @@ sudo systemctl enable --now exflower-license-server
177
177
 
178
178
  ## 模板系统
179
179
 
180
- 模板用于向客户端分发预设配置。管理后台支持创建 `agent`、`crew`、`excard`、`workflow`、`doc` 五种类型的模板。
180
+ 模板用于向客户端分发预设配置。管理后台支持创建 `agent`、`excard`、`workflow`、`doc` 四种类型的模板。
181
+
182
+ ### 上传方式(v1.0.7 起)
183
+
184
+ 管理后台根据类型提供不同的上传方式:
185
+
186
+ - **agent / excard / doc**:**Markdown 原生上传**。直接上传客户端导出的 `.md` 文件(或粘贴 Markdown 文本),后台自动解析 frontmatter 预填模板名称并生成 `content_json`,无需手写 JSON。
187
+ - **workflow**:仍以 JSON 描述步骤结构(步骤间的 excardId 引用和分支跳转无法由 Markdown 表达),上传框预填骨架示例。
188
+
189
+ 通过 API 创建模板时,`content_json` 与 `content_md` 至少提供一个(`workflow` 类型必须提供 `content_json`)。
181
190
 
182
191
  ### 通用字段
183
192
 
184
193
  | 字段 | 必填 | 说明 |
185
194
  |------|------|------|
186
- | `type` | 是 | 模板类型:`agent` / `crew` / `excard` / `workflow` / `doc` |
195
+ | `type` | 是 | 模板类型:`agent` / `excard` / `workflow` / `doc` |
187
196
  | `name` | 是 | 模板名称 |
188
197
  | `description` | 否 | 模板简介(一句话描述) |
189
- | `content_json` | | 结构化数据(JSON 对象),各类型字段见下方 |
190
- | `content_md` | | Markdown 格式说明文档,部分类型必须 |
198
+ | `content_json` | 视类型 | 结构化数据(JSON 对象);`workflow` 必填,其余类型可由 `content_md` 代替 |
199
+ | `content_md` | 视类型 | Markdown 内容;`agent` / `excard` / `doc` 推荐以此为主 |
191
200
  | `company_id` | 否 | `NULL` = 全局模板(所有公司可见);指定公司 ID = 仅该公司可见 |
192
201
  | `tags` | 否 | 标签数组 JSON,如 `["营销", "运营"]` |
193
202
  | `version` | 否 | 版本号,默认 `1.0` |
@@ -196,9 +205,9 @@ sudo systemctl enable --now exflower-license-server
196
205
 
197
206
  #### `agent` — Agent 成员模板
198
207
 
199
- 用于创建 CrewAI Agent
208
+ 用于创建 CrewAI Agent。**推荐直接上传客户端 agent 的 `.md` 文件**(YAML frontmatter + Backstory/Experience 正文),frontmatter 字段即 `content_json`。
200
209
 
201
- **content_json 字段:**
210
+ **frontmatter / content_json 字段:**
202
211
 
203
212
  | 字段 | 必填 | 类型 | 说明 |
204
213
  |------|------|------|------|
@@ -217,6 +226,18 @@ sudo systemctl enable --now exflower-license-server
217
226
  **content_md 格式(推荐提供):**
218
227
 
219
228
  ```markdown
229
+ ---
230
+ id: agent-xxx
231
+ name: 小红书运营专家
232
+ role: 小红书内容运营与增长策略师
233
+ goal: 帮助用户制定并执行高效的小红书内容策略
234
+ tools: []
235
+ allowDelegation: false
236
+ maxIter: 25
237
+ memory: true
238
+ allowScriptExecution: disabled
239
+ ---
240
+
220
241
  # Backstory
221
242
 
222
243
  Agent 的完整背景故事,支持 Markdown 格式...
@@ -231,33 +252,11 @@ Agent 的完整背景故事,支持 Markdown 格式...
231
252
 
232
253
  ---
233
254
 
234
- #### `crew` — 项目组模板
235
-
236
- 用于创建 Crew(Agent 团队)。
237
-
238
- **content_json 字段:**
239
-
240
- | 字段 | 必填 | 类型 | 说明 |
241
- |------|------|------|------|
242
- | `name` | 是 | string | 项目组名称 |
243
- | `description` | 否 | string | 项目组描述 |
244
- | `agentIds` | 否 | string[] | 成员 Agent ID 列表 |
245
- | `tasks` | 否 | object[] | 任务列表,每个任务包含: |
246
- | `tasks[].id` | 是 | string | 任务 ID |
247
- | `tasks[].agentId` | 是 | string | 执行任务的 Agent ID |
248
- | `tasks[].description` | 是 | string | 任务描述 |
249
- | `tasks[].order` | 否 | number | 执行顺序 |
250
- | `tasks[].expectedOutput` | 否 | string | 期望输出 |
251
- | `process` | 否 | string | 执行流程:`sequential`(顺序)/ `hierarchical`(层级),默认 `sequential` |
252
- | `managerAgentId` | 否 | string | Manager Agent ID(层级流程时必填) |
253
-
254
- ---
255
-
256
255
  #### `excard` — ExCard 执行模板
257
256
 
258
- 用于创建工作流执行的 ExCard 模板。
257
+ 用于创建工作流执行的 ExCard 模板。**推荐直接上传客户端导出的标准 ExCard `.md` 文件**(与客户端"导出 ExCard"产物格式一致):模板只需存 `content_md`,客户端导入时走标准 MD 导入链路(`POST /api/excards/import`),由客户端解析为结构化数据。frontmatter 会被后台自动提取为 `content_json` 用于列表展示。
259
258
 
260
- **content_json 字段:**
259
+ **frontmatter / content_json 字段:**
261
260
 
262
261
  | 字段 | 必填 | 类型 | 说明 |
263
262
  |------|------|------|------|
@@ -271,7 +270,7 @@ Agent 的完整背景故事,支持 Markdown 格式...
271
270
 
272
271
  **content_md 格式(必须提供):**
273
272
 
274
- ExCard 的完整 Markdown 文档,包含执行约定、资源依赖、工作流步骤等。
273
+ ExCard 的完整 Markdown 文档(frontmatter + 资源依赖 + 执行步骤 + 执行约定),与客户端 `~/.exflower/excards-md/` 下的文件格式一致。
275
274
 
276
275
  ---
277
276
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "exflower-license-server",
3
- "version": "1.0.7",
3
+ "version": "1.0.8",
4
4
  "description": "ExFlower License Server - 在线授权验证服务",
5
5
  "main": "index.js",
6
6
  "bin": {
package/routes.js CHANGED
@@ -267,11 +267,18 @@ function setupRoutes(app) {
267
267
  return res.status(404).json({ success: false, message: 'Invalid license key' });
268
268
  }
269
269
 
270
- const rows = queryAll(
271
- `SELECT template_id, COUNT(*) as count, MIN(imported_at) as first_import, MAX(imported_at) as last_import
272
- FROM template_imports WHERE company_id = ? GROUP BY template_id`,
273
- [company.id]
274
- );
270
+ // 按设备过滤:导入状态跟着设备(instance_id)走,而非激活码;
271
+ // 未传 instance_id 的旧版客户端保持 company 级聚合(向后兼容)
272
+ const instanceId = req.query.instance_id;
273
+ let sql = `SELECT template_id, COUNT(*) as count, MIN(imported_at) as first_import, MAX(imported_at) as last_import
274
+ FROM template_imports WHERE company_id = ?`;
275
+ const params = [company.id];
276
+ if (instanceId) {
277
+ sql += ' AND instance_id = ?';
278
+ params.push(instanceId);
279
+ }
280
+ sql += ' GROUP BY template_id';
281
+ const rows = queryAll(sql, params);
275
282
  const map = {};
276
283
  for (const r of rows) {
277
284
  map[r.template_id] = { count: r.count, first_import: r.first_import, last_import: r.last_import };
@@ -511,11 +518,16 @@ function setupRoutes(app) {
511
518
  return res.status(404).json({ success: false, message: 'Invalid license key' });
512
519
  }
513
520
 
514
- const stats = queryGet(
515
- `SELECT COUNT(*) as count, MIN(imported_at) as first_import, MAX(imported_at) as last_import
516
- FROM template_imports WHERE template_id = ? AND company_id = ?`,
517
- [req.params.id, company.id]
518
- );
521
+ // 按设备过滤(见 import-summary 注释)
522
+ const instanceId = req.query.instance_id;
523
+ let sql = `SELECT COUNT(*) as count, MIN(imported_at) as first_import, MAX(imported_at) as last_import
524
+ FROM template_imports WHERE template_id = ? AND company_id = ?`;
525
+ const params = [req.params.id, company.id];
526
+ if (instanceId) {
527
+ sql += ' AND instance_id = ?';
528
+ params.push(instanceId);
529
+ }
530
+ const stats = queryGet(sql, params);
519
531
  res.json({ success: true, imported: stats.count > 0, count: stats.count, first_import: stats.first_import, last_import: stats.last_import });
520
532
  });
521
533