@limecloud/agent-app-studio 0.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.
@@ -0,0 +1,451 @@
1
+ # Lime Agent App Studio v1 PRD
2
+
3
+ 更新时间:2026-05-18
4
+
5
+ ## 一句话目标
6
+
7
+ Lime Agent App Studio 是面向 Agent App 开发者的发布工作台,提供可视化客户端和 CLI 两种入口,帮助开发者把本地 Agent App 从诊断、构建、打包、上传到云端 Release 的全过程做成可复现、可审计、可回滚的闭环。
8
+
9
+ ## 背景
10
+
11
+ Lime 已经具备 Agent App 应用中心的基本消费形态:用户可以看到应用来源、状态、本地版本、云端版本和更新入口。但开发者侧仍缺少完整发布工具链:
12
+
13
+ - 本地 Agent App 的 `dist/`、`vendor/`、`APP.md`、`app.*.yaml`、`locales/`、`skills/` 是否完整,需要人工检查。
14
+ - 云端 release 需要可信的 `packageUrl`、`packageHash`、`manifestHash` 和 `manifestSummary`,手动填写容易出错。
15
+ - `content-factory-app` 这类真实 App 需要把本地包发布到 LimeCore,再由 Lime Desktop 应用中心发现更新。
16
+ - 现有 LimeCore 已有 Agent App catalog、release、package-upload、tenant enablement、audit 等控制面能力,但缺少开发者友好的编排入口。
17
+ - 发布动作同时需要人机协作体验和自动化能力:人工发布适合可视化工作台,CI/CD 和脚本化发布需要 CLI。
18
+
19
+ 因此 Studio v1 的重点不是重建云端运行时,而是把现有 Agent App 标准、本地构建校验和 LimeCore 控制面串成一个稳定产品。
20
+
21
+ ## 产品目标
22
+
23
+ - 提供一条从本地 App 目录到 LimeCore 云端 release 的标准发布路径。
24
+ - 支持可视化客户端,让开发者能看到诊断结果、版本差异、包内容、发布风险和发布后状态。
25
+ - 支持 CLI,作为可复现发布内核,并发布到 npmjs 供本地终端、CI/CD 和其他工具调用。
26
+ - 支持开发者认证与权限校验,确保只有已认证开发者能看到 Studio App,并且只有有权限的开发者可以发布指定 App。
27
+ - 支持 App 分类、版本、渠道和可见性管理,为应用中心的筛选、更新和治理提供事实源。
28
+ - 复用 LimeCore 现有 `package-upload`、release、catalog、tenant enablement 和 audit,不新增平行发布协议。
29
+
30
+ ## 核心收益
31
+
32
+ | 对象 | 收益 |
33
+ |---|---|
34
+ | Agent App 开发者 | 不再手工拼包、复制 URL、计算 hash;可用可视化步骤和 CLI dry-run 规避发布事故。 |
35
+ | 平台发布人员 | 发布过程可审计,包元数据、版本、渠道和权限统一进入 LimeCore。 |
36
+ | 租户管理员 | 只看到已授权、可安装、可更新的 App,降低错误版本进入企业环境的风险。 |
37
+ | Lime 普通用户 | 应用中心中的“可更新”“需要授权”“本地 + 云端”等状态有可信来源。 |
38
+ | CI/CD | 通过 npm CLI 复用同一发布内核,实现自动化打包、上传和 release 创建。 |
39
+
40
+ ## 产品形态
41
+
42
+ Studio v1 分成两个客户端形态,但共享同一个发布内核。
43
+
44
+ ```text
45
+ Lime Agent App Studio
46
+ ├─ 可视化客户端:人机协作、诊断、预览、发布确认、审计查看
47
+ └─ CLI:脚本化、CI/CD、可复现 dry-run、npmjs 分发
48
+ ```
49
+
50
+ ### 可视化客户端
51
+
52
+ 可视化客户端面向日常开发者和平台发布人员,重点是“看得懂、可确认、可追溯”。首版能力:
53
+
54
+ - 选择本地 Agent App 目录。
55
+ - 识别 `appId`、版本、标准版本、入口、能力声明和本地构建状态。
56
+ - 展示本地版本、云端最新版本、已安装版本和可更新状态。
57
+ - 执行或引导执行 build、validate、readiness 等校验。
58
+ - 展示将进入 `.lapp` / `.zip` 的文件清单、大小、hash 和 manifest summary。
59
+ - 支持 dry-run,输出将调用的云端 API、release payload 和潜在风险。
60
+ - 支持正式发布,完成 package upload 和 release 创建。
61
+ - 支持发布后验证,回读云端 catalog / release 状态。
62
+ - 展示当前开发者权限、App 归属、发布渠道和审计记录。
63
+
64
+ ### CLI
65
+
66
+ CLI 是发布内核和自动化入口,必须可脱离可视化客户端运行。CLI 首版发布到 npmjs:
67
+
68
+ | 项 | 建议 |
69
+ |---|---|
70
+ | npm package | `@limecloud/agent-app-studio` |
71
+ | bin 主命令 | `lime-agent-app-studio` |
72
+ | bin 短命令 | `lime-agent-app` |
73
+ | 分发渠道 | npmjs public package |
74
+ | Node 基线 | Node.js 20+ |
75
+ | 默认行为 | `dry-run` 优先,正式写云端必须显式 `--publish` |
76
+
77
+ CLI 首版命令:
78
+
79
+ ```bash
80
+ lime-agent-app-studio auth login
81
+ lime-agent-app-studio auth status
82
+ lime-agent-app-studio project inspect --app-dir ./content-factory-app
83
+ lime-agent-app-studio package --app-dir ./content-factory-app
84
+ lime-agent-app-studio publish --app-dir ./content-factory-app --app-id content-factory-app --channel stable --dry-run
85
+ lime-agent-app-studio publish --app-dir ./content-factory-app --app-id content-factory-app --channel stable --publish
86
+ ```
87
+
88
+ CLI 约束:
89
+
90
+ - 不内置云端密钥,不写死生产 token。
91
+ - 登录态存放在用户级安全存储或系统标准配置目录,不进入项目仓库。
92
+ - 所有写云端动作默认输出计划和确认信息;正式发布必须显式传入 `--publish`。
93
+ - npm 发布前必须通过 `npm pack --dry-run`、基础命令测试和版本一致性检查。
94
+ - CI/CD 使用 token 时必须通过环境变量或平台 secret 注入,不写入配置文件。
95
+
96
+ ## 目标用户与角色
97
+
98
+ | 角色 | 说明 | 关键动作 |
99
+ |---|---|---|
100
+ | 个人开发者 | 为自己或小团队开发 Agent App | 本地诊断、打包、发布 draft / beta。 |
101
+ | 团队开发者 | 在组织内协作维护 App | 共享 App 权限、提交 release、查看审计。 |
102
+ | App Owner | 对某个 App 有最高开发者权限 | 授权维护者、发布 stable、撤销版本。 |
103
+ | Maintainer | 维护 App 代码和包 | 执行 build、package、提交 release 候选。 |
104
+ | Publisher | 负责发布上线 | 创建 release、切渠道、发布公告。 |
105
+ | Viewer | 只读查看发布状态 | 查看版本、校验结果和审计。 |
106
+ | 平台管理员 | LimeCore 平台运营 | 管理官方 App、审核开发者、处理违规包。 |
107
+ | 租户管理员 | 企业或代理侧管理员 | 启用 App、绑定版本、配置注册码和可见范围。 |
108
+ | 普通 Lime 用户 | 使用应用中心安装 / 打开 App | 消费已发布和已授权的 App。 |
109
+
110
+ ## 用户故事
111
+
112
+ - 作为个人开发者,我希望在 Studio 中选择本地 App 目录后自动看到缺失文件和校验结果,避免发布一个不完整包。
113
+ - 作为团队开发者,我希望用 CLI 在 CI 里执行 dry-run,提前发现版本、manifest、dist、hash 或权限问题。
114
+ - 作为 App Owner,我希望只有被授权的人可以发布我的 App,所有发布动作都进入审计记录。
115
+ - 作为 Publisher,我希望在发布前看到本地版本和云端版本差异,并确认要发布到 draft、beta 还是 stable。
116
+ - 作为平台管理员,我希望所有上传包都经过静态校验、hash 计算和敏感字段过滤,避免不可信 release 进入应用中心。
117
+ - 作为租户管理员,我希望企业定制 App 可以通过注册码激活,未激活前客户端不能拿到 package URL。
118
+ - 作为普通用户,我希望应用中心显示的“可更新”状态准确,不会下载到错误版本。
119
+
120
+ ## 用户用例
121
+
122
+ ### 用例 1:首次发布本地 Agent App
123
+
124
+ 1. 开发者在用户中心完成开发者认证。
125
+ 2. 开发者打开 Studio 可视化客户端并登录 LimeCloud。
126
+ 3. 选择本地 App 目录。
127
+ 4. Studio 识别 `APP.md`、`app.capabilities.yaml`、`dist/` 和版本号。
128
+ 5. Studio 执行构建与校验。
129
+ 6. Studio 生成 `.lapp` 包并展示包预览。
130
+ 7. 开发者选择 `draft` 渠道并执行 dry-run。
131
+ 8. dry-run 通过后,开发者点击发布。
132
+ 9. Studio 上传 package 并创建 release。
133
+ 10. Studio 回读云端 release,显示发布成功。
134
+
135
+ ### 用例 2:CI/CD 自动发布 beta
136
+
137
+ 1. CI 安装 npm CLI:`npm install -g @limecloud/agent-app-studio`。
138
+ 2. CI 使用 secret 注入 LimeCloud 发布 token。
139
+ 3. CI 执行 `lime-agent-app publish --app-dir . --channel beta --dry-run`。
140
+ 4. dry-run 通过后,受保护分支执行 `--publish`。
141
+ 5. LimeCore 写入 release 和 audit。
142
+ 6. 应用中心 beta 通道用户可看到更新。
143
+
144
+ ### 用例 3:企业定制 App 发布后授权
145
+
146
+ 1. 开发者发布企业定制 App release。
147
+ 2. 平台或代理后台为租户启用该 App。
148
+ 3. 租户管理员设置或轮换注册码。
149
+ 4. Lime 客户端应用中心显示“需要激活”。
150
+ 5. 用户输入注册码后,客户端获得 package metadata 并安装。
151
+
152
+ ### 用例 4:发布失败排查
153
+
154
+ 1. Studio 显示 package upload 失败。
155
+ 2. 开发者查看错误分类:认证失败、权限不足、包超限、manifest 不匹配、存储未配置、网络失败。
156
+ 3. Studio 展示可复制的 CLI 复现命令。
157
+ 4. 开发者修复后重新执行 dry-run。
158
+
159
+ ## 信息架构
160
+
161
+ ```text
162
+ Lime Agent App Studio
163
+ 首页 / 项目列表
164
+ ├─ 最近项目
165
+ ├─ 本地目录导入
166
+ └─ 云端 App 列表
167
+ 项目工作台
168
+ ├─ 概览:本地版本、云端版本、权限、风险
169
+ ├─ 诊断:文件、manifest、dist、依赖、标准版本
170
+ ├─ 构建:build、validate、readiness、测试建议
171
+ ├─ 打包:包内容、体积、hash、manifest summary
172
+ ├─ 发布:dry-run、upload、release、渠道、release notes
173
+ ├─ 云端:catalog、releases、tenant enablement、audit
174
+ └─ 设置:登录、开发者认证、默认 API endpoint、npm CLI 指引
175
+ ```
176
+
177
+ ## App 分类设计
178
+
179
+ Studio v1 需要同时支持“来源分类”和“领域分类”。来源分类决定治理和权限,领域分类决定应用中心展示和筛选。
180
+
181
+ ### 来源分类
182
+
183
+ | 分类 | 说明 | 默认权限 |
184
+ |---|---|---|
185
+ | 官方应用 | Lime 官方维护的 App | 平台管理员和官方 Publisher 发布。 |
186
+ | 企业定制应用 | 为特定租户或代理定制 | App Owner / Publisher 发布,租户启用后可见。 |
187
+ | 团队私有应用 | 团队内部使用 | 团队成员按角色发布和查看。 |
188
+ | 开发调试应用 | 仅用于本地或 beta 测试 | 默认不可进入 stable。 |
189
+ | 模板应用 | 可复制、可二次开发 | 可公开展示,但发布实例需绑定 owner。 |
190
+
191
+ ### 领域分类
192
+
193
+ | 分类 | 示例 |
194
+ |---|---|
195
+ | 内容生产 | 内容工厂、公众号文章、短视频脚本、营销素材。 |
196
+ | 知识管理 | 项目资料、知识库整理、问答助手。 |
197
+ | 办公自动化 | 表格处理、文档生成、会议纪要。 |
198
+ | 数据分析 | 报表、指标解释、业务复盘。 |
199
+ | 开发者工具 | 代码审查、发布工具、接口调试。 |
200
+ | 行业应用 | 教育、法务、医疗、金融、跨境电商等垂直场景。 |
201
+
202
+ 分类规则:
203
+
204
+ - 每个 App 必须有一个来源分类。
205
+ - 每个 App 可以有多个领域分类。
206
+ - 开发调试应用默认只允许 draft / beta,不允许直接 stable。
207
+ - 企业定制应用默认需要 tenant enablement 和 registration code。
208
+ - 官方应用需要平台管理员或官方 Publisher 权限。
209
+
210
+ ## 开发者认证与权限
211
+
212
+ Studio v1 依赖 LimeCloud 用户中心提供开发者认证。认证通过后,当前用户获得 developer profile,并可在 Studio 和 CLI 中使用。
213
+
214
+ ### 开发者认证状态
215
+
216
+ | 状态 | 说明 | Studio 行为 |
217
+ |---|---|---|
218
+ | `not_requested` | 未申请 | 应用中心不可见 Studio App;只能在用户中心查看认证入口、公开文档和 CLI 指引。 |
219
+ | `pending` | 已提交申请 | 应用中心不可见 Studio App;可查看申请进度,不可上传和创建 release。 |
220
+ | `approved` | 已认证 | 应用中心可见 Studio App;可按权限管理 App 和 release。 |
221
+ | `suspended` | 暂停 | 应用中心隐藏或禁用 Studio App;禁止上传、发布和授权变更。 |
222
+ | `rejected` | 审核拒绝 | 应用中心不可见 Studio App;展示拒绝原因和重新申请入口。 |
223
+
224
+ ### App 权限角色
225
+
226
+ | 角色 | 权限 |
227
+ |---|---|
228
+ | Owner | 管理 App 信息、成员、发布 stable、撤销 release、转移归属。 |
229
+ | Maintainer | 本地诊断、打包、上传候选包、创建 draft / beta release。 |
230
+ | Publisher | 创建 release、切换渠道、发布 stable、填写 release notes。 |
231
+ | Viewer | 查看 App、release、diagnostics 和 audit。 |
232
+
233
+ Studio App 可见性规则:
234
+
235
+ - Lime Desktop 应用中心只向 `approved` 开发者展示 Lime Agent App Studio。
236
+ - `not_requested`、`pending`、`rejected` 用户不能在应用中心看到、安装或打开 Studio App。
237
+ - `suspended` 用户应隐藏 Studio App,或展示禁用态并阻止所有写云端动作。
238
+ - 用户中心的“开发者认证”入口始终可见,负责承接未认证用户的开通路径。
239
+ - CLI 可以通过 npmjs 公开安装,但 `auth status` 和所有写云端命令必须以服务端开发者认证状态为准。
240
+
241
+ 发布动作必须同时满足:
242
+
243
+ - 当前用户已完成开发者认证。
244
+ - 当前用户拥有目标 App 的有效角色。
245
+ - 目标 App 来源分类允许当前渠道。
246
+ - 目标租户或组织范围允许该 release 可见。
247
+ - 云端 API 返回的权限快照与本地展示一致。
248
+
249
+ ## 发布工作流
250
+
251
+ ```text
252
+ 选择目录
253
+ -> 本地识别
254
+ -> 构建校验
255
+ -> 打包预览
256
+ -> dry-run
257
+ -> 上传 package
258
+ -> 创建 release
259
+ -> 回读云端状态
260
+ -> 应用中心发现更新
261
+ ```
262
+
263
+ 发布状态:
264
+
265
+ | 状态 | 说明 |
266
+ |---|---|
267
+ | `local_detected` | 已识别本地 Agent App。 |
268
+ | `diagnostic_failed` | 本地诊断失败,不能发布。 |
269
+ | `ready_to_package` | 构建和校验通过,可打包。 |
270
+ | `packaged` | 已生成 `.lapp` / `.zip` 和 hash。 |
271
+ | `dry_run_passed` | 云端权限、payload、版本检查通过。 |
272
+ | `uploaded` | package 已上传并生成 URL / hash。 |
273
+ | `release_created` | release metadata 已写入 LimeCore。 |
274
+ | `published` | 目标渠道可见。 |
275
+ | `failed` | 发布失败,可重试或回滚。 |
276
+
277
+ ## 系统架构图
278
+
279
+ ```mermaid
280
+ flowchart LR
281
+ Developer[开发者] --> Visual[Studio 可视化客户端]
282
+ Developer --> CLI[Studio CLI npm 包]
283
+ Visual --> Core[发布内核 Packager + Orchestrator]
284
+ CLI --> Core
285
+ Core --> LocalApp[本地 Agent App 目录]
286
+ Core --> Validator[本地构建与标准校验]
287
+ Core --> Package[.lapp / .zip 包]
288
+ Core --> API[LimeCore API Client]
289
+ API --> Upload[package-upload]
290
+ API --> Release[create release]
291
+ Upload --> R2[云端对象存储]
292
+ Release --> Catalog[Agent App Catalog / Release]
293
+ Catalog --> LimeDesktop[Lime Desktop 应用中心]
294
+ UserCenter[用户中心开发者认证] --> API
295
+ ```
296
+
297
+ ## CLI 与可视化共享内核图
298
+
299
+ ```mermaid
300
+ flowchart TB
301
+ UI[可视化客户端] --> Orchestrator[Publish Orchestrator]
302
+ CLI[CLI] --> Orchestrator
303
+ Orchestrator --> Inspect[Project Inspector]
304
+ Orchestrator --> Build[Build Runner]
305
+ Orchestrator --> Pack[Package Builder]
306
+ Orchestrator --> Hash[Hash + Manifest Summary]
307
+ Orchestrator --> Cloud[LimeCore Publisher]
308
+ Cloud --> Auth[Developer Auth]
309
+ Cloud --> Upload[Upload Package]
310
+ Cloud --> CreateRelease[Create Release]
311
+ Cloud --> Verify[Read-back Verify]
312
+ ```
313
+
314
+ ## 发布时序图
315
+
316
+ ```mermaid
317
+ sequenceDiagram
318
+ actor Dev as 开发者
319
+ participant Studio as Studio UI / CLI
320
+ participant Local as 本地 Agent App
321
+ participant Core as 发布内核
322
+ participant LimeCore as LimeCore Control Plane
323
+ participant Store as 云端对象存储
324
+ participant Desktop as Lime Desktop 应用中心
325
+
326
+ Dev->>Studio: 选择 app-dir / 执行 publish
327
+ Studio->>Core: inspect(appDir)
328
+ Core->>Local: 读取 APP.md / app.*.yaml / dist
329
+ Core-->>Studio: 返回诊断结果
330
+ Dev->>Studio: 确认 dry-run
331
+ Studio->>Core: package + dry-run
332
+ Core->>LimeCore: 校验开发者权限和 release payload
333
+ LimeCore-->>Core: dry-run 通过
334
+ Dev->>Studio: 确认 --publish
335
+ Core->>LimeCore: POST package-upload
336
+ LimeCore->>Store: 写入 .lapp / .zip
337
+ Store-->>LimeCore: objectKey / public URL
338
+ LimeCore-->>Core: packageUrl / packageHash / manifestSummary
339
+ Core->>LimeCore: POST releases
340
+ LimeCore-->>Core: releaseCreated
341
+ Core->>LimeCore: 回读 catalog / release
342
+ LimeCore-->>Desktop: bootstrap / client agent-apps 可发现更新
343
+ Core-->>Studio: 发布成功
344
+ ```
345
+
346
+ ## 开发者认证流程图
347
+
348
+ ```mermaid
349
+ flowchart TD
350
+ Start[用户进入用户中心] --> Entry[打开开发者认证]
351
+ Entry --> Submit[提交开发者资料 / 接受协议]
352
+ Submit --> Review{审核方式}
353
+ Review -->|自动规则通过| Approved[developer profile approved]
354
+ Review -->|需要人工| Pending[pending]
355
+ Pending --> Approved
356
+ Pending --> Rejected[rejected]
357
+ Approved --> Bind[绑定当前 LimeCloud 用户]
358
+ Bind --> Token[Studio / CLI 获取开发者会话]
359
+ Token --> Publish[允许按 App 权限发布]
360
+ Rejected --> Retry[展示原因并允许重新提交]
361
+ ```
362
+
363
+ ## 发布流程图
364
+
365
+ ```mermaid
366
+ flowchart TD
367
+ A[选择本地目录] --> B{是否为 Agent App}
368
+ B -->|否| C[提示缺少 APP.md 或 app manifest]
369
+ B -->|是| D[读取版本和 appId]
370
+ D --> E[执行 build / validate]
371
+ E -->|失败| F[展示诊断和修复建议]
372
+ E -->|通过| G[生成 .lapp / .zip]
373
+ G --> H[计算 packageHash / manifestHash]
374
+ H --> I[执行 dry-run]
375
+ I -->|失败| J[展示权限或 payload 错误]
376
+ I -->|通过| K{用户确认发布}
377
+ K -->|取消| L[保留本地包和 dry-run 报告]
378
+ K -->|确认| M[上传 package]
379
+ M --> N[创建 release]
380
+ N --> O[回读云端状态]
381
+ O --> P[应用中心可发现更新]
382
+ ```
383
+
384
+ ## 发布状态机
385
+
386
+ ```mermaid
387
+ stateDiagram-v2
388
+ [*] --> LocalDetected
389
+ LocalDetected --> DiagnosticFailed: 校验失败
390
+ DiagnosticFailed --> LocalDetected: 修复后重试
391
+ LocalDetected --> ReadyToPackage: 校验通过
392
+ ReadyToPackage --> Packaged: 打包完成
393
+ Packaged --> DryRunPassed: dry-run 通过
394
+ Packaged --> DiagnosticFailed: dry-run 失败
395
+ DryRunPassed --> Uploaded: 上传成功
396
+ Uploaded --> ReleaseCreated: release 创建成功
397
+ ReleaseCreated --> Published: 渠道可见
398
+ Uploaded --> Failed: 创建 release 失败
399
+ DryRunPassed --> Failed: 上传失败
400
+ Failed --> DryRunPassed: 重试
401
+ Published --> [*]
402
+ ```
403
+
404
+ ## 云端接口依赖
405
+
406
+ Studio v1 不发明平行协议,优先复用 LimeCore 已有 Agent App 控制面:
407
+
408
+ - `GET /api/v1/platform/agent-apps`
409
+ - `POST /api/v1/public/tenants/:tenantId/client/developer/agent-apps/:appId/package-upload`
410
+ - `POST /api/v1/public/tenants/:tenantId/client/developer/agent-apps/:appId/releases`
411
+ - `POST /api/v1/platform/agent-apps/:appId/package-upload`(平台后台保留)
412
+ - `POST /api/v1/platform/agent-apps/:appId/releases`(平台后台保留)
413
+ - `GET /api/v1/platform/agent-apps/:appId/releases`
414
+ - `GET /api/v1/public/tenants/:tenantId/client/agent-apps`
415
+ - `POST /api/v1/public/tenants/:tenantId/client/agent-apps/:appId/registration`
416
+
417
+ Studio 需要的新增云端能力优先收敛到开发者认证、权限查询、开发者上传 / release 代理入口和 audit 查询,不新增 Agent App 执行面。
418
+
419
+ ## 安全与风控
420
+
421
+ - 上传包只做静态检查,不运行包内代码。
422
+ - `manifestSummary` 禁止包含 api key、token、secret、credential、客户内容和私有知识全文。
423
+ - 正式发布必须记录操作者、App、版本、渠道、包 hash、manifest hash、时间和来源客户端。
424
+ - 企业定制 App 未激活注册码前,客户端不得获得 package URL / hash。
425
+ - CLI token 不得写入项目目录或 Git 仓库。
426
+ - 失败日志不得输出云端密钥、注册码明文或用户隐私内容。
427
+
428
+ ## 非目标
429
+
430
+ - 不在 Studio v1 中实现 Agent App 运行时、Worker 执行或 Host Bridge。
431
+ - 不在 LimeCore 中执行 Agent App 包内 UI、脚本、worker 或 agent runtime。
432
+ - 不覆盖 Service Skill、专家、站点适配器等非 Agent App 资源发布。
433
+ - 不在首版实现复杂审核市场、收费结算、插件分成或公开市场排名。
434
+ - 不要求普通 Lime 用户理解 package、hash、release 或 manifest。
435
+
436
+ ## 验收标准
437
+
438
+ - Studio PRD 清楚定义可视化客户端和 CLI 两种产品形态。
439
+ - CLI npmjs 发布策略清楚,包括包名、bin 名、Node 基线、dry-run 和 publish 行为。
440
+ - 发布链路能从本地 App 目录闭环到 LimeCore release,并回读云端状态。
441
+ - 开发者认证和 App 权限是发布前置条件。
442
+ - App 分类同时覆盖来源治理和应用中心筛选。
443
+ - 文档明确复用 LimeCore 现有控制面,不新增云端 Agent Runtime。
444
+
445
+ ## v1 默认假设
446
+
447
+ - Studio v1 只写 Agent App 发布工具链,不做 App 内业务开发 IDE。
448
+ - 可视化客户端和 CLI 共享发布内核;可视化层不得复制一套独立发布逻辑。
449
+ - CLI 必须发布到 npmjs,便于开发者本地安装和 CI/CD 使用。
450
+ - 首版开发者认证可以从“申请 + 审核 + developer profile”开始,细节可后续落到用户中心实现文档。
451
+ - `content-factory-app` 是首个端到端验证对象。
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@limecloud/agent-app-studio",
3
+ "version": "0.1.0",
4
+ "description": "Lime Agent App Studio CLI and visual publisher for Agent App packages.",
5
+ "type": "module",
6
+ "private": false,
7
+ "license": "Apache-2.0",
8
+ "bin": {
9
+ "lime-agent-app-studio": "bin/lime-agent-app-studio.mjs",
10
+ "lime-agent-app": "bin/lime-agent-app-studio.mjs"
11
+ },
12
+ "files": [
13
+ "bin",
14
+ "src",
15
+ "app",
16
+ "docs/v1/README.md",
17
+ "LICENSE",
18
+ "README.md"
19
+ ],
20
+ "scripts": {
21
+ "test": "node --test tests/*.test.mjs",
22
+ "pack:dry-run": "npm pack --dry-run",
23
+ "publish:dry-run": "npm publish --access public --dry-run",
24
+ "publish:npm": "npm publish --access public"
25
+ },
26
+ "engines": {
27
+ "node": ">=20.0.0"
28
+ },
29
+ "dependencies": {
30
+ "yazl": "^3.3.1"
31
+ },
32
+ "publishConfig": {
33
+ "access": "public"
34
+ }
35
+ }
package/src/cli.mjs ADDED
@@ -0,0 +1,91 @@
1
+ // input: lime-agent-app-studio 命令
2
+ // output: auth、inspect、package、publish 与可视化工作台
3
+
4
+ import { parseArgs } from "./core/args.mjs";
5
+ import { loadStudioConfig, resolveAuthContext, saveStudioConfig } from "./core/config.mjs";
6
+ import { getDeveloperProfile } from "./core/api.mjs";
7
+ import { inspectProject } from "./core/project.mjs";
8
+ import { packageProject } from "./core/packager.mjs";
9
+ import { publishProject } from "./core/publisher.mjs";
10
+ import { startStudioServer } from "./server.mjs";
11
+
12
+ export async function runCli(argv) {
13
+ const { command, options } = parseArgs(argv);
14
+ switch (command) {
15
+ case "auth login":
16
+ return authLogin(options);
17
+ case "auth status":
18
+ return authStatus(options);
19
+ case "project inspect":
20
+ return printJson(await inspectProject(options.appDir || "."));
21
+ case "package":
22
+ return printJson(await packageProject({ appDir: options.appDir || ".", outDir: options.outDir }));
23
+ case "publish": {
24
+ const auth = await resolveAuthContext(options);
25
+ return printJson(
26
+ await publishProject({
27
+ ...options,
28
+ ...auth,
29
+ dryRun: Boolean(options.dryRun) || !options.publish,
30
+ publish: Boolean(options.publish),
31
+ })
32
+ );
33
+ }
34
+ case "studio": {
35
+ const { url } = await startStudioServer(options);
36
+ console.log(`Lime Agent App Studio 已启动:${url}`);
37
+ console.log("按 Ctrl+C 停止。");
38
+ return new Promise(() => {});
39
+ }
40
+ case "":
41
+ case "help":
42
+ default:
43
+ return printHelp();
44
+ }
45
+ }
46
+
47
+ async function authLogin(options) {
48
+ if (!options.token) {
49
+ throw new Error("请通过 --token 传入开发者 token;后续版本会接入浏览器 / 设备码登录。");
50
+ }
51
+ const config = await saveStudioConfig({
52
+ token: options.token,
53
+ tenantId: options.tenantId,
54
+ apiBase: options.apiBase,
55
+ });
56
+ console.log(`已保存 Studio 登录配置:tenantId=${config.tenantId || "未设置"}`);
57
+ }
58
+
59
+ async function authStatus(options) {
60
+ const auth = await resolveAuthContext(options);
61
+ const config = await loadStudioConfig();
62
+ if (!auth.token || !auth.tenantId) {
63
+ return printJson({
64
+ authenticated: false,
65
+ tenantId: auth.tenantId,
66
+ apiBase: auth.apiBase,
67
+ hasLocalToken: Boolean(config.token),
68
+ message: "缺少 token 或 tenantId,无法查询云端开发者认证状态。",
69
+ });
70
+ }
71
+ const profile = await getDeveloperProfile(auth);
72
+ return printJson({ authenticated: true, apiBase: auth.apiBase, tenantId: auth.tenantId, profile });
73
+ }
74
+
75
+ function printJson(value) {
76
+ console.log(JSON.stringify(value, null, 2));
77
+ }
78
+
79
+ function printHelp() {
80
+ console.log(`Lime Agent App Studio
81
+
82
+ Usage:
83
+ lime-agent-app-studio auth login --tenant-id <id> --token <token> [--api-base <url>]
84
+ lime-agent-app-studio auth status --tenant-id <id>
85
+ lime-agent-app-studio project inspect --app-dir <path>
86
+ lime-agent-app-studio package --app-dir <path> [--out-dir <path>]
87
+ lime-agent-app-studio publish --app-dir <path> --app-id <id> --tenant-id <id> --channel beta --dry-run
88
+ lime-agent-app-studio publish --app-dir <path> --app-id <id> --tenant-id <id> --channel stable --publish
89
+ lime-agent-app-studio studio --port 4177
90
+ `);
91
+ }
@@ -0,0 +1,68 @@
1
+ // input: LimeCore API base、tenantId、token 与发布包
2
+ // output: 开发者认证、上传包、创建 release 的 HTTP 调用
3
+
4
+ import { readFile } from "node:fs/promises";
5
+ import { basename } from "node:path";
6
+
7
+ export async function getDeveloperProfile({ apiBase, tenantId, token }) {
8
+ return unwrap(await requestJson(`${apiBase}/v1/public/tenants/${tenantId}/client/developer-profile`, { token }));
9
+ }
10
+
11
+ export async function applyDeveloperCertification({ apiBase, tenantId, token, displayName = "" }) {
12
+ return unwrap(
13
+ await requestJson(`${apiBase}/v1/public/tenants/${tenantId}/client/developer-profile/apply`, {
14
+ token,
15
+ method: "POST",
16
+ body: { agreementAccepted: true, displayName },
17
+ })
18
+ );
19
+ }
20
+
21
+ export async function uploadDeveloperAgentAppPackage({ apiBase, tenantId, token, appId, packagePath }) {
22
+ const data = await readFile(packagePath);
23
+ const formData = new FormData();
24
+ formData.append("file", new Blob([data], { type: "application/octet-stream" }), basename(packagePath));
25
+ return unwrap(
26
+ await requestRaw(`${apiBase}/v1/public/tenants/${tenantId}/client/developer/agent-apps/${encodeURIComponent(appId)}/package-upload`, {
27
+ token,
28
+ method: "POST",
29
+ body: formData,
30
+ })
31
+ );
32
+ }
33
+
34
+ export async function createDeveloperAgentAppRelease({ apiBase, tenantId, token, appId, payload }) {
35
+ return unwrap(
36
+ await requestJson(`${apiBase}/v1/public/tenants/${tenantId}/client/developer/agent-apps/${encodeURIComponent(appId)}/releases`, {
37
+ token,
38
+ method: "POST",
39
+ body: payload,
40
+ })
41
+ );
42
+ }
43
+
44
+ async function requestJson(url, options = {}) {
45
+ return requestRaw(url, {
46
+ ...options,
47
+ body: options.body === undefined ? undefined : JSON.stringify(options.body),
48
+ headers: { "Content-Type": "application/json", ...(options.headers || {}) },
49
+ });
50
+ }
51
+
52
+ async function requestRaw(url, options = {}) {
53
+ const headers = new Headers(options.headers || {});
54
+ if (options.token) headers.set("Authorization", `Bearer ${options.token}`);
55
+ const response = await fetch(url, { method: options.method || "GET", headers, body: options.body });
56
+ const contentType = response.headers.get("content-type") || "";
57
+ const payload = contentType.includes("application/json") ? await response.json() : await response.text();
58
+ if (!response.ok) {
59
+ const message = typeof payload === "object" && payload ? payload.message || payload.error : payload;
60
+ throw new Error(`${response.status} ${message || response.statusText}`);
61
+ }
62
+ return payload;
63
+ }
64
+
65
+ function unwrap(payload) {
66
+ if (payload && typeof payload === "object" && "data" in payload) return payload.data;
67
+ return payload;
68
+ }
@@ -0,0 +1,40 @@
1
+ // input: CLI argv
2
+ // output: 稳定的命令名、选项与位置参数
3
+
4
+ export function parseArgs(argv) {
5
+ const tokens = [...argv];
6
+ const command = [];
7
+ const options = {};
8
+ const positionals = [];
9
+
10
+ while (tokens.length > 0) {
11
+ const token = tokens.shift();
12
+ if (!token.startsWith("-")) {
13
+ if (command.length < 2) {
14
+ command.push(token);
15
+ } else {
16
+ positionals.push(token);
17
+ }
18
+ continue;
19
+ }
20
+
21
+ const [rawKey, inlineValue] = token.replace(/^--?/, "").split("=", 2);
22
+ const key = toCamelCase(rawKey);
23
+ if (inlineValue !== undefined) {
24
+ options[key] = inlineValue;
25
+ continue;
26
+ }
27
+ const next = tokens[0];
28
+ if (!next || next.startsWith("-")) {
29
+ options[key] = true;
30
+ continue;
31
+ }
32
+ options[key] = tokens.shift();
33
+ }
34
+
35
+ return { command: command.join(" "), options, positionals };
36
+ }
37
+
38
+ function toCamelCase(value) {
39
+ return String(value || "").replace(/-([a-z])/g, (_, char) => char.toUpperCase());
40
+ }