Merge remote-tracking branch 'github/devlop'
This commit is contained in:
127
.cursor/README.md
Normal file
127
.cursor/README.md
Normal file
@@ -0,0 +1,127 @@
|
||||
# Soul 创业派对 - .cursor 配置说明
|
||||
|
||||
本目录按 **cursor标准模板** 重构,rules、skills、agent 为**开发团队**服务,用于约束开发、防止互窜、经验升级。
|
||||
|
||||
---
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
.cursor/
|
||||
├── README.md # 本说明(入口)
|
||||
├── config/ # 配置(paths.py、workspace.txt、model_switch.json)
|
||||
├── rules/ # 规则(boundary、checklist、助理、会议、老板分身-索引)
|
||||
├── skills/ # Skills(按角色分配)
|
||||
├── agent/ # 智能体(标准开发团队结构)
|
||||
│ ├── 老板分身/ # 最高权限,协调所有角色
|
||||
│ ├── 开发助理/ # 规则进化、通用经验、项目索引、bat 入口
|
||||
│ │ ├── evolution/ # 通用经验池
|
||||
│ │ ├── script/ # 一键-列出经验池.bat、一键-添加经验.bat 等
|
||||
│ │ └── 项目索引/ # 各角色开发进度(小程序.md、管理端.md 等)
|
||||
│ ├── 小程序开发工程师/
|
||||
│ ├── 管理端开发工程师/
|
||||
│ ├── 后端工程师/
|
||||
│ ├── 产品经理/
|
||||
│ ├── 软件测试/
|
||||
│ └── 团队/ # 跨角色共享经验
|
||||
├── scripts/ # 共享脚本(evolution.py、经验模板.md、db-exec)
|
||||
├── docs/ # 文档(职责定义、边界、分析)
|
||||
├── process/ # 工作流
|
||||
├── meeting/ # 会议纪要(橙子生成)
|
||||
└── archive/ # 历史归档
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 开发团队
|
||||
|
||||
| 角色 | 负责 | 主 Skill | Agent 目录 |
|
||||
|------|------|----------|------------|
|
||||
| 小程序开发工程师 | miniprogram/ | SKILL-小程序开发.md | agent/小程序开发工程师/ |
|
||||
| 管理端开发工程师 | soul-admin/ | SKILL-管理端开发.md | agent/管理端开发工程师/ |
|
||||
| 后端开发 | soul-api/ | SKILL-API开发.md | agent/后端工程师/ |
|
||||
| 产品经理 | 开发文档/1、需求/、临时需求池/ | SKILL-产品经理.md | agent/产品经理/ |
|
||||
| 测试人员 | miniprogram、soul-admin、soul-api | SKILL-测试.md | agent/软件测试/ |
|
||||
| 助理橙子 | 讨论后记录、经验升级 | SKILL-助理橙子-文档同步.md | agent/开发助理/ |
|
||||
|
||||
**经验**:每角色 `agent/{角色}/evolution/`,团队共享 `agent/团队/evolution/`。用户说「吸收经验」「升级 skills」→ 入库 + 升级 Skill;说「保存开发进度」「任务完成」→ 更新 `agent/开发助理/项目索引/{角色}.md`。
|
||||
|
||||
---
|
||||
|
||||
## 快速决策(必须 Read = 使用 Read 工具读取完整内容)
|
||||
|
||||
| 编辑/场景 | 必须 Read 的 Skill | 自动加载的 Rule |
|
||||
|-----------|-------------------|----------------|
|
||||
| miniprogram/ | `SKILL-小程序开发.md` | soul-miniprogram-boundary |
|
||||
| soul-admin/ | `SKILL-管理端开发.md` | soul-admin-boundary |
|
||||
| soul-api/ | `SKILL-API开发.md` | soul-api |
|
||||
| 开发文档/1、需求/、临时需求池/ | `SKILL-产品经理.md` | product-manager |
|
||||
| 测试、测试用例、回归测试、功能测试、QA | `SKILL-测试.md` | - |
|
||||
| 小橙、橙子、讨论完毕、记录、同步文档 | `SKILL-助理橙子-文档同步.md` | assistant-xiaofeng |
|
||||
| 吸收经验、升级 skills、保存开发进度、任务完成、搞定了 | `SKILL-助理橙子-文档同步.md` | assistant-xiaofeng |
|
||||
| 跨端功能开发 | `SKILL-角色流程控制.md` | - |
|
||||
| 变更完成 | `SKILL-变更关联检查.md` | soul-change-checklist |
|
||||
| 开个会、团队会议、需求评审、方案讨论 | `SKILL-团队会议.md` | soul-meeting |
|
||||
| 会议结束、散会 | `SKILL-助理橙子-文档同步.md`(会议收尾) | soul-meeting |
|
||||
|
||||
---
|
||||
|
||||
## Rules 一览
|
||||
|
||||
| 规则 | 生效范围 | 用途 |
|
||||
|------|----------|------|
|
||||
| soul-project-boundary | `**`(alwaysApply) | 项目组成、核心原则、会话自检 |
|
||||
| 老板分身-索引 | `**`(alwaysApply) | 经验自动收集、Soul 角色推断、编码习惯 |
|
||||
| soul-change-checklist | miniprogram、soul-admin、soul-api | 变更后必过 |
|
||||
| assistant-xiaofeng | 触发词 | 小橙触发器 → SKILL-助理橙子-文档同步 |
|
||||
| soul-miniprogram-boundary | miniprogram/** | 只调 /api/miniprogram/* |
|
||||
| soul-admin-boundary | soul-admin/** | 只调 /api/admin/*、/api/db/* |
|
||||
| soul-api | soul-api/** | 路由边界 + 编码规范(合并版) |
|
||||
| product-manager | 开发文档/1、需求/、临时需求池/ | 产品经理 glob 触发 |
|
||||
| soul-meeting | 触发词 | 开个会、团队会议、需求评审 → SKILL-团队会议 |
|
||||
|
||||
---
|
||||
|
||||
## Skills 一览
|
||||
|
||||
### 角色主 Skill
|
||||
|
||||
| 角色 | 主 Skill | 辅助 Skill |
|
||||
|------|----------|------------|
|
||||
| 小程序开发工程师 | SKILL-小程序开发 | 三端架构 → API开发 → 变更关联检查 |
|
||||
| 管理端开发工程师 | SKILL-管理端开发 | 三端架构 → API开发 → 变更关联检查 |
|
||||
| 后端开发 | SKILL-API开发 | soul-api 规范 → 三端架构 → 变更关联检查 → MySQL直接操作 |
|
||||
| 产品经理 | SKILL-产品经理 | 需求汇总、运营与变更 |
|
||||
| 测试人员 | SKILL-测试 | 变更关联检查、小程序/管理端/API 规范 |
|
||||
| 助理橙子 | SKILL-助理橙子-文档同步 | - |
|
||||
|
||||
### 场景 Skill
|
||||
|
||||
| 场景 | Skill |
|
||||
|------|-------|
|
||||
| 跨端协同 | SKILL-角色流程控制 |
|
||||
| 变更检查 | SKILL-变更关联检查、soul-change-checklist |
|
||||
| 文档同步、经验升级 | SKILL-助理橙子-文档同步 |
|
||||
| **多角色会议** | **SKILL-团队会议** |
|
||||
| next-project | SKILL-next-project仅预览 |
|
||||
| 项目拆解 | SKILL-Next全栈拆解为前后端分离与小程序 |
|
||||
|
||||
---
|
||||
|
||||
## 文档与脚本
|
||||
|
||||
| 文档 | 说明 |
|
||||
|------|------|
|
||||
| [开发团队职责定义](./docs/开发团队职责定义.md) | 六角色职责、Skills 分配 |
|
||||
| [三角色边界定义](./docs/三角色边界定义.md) | 开发三角色源码与业务边界 |
|
||||
| [config/目录地图](./config/目录地图.md) | paths.py 路径别名 |
|
||||
| [meeting/](./meeting/) | 会议纪要(橙子生成) |
|
||||
| [经验清单](./agent/开发助理/经验清单.md) | 跨角色经验索引 |
|
||||
| evolution 脚本 | `python .cursor/scripts/evolution.py list` 列出经验池;`add --stdin` 添加经验 |
|
||||
| 一键 bat | `agent/开发助理/script/一键-列出经验池.bat` 等 |
|
||||
|
||||
---
|
||||
|
||||
## 会话启动自检
|
||||
|
||||
新 Cursor 打开本项目时,优先执行 soul-project-boundary 中的「会话启动自检」:仅沿用本项目的 rules、skills、开发风格与配置,排除无关规则。
|
||||
0
.cursor/agent/产品经理/evolution/.gitkeep
Normal file
0
.cursor/agent/产品经理/evolution/.gitkeep
Normal file
5
.cursor/agent/产品经理/evolution/2026-02-26.md
Normal file
5
.cursor/agent/产品经理/evolution/2026-02-26.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# 2026-02-26 | 产品经验
|
||||
|
||||
> 本日经验条目,格式:类型 | 摘要 | 升级 Skill
|
||||
|
||||
---
|
||||
19
.cursor/agent/产品经理/evolution/2026-02-28.md
Normal file
19
.cursor/agent/产品经理/evolution/2026-02-28.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# 产品经理 经验记录 - 2026-02-28
|
||||
|
||||
## stitch_soul 需求评审会议
|
||||
|
||||
- **stitch_soul 串联「内容→会员→导师」变现路径**:临时需求池 10 个稿子覆盖目录、导师、会员、首页、资料编辑,需在正式需求文档中明确 73 章、导师、案例库、会员的业务定义与验收标准。
|
||||
- **待澄清项**:73 章与现有内容库是否同一套;导师与内容作者是否同一人;「案例库」是独立内容池还是章节分类;会员权益与价格策略。
|
||||
- **优先级建议**:首页/目录/会员 > 导师列表/详情 > 资料编辑。
|
||||
|
||||
## 个人资料页实现评估会议
|
||||
|
||||
- **展示/编辑页一致性**:展示页(enhanced_professional_profile)与编辑页(comprehensive_profile_editor_v1_1)需字段一一对应、配色统一。
|
||||
- **skills「我擅长」**:展示页已有,编辑页必须补充;验收时确认两页数据一致。
|
||||
|
||||
## 文章类型(普通版/增值版)需求分析会议
|
||||
|
||||
- **普通版**:9.9 元买断,与现有 fullbook 一致。
|
||||
- **增值版**:基础价 + 后 N 章(N 可配置)按章额外付费;每购一章价格累加该章单价。
|
||||
- **已确认**:普通版与增值版**分开、互斥**,用户购买其一,非叠加。
|
||||
- **待输出**:增值版基础价是否固定 9.9;N 默认值。
|
||||
12
.cursor/agent/产品经理/evolution/2026-03-05.md
Normal file
12
.cursor/agent/产品经理/evolution/2026-03-05.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# 产品经理 经验记录 - 2026-03-05
|
||||
|
||||
## 分支冲突后功能完整性分析会议
|
||||
|
||||
- **分支冲突后需优先核对需求文档与实现一致性**:避免「文档在合并中丢失」导致需求与实现脱节。重点核对 `开发文档/1、需求/`、`临时需求池/` 与当前实现是否一致。
|
||||
- **重点确认项**:个人资料页、增值版/普通版计价、找伙伴联系方式完善弹窗等近期需求是否按文档落地。
|
||||
|
||||
## 文章详情 @某人 高亮与一键加好友方案讨论
|
||||
|
||||
- **需求**:文章中支持 @某人,名称高亮、点击添加好友;编辑侧能插入 @用户并落库(含用户 id)。
|
||||
- **验收**:详情页 @ 高亮可点击;点击调起添加好友并提示;管理端插入 @ 后保存再编辑不错位。
|
||||
- **待确认**:添加好友接口 path、入参/出参及业务规则(已是好友、重复请求等);开发文档中接口放置位置。
|
||||
6
.cursor/agent/产品经理/evolution/索引.md
Normal file
6
.cursor/agent/产品经理/evolution/索引.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# 产品经理 经验索引
|
||||
|
||||
| 日期 | 摘要 | 文件 |
|
||||
|------|------|------|
|
||||
| 2026-03-05 | 分支冲突后需求文档与实现一致性核对 | [2026-03-05.md](./2026-03-05.md) |
|
||||
| 2026-03-05 | 文章详情@某人高亮与一键加好友验收标准与待确认 | [2026-03-05.md](./2026-03-05.md) |
|
||||
0
.cursor/agent/后端工程师/evolution/.gitkeep
Normal file
0
.cursor/agent/后端工程师/evolution/.gitkeep
Normal file
5
.cursor/agent/后端工程师/evolution/2026-02-26.md
Normal file
5
.cursor/agent/后端工程师/evolution/2026-02-26.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# 2026-02-26 | 后端经验
|
||||
|
||||
> 本日经验条目,格式:类型 | 摘要 | 升级 Skill
|
||||
|
||||
---
|
||||
23
.cursor/agent/后端工程师/evolution/2026-02-28.md
Normal file
23
.cursor/agent/后端工程师/evolution/2026-02-28.md
Normal file
@@ -0,0 +1,23 @@
|
||||
# 后端开发 经验记录 - 2026-02-28
|
||||
|
||||
## stitch_soul 需求评审会议
|
||||
|
||||
- **现有基础**:soul-api 已有 chapter、book、vip 模型;导师能力需新建或扩展现有 match 体系(现有 mentor 为 match 类型,非独立导师实体)。
|
||||
- **待设计**:导师列表/详情/搜索筛选、预约单、会员权益与预约支付打通;接口挂 `/api/miniprogram/*`。
|
||||
- **协同**:与产品核对 chapter/book/vip 现状后,给出导师/预约/会员权益的模型与接口方案。
|
||||
|
||||
## chapter/book/vip 模型补充(问题 5 作答)
|
||||
|
||||
- **chapters 表**:每行一节,id 如 1.1/preface;part/chapter/section 三层;73 章=行数统计。
|
||||
- **book**:无独立表,= chapters 聚合;接口 `/api/book/all-chapters`、`/api/book/chapter/:id`。
|
||||
- **vip**:vip_roles 配置角色;users 存 is_vip/vip_expire_date 等;权益优先 users,无则 orders 兜底;¥1980。
|
||||
|
||||
## 个人资料页实现评估会议
|
||||
|
||||
- **profile API**:`GET/POST /api/miniprogram/user/profile` 已覆盖 skills 等全部扩展字段;无需新增接口。
|
||||
|
||||
## 文章类型(普通版/增值版)需求分析会议
|
||||
|
||||
- **premium_config**:system_config 新增 premium_base_price、premium_chapter_count(后 N 个 section)。
|
||||
- **增值章节购买**:沿用 product_type=section、product_id=section_id,金额为 chapters.price。
|
||||
- **purchase-status 扩展**:需返回 editionType、premiumPurchasedSections 等。
|
||||
13
.cursor/agent/后端工程师/evolution/2026-03-05.md
Normal file
13
.cursor/agent/后端工程师/evolution/2026-03-05.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# 后端工程师 经验记录 - 2026-03-05
|
||||
|
||||
## 分支冲突后功能完整性分析会议
|
||||
|
||||
- **soul-api 被 gitignore 时**:需在 soul-api 所在位置单独确认 git 状态与合并情况,无法从本仓库直接检查。
|
||||
- **重点核对接口**:`/api/miniprogram/orders`(购买记录)、`/api/db/distribution`(分销)是否已实现并挂载到对应路由组。
|
||||
- **建议**:对照「三端需求业务对齐」文档逐项核对接口注册与实现;明确 soul-api 的版本管理与合并策略。
|
||||
|
||||
## 文章详情 @某人 高亮与一键加好友方案讨论
|
||||
|
||||
- **内容存储**:推荐正文内嵌 @ 标记,格式 `@[昵称](userId)`(或 `{{@userId:昵称}}`),后端只存不解析;章节/文章接口原样返回 content。
|
||||
- **添加好友接口**:在 miniprogram 路由组新增,如 `POST /api/miniprogram/friend/add`,入参 `targetUserId`;与存客宝 api_v1 分离,在开发文档中单独说明或 api_v1 新增小节。
|
||||
- **数据模型**:无需单独 mention 表,扩展内容表 content 存带 @ 标记字符串即可。
|
||||
6
.cursor/agent/后端工程师/evolution/索引.md
Normal file
6
.cursor/agent/后端工程师/evolution/索引.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# 后端工程师 经验索引
|
||||
|
||||
| 日期 | 摘要 | 文件 |
|
||||
|------|------|------|
|
||||
| 2026-03-05 | soul-api 合并状态确认;orders、distribution 接口核对 | [2026-03-05.md](./2026-03-05.md) |
|
||||
| 2026-03-05 | 文章详情@某人:content 内嵌 @ 标记、miniprogram 添加好友接口 | [2026-03-05.md](./2026-03-05.md) |
|
||||
0
.cursor/agent/团队/evolution/.gitkeep
Normal file
0
.cursor/agent/团队/evolution/.gitkeep
Normal file
10
.cursor/agent/团队/evolution/2026-02-27.md
Normal file
10
.cursor/agent/团队/evolution/2026-02-27.md
Normal file
@@ -0,0 +1,10 @@
|
||||
# 2026-02-27 | 团队经验
|
||||
|
||||
> 本日跨角色共享的架构决策、业务规则。格式:类型 | 摘要 | 关联 Skill
|
||||
|
||||
---
|
||||
|
||||
## 输入框样式(前端通用)
|
||||
|
||||
- **最佳实践 | 输入框 padding**:设置 input 的 padding/背景/边框时,用 div 或 view 包裹 input;padding 写在容器上,input 仅做文字样式,可避免光标截断、布局异常。
|
||||
- **适用**:小程序、管理端(React input 同理)
|
||||
21
.cursor/agent/团队/evolution/2026-02-28.md
Normal file
21
.cursor/agent/团队/evolution/2026-02-28.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# 团队共享 经验记录 - 2026-02-28
|
||||
|
||||
## stitch_soul 需求评审会议
|
||||
|
||||
- **stitch_soul 定位**: stitch 产品线在 Soul 创业派对上的扩展,串联「内容阅读 + 导师咨询」变现路径。
|
||||
- **架构协同**:需与现有 soul-api/soul-admin/miniprogram 架构协同;严禁混用 admin/miniprogram 路由;接口按使用方挂载。
|
||||
- **开发顺序**:产品补充需求文档 → 后端给出模型与接口方案 → 管理端/小程序按优先级分阶段实现。
|
||||
|
||||
## 会议规则升级
|
||||
|
||||
- **问题与作答区**:开完会后必须将待确认/待澄清问题列出,在会议纪要中增加「问题与作答区」节,问题表含:序号、问题、责任角色、作答(留空供后续填写);便于追溯闭环。
|
||||
|
||||
## 个人资料页实现评估会议
|
||||
|
||||
- **展示/编辑页协同**:profile-show 与 profile-edit 共用同一 API,skills 等扩展字段需双向同步;配色统一为 enhanced(#5EEAD4)强化品牌一致。
|
||||
|
||||
## 文章类型(普通版/增值版)需求分析会议
|
||||
|
||||
- **增值版计价**:基础价 + Σ(增值章节单价),按章购买、按章累加。
|
||||
- **后 N 章**:指全书最后 N 个 section;N 可配置。
|
||||
- **普通版与增值版**:分开、互斥的两套产品,用户购买其一。
|
||||
17
.cursor/agent/团队/evolution/2026-03-05.md
Normal file
17
.cursor/agent/团队/evolution/2026-03-05.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# 团队 经验记录 - 2026-03-05
|
||||
|
||||
## 分支冲突后功能完整性分析会议(跨角色共享)
|
||||
|
||||
- **分支冲突后各端需做完整性自查**:
|
||||
- 产品:核对需求文档与实现一致性
|
||||
- 后端:在 soul-api 确认合并状态,核对 orders、distribution 等接口
|
||||
- 管理端:全功能自测,记录 404/异常接口
|
||||
- 小程序:核心流程自测,确认 orders 接口;修正 app.json 格式
|
||||
- 测试:制定「分支合并后回归清单」
|
||||
- **待确认**:`完整的` 分支上的提交是否已全部并入 devlop;soul-api 的版本管理与合并策略。
|
||||
|
||||
## 文章详情 @某人 高亮与一键加好友方案讨论(跨角色共享)
|
||||
|
||||
- **内容格式**:正文内嵌 @ 标记,统一格式 `@[昵称](userId)`(或约定等价格式),后端/管理端/小程序共用。
|
||||
- **添加好友接口**:归属 soul-api 的 miniprogram 组,与存客宝 api_v1 分离;path、入参由后端/产品确认后写入开发文档。
|
||||
- **分工**:管理端编辑侧插入 @ 并写入 content;小程序解析、高亮、点击调添加好友;后端提供章节 content 与添加好友接口。
|
||||
7
.cursor/agent/团队/evolution/索引.md
Normal file
7
.cursor/agent/团队/evolution/索引.md
Normal file
@@ -0,0 +1,7 @@
|
||||
# 团队 经验索引(跨角色共享)
|
||||
|
||||
> 架构决策、业务规则、路由约定等跨角色共享内容。
|
||||
|
||||
| 日期 | 摘要 | 文件 |
|
||||
|------|------|------|
|
||||
| 2026-03-05 | 分支冲突后各端完整性自查流程 | [2026-03-05.md](./2026-03-05.md) |
|
||||
0
.cursor/agent/小程序开发工程师/evolution/.gitkeep
Normal file
0
.cursor/agent/小程序开发工程师/evolution/.gitkeep
Normal file
5
.cursor/agent/小程序开发工程师/evolution/2026-02-26.md
Normal file
5
.cursor/agent/小程序开发工程师/evolution/2026-02-26.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# 2026-02-26 | 小程序经验
|
||||
|
||||
> 本日经验条目,格式:类型 | 摘要 | 升级 Skill
|
||||
|
||||
---
|
||||
19
.cursor/agent/小程序开发工程师/evolution/2026-02-27.md
Normal file
19
.cursor/agent/小程序开发工程师/evolution/2026-02-27.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# 小程序开发工程师 经验记录 - 2026-02-27
|
||||
|
||||
---
|
||||
|
||||
## 输入框 padding 最佳实践
|
||||
|
||||
- **场景**:设置 input 的 padding、背景、边框等样式时,直接作用于 input 可能导致光标被截断、布局异常。
|
||||
- **方案**:用 `<view>` 包裹 `<input>`,padding/背景/边框写在 view 上,input 仅设置 width、font-size、color 等文字相关样式。
|
||||
- **示例**:
|
||||
```xml
|
||||
<view class="form-input">
|
||||
<input placeholder="提示文字" value="{{value}}" bindinput="onInput" />
|
||||
</view>
|
||||
```
|
||||
```css
|
||||
.form-input { padding: 16rpx 24rpx; background: rgba(255,255,255,0.06); border: 1rpx solid rgba(255,255,255,0.1); border-radius: 12rpx; }
|
||||
.form-input input { width: 100%; font-size: 28rpx; color: #fff; background: transparent; }
|
||||
```
|
||||
- **升级**:已写入 SKILL-小程序开发 §6 表单与输入框
|
||||
31
.cursor/agent/小程序开发工程师/evolution/2026-02-28.md
Normal file
31
.cursor/agent/小程序开发工程师/evolution/2026-02-28.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# 小程序开发工程师 经验记录 - 2026-02-28
|
||||
|
||||
## stitch_soul 需求评审会议
|
||||
|
||||
- **页面范围**:首页、目录、导师列表/详情、会员落地页、个人资料/编辑;全部接口走 `/api/miniprogram/*`。
|
||||
- **支付**:会员购买、导师预约支付需按微信支付规范实现。
|
||||
- **时机**:待需求与接口确定后按优先级分阶段排期(建议:内容→会员→导师→资料编辑)。
|
||||
|
||||
## 个人资料页实现评估会议
|
||||
|
||||
- **profile-show**:已按 enhanced_professional_profile 完成,accent #5EEAD4;profile-edit 需与其视觉统一。
|
||||
- **profile-edit 待做**:① 增加「我擅长」输入框(skills 后端已支持);② 配色统一为 enhanced(#5EEAD4 / #050B14 / #0F1720)。
|
||||
- **流程**:我的 → profile-show → ⋯ 编辑 → profile-edit → 保存 → 返回;已打通,无需改。
|
||||
|
||||
## input/textarea padding 规范
|
||||
|
||||
- **原则**:给 input 或 textarea 设置 padding 时,必须用 view 包裹,padding 写在 view 上;不在 input/textarea 自身上设 padding,避免原生组件光标截断、布局异常。
|
||||
- **口诀**:外边包 view,内部 input width 100%。
|
||||
- **已升级**:miniprogram-dev SKILL §6 加入口诀;admin-dev §4.1 同步补充。
|
||||
|
||||
## 找伙伴-资源对接弹窗 input 边距修正
|
||||
|
||||
- **问题**:弹窗内 input 文字贴边,padding 直接写在 input 上导致布局异常。
|
||||
- **正确做法**:按 Skill §6,用 view 包裹,padding 写 view,内部 input 设 `width: 100%`。
|
||||
- **修改**:match 页资源对接两个输入框 + 联系方式输入框,统一改为 `form-input-wrap` + `form-input-inner` / `input-field-wrap` + `input-field-inner` 结构。
|
||||
|
||||
## 文章类型(普通版/增值版)需求分析会议
|
||||
|
||||
- **选购**:目录/书籍页区分普通版 9.9 与增值版(基础价 + 增值章按章付费)。
|
||||
- **解锁**:进入增值章节未购时展示「该章需额外 ¥X.X 解锁」,点击发起支付。
|
||||
- **依赖**:purchase-status 需返回 editionType、premiumPurchasedSections。
|
||||
27
.cursor/agent/小程序开发工程师/evolution/2026-03-03.md
Normal file
27
.cursor/agent/小程序开发工程师/evolution/2026-03-03.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# 2026-03-03 经验
|
||||
|
||||
## 我的页面卡片区边距优化
|
||||
|
||||
### 问题/场景
|
||||
|
||||
用户反馈「我的」页面的卡片区域左右边距过大,内容区在水平方向上显得较窄,未充分利用屏幕横向空间。
|
||||
|
||||
### 解决方案
|
||||
|
||||
将卡片区域及上下关联区块的左右边距统一缩小:
|
||||
|
||||
| 区块 | 修改前 | 修改后 |
|
||||
|------|--------|--------|
|
||||
| `.main-content` | 32rpx | 16rpx |
|
||||
| `.header-block` | 40rpx | 16rpx |
|
||||
| `.guest-block` | 48rpx | 16rpx |
|
||||
| `.card` padding | 40rpx | 32rpx |
|
||||
| `.card` margin-bottom | 32rpx | 24rpx |
|
||||
|
||||
### 提炼规则
|
||||
|
||||
个人中心、设置类页面(如「我的」)的卡片区左右边距宜紧凑,**推荐 16rpx**;卡片内边距 32rpx、卡片间距 24rpx,以充分利用横向空间。
|
||||
|
||||
### 适用
|
||||
|
||||
- `miniprogram/pages/my/` 及类似个人中心、设置页
|
||||
13
.cursor/agent/小程序开发工程师/evolution/2026-03-05.md
Normal file
13
.cursor/agent/小程序开发工程师/evolution/2026-03-05.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# 小程序开发工程师 经验记录 - 2026-03-05
|
||||
|
||||
## 分支冲突后功能完整性分析会议
|
||||
|
||||
- **app.json 多页面配置**:建议拆行便于维护,避免多页面写在同一行(如第 21 行)。
|
||||
- **分支合并后需做核心流程自测**:登录→阅读→购买→提现→找伙伴→个人资料→VIP,确认无白屏、无接口报错。
|
||||
- **重点确认**:`/api/miniprogram/orders`(购买记录)是否已实现;`完整的` 分支上的优化(如 5a5f0087 卡片边距)是否已并入 devlop。
|
||||
|
||||
## 文章详情 @某人 高亮与一键加好友方案讨论
|
||||
|
||||
- **展示**:阅读页 content 需解析「@ 标记」格式(如 `@[昵称](userId)`),将 @ 片段渲染为高亮可点击 `<text data-user-id>`,点击调 miniprogram 添加好友接口。
|
||||
- **接口**:添加好友接口由后端在 miniprogram 组提供(如 `POST /api/miniprogram/friend/add`),入参 `targetUserId`;不调用 api_v1 存客宝接口。
|
||||
- **实现要点**:在现有 contentParagraphs 按行渲染基础上,对每行再做 mention 解析,得到 text/mention 片段数组后 WXML 分支渲染;不改动现有阅读权限、进度、购买逻辑。
|
||||
8
.cursor/agent/小程序开发工程师/evolution/索引.md
Normal file
8
.cursor/agent/小程序开发工程师/evolution/索引.md
Normal file
@@ -0,0 +1,8 @@
|
||||
# 小程序开发工程师 经验索引
|
||||
|
||||
| 日期 | 摘要 | 文件 |
|
||||
|------|------|------|
|
||||
| 2026-02-28 | input 边距口诀、match 资源对接弹窗修正 | [2026-02-28.md](./2026-02-28.md) |
|
||||
| 2026-03-03 | 我的页面卡片区边距优化,16rpx 推荐值 | [2026-03-03.md](./2026-03-03.md) |
|
||||
| 2026-03-05 | 分支合并后核心流程自测;app.json 拆行;orders 接口确认 | [2026-03-05.md](./2026-03-05.md) |
|
||||
| 2026-03-05 | 文章详情@某人高亮与一键加好友(解析@、调添加好友接口) | [2026-03-05.md](./2026-03-05.md) |
|
||||
12
.cursor/agent/开发助理/README.md
Normal file
12
.cursor/agent/开发助理/README.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# 开发助理(橙子)
|
||||
|
||||
> 规则进化执行、通用经验池、项目索引。经验:`.cursor/agent/开发助理/evolution/`
|
||||
|
||||
## 目录结构
|
||||
|
||||
| 目录 | 说明 |
|
||||
|------|------|
|
||||
| evolution/ | 通用经验池 |
|
||||
| archived/ | 已归档经验 |
|
||||
| script/ | 规则进化 bat 入口 |
|
||||
| 项目索引/ | 各角色开发进度索引 |
|
||||
0
.cursor/agent/开发助理/archived/.gitkeep
Normal file
0
.cursor/agent/开发助理/archived/.gitkeep
Normal file
0
.cursor/agent/开发助理/evolution/.gitkeep
Normal file
0
.cursor/agent/开发助理/evolution/.gitkeep
Normal file
5
.cursor/agent/开发助理/evolution/2026-02-26.md
Normal file
5
.cursor/agent/开发助理/evolution/2026-02-26.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# 2026-02-26 | 助理橙子经验
|
||||
|
||||
> 本日经验条目,格式:类型 | 摘要 | 升级 Skill
|
||||
|
||||
---
|
||||
6
.cursor/agent/开发助理/evolution/索引.md
Normal file
6
.cursor/agent/开发助理/evolution/索引.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# 开发助理 经验索引(通用)
|
||||
|
||||
> 无明确角色归属的通用经验。助理橙子执行时可按需参考。
|
||||
|
||||
| 日期 | 摘要 | 文件 |
|
||||
|------|------|------|
|
||||
46
.cursor/agent/开发助理/script/一键-全部.bat
Normal file
46
.cursor/agent/开发助理/script/一键-全部.bat
Normal file
@@ -0,0 +1,46 @@
|
||||
@echo off
|
||||
chcp 65001 >nul
|
||||
set PYTHONUTF8=1
|
||||
set PYTHONIOENCODING=utf-8
|
||||
cd /d "%~dp0..\..\..\.."
|
||||
:menu
|
||||
cls
|
||||
echo ========================================
|
||||
echo 开发助理 - 规则进化 一键操作
|
||||
echo ========================================
|
||||
echo.
|
||||
echo 1. 添加经验(从 stdin 粘贴 JSON)
|
||||
echo 2. 列出经验池
|
||||
echo 3. 执行进化(归档 + 可选应用新规则)
|
||||
echo 4. 退出
|
||||
echo.
|
||||
set /p choice=请选择 (1-4):
|
||||
if "%choice%"=="1" goto add
|
||||
if "%choice%"=="2" goto list
|
||||
if "%choice%"=="3" goto evolve
|
||||
if "%choice%"=="4" exit
|
||||
goto menu
|
||||
|
||||
:add
|
||||
echo.
|
||||
echo 请粘贴 AI 输出的 JSON,按 Ctrl+Z 回车结束:
|
||||
python .cursor\scripts\evolution.py add --stdin
|
||||
pause
|
||||
goto menu
|
||||
|
||||
:list
|
||||
echo.
|
||||
python .cursor\scripts\evolution.py list
|
||||
pause
|
||||
goto menu
|
||||
|
||||
:evolve
|
||||
echo.
|
||||
set /p RULE_FILE=新规则文件路径(留空则仅归档):
|
||||
if "%RULE_FILE%"=="" (
|
||||
python .cursor\scripts\evolution.py evolve --archive
|
||||
) else (
|
||||
python .cursor\scripts\evolution.py evolve --archive --rule "%RULE_FILE%"
|
||||
)
|
||||
pause
|
||||
goto menu
|
||||
6
.cursor/agent/开发助理/script/一键-列出经验池.bat
Normal file
6
.cursor/agent/开发助理/script/一键-列出经验池.bat
Normal file
@@ -0,0 +1,6 @@
|
||||
@echo off
|
||||
chcp 65001 >nul
|
||||
cd /d "%~dp0..\..\..\.."
|
||||
echo 开发助理 - 列出经验池
|
||||
python .cursor\scripts\evolution.py list
|
||||
pause
|
||||
6
.cursor/agent/开发助理/script/一键-执行进化.bat
Normal file
6
.cursor/agent/开发助理/script/一键-执行进化.bat
Normal file
@@ -0,0 +1,6 @@
|
||||
@echo off
|
||||
chcp 65001 >nul
|
||||
cd /d "%~dp0..\..\..\.."
|
||||
echo 开发助理 - 执行进化(归档经验池)
|
||||
python .cursor\scripts\evolution.py evolve --archive
|
||||
pause
|
||||
12
.cursor/agent/开发助理/script/一键-添加经验.bat
Normal file
12
.cursor/agent/开发助理/script/一键-添加经验.bat
Normal file
@@ -0,0 +1,12 @@
|
||||
@echo off
|
||||
chcp 65001 >nul
|
||||
set PYTHONUTF8=1
|
||||
set PYTHONIOENCODING=utf-8
|
||||
cd /d "%~dp0..\..\..\.."
|
||||
echo 开发助理 - 添加经验
|
||||
echo.
|
||||
echo 请将 AI 输出的 JSON 粘贴到下方,按 Ctrl+Z 回车结束:
|
||||
echo.
|
||||
python .cursor\scripts\evolution.py add --stdin
|
||||
echo.
|
||||
pause
|
||||
38
.cursor/agent/开发助理/经验清单.md
Normal file
38
.cursor/agent/开发助理/经验清单.md
Normal file
@@ -0,0 +1,38 @@
|
||||
# 开发团队经验清单
|
||||
|
||||
> 跨角色经验索引。经验在 `agent/*/evolution/`,项目索引在 `agent/开发助理/项目索引/`。
|
||||
|
||||
---
|
||||
|
||||
## 各角色经验库
|
||||
|
||||
| 角色 | 项目索引 | 按日经验 |
|
||||
|------|----------|----------|
|
||||
| 小程序 | [agent/开发助理/项目索引/小程序.md](./项目索引/小程序.md) | agent/小程序开发工程师/evolution/ |
|
||||
| 管理端 | [agent/开发助理/项目索引/管理端.md](./项目索引/管理端.md) | agent/管理端开发工程师/evolution/ |
|
||||
| 后端 | [agent/开发助理/项目索引/后端.md](./项目索引/后端.md) | agent/后端工程师/evolution/ |
|
||||
| 产品 | [agent/开发助理/项目索引/产品.md](./项目索引/产品.md) | agent/产品经理/evolution/ |
|
||||
| 测试 | [agent/开发助理/项目索引/测试.md](./项目索引/测试.md) | agent/软件测试/evolution/ |
|
||||
| 助理橙子 | [agent/开发助理/项目索引/助理橙子.md](./项目索引/助理橙子.md) | agent/开发助理/evolution/ |
|
||||
| 团队(跨角色共享) | [agent/开发助理/项目索引/团队.md](./项目索引/团队.md) | agent/团队/evolution/ |
|
||||
|
||||
---
|
||||
|
||||
## 索引表
|
||||
|
||||
| 日期 | 角色 | 类型 | 升级 Skill | 摘要 |
|
||||
|------|------|------|------------|------|
|
||||
| 2026-02-27 | 小程序、团队 | 最佳实践 | SKILL-小程序开发 §6、SKILL-管理端开发 §4.1 | 输入框 padding 用 view/div 包裹 |
|
||||
| 2026-02-28 | 小程序、管理端 | 最佳实践 | miniprogram §6、admin §4.1 | input 边距口诀「外边包 view、内部 width 100%」;match 弹窗已修正 |
|
||||
| 2026-03-03 | 小程序 | 最佳实践 | miniprogram §8 | 我的页面卡片区边距 16rpx,个人中心类页面布局规范 |
|
||||
|
||||
---
|
||||
|
||||
## 已吸收经验(历史)
|
||||
|
||||
- **SetVipModal**:SKILL-管理端开发 4.1 表单弹窗
|
||||
- **vip_roles**:SKILL-API开发 3.2、SKILL-MySQL直接操作 8
|
||||
|
||||
---
|
||||
|
||||
**最后更新**:2026-03-03
|
||||
3
.cursor/agent/开发助理/项目索引/README.md
Normal file
3
.cursor/agent/开发助理/项目索引/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# 项目索引
|
||||
|
||||
存放各角色子项目开发进度、状态。每角色对应一份索引。
|
||||
27
.cursor/agent/开发助理/项目索引/产品.md
Normal file
27
.cursor/agent/开发助理/项目索引/产品.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# 产品 - 项目索引
|
||||
|
||||
> 根据开发进度对项目做总结,保存开发进度,方便下次继续开发。**每次保存必须写日期**。
|
||||
|
||||
---
|
||||
|
||||
## 项目总结
|
||||
|
||||
Soul 创业派对产品定位:面向创业者的社区/工具型小程序。核心需求文档在 `开发文档/1、需求/需求汇总.md`,项目推进表在 `开发文档/10、项目管理/项目落地推进表.md`,临时需求/分析在 `临时需求池/`。
|
||||
|
||||
---
|
||||
|
||||
## 开发进度
|
||||
|
||||
| 日期 | 摘要 | 状态 |
|
||||
|------|------|------|
|
||||
| 2026-02-26 | 项目索引初始化,.cursor 规则优化完成 | 已完成 |
|
||||
| 2026-02-27 | 开发进度同步会议:汇报进度,待办「资料不解锁」补充、≥3 章弹窗明确 | 已完成 |
|
||||
| 2026-02-28 | stitch_soul 需求评审:内容→会员→导师变现路径,待产品补充正式需求文档 | 待续 |
|
||||
| 2026-03-05 | 分支冲突后功能完整性分析会议:核对需求文档与实现一致性 | 待续 |
|
||||
| 2026-03-05 | 文章详情@某人加好友方案讨论:验收标准、添加好友接口 path 待确认 | 待续 |
|
||||
|
||||
> **格式说明**:每次开发后在此追加一行,日期格式 YYYY-MM-DD,状态用:已完成 / 进行中 / 待续 / 搁置
|
||||
|
||||
---
|
||||
|
||||
**最后更新**:2026-03-05
|
||||
24
.cursor/agent/开发助理/项目索引/助理橙子.md
Normal file
24
.cursor/agent/开发助理/项目索引/助理橙子.md
Normal file
@@ -0,0 +1,24 @@
|
||||
# 助理橙子 - 项目索引
|
||||
|
||||
> 根据开发进度对项目做总结,保存开发进度,方便下次继续开发。**每次保存必须写日期**。
|
||||
|
||||
---
|
||||
|
||||
## 项目总结
|
||||
|
||||
助理橙子负责开发团队文档同步与经验升级。触发词:小橙/橙子/橙橙/🍊。核心流程文件:`SKILL-助理橙子-文档同步.md`。经验结构:agent/*/evolution 按角色 + 按日/按条存储 + 项目索引。
|
||||
|
||||
---
|
||||
|
||||
## 开发进度
|
||||
|
||||
| 日期 | 摘要 | 状态 |
|
||||
|------|------|------|
|
||||
| 2026-02-26 | 项目索引初始化;经验库五角色目录结构搭建;SKILL 补充角色映射表与跨端写入规则 | 已完成 |
|
||||
| 2026-02-28 | .cursor 按 cursor标准模板 重构:agent 目录、config、evolution.py、meeting | 已完成 |
|
||||
|
||||
> **格式说明**:每次开发后在此追加一行,日期格式 YYYY-MM-DD,状态用:已完成 / 进行中 / 待续 / 搁置
|
||||
|
||||
---
|
||||
|
||||
**最后更新**:2026-02-28
|
||||
28
.cursor/agent/开发助理/项目索引/后端.md
Normal file
28
.cursor/agent/开发助理/项目索引/后端.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# 后端 - 项目索引
|
||||
|
||||
> 根据开发进度对项目做总结,保存开发进度,方便下次继续开发。**每次保存必须写日期**。
|
||||
|
||||
---
|
||||
|
||||
## 项目总结
|
||||
|
||||
soul-api(Go + Gin + GORM + MySQL)提供三组路由:`/api/miniprogram/*`(小程序)、`/api/admin/*` + `/api/db/*`(管理端)、`/api/payment/*`(支付回调)。微信生态通过 PowerWeChat 集成。当前核心模块:用户、订单、分销、VIP、提现、章节、配置。
|
||||
|
||||
---
|
||||
|
||||
## 开发进度
|
||||
|
||||
| 日期 | 摘要 | 状态 |
|
||||
|------|------|------|
|
||||
| 2026-02-26 | 项目索引初始化,.cursor 规则优化完成 | 已完成 |
|
||||
| 2026-02-27 | 开发进度汇报:computeOrderCommission 会员分润差异化(20%/10%)已实现;vip_roles、vip_activated_at、referral_config 扩展已完成;miniprogram/admin/db 三组路由就绪 | 已完成 |
|
||||
| 2026-02-27 | 开发进度同步会议:进度已同步至开发文档,待办资料完善校验 | 已完成 |
|
||||
| 2026-02-28 | stitch_soul 需求评审:需梳理 chapter/book/vip,设计导师/预约/会员权益模型与接口 | 待续 |
|
||||
| 2026-03-05 | 分支冲突后功能完整性分析会议:在 soul-api 确认合并状态,核对 orders、distribution 接口 | 待续 |
|
||||
| 2026-03-05 | 文章详情@某人加好友方案讨论:content 内嵌 @ 标记、miniprogram 添加好友接口 | 待续 |
|
||||
|
||||
> **格式说明**:每次开发后在此追加一行,日期格式 YYYY-MM-DD,状态用:已完成 / 进行中 / 待续 / 搁置
|
||||
|
||||
---
|
||||
|
||||
**最后更新**:2026-03-05
|
||||
24
.cursor/agent/开发助理/项目索引/团队.md
Normal file
24
.cursor/agent/开发助理/项目索引/团队.md
Normal file
@@ -0,0 +1,24 @@
|
||||
# 团队 - 项目索引
|
||||
|
||||
> 跨角色共享的架构决策、业务规则、团队级经验。根据讨论进度更新,**每次保存必须写日期**。
|
||||
|
||||
---
|
||||
|
||||
## 项目总结
|
||||
|
||||
Soul 创业派对全项目架构与约定:路由隔离(miniprogram/admin/db)、三端协同流程、经验按角色+按日存储、会议纪要独立存档、语义触发词驱动角色切换。
|
||||
|
||||
---
|
||||
|
||||
## 开发进度
|
||||
|
||||
| 日期 | 摘要 | 状态 |
|
||||
|------|------|------|
|
||||
| 2026-02-27 | 项目索引初始化;团队经验库目录建立 | 已完成 |
|
||||
| 2026-02-28 | stitch_soul 需求评审:内容→会员→导师变现路径,需与现有三端架构协同 | 已完成 |
|
||||
|
||||
> **格式说明**:每次架构级讨论后在此追加一行,日期格式 YYYY-MM-DD
|
||||
|
||||
---
|
||||
|
||||
**最后更新**:2026-02-28
|
||||
31
.cursor/agent/开发助理/项目索引/小程序.md
Normal file
31
.cursor/agent/开发助理/项目索引/小程序.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# 小程序 - 项目索引
|
||||
|
||||
> 根据开发进度对项目做总结,保存开发进度,方便下次继续开发。**每次保存必须写日期**。
|
||||
|
||||
---
|
||||
|
||||
## 项目总结
|
||||
|
||||
小程序(微信原生)C 端主要功能:用户注册/登录、VIP 购买、章节阅读、分销推荐、提现申请、找伙伴。当前已上线核心功能,持续迭代优化中。
|
||||
|
||||
---
|
||||
|
||||
## 开发进度
|
||||
|
||||
| 日期 | 摘要 | 状态 |
|
||||
|------|------|------|
|
||||
| 2026-02-26 | 项目索引初始化,.cursor 规则优化完成 | 已完成 |
|
||||
| 2026-02-27 | 开发进度汇报:永平落地已完成(海报 scene、我的收益、推广中心、VIP 相关);找伙伴、提现、阅读、分销核心功能已上线 | 已完成 |
|
||||
| 2026-02-27 | 开发进度同步会议:进度已同步至开发文档,待办资料完善弹窗、≥3 章弹窗 | 已完成 |
|
||||
| 2026-02-27 | 吸收经验:输入框 padding 用 view 包裹,已升级 SKILL-小程序开发 §6 | 已完成 |
|
||||
| 2026-02-28 | stitch_soul 需求评审:首页/目录/导师/会员/资料五类页面,待需求与接口确定后分阶段实现 | 待续 |
|
||||
| 2026-02-28 | 吸收经验:input 边距口诀「外边包 view、内部 width 100%」写入 Skill §6;match 资源对接弹窗已按规范修正 | 已完成 |
|
||||
| 2026-03-03 | 吸收经验:我的页面卡片区边距优化,16rpx 为个人中心类页面推荐值,已升级 SKILL §8 | 已完成 |
|
||||
| 2026-03-05 | 分支冲突后功能完整性分析会议:修正 app.json 拆行、核心流程自测、确认 orders 接口 | 待续 |
|
||||
| 2026-03-05 | 文章详情@某人加好友方案讨论:阅读页解析 @、高亮可点击、调添加好友接口 | 待续 |
|
||||
|
||||
> **格式说明**:每次开发后在此追加一行,日期格式 YYYY-MM-DD,状态用:已完成 / 进行中 / 待续 / 搁置
|
||||
|
||||
---
|
||||
|
||||
**最后更新**:2026-03-05
|
||||
25
.cursor/agent/开发助理/项目索引/测试.md
Normal file
25
.cursor/agent/开发助理/项目索引/测试.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# 测试 - 项目索引
|
||||
|
||||
> 测试人员经验与测试进度。**每次保存必须写日期**。
|
||||
|
||||
---
|
||||
|
||||
## 项目总结
|
||||
|
||||
测试人员负责小程序、管理端、API 的功能测试、回归测试与三端联调。主 Skill:SKILL-测试.md。
|
||||
|
||||
---
|
||||
|
||||
## 开发/测试进度
|
||||
|
||||
| 日期 | 进度摘要 | 状态 |
|
||||
|------|----------|------|
|
||||
| 2026-02-27 | 测试人员角色与 Skill 初始化 | 已完成 |
|
||||
| 2026-02-27 | 小程序静态审查(API 路径、页面接口、手工验证建议) | 已完成 |
|
||||
| 2026-02-28 | stitch_soul 需求评审:关键场景为阅读/付费/会员/导师预约/资料;待需求确定后补充联调用例 | 待续 |
|
||||
| 2026-03-05 | 分支冲突后功能完整性分析会议:制定「分支合并后回归清单」 | 待续 |
|
||||
| 2026-03-05 | 文章详情@某人加好友方案讨论:@ 展示与添加好友用例、联调与回归 | 待续 |
|
||||
|
||||
---
|
||||
|
||||
**最后更新**:2026-03-05
|
||||
28
.cursor/agent/开发助理/项目索引/管理端.md
Normal file
28
.cursor/agent/开发助理/项目索引/管理端.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# 管理端 - 项目索引
|
||||
|
||||
> 根据开发进度对项目做总结,保存开发进度,方便下次继续开发。**每次保存必须写日期**。
|
||||
|
||||
---
|
||||
|
||||
## 项目总结
|
||||
|
||||
管理端(React + Vite + Tailwind)主要功能:用户管理、订单管理、提现审核、VIP 管理、内容/章节管理、配置项管理、数据统计。调用 `/api/admin/*` 与 `/api/db/*` 接口,JWT Bearer 鉴权。
|
||||
|
||||
---
|
||||
|
||||
## 开发进度
|
||||
|
||||
| 日期 | 摘要 | 状态 |
|
||||
|------|------|------|
|
||||
| 2026-02-26 | 项目索引初始化,.cursor 规则优化完成 | 已完成 |
|
||||
| 2026-02-27 | 开发进度汇报:内容管理仅 API 按钮、推广中心、SetVipModal、VIP 角色管理、推广设置会员分润配置、VIP 排序等均已落地 | 已完成 |
|
||||
| 2026-02-27 | 开发进度同步会议:进度已同步至运营与变更 | 已完成 |
|
||||
| 2026-02-28 | stitch_soul 需求评审:待后端方案确定后规划章节/导师/会员/预约管理页面 | 待续 |
|
||||
| 2026-03-05 | 分支冲突后功能完整性分析会议:全功能自测,记录 404/异常接口 | 待续 |
|
||||
| 2026-03-05 | 文章详情@某人加好友方案讨论:编辑页插入 @用户、保存约定 content 格式 | 待续 |
|
||||
|
||||
> **格式说明**:每次开发后在此追加一行,日期格式 YYYY-MM-DD,状态用:已完成 / 进行中 / 待续 / 搁置
|
||||
|
||||
---
|
||||
|
||||
**最后更新**:2026-03-05
|
||||
0
.cursor/agent/管理端开发工程师/evolution/.gitkeep
Normal file
0
.cursor/agent/管理端开发工程师/evolution/.gitkeep
Normal file
5
.cursor/agent/管理端开发工程师/evolution/2026-02-26.md
Normal file
5
.cursor/agent/管理端开发工程师/evolution/2026-02-26.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# 2026-02-26 | 管理端经验
|
||||
|
||||
> 本日经验条目,格式:类型 | 摘要 | 升级 Skill
|
||||
|
||||
---
|
||||
16
.cursor/agent/管理端开发工程师/evolution/2026-02-28.md
Normal file
16
.cursor/agent/管理端开发工程师/evolution/2026-02-28.md
Normal file
@@ -0,0 +1,16 @@
|
||||
# 管理端开发工程师 经验记录 - 2026-02-28
|
||||
|
||||
## stitch_soul 需求评审会议
|
||||
|
||||
- **待支撑能力**:章节管理(增删改、排序、免费/付费/NEW)、导师管理(审核、标签、价格、展示)、会员配置(权益、价格、有效期)、预约管理(列表、状态)。
|
||||
- **接口依赖**:`/api/admin/*` 与 `/api/db/*`;字段需与 miniprogram 端统一。
|
||||
- **时机**:待后端方案确定后规划管理端页面与接口对接。
|
||||
|
||||
## 个人资料页实现评估会议
|
||||
|
||||
- **无新增任务**:个人资料展示/编辑为 C 端能力,管理端沿用现有能力即可。
|
||||
|
||||
## 文章类型(普通版/增值版)需求分析会议
|
||||
|
||||
- **书籍版本配置**:支持选择普通版/增值版;配置「后 N 章」的 N。
|
||||
- **章节标注**:章节列表需标注是否为增值章节;单价取自 chapters.price。
|
||||
12
.cursor/agent/管理端开发工程师/evolution/2026-03-05.md
Normal file
12
.cursor/agent/管理端开发工程师/evolution/2026-03-05.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# 管理端开发工程师 经验记录 - 2026-03-05
|
||||
|
||||
## 分支冲突后功能完整性分析会议
|
||||
|
||||
- **路由与页面结构完整时**:主要风险在接口可用性。全功能自测可快速暴露 404 或异常接口。
|
||||
- **重点确认**:`DistributionPage` 调用的 `GET /api/db/distribution` 是否已实现;`OrdersPage` 的订单接口路径是否与 soul-api 一致。
|
||||
- **建议**:分支合并后做一次管理端全流程自测(登录→订单→提现→分销→VIP 角色→导师→配置),记录异常接口反馈后端。
|
||||
|
||||
## 文章详情 @某人 高亮与一键加好友方案讨论
|
||||
|
||||
- **编辑侧**:文章/章节编辑页增加「插入 @用户」,选择用户后插入到光标位置,保存时写入约定格式 content(如 `@[昵称](userId)`);仅调 `/api/admin/*`、`/api/db/*`。
|
||||
- **一致性**:与小程序、后端共用同一 content 格式,避免多套标记;列表/预览可简单高亮或原样显示。
|
||||
6
.cursor/agent/管理端开发工程师/evolution/索引.md
Normal file
6
.cursor/agent/管理端开发工程师/evolution/索引.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# 管理端开发工程师 经验索引
|
||||
|
||||
| 日期 | 摘要 | 文件 |
|
||||
|------|------|------|
|
||||
| 2026-03-05 | 分支合并后全功能自测,404/异常接口记录 | [2026-03-05.md](./2026-03-05.md) |
|
||||
| 2026-03-05 | 文章详情@某人:编辑页插入 @用户、保存约定 content 格式 | [2026-03-05.md](./2026-03-05.md) |
|
||||
0
.cursor/agent/老板分身/evolution/.gitkeep
Normal file
0
.cursor/agent/老板分身/evolution/.gitkeep
Normal file
4
.cursor/agent/老板分身/evolution/索引.md
Normal file
4
.cursor/agent/老板分身/evolution/索引.md
Normal file
@@ -0,0 +1,4 @@
|
||||
# 老板分身 经验索引
|
||||
|
||||
| 日期 | 摘要 | 文件 |
|
||||
|------|------|------|
|
||||
0
.cursor/agent/软件测试/evolution/.gitkeep
Normal file
0
.cursor/agent/软件测试/evolution/.gitkeep
Normal file
65
.cursor/agent/软件测试/evolution/2026-02-27.md
Normal file
65
.cursor/agent/软件测试/evolution/2026-02-27.md
Normal file
@@ -0,0 +1,65 @@
|
||||
# 测试 - 经验记录 - 2026-02-27
|
||||
|
||||
## 小程序静态审查报告
|
||||
|
||||
**测试时间**:2026-02-27
|
||||
**测试方式**:代码级静态分析
|
||||
**测试范围**:miniprogram 全目录(不含 backup 文件)
|
||||
|
||||
---
|
||||
|
||||
### 一、API 路径隔离检查 ✅ 通过
|
||||
|
||||
| 检查项 | 结果 | 说明 |
|
||||
|--------|------|------|
|
||||
| 是否只调 /api/miniprogram/* | ✅ | 所有 app.request 均使用 miniprogram 路径 |
|
||||
| 是否误调 /api/admin/*、/api/db/* | ✅ | 无违规调用 |
|
||||
| wx.uploadFile URL | ✅ | 使用 baseUrl + /api/miniprogram/upload |
|
||||
|
||||
**说明**:`read.js.backup` 中曾有 `/api/db/config`,该文件为备份,非线上代码。
|
||||
|
||||
---
|
||||
|
||||
### 二、主要页面与接口映射
|
||||
|
||||
| 页面/模块 | 主要接口 | 状态 |
|
||||
|-----------|----------|------|
|
||||
| 首页 index | vip/members、users、book/all-chapters | ✅ |
|
||||
| 目录 chapters | book/all-chapters | ✅ |
|
||||
| 阅读 read | book/chapter、purchase-status、pay、qrcode | ✅ |
|
||||
| 我的 my | config、withdraw/*、earnings、user/update、vip/status | ✅ |
|
||||
| VIP vip | vip/status、vip/profile、upload、pay | ✅ |
|
||||
| 推广 referral | referral/data、qrcode、withdraw | ✅ |
|
||||
| 匹配 match | match/config、match/users、ckb/join、ckb/match、pay | ✅ |
|
||||
| 设置 settings | user/update、user/profile、phone、upload | ✅ |
|
||||
| 地址 addresses | user/addresses | ✅ |
|
||||
| 提现记录 | withdraw/records、confirm-info | ✅ |
|
||||
| 购买记录 purchases | orders | ✅ |
|
||||
| 会员详情 member-detail | vip/members、users | ✅ |
|
||||
| 搜索 search | book/hot、book/search | ✅ |
|
||||
|
||||
---
|
||||
|
||||
### 三、建议手工验证场景
|
||||
|
||||
| 场景 | 验证点 | 优先级 |
|
||||
|------|--------|--------|
|
||||
| 登录 | 微信登录、token 持久化、401 跳转 | 高 |
|
||||
| VIP 购买 | 下单、支付、开通成功、资料填写、头像上传 | 高 |
|
||||
| 推荐码 | 分享带 ref、扫码绑定、分润展示 | 高 |
|
||||
| 超级个体 | 加载骨架、头像展示、点击进详情 | 中 |
|
||||
| 朋友圈分享 | 所有页面右上角「分享到朋友圈」可点 | 中 |
|
||||
| 提现 | 申请、记录、确认收款 | 中 |
|
||||
| 地址管理 | 增删改查、默认地址 | 低 |
|
||||
|
||||
---
|
||||
|
||||
### 四、发现与建议
|
||||
|
||||
1. **输入框规范**:VIP 等表单已按「view 包裹 input」规范实现,符合 SKILL-小程序开发 §6。
|
||||
2. **朋友圈分享**:各页面已启用 wx.showShareMenu + onShareTimeline,推荐码会随 query 传递。
|
||||
3. **超级个体**:已有 4 圆形骨架加载动画,加载完成后再展示内容或空态。
|
||||
|
||||
---
|
||||
|
||||
**结论**:小程序代码在 API 路径隔离、规范遵从方面**通过静态审查**。建议在真机/模拟器中按上表手工验证核心流程。
|
||||
16
.cursor/agent/软件测试/evolution/2026-02-28.md
Normal file
16
.cursor/agent/软件测试/evolution/2026-02-28.md
Normal file
@@ -0,0 +1,16 @@
|
||||
# 测试人员 经验记录 - 2026-02-28
|
||||
|
||||
## stitch_soul 需求评审会议
|
||||
|
||||
- **关键联调场景**:阅读进度、免费/付费解锁、会员权益、导师预约与支付、资料完善与提现限制。
|
||||
- **三端**:miniprogram ↔ soul-api、soul-admin ↔ soul-api;变更后需回归支付、登录、提现等现有流程。
|
||||
- **待办**:需求确定后补充三端联调用例与回归清单。
|
||||
|
||||
## 个人资料页实现评估会议
|
||||
|
||||
- **验证点**:profile-show 与 profile-edit 字段一一对应;保存后两页及「我的」数据一致;手机/微信号脱敏与复制;头像上传、昵称、MBTI 选择。
|
||||
|
||||
## 文章类型(普通版/增值版)需求分析会议
|
||||
|
||||
- **用例**:普通版 9.9 买断全书;增值版基础价+逐章购买、价格累加正确。
|
||||
- **边界**:N=0、N=全书、章节无单价时的降级逻辑。
|
||||
13
.cursor/agent/软件测试/evolution/2026-03-05.md
Normal file
13
.cursor/agent/软件测试/evolution/2026-03-05.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# 软件测试 经验记录 - 2026-03-05
|
||||
|
||||
## 分支冲突后功能完整性分析会议
|
||||
|
||||
- **分支合并后应制定「回归清单」**:覆盖三端联调关键路径(登录、VIP、阅读、分销、提现、找伙伴、个人资料、导师、购买记录)。
|
||||
- **soul-api 不在仓库时**:需与后端协作确认接口契约,无法在仓库内直接检查。
|
||||
- **多分支合并**:`完整的`、`soul-content`、`yongpxu-soul` 等分支合并结果需确认,各端自测 + 测试抽检。
|
||||
|
||||
## 文章详情 @某人 高亮与一键加好友方案讨论
|
||||
|
||||
- **用例**:无 @ 行为不变;有 @ 高亮且点击调起添加好友并提示;重复点击、未登录、无权限等边界;管理端插入 @ 后保存再编辑不错位。
|
||||
- **联调**:小程序↔章节接口(content 含 @)、小程序↔添加好友接口;管理端↔内容保存与用户列表。
|
||||
- **回归**:阅读页进度、购买、分享等不受 @ 功能影响。
|
||||
6
.cursor/agent/软件测试/evolution/索引.md
Normal file
6
.cursor/agent/软件测试/evolution/索引.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# 软件测试 经验索引
|
||||
|
||||
| 日期 | 摘要 | 文件 |
|
||||
|------|------|------|
|
||||
| 2026-03-05 | 分支合并后回归清单制定;三端联调验证 | [2026-03-05.md](./2026-03-05.md) |
|
||||
| 2026-03-05 | 文章详情@某人:@ 展示与添加好友用例、联调与回归点 | [2026-03-05.md](./2026-03-05.md) |
|
||||
3
.cursor/archive/README.md
Normal file
3
.cursor/archive/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# 历史归档
|
||||
|
||||
存放已归档的文档、分析报告等。
|
||||
BIN
.cursor/config/__pycache__/paths.cpython-311.pyc
Normal file
BIN
.cursor/config/__pycache__/paths.cpython-311.pyc
Normal file
Binary file not shown.
13
.cursor/config/model_switch.json
Normal file
13
.cursor/config/model_switch.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"default": "cursor",
|
||||
"roles": [
|
||||
{"role": "老板分身", "model": "cursor"},
|
||||
{"role": "开发助理", "model": "cursor"},
|
||||
{"role": "小程序开发工程师", "model": "cursor"},
|
||||
{"role": "管理端开发工程师", "model": "cursor"},
|
||||
{"role": "后端工程师", "model": "cursor"},
|
||||
{"role": "产品经理", "model": "cursor"},
|
||||
{"role": "软件测试", "model": "cursor"},
|
||||
{"role": "团队", "model": "cursor"}
|
||||
]
|
||||
}
|
||||
97
.cursor/config/paths.py
Normal file
97
.cursor/config/paths.py
Normal file
@@ -0,0 +1,97 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Soul 创业派对 - 路径别名
|
||||
以项目根为工作区,脚本统一引用。迁移到其他电脑时只需修改 workspace.txt。
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
# ========== 工作区根目录 ==========
|
||||
_THIS_FILE = Path(__file__).resolve()
|
||||
_CURSOR_DIR = _THIS_FILE.parent.parent
|
||||
ROOT = _CURSOR_DIR.parent
|
||||
|
||||
_WORKSPACE_OVERRIDE = _THIS_FILE.parent / "workspace.txt"
|
||||
if _WORKSPACE_OVERRIDE.exists():
|
||||
for line in _WORKSPACE_OVERRIDE.read_text(encoding="utf-8").strip().splitlines():
|
||||
line = line.strip()
|
||||
if line and not line.startswith("#"):
|
||||
ROOT = Path(line).resolve()
|
||||
break
|
||||
|
||||
# ========== 核心目录别名 ==========
|
||||
CURSOR = ROOT / ".cursor"
|
||||
RULES = CURSOR / "rules"
|
||||
SKILLS = CURSOR / "skills"
|
||||
SCRIPTS = CURSOR / "scripts"
|
||||
PROCESS = CURSOR / "process"
|
||||
MEETING = CURSOR / "meeting"
|
||||
ARCHIVE = CURSOR / "archive"
|
||||
CONFIG = CURSOR / "config"
|
||||
MODEL_SWITCH = CONFIG / "model_switch.json"
|
||||
DOCS = CURSOR / "docs"
|
||||
|
||||
# ========== Agent 目录(Soul 开发团队结构) ==========
|
||||
AGENT = CURSOR / "agent"
|
||||
|
||||
# 管理层
|
||||
AGENT_LEAD = AGENT / "老板分身"
|
||||
EVOLUTION_LEAD = AGENT_LEAD / "evolution"
|
||||
|
||||
# 支撑层
|
||||
AGENT_ASSISTANT = AGENT / "开发助理"
|
||||
EVOLUTION_ORANGE = AGENT_ASSISTANT / "evolution"
|
||||
ARCHIVED_ORANGE = AGENT_ASSISTANT / "archived"
|
||||
PROJECT_INDEX = AGENT_ASSISTANT / "项目索引"
|
||||
SCRIPT_ORANGE = AGENT_ASSISTANT / "script"
|
||||
|
||||
# Soul 开发角色
|
||||
AGENT_MINIPROGRAM = AGENT / "小程序开发工程师"
|
||||
AGENT_ADMIN = AGENT / "管理端开发工程师"
|
||||
AGENT_BACKEND = AGENT / "后端工程师"
|
||||
AGENT_PRODUCT = AGENT / "产品经理"
|
||||
AGENT_TEST = AGENT / "软件测试"
|
||||
AGENT_TEAM = AGENT / "团队"
|
||||
|
||||
# ========== 常用文件 ==========
|
||||
RULE_MAIN = RULES / "老板分身-索引.mdc"
|
||||
LOG_EVOLUTION = SCRIPTS / "进化日志.md"
|
||||
TEMPLATE_EXPERIENCE = SCRIPTS / "经验模板.md"
|
||||
|
||||
# ========== 角色 → agent 目录名映射 ==========
|
||||
ROLE_TO_AGENT = {
|
||||
# 管理层
|
||||
"老板分身": "老板分身",
|
||||
"开发助理": "开发助理",
|
||||
"助理橙子": "开发助理",
|
||||
"助手橙子": "开发助理",
|
||||
# Soul 开发角色
|
||||
"小程序开发工程师": "小程序开发工程师",
|
||||
"小程序": "小程序开发工程师",
|
||||
"管理端开发工程师": "管理端开发工程师",
|
||||
"管理端": "管理端开发工程师",
|
||||
"后端工程师": "后端工程师",
|
||||
"后端": "后端工程师",
|
||||
"后端开发": "后端工程师",
|
||||
# 产品与质量
|
||||
"产品经理": "产品经理",
|
||||
"产品": "产品经理",
|
||||
"软件测试": "软件测试",
|
||||
"测试": "软件测试",
|
||||
"测试人员": "软件测试",
|
||||
# 通用
|
||||
"团队": "团队",
|
||||
}
|
||||
|
||||
|
||||
def agent_evolution(role: str) -> Path:
|
||||
"""获取角色对应的 evolution 目录。"""
|
||||
agent_name = ROLE_TO_AGENT.get(role, role)
|
||||
return AGENT / agent_name / "evolution"
|
||||
|
||||
|
||||
def agent_script(role: str) -> Path:
|
||||
"""获取角色对应的 script 目录。"""
|
||||
agent_name = ROLE_TO_AGENT.get(role, role)
|
||||
return AGENT / agent_name / "script"
|
||||
1
.cursor/config/workspace.txt
Normal file
1
.cursor/config/workspace.txt
Normal file
@@ -0,0 +1 @@
|
||||
E:/Gongsi/Mycontent
|
||||
2
.cursor/config/workspace.txt.example
Normal file
2
.cursor/config/workspace.txt.example
Normal file
@@ -0,0 +1,2 @@
|
||||
# 复制本文件为 workspace.txt,取消下行注释并填入你的项目根绝对路径
|
||||
# {{PROJECT_ROOT_PATH}}
|
||||
45
.cursor/config/目录地图.md
Normal file
45
.cursor/config/目录地图.md
Normal file
@@ -0,0 +1,45 @@
|
||||
# .cursor 目录地图 - Soul 创业派对
|
||||
|
||||
> 脚本统一通过 `config/paths.py` 引用路径。迁移时只需改 `workspace.txt` 即可。
|
||||
|
||||
---
|
||||
|
||||
## 一、工作区覆盖(迁移用)
|
||||
|
||||
| 文件 | 说明 |
|
||||
|------|------|
|
||||
| `.cursor/config/workspace.txt` | 可选。写入一行**绝对路径**,覆盖自动推断的项目根。迁移到其他电脑时创建此文件即可。 |
|
||||
|
||||
---
|
||||
|
||||
## 二、核心别名一览
|
||||
|
||||
| 别名 | 路径 | 说明 |
|
||||
|------|------|------|
|
||||
| `ROOT` | 项目根 | 工作区根目录 |
|
||||
| `CURSOR` | `.cursor/` | cursor 配置根 |
|
||||
| `RULES` | `.cursor/rules/` | 规则 |
|
||||
| `SKILLS` | `.cursor/skills/` | 技能 |
|
||||
| `SCRIPTS` | `.cursor/scripts/` | 脚本 |
|
||||
| `PROCESS` | `.cursor/process/` | 工作流 |
|
||||
| `MEETING` | `.cursor/meeting/` | 会议纪要 |
|
||||
| `ARCHIVE` | `.cursor/archive/` | 历史归档 |
|
||||
| `DOCS` | `.cursor/docs/` | 文档 |
|
||||
| `CONFIG` | `.cursor/config/` | 配置 |
|
||||
| `MODEL_SWITCH` | `.cursor/config/model_switch.json` | 按角色配置模型 |
|
||||
|
||||
---
|
||||
|
||||
## 三、Agent 目录(Soul 开发团队结构)
|
||||
|
||||
| 别名 | 路径 | 说明 |
|
||||
|------|------|------|
|
||||
| `AGENT` | `.cursor/agent/` | 智能体根 |
|
||||
| `AGENT_LEAD` | `.cursor/agent/老板分身/` | 老板分身(最高权限) |
|
||||
| `AGENT_ASSISTANT` | `.cursor/agent/开发助理/` | 开发助理(橙子) |
|
||||
| `AGENT_MINIPROGRAM` | `.cursor/agent/小程序开发工程师/` | 小程序开发 |
|
||||
| `AGENT_ADMIN` | `.cursor/agent/管理端开发工程师/` | 管理端开发 |
|
||||
| `AGENT_BACKEND` | `.cursor/agent/后端工程师/` | 后端开发 |
|
||||
| `AGENT_PRODUCT` | `.cursor/agent/产品经理/` | 产品经理 |
|
||||
| `AGENT_TEST` | `.cursor/agent/软件测试/` | 测试人员 |
|
||||
| `AGENT_TEAM` | `.cursor/agent/团队/` | 跨角色共享经验 |
|
||||
174
.cursor/docs/三角色边界定义.md
Normal file
174
.cursor/docs/三角色边界定义.md
Normal file
@@ -0,0 +1,174 @@
|
||||
# Soul 创业派对 - 三角色边界定义(开发)
|
||||
|
||||
> 按各自负责的**源码目录**与**业务功能**定义,防止互窜、明确职责。团队为 **2 前端 + 1 后端 + 1 产品 + 1 助理**,详见 [开发团队职责定义.md](./开发团队职责定义.md)。
|
||||
|
||||
---
|
||||
|
||||
## 一、开发角色总览
|
||||
|
||||
| 角色 | 源码目录 | 对接 API 前缀 | 技术栈 |
|
||||
|------|----------|---------------|--------|
|
||||
| 小程序开发工程师 | miniprogram/ | /api/miniprogram/* | 微信原生 WXML/WXSS/JS |
|
||||
| 管理端开发工程师 | soul-admin/ | /api/admin/*、/api/db/* | React + Vite + TypeScript + Tailwind |
|
||||
| 后端开发 | soul-api/ | 实现上述全部 | Go + Gin + GORM + PowerWeChat |
|
||||
|
||||
---
|
||||
|
||||
## 二、小程序开发工程师
|
||||
|
||||
### 2.1 负责源码
|
||||
|
||||
| 路径 | 说明 |
|
||||
|------|------|
|
||||
| miniprogram/pages/* | 页面(index、chapters、read、my、referral、match、settings、withdraw-records、vip 等) |
|
||||
| miniprogram/utils/* | 工具(scene、payment、chapterAccessManager、readingTracker) |
|
||||
| miniprogram/components/* | 组件 |
|
||||
| miniprogram/custom-tab-bar/* | 自定义 TabBar |
|
||||
| miniprogram/app.js、app.json、app.wxss | 全局配置与入口 |
|
||||
|
||||
### 2.2 负责业务功能
|
||||
|
||||
| 功能域 | 页面/入口 | 对接接口 |
|
||||
|--------|-----------|----------|
|
||||
| 首页与浏览 | index、chapters、search | /api/miniprogram/book/*、config |
|
||||
| 阅读与付费 | read | /api/miniprogram/pay、pay/notify、user/check-purchased、user/purchase-status |
|
||||
| 找伙伴 | match | /api/miniprogram/match/*、ckb/* |
|
||||
| 推广与分销 | referral | /api/miniprogram/referral/*、earnings |
|
||||
| 提现 | 推广中心申请、我的待确认、withdraw-records | /api/miniprogram/withdraw、withdraw/records、withdraw/pending-confirm |
|
||||
| 我的 | my | /api/miniprogram/user/*、vip/*、withdraw/* |
|
||||
| 设置 | settings | /api/miniprogram/login、phone、config |
|
||||
| 地址 | addresses | /api/miniprogram/user/addresses |
|
||||
|
||||
### 2.3 边界约束
|
||||
|
||||
- **禁止**:调用 `/api/admin/*`、`/api/db/*`;不得使用 next-project 接口。
|
||||
- **请求**:统一通过 `getApp().request(url, options)`,baseUrl 指向 soul-api。
|
||||
|
||||
---
|
||||
|
||||
## 三、管理端开发工程师
|
||||
|
||||
### 3.1 负责源码
|
||||
|
||||
| 路径 | 说明 |
|
||||
|------|------|
|
||||
| soul-admin/src/pages/* | 页面(Dashboard、Content、Chapters、Orders、Users、Withdrawals、Payment、Settings、QRCodes、Distribution 等) |
|
||||
| soul-admin/src/components/* | 组件(ui、modules 等) |
|
||||
| soul-admin/src/api/* | 请求封装(client.ts、auth.ts) |
|
||||
| soul-admin/src/layouts/* | 布局 |
|
||||
| soul-admin/src/hooks/* | hooks |
|
||||
|
||||
### 3.2 负责业务功能
|
||||
|
||||
| 功能域 | 页面 | 对接接口 |
|
||||
|--------|------|----------|
|
||||
| 仪表盘 | DashboardPage | /api/admin/* |
|
||||
| 内容管理 | ContentPage | /api/admin/content |
|
||||
| 章节管理 | ChaptersPage | /api/admin/chapters |
|
||||
| 订单 | OrdersPage | /api/orders |
|
||||
| 用户管理 | UsersPage | /api/db/users |
|
||||
| 提现审核 | WithdrawalsPage | /api/admin/withdrawals |
|
||||
| 支付配置 | PaymentPage | /api/admin/payment |
|
||||
| 推广设置 | ReferralSettingsPage | /api/admin/referral-settings |
|
||||
| 系统设置 | SettingsPage | /api/admin/settings |
|
||||
| 二维码 | QRCodesPage | /api/db/config 等 |
|
||||
| 分销概览 | DistributionPage | /api/admin/distribution/overview |
|
||||
| VIP 角色 | VipRolesPage | /api/db/vip-roles |
|
||||
|
||||
### 3.3 边界约束
|
||||
|
||||
- **允许**:`/api/admin/*`、`/api/db/*`,以及 `/api/orders` 等与现网一致的管理端接口。
|
||||
- **禁止**:调用 `/api/miniprogram/*`;不得使用小程序登录或小程序 token。
|
||||
- **请求**:统一通过 `client.ts` 的 get/post/put/del;鉴权用 `auth.ts` 的 Bearer admin_token。
|
||||
|
||||
---
|
||||
|
||||
## 四、后端开发
|
||||
|
||||
### 4.1 负责源码
|
||||
|
||||
| 路径 | 说明 |
|
||||
|------|------|
|
||||
| soul-api/internal/router | 路由注册(miniprogram、admin、db、payment 各组) |
|
||||
| soul-api/internal/handler | 业务 handler |
|
||||
| soul-api/internal/model | 数据模型 |
|
||||
| soul-api/internal/wechat | 微信、支付、转账等封装 |
|
||||
| soul-api/internal/config | 配置加载 |
|
||||
| soul-api/internal/database | 数据库连接 |
|
||||
| soul-api/internal/auth | 鉴权(JWT) |
|
||||
| soul-api/internal/middleware | 中间件 |
|
||||
|
||||
### 4.2 负责路由分组与业务
|
||||
|
||||
| 路由组 | 前缀 | 使用方 | 典型业务 |
|
||||
|--------|------|--------|----------|
|
||||
| miniprogram | /api/miniprogram/* | 小程序 | 登录、支付、书籍、推荐、提现、VIP、用户 |
|
||||
| admin | /api/admin/* | 管理端 | 登录、章节、内容、支付配置、提现审核、设置、分销 |
|
||||
| db | /api/db/* | 管理端 | 用户、配置、书籍、章节、VIP 角色、初始化 |
|
||||
| payment | /api/payment/* | 微信/支付宝回调 | 支付回调、订单、商家转账回调 |
|
||||
|
||||
### 4.3 边界约束
|
||||
|
||||
- **按使用方挂路由**:小程序接口只挂 miniprogram;管理端接口只挂 admin/db;不得混用。
|
||||
- **禁止**:在 miniprogram 组挂仅 admin 用的接口;在 admin/db 组挂小程序专属逻辑。
|
||||
|
||||
### 4.4 特殊路由说明
|
||||
|
||||
| 类型 | 示例 | 说明 |
|
||||
|------|------|------|
|
||||
| 微信/支付宝回调 | /api/payment/*、/api/miniprogram/pay/notify | 由微信/支付宝主动调用,无鉴权;后端负责验签、解密 |
|
||||
| 管理端扁平路径 | /api/orders | 管理端使用,与 /api/admin/*、/api/db/* 并列 |
|
||||
|
||||
---
|
||||
|
||||
## 五、支付/提现相关职责归属
|
||||
|
||||
| 环节 | 小程序开发工程师 | 管理端开发工程师 | 后端开发 |
|
||||
|------|--------------|--------------|----------------|
|
||||
| 支付下单 | 调 /api/miniprogram/pay,调起 wx.requestPayment | - | 实现 Pay handler,调用微信统一下单 |
|
||||
| 支付回调 | - | - | 实现 PayNotify,验签、更新订单、分佣 |
|
||||
| 提现申请 | 调 /api/miniprogram/withdraw | - | 实现 WithdrawPost;校验余额、写 withdrawals |
|
||||
| 提现审核 | - | 调 /api/admin/withdrawals 列表、通过/拒绝 | 实现 AdminWithdrawalsList、Action;调微信打款 |
|
||||
| 提现回调 | - | - | 实现 PaymentWechatTransferNotify;验签、解密、更新状态 |
|
||||
| 待确认收款 | 调 /api/miniprogram/withdraw/pending-confirm | - | 实现 WithdrawPendingConfirm |
|
||||
|
||||
---
|
||||
|
||||
## 六、速查:编辑目录 → 角色
|
||||
|
||||
| 编辑目录 | 角色 | 必遵守 | 主 Skill |
|
||||
|----------|------|--------|----------|
|
||||
| miniprogram/** | 小程序开发工程师 | soul-miniprogram-boundary | SKILL-小程序开发.md |
|
||||
| soul-admin/** | 管理端开发工程师 | soul-admin-boundary | SKILL-管理端开发.md |
|
||||
| soul-api/** | 后端开发 | soul-api | SKILL-API开发.md |
|
||||
|
||||
---
|
||||
|
||||
## 七、跨端协同与变更检查
|
||||
|
||||
| 场景 | 动作 |
|
||||
|------|------|
|
||||
| **跨端功能开发** | 加载 SKILL-角色流程控制.md,按「需求分析 → 并行开发 → 管理端启动」执行 |
|
||||
| **变更完成准备提交** | **必过** soul-change-checklist.mdc + SKILL-变更关联检查.md |
|
||||
| **接口契约** | 后端开发输出(路径、请求/响应、字段);小程序/管理端按契约对接 |
|
||||
|
||||
---
|
||||
|
||||
## 八、排除项
|
||||
|
||||
- **next-project/**:仅预览,不参与线上;新增/优化以 miniprogram、soul-admin、soul-api 为准。
|
||||
|
||||
---
|
||||
|
||||
## 九、相关文档
|
||||
|
||||
| 文档 | 说明 |
|
||||
|------|------|
|
||||
| [开发团队职责定义](./开发团队职责定义.md) | 五角色团队、Skills 分配 |
|
||||
| [角色驱动Skills分析](./角色驱动Skills分析.md) | Skills 组织方式、改进点 |
|
||||
| [SKILL-角色流程控制](../skills/role-flow-control/SKILL.md) | 跨端协同流程、决策表 |
|
||||
| soul-project-boundary.mdc | 项目边界、防互窜原则 |
|
||||
|
||||
---
|
||||
|
||||
**更新日期**:2026-02
|
||||
149
.cursor/docs/开发团队职责定义.md
Normal file
149
.cursor/docs/开发团队职责定义.md
Normal file
@@ -0,0 +1,149 @@
|
||||
# Soul 创业派对 - 开发团队职责定义
|
||||
|
||||
> **开发团队**:2 前端 + 1 后端 + 1 产品 + 1 测试 + 1 助理。按职责分配 Skills,有**经验库**用于根据经验自动升级 Skills。速查见 [.cursor/README.md](../README.md)。
|
||||
|
||||
---
|
||||
|
||||
## 一、开发团队总览
|
||||
|
||||
| 角色 | 职责 | 负责目录/场景 | 主 Skill |
|
||||
|------|------|---------------|----------|
|
||||
| **小程序开发工程师** | 微信原生小程序 C 端 | miniprogram/ | SKILL-小程序开发.md |
|
||||
| **管理端开发工程师** | React 管理后台 | soul-admin/ | SKILL-管理端开发.md |
|
||||
| **后端开发** | Go + Gin + GORM 接口服务 | soul-api/ | SKILL-API开发.md |
|
||||
| **产品经理** | 需求、验收、协调 | 开发文档/1、需求/、临时需求池/ | SKILL-产品经理.md |
|
||||
| **测试人员** | 功能测试、回归测试、三端联调 | miniprogram、soul-admin、soul-api | SKILL-测试.md |
|
||||
| **助理橙子** | 讨论后记录、文档同步 | 触发词:小橙、橙子、讨论完毕 | SKILL-助理橙子-文档同步.md |
|
||||
|
||||
---
|
||||
|
||||
## 二、开发角色(源码)
|
||||
|
||||
### 2.1 小程序开发工程师
|
||||
|
||||
| 项目 | 说明 |
|
||||
|------|------|
|
||||
| **源码** | miniprogram/pages、utils、components、app.js |
|
||||
| **API** | 只调 `/api/miniprogram/*` |
|
||||
| **禁止** | 不调 `/api/admin/*`、`/api/db/*` |
|
||||
| **主 Skill** | SKILL-小程序开发.md |
|
||||
| **辅助** | 三端架构 → API开发 → 变更关联检查 |
|
||||
| **协同** | SKILL-角色流程控制.md(跨端时) |
|
||||
|
||||
### 2.2 管理端开发工程师
|
||||
|
||||
| 项目 | 说明 |
|
||||
|------|------|
|
||||
| **源码** | soul-admin/src/pages、components、api、layouts |
|
||||
| **API** | 只调 `/api/admin/*`、`/api/db/*`、`/api/orders` 等 |
|
||||
| **禁止** | 不调 `/api/miniprogram/*` |
|
||||
| **主 Skill** | SKILL-管理端开发.md |
|
||||
| **辅助** | 三端架构 → API开发 → 变更关联检查 |
|
||||
| **协同** | SKILL-角色流程控制.md(跨端时) |
|
||||
|
||||
### 2.3 后端开发
|
||||
|
||||
| 项目 | 说明 |
|
||||
|------|------|
|
||||
| **源码** | soul-api/internal/router、handler、model、wechat、config |
|
||||
| **路由** | 按使用方挂 miniprogram / admin / db / payment |
|
||||
| **主 Skill** | SKILL-API开发.md |
|
||||
| **辅助** | soul-api 规范 → 三端架构 → 变更关联检查 → MySQL直接操作 |
|
||||
| **协同** | SKILL-角色流程控制.md(跨端时) |
|
||||
|
||||
---
|
||||
|
||||
## 三、非开发角色
|
||||
|
||||
### 3.1 产品经理
|
||||
|
||||
| 项目 | 说明 |
|
||||
|------|------|
|
||||
| **职责** | 需求分析、需求文档、验收标准、与开发协调 |
|
||||
| **文档** | 开发文档/1、需求/、临时需求池/、开发文档/10、项目管理/ |
|
||||
| **主 Skill** | SKILL-产品经理.md |
|
||||
| **产出** | 需求汇总、需求分析、验收清单、项目推进表 |
|
||||
|
||||
### 3.2 测试人员
|
||||
|
||||
| 项目 | 说明 |
|
||||
|------|------|
|
||||
| **职责** | 功能测试、回归测试、三端(小程序、管理端、API)联调验证 |
|
||||
| **测试范围** | miniprogram、soul-admin、soul-api |
|
||||
| **主 Skill** | SKILL-测试.md |
|
||||
| **产出** | 测试用例、测试报告、Bug 列表 |
|
||||
| **协同** | 与开发角色对接 Bug、验收前测试 |
|
||||
|
||||
### 3.3 助理橙子
|
||||
|
||||
| 项目 | 说明 |
|
||||
|------|------|
|
||||
| **职责** | 讨论后记录、文档同步、更新开发文档 |
|
||||
| **触发** | 小橙、橙子、橙橙、🍊、「讨论完毕」「记录一下」「同步到开发文档」 |
|
||||
| **主 Skill** | SKILL-助理橙子-文档同步.md |
|
||||
| **规则** | assistant-xiaofeng.mdc |
|
||||
|
||||
---
|
||||
|
||||
## 四、Skills 分配速查
|
||||
|
||||
| 角色 | 主 Skill | 辅助 Skill | 协同 Skill |
|
||||
|------|----------|------------|------------|
|
||||
| 小程序开发工程师 | SKILL-小程序开发 | 三端架构、API开发、变更关联检查 | 角色流程控制 |
|
||||
| 管理端开发工程师 | SKILL-管理端开发 | 三端架构、API开发、变更关联检查 | 角色流程控制 |
|
||||
| 后端开发 | SKILL-API开发 | soul-api 规范、三端架构、变更关联检查、MySQL直接操作 | 角色流程控制 |
|
||||
| 产品经理 | SKILL-产品经理 | 需求汇总、运营与变更 | - |
|
||||
| 测试人员 | SKILL-测试 | 变更关联检查、小程序/管理端/API 规范 | - |
|
||||
| 助理橙子 | SKILL-助理橙子-文档同步 | - | - |
|
||||
|
||||
### 通用 / 场景 Skill(全员)
|
||||
|
||||
| 场景 | Skill | 何时选用 |
|
||||
|------|-------|----------|
|
||||
| 跨端功能开发 | SKILL-角色流程控制 | 开发涉及多端时 |
|
||||
| 变更完成 | SKILL-变更关联检查、soul-change-checklist | **开发改完必过** |
|
||||
| 文档同步 | SKILL-助理橙子-文档同步 | 讨论完毕、记录、同步文档 |
|
||||
| next-project | SKILL-next-project仅预览 | 编辑 next-project/ 或区分线上后端 |
|
||||
|
||||
---
|
||||
|
||||
## 五、角色推断
|
||||
|
||||
| 触发条件 | 推断角色 | 加载 |
|
||||
|----------|----------|------|
|
||||
| 编辑 miniprogram/** | 小程序开发工程师 | SKILL-小程序开发 + soul-miniprogram-boundary |
|
||||
| 编辑 soul-admin/** | 管理端开发工程师 | SKILL-管理端开发 + soul-admin-boundary |
|
||||
| 编辑 soul-api/** | 后端开发 | SKILL-API开发 + soul-api |
|
||||
| 编辑 开发文档/1、需求/、临时需求池/ | 产品经理 | SKILL-产品经理 |
|
||||
| 说 测试、测试用例、回归测试、功能测试、QA | 测试人员 | SKILL-测试 |
|
||||
| 说 小橙、橙子、讨论完毕、记录、同步文档 | 助理橙子 | SKILL-助理橙子-文档同步 |
|
||||
|
||||
---
|
||||
|
||||
## 六、开发团队经验库
|
||||
|
||||
| 项目 | 说明 |
|
||||
|------|------|
|
||||
| **位置** | `.cursor/agent/*/evolution/`,每角色独立 evolution 目录 |
|
||||
| **项目索引** | 每角色有 `项目索引.md`,根据开发进度做总结、保存进度,**每次保存写日期** |
|
||||
| **经验存储** | 按天存储,文件名 `YYYY-MM-DD.md`,在对应角色文件夹下 |
|
||||
| **用途** | 沉淀 bug 修复、最佳实践、决策、踩坑;根据经验**自动升级 Skills** |
|
||||
| **触发** | 用户说「吸收经验」「升级 skills」「记录经验」→ 助理橙子执行入库 + 升级 |
|
||||
| **流程** | 提炼 → 写入 `{角色}/YYYY-MM-DD.md` → 更新 `{角色}/项目索引.md` → 更新 `经验清单.md` → 升级 SKILL |
|
||||
|
||||
详见 [经验清单](../agent/开发助理/经验清单.md)、[.cursor README](../README.md)。
|
||||
|
||||
---
|
||||
|
||||
## 七、相关文档
|
||||
|
||||
| 文档 | 说明 |
|
||||
|------|------|
|
||||
| [经验清单](../agent/开发助理/经验清单.md) | 经验索引、Skills 升级触发 |
|
||||
| [三角色边界定义](./三角色边界定义.md) | 开发三角色源码与业务边界 |
|
||||
| [角色驱动Skills分析](./角色驱动Skills分析.md) | Skills 组织方式 |
|
||||
| [SKILL-角色流程控制](../skills/role-flow-control/SKILL.md) | 跨端协同流程 |
|
||||
|
||||
---
|
||||
|
||||
**更新日期**:2026-02
|
||||
140
.cursor/docs/角色协同流程图.html
Normal file
140
.cursor/docs/角色协同流程图.html
Normal file
@@ -0,0 +1,140 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Soul 创业派对 - 角色协同流程图</title>
|
||||
<script src="https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js"></script>
|
||||
<style>
|
||||
* { box-sizing: border-box; }
|
||||
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; margin: 0; padding: 24px; background: #f5f5f5; }
|
||||
h1 { color: #333; margin-bottom: 8px; }
|
||||
.subtitle { color: #666; font-size: 14px; margin-bottom: 24px; }
|
||||
.diagram { background: #fff; border-radius: 8px; padding: 24px; margin-bottom: 24px; box-shadow: 0 1px 3px rgba(0,0,0,.1); }
|
||||
.diagram h2 { margin-top: 0; color: #444; font-size: 16px; border-bottom: 1px solid #eee; padding-bottom: 8px; }
|
||||
.mermaid { display: flex; justify-content: center; }
|
||||
.mermaid svg { max-width: 100%; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Soul 创业派对 - 角色协同流程图</h1>
|
||||
<p class="subtitle">小程序功能开发(新增/优化)驱动的三端协同流程 · 线框图</p>
|
||||
|
||||
<div class="diagram">
|
||||
<h2>1. 主流程图(阶段划分)</h2>
|
||||
<div class="mermaid">
|
||||
flowchart TB
|
||||
subgraph 阶段1["阶段 1:需求分析与接口设计"]
|
||||
A[需求/变更发起] --> B[API 开发者分析 miniprogram 接口]
|
||||
A --> C[管理端开发者分析]
|
||||
C --> C1{管理端是否需要?}
|
||||
C1 -->|需要| C2[记录:字段/配置/审核/统计]
|
||||
C1 -->|不需要| C3[无需管理端调整]
|
||||
B --> D[输出接口契约]
|
||||
C2 --> D
|
||||
end
|
||||
|
||||
阶段1 --> 阶段2
|
||||
|
||||
subgraph 阶段2["阶段 2:并行开发"]
|
||||
E[API 开发者实现 miniprogram 接口]
|
||||
F[API 开发者实现 admin/db 接口<br/>若管理端需要]
|
||||
G[小程序开发者实现功能]
|
||||
E --> G
|
||||
end
|
||||
|
||||
阶段2 --> 阶段3
|
||||
|
||||
subgraph 阶段3["阶段 3:小程序完成 → 管理端启动"]
|
||||
H[小程序完成并自测 ✓]
|
||||
H --> I{管理端需要?}
|
||||
I -->|是| J[管理端开发者开始调整]
|
||||
I -->|否| K[跳过]
|
||||
J --> L[API 开发者补充 admin/db<br/>若有新增需求]
|
||||
end
|
||||
|
||||
阶段3 --> 阶段4
|
||||
|
||||
subgraph 阶段4["阶段 4:联调与收尾"]
|
||||
M[三端联调]
|
||||
N[过 soul-change-checklist]
|
||||
O[提交]
|
||||
M --> N --> O
|
||||
end
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="diagram">
|
||||
<h2>2. 角色时序图(谁在何时做什么)</h2>
|
||||
<div class="mermaid">
|
||||
sequenceDiagram
|
||||
participant P as 产品/需求
|
||||
participant MP as 小程序开发者
|
||||
participant AD as 管理端开发者
|
||||
participant API as API 开发者
|
||||
|
||||
P->>API: 1. 需求/变更
|
||||
P->>AD: 1. 需求/变更
|
||||
|
||||
Note over API,AD: 阶段 1:需求分析
|
||||
API->>API: 分析 miniprogram 接口需求
|
||||
AD->>AD: 分析管理端是否需要字段/配置/审核/统计
|
||||
AD->>API: 反馈:需要 / 不需要 + 具体项
|
||||
API->>API: 输出接口契约
|
||||
|
||||
Note over API,MP: 阶段 2:并行开发
|
||||
API->>API: 实现 miniprogram 接口
|
||||
par 若管理端需要
|
||||
API->>API: 实现 admin/db 接口
|
||||
end
|
||||
API->>MP: 接口可用
|
||||
MP->>MP: 实现小程序功能
|
||||
|
||||
Note over MP,AD: 阶段 3:小程序完成 → 管理端
|
||||
MP->>MP: 完成并自测 ✓
|
||||
MP->>AD: 小程序完成
|
||||
alt 管理端需要
|
||||
AD->>AD: 开始管理端调整
|
||||
AD->>API: 若有新增接口需求
|
||||
API->>API: 补充 admin/db 接口
|
||||
end
|
||||
|
||||
Note over API,AD: 阶段 4:联调
|
||||
API->>API: 联调
|
||||
MP->>MP: 联调
|
||||
AD->>AD: 联调
|
||||
Note over P,AD: 过 soul-change-checklist → 提交
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="diagram">
|
||||
<h2>3. 三角色职责与依赖</h2>
|
||||
<div class="mermaid">
|
||||
flowchart LR
|
||||
subgraph 角色["三角色"]
|
||||
MP[小程序开发者<br/>miniprogram/]
|
||||
AD[管理端开发者<br/>soul-admin/]
|
||||
API[API 开发者<br/>soul-api/]
|
||||
end
|
||||
|
||||
subgraph 路径["API 路径"]
|
||||
P1["/api/miniprogram/*"]
|
||||
P2["/api/admin/*<br/>/api/db/*"]
|
||||
end
|
||||
|
||||
MP -->|只调| P1
|
||||
AD -->|只调| P2
|
||||
API -->|提供| P1
|
||||
API -->|提供| P2
|
||||
|
||||
MP -.->|依赖| API
|
||||
AD -.->|依赖| API
|
||||
AD -.->|小程序完成后启动| MP
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
mermaid.initialize({ startOnLoad: true, theme: 'neutral' });
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
91
.cursor/docs/角色驱动Skills分析.md
Normal file
91
.cursor/docs/角色驱动Skills分析.md
Normal file
@@ -0,0 +1,91 @@
|
||||
# 角色驱动 Skills 方式 - 分析与完善
|
||||
|
||||
## 一、当前方式概述
|
||||
|
||||
**开发团队**五角色:小程序开发工程师、管理端开发工程师、后端开发、产品经理、助理橙子。Skills 按角色分配:
|
||||
|
||||
> 职责定义:[开发团队职责定义.md](./开发团队职责定义.md) | 源码边界:[三角色边界定义.md](./三角色边界定义.md) | 入口:[.cursor/README.md](../README.md)
|
||||
|
||||
- **主 Skill**:开发风格与规范(必须遵循)
|
||||
- **辅助 Skill**:按需选用
|
||||
- **协同 Skill**:跨端时用 SKILL-角色流程控制
|
||||
|
||||
---
|
||||
|
||||
## 二、优点
|
||||
|
||||
| 优点 | 说明 |
|
||||
|------|------|
|
||||
| **职责清晰** | 每个角色对应明确的主 Skill,开发风格不混用 |
|
||||
| **顺序明确** | 辅助 Skill 有推荐查阅顺序,减少「不知道该看哪个」 |
|
||||
| **协同有据** | SKILL-角色流程控制 统一跨端协作流程 |
|
||||
| **与 boundary 一致** | 角色 ↔ 目录 ↔ boundary 一一对应 |
|
||||
|
||||
---
|
||||
|
||||
## 三、可改进点
|
||||
|
||||
| 问题 | 影响 | 改进方向 |
|
||||
|------|------|----------|
|
||||
| **目录→角色推断不显式** | Agent 需从「编辑目录」推断「当前角色」,再查 Skills | 增加「目录→角色→应加载 Skills」速查表 |
|
||||
| **辅助 Skill 何时选用不明确** | 辅助 1、2、3 的触发场景模糊 | 为每个辅助 Skill 补充「何时选用」 |
|
||||
| **主 Skill 缺少触发词** | Cursor 可能难以自动发现应加载的 Skill | 为主 Skill 增加 YAML description,含 miniprogram、soul-admin、soul-api 等触发词 |
|
||||
| **协同场景单一** | 仅覆盖「小程序驱动」流程 | 可补充「API 先行」「管理端先行」的简要说明 |
|
||||
| **通用 Skill 与角色关系** | 变更检查、MySQL 等何时介入不够清晰 | 在角色清单中标注「变更后必过」「API 开发者数据库操作时」 |
|
||||
|
||||
---
|
||||
|
||||
## 四、完善措施(已实施)
|
||||
|
||||
1. **README**:增加「目录→角色→Skills」速查表;辅助 Skill 补充「何时选用」。
|
||||
2. **soul-project-boundary**:开发时增加「根据当前编辑目录推断角色,加载对应主 Skill」。
|
||||
3. **主 Skill**:增加 YAML frontmatter,description 含触发词(miniprogram、soul-admin、soul-api)。
|
||||
4. **SKILL-角色流程控制**:补充「API 先行」「管理端先行」的简要流程说明。
|
||||
|
||||
---
|
||||
|
||||
## 五、使用流程(完善后)
|
||||
|
||||
```
|
||||
1. 用户/Agent 在 miniprogram/ 下编辑
|
||||
→ 推断:当前角色 = 小程序开发者
|
||||
→ 加载:主 Skill(SKILL-小程序开发)+ 对应 boundary
|
||||
|
||||
2. 若涉及跨端功能(如新功能需管理端配置)
|
||||
→ 加载:SKILL-角色流程控制
|
||||
→ 按阶段执行
|
||||
|
||||
3. 变更完成后
|
||||
→ 加载:SKILL-变更关联检查、soul-change-checklist
|
||||
→ 过一遍关联层
|
||||
|
||||
4. 若 API 开发者需操作数据库且 MCP 不可用
|
||||
→ 加载:SKILL-MySQL直接操作
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 六、优化效果
|
||||
|
||||
| 优化项 | 效果 |
|
||||
|--------|------|
|
||||
| 速查表 | 目录→角色→Skills 一目了然,减少查找时间 |
|
||||
| 何时选用 | 辅助 Skill 触发场景明确,避免误用或漏用 |
|
||||
| 主/辅 Skill frontmatter | 含触发词,便于 Cursor Agent 自动发现 |
|
||||
| 角色推断表 | soul-project-boundary 中显式映射,开发时直接对照 |
|
||||
| API/管理端先行 | 角色流程控制补充多驱动场景 |
|
||||
|
||||
---
|
||||
|
||||
## 七、后续迭代方向
|
||||
|
||||
| 方向 | 说明 |
|
||||
|------|------|
|
||||
| **Glob 自动加载** | 若 Cursor 支持按 glob 自动加载 Skill,可配置 miniprogram/** → soul-miniprogram-dev |
|
||||
| **Checklist 自动化** | 变更后自动提示「请过 soul-change-checklist」 |
|
||||
| **角色切换提醒** | 跨目录编辑时提醒「当前角色已切换」 |
|
||||
| **Skill 版本号** | 主 Skill 增加版本/更新日期,便于追踪迭代 |
|
||||
|
||||
---
|
||||
|
||||
**更新日期**:2026-02
|
||||
74
.cursor/meeting/2026-02-27_开发进度同步会议.md
Normal file
74
.cursor/meeting/2026-02-27_开发进度同步会议.md
Normal file
@@ -0,0 +1,74 @@
|
||||
# 会议纪要 - 2026-02-27 | 开发进度同步会议
|
||||
|
||||
> 本文件由**助理橙子**在会议结束后自动生成。
|
||||
|
||||
---
|
||||
|
||||
## 基本信息
|
||||
|
||||
- **时间**:2026-02-27
|
||||
- **议题**:同步开发进度给橙子,会议结束后同步到开发文档
|
||||
- **触发方式**:开个会议
|
||||
- **参与角色**:产品经理、后端开发、管理端开发工程师、小程序开发工程师
|
||||
|
||||
---
|
||||
|
||||
## 各角色发言
|
||||
|
||||
### 【产品经理】
|
||||
|
||||
- 项目索引初始化、.cursor 规则优化已完成
|
||||
- 《分销规则》《规则说明》已讨论,决议见会议纪要
|
||||
- 待办:补充「资料不解锁」含义;明确购买内容 ≥3 章弹窗的触发与跳转逻辑
|
||||
|
||||
### 【后端开发】
|
||||
|
||||
- computeOrderCommission 会员分润差异化(20%/10%)已实现
|
||||
- vip_roles、vip_activated_at、referral_config 扩展已完成;miniprogram/admin/db 三组路由就绪
|
||||
- 后续:提现、找伙伴接口增加资料完善校验,返回 ERR_PROFILE_INCOMPLETE
|
||||
|
||||
### 【管理端开发工程师】
|
||||
|
||||
- 内容管理仅 API 按钮、推广中心、SetVipModal、VIP 角色管理、推广设置会员分润配置、VIP 排序均已落地
|
||||
- 功能:用户管理、订单管理、提现审核、VIP 管理、内容/章节管理、配置项管理、数据统计
|
||||
|
||||
### 【小程序开发工程师】
|
||||
|
||||
- 永平落地已完成:海报 scene、我的收益、推广中心、VIP 相关;找伙伴、提现、阅读、分销核心功能已上线
|
||||
- 后续:资料完善弹窗、≥3 章购买弹窗、找伙伴前置校验
|
||||
|
||||
---
|
||||
|
||||
## 讨论过程
|
||||
|
||||
- 各角色按项目索引汇报进度,无分歧
|
||||
- 共识:永平落地与会员分润已完成,下一阶段聚焦资料完善与购买引导
|
||||
|
||||
---
|
||||
|
||||
## 会议决议
|
||||
|
||||
1. 永平落地与会员分润差异化已完成
|
||||
2. 下一阶段:资料完善校验(提现/找伙伴)、≥3 章购买弹窗
|
||||
3. 搁置:打包购买引导、存客宝对接
|
||||
|
||||
---
|
||||
|
||||
## 待办事项
|
||||
|
||||
| 责任角色 | 任务 | 优先级 | 截止建议 |
|
||||
|---------|------|--------|---------|
|
||||
| 产品经理 | 补充《规则说明》「资料不解锁」含义 | 中 | 开发前 |
|
||||
| 产品经理 | 明确购买内容 ≥3 章弹窗触发与跳转逻辑 | 中 | 开发前 |
|
||||
| 后端开发 | 提现、找伙伴接口增加资料完善校验 | 中 | 资料完善功能开发时 |
|
||||
| 小程序开发工程师 | 资料完善弹窗、≥3 章弹窗、找伙伴前置校验 | 中 | 按排期 |
|
||||
|
||||
---
|
||||
|
||||
## 各角色经验与业务理解更新
|
||||
|
||||
> 本次为进度同步会议,无新增经验条目;开发进度已同步至开发文档。
|
||||
|
||||
---
|
||||
|
||||
*会议纪要由助理橙子生成 | 开发进度已同步至 `开发文档/10、项目管理/运营与变更.md` 第七部分*
|
||||
80
.cursor/meeting/2026-02-28_P0测试清单.md
Normal file
80
.cursor/meeting/2026-02-28_P0测试清单.md
Normal file
@@ -0,0 +1,80 @@
|
||||
# stitch_soul P0 测试清单
|
||||
|
||||
> 测试人员按此清单验证 P0 功能。
|
||||
|
||||
---
|
||||
|
||||
## 一、开发完成情况
|
||||
|
||||
| 阶段 | 状态 | 说明 |
|
||||
|------|------|------|
|
||||
| **P0** | ✅ 完成 | 首页/目录 + NEW + 精选推荐算法 |
|
||||
| P1 | 未开始 | 会员落地页 |
|
||||
| P2 | 未开始 | 导师 + 预约 |
|
||||
| P3 | 未开始 | 资料编辑扩展 |
|
||||
|
||||
---
|
||||
|
||||
## 二、P0 接口测试
|
||||
|
||||
**前提**:soul-api 已启动,数据库已执行 `add-chapters-is-new.sql`。
|
||||
|
||||
### 2.1 后端接口(可用 PowerShell 脚本或 curl 验证)
|
||||
|
||||
```powershell
|
||||
# 在 soul-api 目录下执行
|
||||
cd e:\Gongsi\Mycontent\soul-api
|
||||
.\scripts\test-p0-endpoints.ps1
|
||||
```
|
||||
|
||||
或手动验证:
|
||||
|
||||
| 接口 | 期望 |
|
||||
|------|------|
|
||||
| `GET /api/miniprogram/book/all-chapters` | success: true,data 为数组,每项含 `isNew` 字段 |
|
||||
| `GET /api/miniprogram/book/recommended` | success: true,data 为 1~3 条,每项含 `tag`(热门/推荐/精选) |
|
||||
| `GET /api/miniprogram/book/latest-chapters` | success: true,data 为数组(按 updated_at 降序) |
|
||||
| `GET /api/miniprogram/book/hot` | success: true,data 为数组(按阅读量或兜底排序) |
|
||||
|
||||
### 2.2 管理端测试
|
||||
|
||||
| 步骤 | 操作 | 期望 |
|
||||
|------|------|------|
|
||||
| 1 | 登录 soul-admin | 成功 |
|
||||
| 2 | 进入「内容管理」 | 章节列表正常 |
|
||||
| 3 | 点击某一节「编辑」 | 弹出编辑框 |
|
||||
| 4 | 勾选「标记 NEW」并保存 | 保存成功,无报错 |
|
||||
| 5 | 刷新列表,再次编辑同一节 | 「标记 NEW」保持勾选 |
|
||||
|
||||
### 2.3 小程序测试
|
||||
|
||||
| 步骤 | 操作 | 期望 |
|
||||
|------|------|------|
|
||||
| 1 | 打开小程序首页 | 加载正常 |
|
||||
| 2 | 查看「最新更新」Banner | 显示一条章节,点击可进入阅读 |
|
||||
| 3 | 查看「精选推荐」 | 显示 3 条,带 热门/推荐/精选 标签 |
|
||||
| 4 | 查看「最新新增」 | 有 isNew 的章节在此展示 |
|
||||
| 5 | 进入「目录」页 | 从服务端加载,按篇章聚合 |
|
||||
| 6 | 在目录中查看标记 NEW 的章节 | 显示 NEW 标签 |
|
||||
| 7 | 查看免费/¥1 显示 | 免费节显示「免费」,付费节显示「¥1」 |
|
||||
|
||||
---
|
||||
|
||||
## 三、联调验证
|
||||
|
||||
| 验证点 | 说明 |
|
||||
|--------|------|
|
||||
| 管理端标记 NEW → 小程序展示 | 在管理端勾选某节 NEW,小程序目录/首页「最新新增」应出现 |
|
||||
| 精选推荐排除序言/尾声/附录 | 若 part_title 含「序言」「尾声」「附录」,不应出现在 recommended/hot |
|
||||
| 阅读量兜底 | 无 reading_progress 数据时,hot/recommended 应返回 updated_at 排序的兜底结果 |
|
||||
|
||||
---
|
||||
|
||||
## 四、已知限制
|
||||
|
||||
- **阅读量**:当前依赖 `reading_progress` 表,新环境无数据时会走兜底(按 updated_at)。
|
||||
- **固定 3 章兜底**:若连章节列表都拿不到,会返回空;未实现「预设固定 3 章」配置。
|
||||
|
||||
---
|
||||
|
||||
*测试完成后可更新本文件,标注通过/失败及问题。*
|
||||
91
.cursor/meeting/2026-02-28_个人资料页实现评估.md
Normal file
91
.cursor/meeting/2026-02-28_个人资料页实现评估.md
Normal file
@@ -0,0 +1,91 @@
|
||||
# 会议纪要 - 2026-02-28 | 个人资料页实现评估
|
||||
|
||||
> 本文件由**助理橙子**在会议结束后自动生成。
|
||||
|
||||
---
|
||||
|
||||
## 基本信息
|
||||
|
||||
- **时间**:2026-02-28
|
||||
- **议题**:个人资料展示页(profile-show)与编辑页(profile-edit)实现评估
|
||||
- **触发方式**:开个会议评估怎么实现
|
||||
- **参与角色**:产品经理、后端开发、管理端开发工程师、小程序开发工程师、测试人员
|
||||
|
||||
---
|
||||
|
||||
## 各角色发言
|
||||
|
||||
### 【产品经理】
|
||||
|
||||
- **展示页**(enhanced_professional_profile):面向他人查看,含头像、昵称、MBTI/地区、基本信息、个人故事、互助需求、项目介绍。
|
||||
- **编辑页**(comprehensive_profile_editor_v1_1):完整表单,需与展示页字段一一对应。
|
||||
- **待澄清**:展示页有「我擅长」展示,编辑页需补充;两页配色建议统一。
|
||||
|
||||
**验收标准**:我的 → 展示页 → 编辑页 → 保存 → 返回,流程闭环;字段完整对应。
|
||||
|
||||
### 【后端开发】
|
||||
|
||||
- 现有 `GET/POST /api/miniprogram/user/profile` 已覆盖 nickname, avatar, mbti, region, industry, position, businessScale, **skills**, phone, wechatId, 个人故事三字段、互助需求两字段、projectIntro。
|
||||
- 无需新接口;skills 已支持读写,编辑页只需前端对接。
|
||||
|
||||
### 【管理端开发工程师】
|
||||
|
||||
- 个人资料为 C 端能力,管理端无新增任务。
|
||||
|
||||
### 【小程序开发工程师】
|
||||
|
||||
- **profile-show**:已按 enhanced_professional_profile 完成,配色 #5EEAD4 / #050B14 / #0F1720。
|
||||
- **profile-edit**:已按 comprehensive_profile_editor_v1_1 实现功能,配色 #4FD1C5 / #000。
|
||||
- **待做**:① 编辑页增加「我擅长」输入框;② 配色统一为 enhanced 风格。
|
||||
|
||||
### 【测试人员】
|
||||
|
||||
- 验证展示页与编辑页字段一致、保存后数据正确回显。
|
||||
- 手机号/微信号脱敏与复制;头像上传、昵称、MBTI 选择;空/超长输入边界。
|
||||
|
||||
---
|
||||
|
||||
## 讨论过程
|
||||
|
||||
- 产品确认:skills 必须在编辑页体现。
|
||||
- 产品确认:两页配色统一为 enhanced 风格(#5EEAD4)以强化品牌一致。
|
||||
- 小程序确认:skills 后端已有,配色替换工作量小。
|
||||
|
||||
---
|
||||
|
||||
## 会议决议
|
||||
|
||||
1. **skills 字段**:在 profile-edit「基本信息」区块增加「我擅长」输入框,与 profile-show 对应。
|
||||
2. **视觉统一**:profile-edit 配色统一为 enhanced(accent #5EEAD4, background #050B14, card #0F1720)。
|
||||
3. **实现顺序**:先补 skills,再做配色统一。
|
||||
4. **流程**:我的 → profile-show → ⋯ → profile-edit → 保存 → 返回,已打通,无需修改。
|
||||
|
||||
---
|
||||
|
||||
## 待办事项
|
||||
|
||||
| 责任角色 | 任务 | 优先级 | 截止建议 |
|
||||
|---------|------|--------|---------|
|
||||
| 小程序开发工程师 | profile-edit 增加「我擅长」输入框及 JS 读写 | 高 | 本次迭代 |
|
||||
| 小程序开发工程师 | profile-edit 配色统一为 enhanced 风格 | 中 | 本次迭代 |
|
||||
|
||||
---
|
||||
|
||||
## 问题与作答区
|
||||
|
||||
| # | 问题 | 责任角色 | 作答 |
|
||||
|---|------|---------|------|
|
||||
| 1 | 编辑页导航栏是否需增加右侧 more_horiz + 头像(设计稿有此元素)? | 产品经理 | (待补充) |
|
||||
| 2 | 展示页「成为超级个体」按钮点击后的具体跳转路径? | 产品经理 | (待补充) |
|
||||
|
||||
---
|
||||
|
||||
## 各角色经验与业务理解更新
|
||||
|
||||
- 个人资料展示页与编辑页需字段、配色、流程一致,便于用户理解。
|
||||
- profile-edit 与 profile-show 共用同一套 API,skills 等扩展字段需双向同步。
|
||||
- 本次会议决议已写入本纪要;各角色经验已同步至 `agent/{角色}/evolution/2026-02-28.md`。
|
||||
|
||||
---
|
||||
|
||||
*会议纪要由助理橙子生成 | 2026-02-28*
|
||||
572
.cursor/meeting/2026-02-28_临时需求池stitch_soul需求评审.md
Normal file
572
.cursor/meeting/2026-02-28_临时需求池stitch_soul需求评审.md
Normal file
@@ -0,0 +1,572 @@
|
||||
# 会议纪要 - 2026-02-28 | 临时需求池 stitch_soul 需求评审
|
||||
|
||||
> 本文件由**助理橙子**在会议结束后自动生成。
|
||||
|
||||
---
|
||||
|
||||
## 基本信息
|
||||
|
||||
- **时间**:2026-02-28
|
||||
- **议题**:分析临时需求池 soul20260228/stitch_soul 全部需求
|
||||
- **触发方式**:开个会议,所有人都来,分析这个需求
|
||||
- **参与角色**:产品经理、后端开发、管理端开发工程师、小程序开发工程师、测试人员
|
||||
|
||||
---
|
||||
|
||||
## 各角色发言
|
||||
|
||||
### 【产品经理】
|
||||
|
||||
从 10 个稿子可归纳出 **stitch_soul 串联「内容→会员→导师」变现路径**:
|
||||
|
||||
- **首页**(optimized_home_content_feed_v1):品牌、搜索、最新更新、阅读进度、超级个体、精选推荐、最新新增(NEW)
|
||||
- **目录**(catalog_with_new_additions_v1):73 章、篇章结构、NEW 标签、免费/¥1 付费
|
||||
- **会员落地**(premium_membership_landing_v1):¥1980/年,内容权益(章节、案例库、智能纪要、会议纪要)+ 社交权益(匹配、排行、资源、VIP 标识)
|
||||
- **导师**:列表(搜索/分类)+ 详情(介绍/服务/价格/预约),单次咨询 ¥600~2500
|
||||
- **个人资料**:展示(基本信息/个人故事/互助需求/项目介绍)、编辑(完整表单)、手机号/微信号弹窗
|
||||
- **我的**:VIP 标识、分享收益、阅读统计、最近阅读、订单
|
||||
|
||||
**待澄清**:73 章与现有内容库是否同一套;导师与内容作者是否同一人;「案例库」是独立内容池还是章节分类;会员权益与价格策略。
|
||||
|
||||
**建议优先级**:首页/目录/会员 > 导师 > 资料。
|
||||
|
||||
### 【后端开发】
|
||||
|
||||
**现有基础**:soul-api 已有 chapter、book、vip 模型;导师能力需新建或扩展现有 match 体系(现有 mentor 为 match 类型,非独立导师实体)。
|
||||
|
||||
**待设计**:导师列表/详情/搜索筛选、预约单、会员权益与预约支付打通;接口挂 `/api/miniprogram/*`。与产品核对 chapter/book/vip 现状后,给出导师/预约/会员权益的模型与接口方案。
|
||||
|
||||
### 【管理端开发工程师】
|
||||
|
||||
管理端需配套:章节/导师 CRUD、NEW 标记、会员权益配置、预约单管理、收益/提现审核。接口走 `/api/admin/*`、`/api/db/*`,字段与小程序/后端一致。待后端方案确定后规划具体页面。
|
||||
|
||||
### 【小程序开发工程师】
|
||||
|
||||
10 个稿子覆盖首页/目录/会员/导师列表/导师详情/资料展示/资料编辑/我的五类页面,交互清晰,需 `/api/miniprogram/*`。待需求与接口确定后分阶段实现。
|
||||
|
||||
### 【测试人员】
|
||||
|
||||
关键场景为阅读/付费、会员、导师预约、资料完善;三端联调(小程序↔API、管理端↔API)验证点。待需求确定后补充联调用例和回归清单。
|
||||
|
||||
---
|
||||
|
||||
## 讨论过程
|
||||
|
||||
- 产品询问后端:73 章、book、vip 现状是否明确。
|
||||
- 后端回复:需与产品共同核对 chapter/book/vip 后再定导师/预约/会员权益模型。
|
||||
- 管理端确认需管理章节、导师、会员、预约、收益。
|
||||
- 小程序确认页面稿清晰,等接口与需求后分阶段开发。
|
||||
- 测试:待业务规则确定后补充用例。
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 会议决议
|
||||
|
||||
1. **stitch_soul 定位**: stitch 产品线在 Soul 创业派对上的扩展,串联「内容阅读 + 会员 + 导师咨询」变现路径。
|
||||
2. **产品**:需在正式需求文档中明确 73 章、导师、案例库、会员的业务定义与验收标准。
|
||||
3. **后端**:梳理 chapter/book/vip,设计导师/预约/会员权益模型与接口方案。
|
||||
4. **开发优先级**:首页/目录/会员 > 导师列表与详情 > 资料编辑 / 我的。
|
||||
5. **待确认项**:73 章与内容库关系、导师与作者关系、案例库定义、会员权益与价格。
|
||||
6. **管理端跟进原则(已采纳)**:以后小程序有功能变更时,管理端须根据 C 端能力主动补充管理功能;后端需支持对应配置能力。**本需求示例**:导师价格 → 后端支持每个导师独立价格配置(单次/半年/年度),管理端导师编辑页提供价格配置。已写入 role-flow-control、admin-dev Skill。
|
||||
|
||||
---
|
||||
|
||||
## 待办事项
|
||||
|
||||
| 责任角色 | 任务 | 优先级 | 截止建议 |
|
||||
|---------|------|--------|---------|
|
||||
| 产品经理 | 撰写 stitch_soul 正式需求文档,明确业务边界 | 高 | 3 天内 |
|
||||
| 后端工程师 | 梳理 chapter/book/vip,输出导师/预约/会员权益模型与接口方案 | 高 | 产品文档确认后 |
|
||||
| 管理端开发工程师 | 待后端方案确定后,规划章节/导师/会员/预约管理页面 | 中 | 后端方案确定后 |
|
||||
| 小程序开发工程师 | 待需求与接口确定后,分阶段实现首页/目录/会员/导师/资料 | 中 | 接口确定后 |
|
||||
| 测试人员 | 待需求确定后,补充阅读/付费/会员/导师/资料联调用例 | 中 | 需求确定后 |
|
||||
|
||||
---
|
||||
|
||||
## 问题与作答区
|
||||
|
||||
| # | 问题 | 责任角色 | 作答 |
|
||||
|---|------|---------|------|
|
||||
| 1 | 73 章与现有内容库是否同一套? | 产品经理 | 73 章为内容章数的统计 |
|
||||
| 2 | 导师与内容作者是否同一人? | 产品经理 | 不是。导师是导师,属于咨询服务对接的人 |
|
||||
| 3 | 「案例库」是独立内容池还是章节分类? | 产品经理 | 章节分类 |
|
||||
| 4 | 会员权益与价格策略(¥1980/年、权益边界)? | 产品经理 | 会员权益:所有章节全部免费,并自动进入超级个体名单 |
|
||||
| 5 | chapter/book/vip 现有模型与业务定义? | 后端工程师 | 见下方「后端补充说明」 |
|
||||
|
||||
### 后端补充说明(问题 5)
|
||||
|
||||
**Chapter(chapters 表)**
|
||||
- 每行 = 一节(section),`id` 为业务标识如 `1.1`、`preface`
|
||||
- `part_id` / `part_title`:篇章;`chapter_id` / `chapter_title`:章;`section_title`:节标题
|
||||
- `content`、`is_free`、`price`、`sort_order`:正文、免费/付费、价格、排序
|
||||
- 73 章 = chapters 表行数统计,与产品「73 章为内容章数」一致
|
||||
|
||||
**Book**
|
||||
- 无独立表;「书」= chapters 的聚合视图
|
||||
- 接口:`/api/book/all-chapters` 返回全部 chapters,`/api/book/chapter/:id` 按 id 查单节
|
||||
|
||||
**VIP**
|
||||
- `vip_roles` 表:超级个体角色配置(name、sort),供管理端下拉选择
|
||||
- `users` 表:`is_vip`、`vip_expire_date`、`vip_activated_at`、`vip_sort`、`vip_role`、`vip_name`、`vip_avatar`、`vip_project`、`vip_contact`、`vip_bio`
|
||||
- 权益判断:`is_vip=1` 且 `vip_expire_date>NOW()`;无则从 orders 兜底(product_type=`fullbook`/`vip`,pay_time+365 天)
|
||||
- 默认价格:¥1980;权益已定义在 vip.go(智能纪要、会议纪要库、案例库、链接资源、解锁全章、匹配伙伴、排行、VIP 标识)
|
||||
|
||||
**精选推荐与热门章节(业务规则补充)**
|
||||
- **精选推荐**(首页「为你推荐」前 3 章):按正文章节阅读量从高到低排序,同量按更新时间;取前 3 章,依次标「热门」「推荐」「精选」。兜底:无阅读数据时按最近更新取 3 章;再兜底为预设固定 3 章。
|
||||
- **热门章节**(搜索页等):同上阅读量排序,取更多条(如 10 条)。兜底:无阅读数据时按购买次数;再兜底为默认列表。
|
||||
- **排除**:序言、尾声、附录不参与排序与推荐。
|
||||
- **管理端**:算法驱动,无需运营勾选「推荐」;固定兜底章节可产品预设或后台配置。
|
||||
|
||||
---
|
||||
|
||||
## 实现方案讨论(基于澄清后的需求)
|
||||
|
||||
> 各角色分析理解 1~5 题作答及后端补充说明后,发表实现看法。
|
||||
|
||||
### 【产品经理】
|
||||
|
||||
需求已厘清,可按以下 MVP 范围推进:
|
||||
|
||||
- **73 章**:沿用 chapters 表,73 = 行数统计;「案例库」按篇章/章节分类展示即可。
|
||||
- **会员**:全章免费 + 自动进入超级个体名单;¥1980 沿用现 vip 逻辑。
|
||||
- **导师**:独立于内容作者,需新建导师实体与预约流程。
|
||||
|
||||
**验收标准建议**:① 首页展示最新更新、阅读进度、超级个体、精选推荐、最新新增;② 目录按篇章聚合、支持 NEW 标识、免费/¥1;③ 会员落地页支付后 is_vip=1、vip_expire_date 正确;④ 导师列表可搜索筛选、详情可预约;⑤ 资料编辑保存后手机/微信号必填方可使用提现与找伙伴。
|
||||
|
||||
### 【后端工程师】
|
||||
|
||||
**可直接复用的**:chapters、users(含 vip 字段)、orders、vip 开通逻辑。小程序已有 `/api/miniprogram/book/*`、`/api/miniprogram/vip/*`、`/api/miniprogram/user/*`。
|
||||
|
||||
**需新增/扩展**:
|
||||
|
||||
1. **chapters 表**:新增 `is_new`(或类似字段)支持 NEW 标签;若无则用 `created_at` 近 N 天判断。
|
||||
2. **首页聚合**:`book/latest-chapters` 已有;可新增 `book/recommended`(精选)、首页「最新新增」复用 latest 按时间筛。
|
||||
3. **导师模块**:新建 `mentors` 表(头像、姓名、简介、技能标签、价格、服务内容、判断风格等);新建 `mentor_consultations`(预约单:user_id、mentor_id、时间、状态、支付);接口:`GET/POST /api/miniprogram/mentors`(列表/详情/预约)。
|
||||
4. **个人资料扩展**:users 表可扩展 `story_*`、`help_offer`、`help_need`、`project_intro` 等;或新建 `user_profiles` 关联 users。编辑接口扩展现有 `user/profile`。
|
||||
|
||||
**实施顺序**:① 章节 NEW 标记 + 首页/目录所需接口补齐 → ② 会员落地(现 vip 已够)→ ③ 导师表 + 预约接口 → ④ 资料扩展。
|
||||
|
||||
### 【管理端开发工程师】
|
||||
|
||||
**可复用**:章节管理(admin/chapters、db/book)、用户/VIP 管理(db/users、db/vip-roles)。
|
||||
|
||||
**需新增**:
|
||||
|
||||
1. **导师管理**:`/api/admin/mentors` 或 `/api/db/mentors`,CRUD + 上下架;依赖后端 mentors 表。
|
||||
2. **预约管理**:`/api/admin/mentor-consultations`,列表、状态筛选、导出。
|
||||
3. **章节 NEW**:若 chapters 新增 is_new,管理端章节编辑页增加「标记 NEW」勾选。
|
||||
4. **会员**:现 db/users 已支持 Set VIP;权益文案可配置化(若后续需要)。
|
||||
|
||||
**实施顺序**:待后端 mentors、consultations 表与接口就绪后,再开发导师管理、预约管理页面;章节 NEW 可与后端同步上线。
|
||||
|
||||
### 【小程序开发工程师】
|
||||
|
||||
**可复用**:首页(index)、目录(catalog)、VIP 页(vip)、个人中心(profile)、支付流程。现有 `book/all-chapters`、`vip/status`、`user/profile`、`pay` 等已覆盖基础能力。
|
||||
|
||||
**需新增/改造**:
|
||||
|
||||
1. **首页**:按稿子接入「最新更新」「精选推荐」「最新新增」;`book/latest-chapters`、`book/hot` 已有,需确认 recommended 接口;超级个体复用 `vip/members`。
|
||||
2. **目录**:按 part 聚合、展示 NEW、免费/¥1;数据源 `book/all-chapters`,NEW 依赖后端字段或策略。
|
||||
3. **会员落地**:新页或改造 vip 页,权益展示 + 购买按钮,支付走现 `pay`。
|
||||
4. **导师**:新页「选择导师」「导师详情」,接入 `mentors` 列表/详情/预约接口。
|
||||
5. **资料编辑**:扩展表单字段(个人故事、互助需求、项目介绍)、手机/微信号弹窗(稿子 comprehensive_profile_editor_v1_2)。
|
||||
|
||||
**实施顺序**:① 首页/目录 UI 与数据对接 → ② 会员落地 → ③ 导师列表+详情 → ④ 资料编辑扩展。
|
||||
|
||||
### 【测试人员】
|
||||
|
||||
**核心场景**:
|
||||
|
||||
1. **阅读/付费**:免费节直接读;付费节未购/VIP 不可读;VIP 全章可读;单节购买与 VIP 购买互不冲突。
|
||||
2. **会员**:开通后 is_vip、vip_expire_date 正确;超级个体名单可见;权益生效。
|
||||
3. **导师**:列表搜索/筛选、详情展示、预约创建、支付(若预约收费)。
|
||||
4. **资料**:编辑保存成功;手机/微信号未填时提现、找伙伴应拦截并引导弹窗。
|
||||
|
||||
**联调**:小程序↔API(book、vip、user、mentors);管理端↔API(chapters、mentors、consultations)。
|
||||
|
||||
**实施顺序**:接口就绪后补充用例;优先阅读/会员,再导师、资料。
|
||||
|
||||
### 实现路线图(共识)
|
||||
|
||||
| 阶段 | 后端 | 管理端 | 小程序 | 测试 |
|
||||
|-----|------|-------|--------|------|
|
||||
| **P0** | chapters 支持 NEW;book/latest、book/recommended 确认或补齐 | 章节编辑支持 NEW | 首页/目录 UI 与数据对接 | 阅读/会员用例 |
|
||||
| **P1** | 会员沿用现 vip;无新增接口 | — | 会员落地页 | 会员开通验收 |
|
||||
| **P2** | mentors 表 + consultations 表;列表/详情/预约接口 | 导师 CRUD、预约列表 | 导师列表+详情+预约 | 导师预约流程 |
|
||||
| **P3** | users 扩展或 user_profiles;profile 接口扩展 | — | 资料编辑扩展、手机/微弹窗 | 资料+拦截校验 |
|
||||
|
||||
**启动条件**:产品确认 MVP 范围与验收标准后,后端先输出 P0 接口方案,管理端/小程序按路线图跟进。
|
||||
|
||||
---
|
||||
|
||||
## 各开发对新需求的看法
|
||||
|
||||
### 【后端开发】
|
||||
|
||||
需求清晰,与现有 chapter/book/vip 模型兼容度高,可复用为主、增量开发。导师和资料扩展是主要新增点,技术风险可控。建议产品尽早确认 P2 导师价格配置方式(固定/可配置)、预约状态流转,便于接口设计。
|
||||
|
||||
### 【管理端开发工程师】
|
||||
|
||||
见下方「管理端建设性与补充说明」。
|
||||
|
||||
### 【小程序开发工程师】
|
||||
|
||||
稿子完整、交互明确,实现难度主要在数据对接和组件复用。首页/目录 P0 已落地;会员、导师、资料按阶段推进即可。建议后端接口响应格式稳定后再做样式微调,减少返工。
|
||||
|
||||
### 【测试人员】
|
||||
|
||||
场景边界清楚,可分批补充用例。需关注:导师预约与支付的联调、资料未填时的拦截逻辑、会员与单节购买的权益优先级。
|
||||
|
||||
---
|
||||
|
||||
## 管理端建设性与补充说明(基于小程序需求)
|
||||
|
||||
> 管理端对应小程序各模块,除基础 CRUD 外,建议补充以下能力以更好支持运营与数据闭环。
|
||||
|
||||
| 小程序模块 | 管理端基础能力 | 建设性补充 | 说明 |
|
||||
|-----------|----------------|------------|------|
|
||||
| **首页/目录** | 章节 NEW 标记 | ① 精选推荐固定兜底章节配置<br>② 章节阅读量/点击数据看板 | 算法兜底可运营配置;运营需看到哪些章节受欢迎 |
|
||||
| **会员落地** | 用户 VIP 开通 | ① 会员权益文案配置化<br>② 会员开通/续费统计 | 权益文案可随活动调整;统计支撑运营决策 |
|
||||
| **导师/预约** | 导师 CRUD、预约列表 | ① 导师排序/推荐位<br>② 咨询项目与价格配置<br>③ 预约数据统计(按导师/按时间) | 小程序列表顺序可运营控制;价格可调;数据支撑导师运营 |
|
||||
| **我的/分享收益** | (若已有收益逻辑) | ① 收益明细与分润规则配置<br>② 提现审核流程 | 小程序有分享收益、可提现金额,管理端需审核与配置 |
|
||||
| **个人资料** | — | ① 用户资料完善率统计<br>② (若涉及敏感)资料审核 | 支撑找伙伴匹配质量;可选能力 |
|
||||
|
||||
### 管理端补充优先级建议
|
||||
|
||||
| 优先级 | 补充项 | 与小程序关联 |
|
||||
|--------|--------|--------------|
|
||||
| 高 | 导师排序/推荐位、咨询项目价格配置 | 小程序导师列表展示顺序、v2 弹窗价格 |
|
||||
| 高 | 精选推荐兜底章节配置 | 小程序首页精选推荐无数据时的展示 |
|
||||
| 中 | 会员权益文案配置、开通统计 | 小程序会员落地页权益展示 |
|
||||
| 中 | 预约数据统计 | 导师运营效果评估 |
|
||||
| 低 | 资料完善率、提现审核 | 找伙伴质量、收益闭环 |
|
||||
|
||||
---
|
||||
|
||||
## 开发协作方案
|
||||
|
||||
> 各开发角色如何协作、谁先谁后、交接点、并行与串行。
|
||||
|
||||
### 协作总原则
|
||||
|
||||
- **产品先行**:MVP 范围与验收标准确定后,开发方可启动。
|
||||
- **后端先行**:接口契约先出,小程序/管理端再对接。
|
||||
- **分阶段接力**:按 P0→P1→P2→P3 推进,每阶段有明确交付与验收。
|
||||
- **接口契约**:后端每阶段输出接口文档(路径、请求/响应、字段),前端按契约开发。
|
||||
|
||||
### 阶段内协作时序
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ P0:首页/目录 + NEW 标记 │
|
||||
└─────────────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
产品确认 MVP 与验收
|
||||
│
|
||||
▼
|
||||
【后端】输出 P0 接口契约
|
||||
· chapters 是否新增 is_new?若否,说明「最新新增」判定规则(如 created_at 近 7 天)
|
||||
· book/latest-chapters、book/recommended 响应格式
|
||||
· book/all-chapters 是否返回 is_new 或等价信息
|
||||
│
|
||||
├──────────────────────────┬──────────────────────────┐
|
||||
▼ ▼ ▼
|
||||
【后端】实现 P0 接口 【管理端】章节编辑支持 NEW 【小程序】首页/目录 UI
|
||||
(迁移脚本 + handler) (依赖 chapters 结构) (按契约 Mock 或直连)
|
||||
│ │ │
|
||||
└──────────────────────────┴──────────────────────────┘
|
||||
│
|
||||
▼
|
||||
【测试】阅读/会员用例补充 ──► 联调验证 ──► P0 验收
|
||||
```
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ P1:会员落地 │
|
||||
└─────────────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
无新接口,沿用现 vip 与 pay
|
||||
│
|
||||
▼
|
||||
【小程序】会员落地页(权益展示 + 购买按钮)
|
||||
│
|
||||
▼
|
||||
【测试】会员开通验收 ──► P1 验收
|
||||
```
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ P2:导师 + 预约 │
|
||||
└─────────────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
【后端】输出 P2 接口契约
|
||||
· mentors 表结构、字段
|
||||
· mentor_consultations 表结构、状态流转
|
||||
· GET/POST /api/miniprogram/mentors(列表/详情/预约)
|
||||
· GET/POST /api/admin/mentors、/api/admin/mentor-consultations
|
||||
│
|
||||
├──────────────────────────┬──────────────────────────┐
|
||||
▼ ▼ ▼
|
||||
【后端】实现 mentors + 预约接口 【管理端】导师 CRUD、预约列表 【小程序】导师列表+详情+预约
|
||||
(迁移 + 小程序接口 + admin 接口) (依赖 admin 接口) (按契约对接)
|
||||
│ │ │
|
||||
└──────────────────────────┴──────────────────────────┘
|
||||
│
|
||||
▼
|
||||
【测试】导师预约流程 ──► 三端联调 ──► P2 验收
|
||||
```
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ P3:资料编辑扩展 │
|
||||
└─────────────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
【后端】输出 P3 接口契约
|
||||
· users 扩展字段 或 user_profiles 表
|
||||
· user/profile 接口扩展(个人故事、互助需求、项目介绍、手机、微信号)
|
||||
· 提现/找伙伴入口的「手机/微未填」校验规则
|
||||
│
|
||||
├──────────────────────────┐
|
||||
▼ ▼
|
||||
【后端】实现 profile 扩展 【小程序】资料编辑扩展、弹窗
|
||||
│ │
|
||||
└──────────────────────────┘
|
||||
│
|
||||
▼
|
||||
【测试】资料 + 拦截校验 ──► P3 验收
|
||||
```
|
||||
|
||||
### 角色职责与交接
|
||||
|
||||
| 角色 | 职责 | 交接给谁 | 交接物 |
|
||||
|------|------|----------|--------|
|
||||
| **产品** | 确认 MVP、验收标准;P0 前完成 | 全体 | 需求文档(或会议纪要中验收部分) |
|
||||
| **后端** | 每阶段输出接口契约并实现 | 管理端、小程序、测试 | 接口文档(路径、字段、示例) |
|
||||
| **管理端** | P0 章节 NEW;P2 导师/预约管理 | 测试 | 可用的管理端页面 |
|
||||
| **小程序** | P0~P3 按阶段实现 C 端页面 | 测试 | 可联调的小程序 |
|
||||
| **测试** | 每阶段补充用例、联调验收 | 产品 | 验收报告 |
|
||||
|
||||
### 并行与串行
|
||||
|
||||
| 关系 | 说明 |
|
||||
|------|------|
|
||||
| **产品 → 后端** | 串行:产品确认后,后端才能定方案 |
|
||||
| **后端 → 管理端/小程序** | 串行开头:接口契约出后才能开发;契约出后可并行 |
|
||||
| **管理端 ↔ 小程序** | 并行:同阶段内各自对接各自接口,无互相依赖 |
|
||||
| **P0 ↔ P1** | P1 可早于 P0 完成(会员无新接口);但建议 P0 先验收再开 P2 |
|
||||
| **P2 管理端** | 依赖后端 mentors 接口;可与小程序并行,但都等后端 |
|
||||
|
||||
### 沟通节点
|
||||
|
||||
| 节点 | 参与 | 目的 |
|
||||
|------|------|------|
|
||||
| 需求确认会 | 产品 + 全体 | 定 MVP、验收标准 |
|
||||
| P0 接口评审 | 后端 + 管理端 + 小程序 | 确认 chapters is_new、book 接口格式 |
|
||||
| P2 接口评审 | 后端 + 管理端 + 小程序 | 确认 mentors、consultations 模型 |
|
||||
| 每阶段联调 | 后端 + 管理端 + 小程序 + 测试 | 验证功能、过 checklist |
|
||||
| 阻塞时 | 阻塞方 + 被依赖方 | 快速澄清、调整契约 |
|
||||
|
||||
### 协作 checklist(每阶段结束前)
|
||||
|
||||
- [ ] 后端:接口已挂到正确路由组,文档已更新
|
||||
- [ ] 管理端:仅用 `/api/admin/*`、`/api/db/*`,字段与接口一致
|
||||
- [ ] 小程序:仅用 `/api/miniprogram/*`,错误处理完整
|
||||
- [ ] 测试:用例已补充,联调通过
|
||||
- [ ] 全体:过 soul-change-checklist
|
||||
|
||||
---
|
||||
|
||||
## 各角色经验与业务理解更新
|
||||
|
||||
本次会议结论已同步至各角色 `agent/{角色}/evolution/2026-02-28.md`。
|
||||
|
||||
### 产品经理
|
||||
|
||||
- stitch_soul 串联「内容→会员→导师」变现路径;临时需求池 10 个稿子覆盖完整流程;需在正式需求文档中明确业务定义与验收标准。
|
||||
|
||||
### 后端开发
|
||||
|
||||
- 需新建或扩展导师实体;现有 chapter/book/vip 可与产品核对后复用;接口挂 `/api/miniprogram/*`。
|
||||
|
||||
### 管理端开发工程师
|
||||
|
||||
- 需管理章节、导师、会员、预约、收益;待后端方案确定后规划管理页面。
|
||||
|
||||
### 小程序开发工程师
|
||||
|
||||
- 首页/目录/会员/导师/资料五类页面;待需求与接口确定后分阶段实现。
|
||||
|
||||
### 测试人员
|
||||
|
||||
- 关键场景:阅读/付费/会员/导师预约/资料;待需求确定后补充联调用例。
|
||||
|
||||
### 团队共享
|
||||
|
||||
- stitch_soul 与现有三端架构协同;路由约定保持不变:小程序 `/api/miniprogram/*`,管理端 `/api/admin/*`、`/api/db/*`。
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
## 开发团队重新分析:怎么实现(可执行方案)
|
||||
|
||||
> 在问题 1~5 作答、精选推荐算法、实现路线图基础上,结合现有代码梳理出的可执行实现方案。
|
||||
|
||||
### 现状与差异
|
||||
|
||||
| 能力 | 现状 | 与需求差异 |
|
||||
|------|------|------------|
|
||||
| 精选推荐 / 热门 | `book/hot` 按 sort_order 取 10 条 | 需按**阅读量**排序;排除序言/尾声/附录;精选取 3 条并打「热门/推荐/精选」 |
|
||||
| 最新更新 / 最新新增 | `book/latest-chapters` 按 updated_at 取 20 条;**未挂 miniprogram** | 需挂到 miniprogram;「最新新增」可复用或加 is_new 筛选 |
|
||||
| 目录 NEW | chapters 无 is_new | 需新增 is_new 或按 created_at 近 N 天 |
|
||||
| 会员 | vip + pay 已有 | 无差异 |
|
||||
| 导师 | 无 | 需新建 mentors、consultations |
|
||||
| 资料扩展 | user/profile 有基础字段 | 需扩展 story/help_offer/help_need/project_intro |
|
||||
|
||||
### 分阶段实现清单(可执行)
|
||||
|
||||
#### P0:首页/目录 + NEW + 精选推荐算法
|
||||
|
||||
| 序号 | 角色 | 动作 | 产出 |
|
||||
|-----|------|------|------|
|
||||
| P0-1 | 后端 | chapters 表新增 `is_new`(bool);迁移脚本 + AutoMigrate | 字段可用 |
|
||||
| P0-2 | 后端 | `book/hot` 改为按阅读量排序:从 reading_progress 按 section_id 分组 count;兜底按 updated_at;排除 part 含「序言/尾声/附录」 | 符合算法 |
|
||||
| P0-3 | 后端 | 新增 `book/recommended`:同 hot 逻辑,取前 3 条,返回时带 tag(热门/推荐/精选) | 首页精选用 |
|
||||
| P0-4 | 后端 | `book/latest-chapters` 挂到 miniprogram 组 | 小程序可调 |
|
||||
| P0-5 | 后端 | `book/all-chapters` 响应中每章带 `isNew` | 目录 NEW 展示 |
|
||||
| P0-6 | 管理端 | 章节编辑页增加「标记 NEW」勾选 | 运营可配置 |
|
||||
| P0-7 | 小程序 | 首页:最新更新(latest)、精选推荐(recommended)、最新新增(all-chapters 筛 isNew)、超级个体(vip/members)、阅读进度(已有) | 首页按稿子完成 |
|
||||
| P0-8 | 小程序 | 目录:按 part 聚合、展示 NEW、免费/¥1 | 目录按稿子完成 |
|
||||
| P0-9 | 测试 | 阅读/会员用例;精选推荐取数、NEW 展示 | 联调通过 |
|
||||
|
||||
**阅读量数据来源**:`reading_progress` 表按 `section_id` 分组 count;若无数据则用兜底(updated_at 或固定 3 章)。
|
||||
|
||||
#### P1:会员落地
|
||||
|
||||
| 序号 | 角色 | 动作 | 产出 |
|
||||
|-----|------|------|------|
|
||||
| P1-1 | 小程序 | 会员落地页(权益展示 + ¥1980 购买),支付走现 pay | 可开通会员 |
|
||||
| P1-2 | 测试 | 会员开通验收 | 通过 |
|
||||
|
||||
#### P2:导师 + 预约
|
||||
|
||||
| 序号 | 角色 | 动作 | 产出 |
|
||||
|-----|------|------|------|
|
||||
| P2-1 | 后端 | 新建 mentors 表(**支持每个导师独立价格配置**:单次/半年/年度)、mentor_consultations 表;迁移脚本 | 表就绪 |
|
||||
| P2-2 | 后端 | `GET/POST /api/miniprogram/mentors`(列表/详情/预约,价格从导师配置读取);`GET/POST /api/admin/mentors`、`/api/admin/mentor-consultations` | 接口可用 |
|
||||
| P2-3 | 管理端 | 导师管理 CRUD、**导师价格配置(每个导师独立)**、预约列表(状态筛选、导出) | 可管理导师 |
|
||||
| P2-4 | 小程序 | 导师列表、导师详情、**联系导师按钮点击 → 弹出 v2 弹窗(选择咨询项目)**、预约入口 | 可预约 |
|
||||
| P2-5 | 测试 | 导师预约流程 | 联调通过 |
|
||||
|
||||
#### P3:资料编辑扩展
|
||||
|
||||
| 序号 | 角色 | 动作 | 产出 |
|
||||
|-----|------|------|------|
|
||||
| P3-1 | 后端 | users 扩展 story_best_month、story_achievement、story_turning、help_offer、help_need、project_intro;或新建 user_profiles | 字段可用 |
|
||||
| P3-2 | 后端 | `user/profile` 接口读写扩展字段;提现/找伙伴入口校验手机/微 | 接口可用 |
|
||||
| P3-3 | 小程序 | 资料编辑扩展表单;手机/微未填时弹窗并拦截提现/找伙伴;**我的页头像资料卡片加「编辑」图标 → 跳转个人资料展示页** | 符合稿子 |
|
||||
| P3-4 | 测试 | 资料保存、拦截校验 | 通过 |
|
||||
|
||||
### 接口契约速查(后端输出后可据此开发)
|
||||
|
||||
**P0**
|
||||
|
||||
- `GET /api/miniprogram/book/recommended` → `{ data: [{ id, mid, sectionTitle, partTitle, tag: "热门"|"推荐"|"精选", ... }] }`
|
||||
- `GET /api/miniprogram/book/hot` → 同算法,limit 10,无 tag
|
||||
- `GET /api/miniprogram/book/latest-chapters` → 新增挂载
|
||||
- `GET /api/miniprogram/book/all-chapters` → 每项增加 `isNew`
|
||||
|
||||
**P2**
|
||||
|
||||
- `GET /api/miniprogram/mentors?q=&skill=` → 列表(含每导师价格,从配置读取)
|
||||
- `GET /api/miniprogram/mentors/:id` → 详情(含单次/半年/年度价格,从配置读取)
|
||||
- `POST /api/miniprogram/mentors/:id/book` → 预约
|
||||
- 后端 mentors 表/模型:支持 `price_single`、`price_half_year`、`price_year` 等按导师配置;管理端 PUT `/api/admin/mentors` 或 db 接口支持写入
|
||||
|
||||
**P3**
|
||||
|
||||
- `user/profile` 请求/响应增加 story_*、help_offer、help_need、project_intro
|
||||
|
||||
### 实施顺序(单人在多端开发时)
|
||||
|
||||
1. 产品确认 MVP 与验收标准(可复用会议纪要)。
|
||||
2. 后端完成 P0-1~P0-5,输出接口契约 → 管理端 P0-6、小程序 P0-7~P0-8 并行。
|
||||
3. P0 联调验收后,P1 小程序独立完成。
|
||||
4. 后端 P2-1~P2-2 → 管理端 P2-3、小程序 P2-4 并行。
|
||||
5. 后端 P3-1~P3-2 → 小程序 P3-3。
|
||||
|
||||
---
|
||||
|
||||
## 附录:页面重构专项会议(设计稿全覆盖 10 张图)
|
||||
|
||||
> **触发**:用户要求读取 stitch_soul 全部图片并开会,明确涉及「页面重构」的需求;此前会议未逐张覆盖设计稿。
|
||||
|
||||
---
|
||||
|
||||
### 各角色发言(页面重构专项)
|
||||
|
||||
**【产品经理】**
|
||||
10 张稿子覆盖 8 类页面:首页、目录、会员落地、我的(VIP+收益)、个人资料展示、资料编辑(完整+弹窗)、导师列表、导师详情(含咨询选择弹窗)。页面重构优先级:首页/目录(P0 已有)→ 会员落地(P1)→ 导师(P2)→ 资料展示与编辑(P3)。需澄清:找伙伴高亮逻辑、导师详情 v1/v2 与弹窗关系、我的页与个人资料的跳转关系。
|
||||
|
||||
**【后端开发】**
|
||||
页面重构主要影响前端;后端需配合:P2 导师列表/详情/预约接口返回的字段需支撑卡片展示(头像、简介、标签数组、价格);P3 资料扩展字段需覆盖个人故事、互助需求、项目介绍。接口契约与现有实现方案一致。
|
||||
|
||||
**【管理端开发工程师】**
|
||||
管理端无对应设计稿,但导师管理、预约列表、章节 NEW 勾选等页面需与小程序风格一致(深色主题、标签样式)。可参考 stitch_soul 的组件规范做管理端组件库扩展。
|
||||
|
||||
**【小程序开发工程师】**
|
||||
10 张稿子结构清晰,适合组件化:权益卡片、标签、弹窗、底部按钮、数据统计卡片可抽成通用组件。深色主题需统一定义变量。首页、目录 P0 已完成;会员落地、导师、资料按阶段推进时需严格按稿子还原布局与交互。
|
||||
|
||||
**【测试人员】**
|
||||
页面重构验收重点:① 各页面与设计稿一致性(布局、颜色、标签);② 弹窗触发时机(手机/微未填、咨询选择);③ 深色主题在小程序中的表现;④ 组件复用时样式无错乱。
|
||||
|
||||
---
|
||||
|
||||
### 设计稿清单与重构识别
|
||||
|
||||
> 基于对 stitch_soul 下 **全部 10 张 design 图片** 的逐张阅读,补充「页面重构」识别与组件化建议。此前会议未逐张覆盖,本节补齐。
|
||||
|
||||
### 设计稿清单与重构识别
|
||||
|
||||
| # | 目录 | 页面类型 | 页面重构要点 | 映射阶段 |
|
||||
|---|------|----------|--------------|----------|
|
||||
| 1 | `optimized_home_content_feed_v1` | 首页内容流 | **布局**:顶部品牌+搜索→最新更新大卡片→阅读进度→超级个体→精选推荐→最新新增;**组件**:搜索框、大卡片、进度条、头像列表、内容卡片、NEW 标签;**交互**:展开/折叠、价格 ¥1 | P0 |
|
||||
| 2 | `catalog_with_new_additions_v1` | 目录 | **布局**:书籍概览卡片→按 part 可展开/折叠列表;**组件**:免费/NEW/¥1 标签、章节列表项、折叠箭头;**主题**:深色模式;**交互**:找伙伴图标高亮(动态状态) | P0 |
|
||||
| 3 | `premium_membership_landing_v1` | 会员落地页 | **布局**:导航→VIP 宣传区→内容权益 4 卡 + 社交权益 4 卡(双列)→底部固定按钮;**组件**:权益卡片(图标+文字)、¥1980 按钮;**色彩**:绿/黄/橙强调色;**需提取**:权益卡片通用组件 | P1 |
|
||||
| 4 | `professional_profile_with_earnings_vip` | 我的(VIP+收益) | **布局**:用户区(VIP 徽章、会员/匹配/排行标签、到期时间)→分享收益→阅读统计→最近阅读→我的订单/关于作者;**组件**:数据卡片、统计三列、最近阅读项;**状态**:VIP、收益、可提现 | P1/P3 |
|
||||
| 5 | `enhanced_professional_profile` | 个人资料展示 | **布局**:头像+昵称+MBTI/地区→基本信息→个人故事→互助需求→项目介绍→「成为超级个体」;**组件**:卡片分组、复制按钮、奖杯/星星/循环图标;**动态内容**:故事/需求长度不固定 | P3 |
|
||||
| 6 | `comprehensive_profile_editor_v1_1` | 资料编辑(完整版) | **布局**:温馨提示→头像→基本信息→核心联系方式→个人故事→互助需求→项目介绍→保存;**组件**:表单输入、下拉、地区图钉、多行文本;**样式**:深色主题,浅绿强调 | P3 |
|
||||
| 7 | `comprehensive_profile_editor_v1_2` | 资料编辑(弹窗) | **组件**:居中弹窗,手机号/微信号输入、保存/取消;**触发**:提现/找伙伴入口时手机或微信号未填;**需设计**:弹窗触发时机、必填校验 | P3 |
|
||||
| 8 | `mentor_listing_screen` | 导师列表 | **布局**:搜索→筛选标签→推荐导师列表;**组件**:导师卡片(头像、姓名、简介、标签、价格、预约);**数据**:需头像、姓名、简介、标签数组、价格、ID | P2 |
|
||||
| 9 | `mentor_detail_profile_1` | 导师详情 v1 | **布局**:头像+姓名+理念+引言→01 为什么找→02 提供什么→03 收费标准→04 判断风格→联系导师;**组件**:编号区块、标签组、收费表格、划线价;**强调色**:青色 | P2 |
|
||||
| 10 | `mentor_detail_profile_2` | 导师详情 v2(咨询选择弹窗) | **组件**:居中弹窗,单选(单次/半年/年度)、原价划掉、推荐标签、确认选择;**背景**:模糊的「我的」页;**复用**:可与会员/购买类弹窗共用模式 | P2 |
|
||||
|
||||
### 跨稿子组件抽取建议
|
||||
|
||||
| 组件 | 复用页面 | 说明 |
|
||||
|------|----------|------|
|
||||
| 权益卡片 | 会员落地、导师详情 | 图标+标题+描述,圆角深灰背景 |
|
||||
| 标签(Tag) | 目录、导师列表、导师详情、个人资料 | 免费/NEW/¥1、技能标签、MBTI/地区 |
|
||||
| 弹窗(手机/微、咨询选择) | 资料编辑、导师详情 | 居中圆角、输入/单选、保存/确认+取消 |
|
||||
| 底部固定按钮 | 会员落地、导师详情、资料编辑 | 宽按钮、主色填充 |
|
||||
| 数据统计卡片 | 我的、阅读进度 | 多列数字+图标+说明 |
|
||||
| 头像+昵称+标签区 | 个人资料、超级个体、导师 | 圆形头像、下方标签 |
|
||||
|
||||
### 深色主题与色彩体系(统一约束)
|
||||
|
||||
- **主色**:深黑/深灰背景,白/浅灰文字
|
||||
- **强调色**:绿色(主 CTA、VIP)、黄色(会员、推荐)、橙色(社交权益、部分标签)、青色(导师详情)
|
||||
- **一致性**:所有 10 张稿均为深色模式,重构时需统一定义 CSS 变量或主题配置
|
||||
|
||||
### 待确认(页面重构相关)— 已澄清
|
||||
|
||||
| # | 问题 | 作答 |
|
||||
|---|------|------|
|
||||
| 1 | 底部导航「找伙伴」高亮逻辑? | **不用改**,保持现状 |
|
||||
| 2 | 导师详情 v1 与 v2 弹窗关系? | **导师详情 v1** 点击下方「联系导师」按钮 → 弹出 **v2 弹窗**(选择咨询项目) |
|
||||
| 3 | 「我的」页与「个人资料展示」的跳转? | **我的**页头像资料卡片增加「编辑」图标,点击进入**个人资料展示页**(enhanced_professional_profile) |
|
||||
|
||||
---
|
||||
|
||||
*会议纪要由助理橙子生成 | 各角色经验已同步至 `agent/{角色}/evolution/2026-02-28.md`*
|
||||
153
.cursor/meeting/2026-02-28_文章类型普通版增值版需求分析.md
Normal file
153
.cursor/meeting/2026-02-28_文章类型普通版增值版需求分析.md
Normal file
@@ -0,0 +1,153 @@
|
||||
# 会议纪要 - 2026-02-28 | 文章增加类型(普通版 / 增值版)需求分析
|
||||
|
||||
> 本文件由**助理橙子**在会议结束后自动生成。
|
||||
|
||||
---
|
||||
|
||||
## 基本信息
|
||||
|
||||
- **时间**:2026-02-28
|
||||
- **议题**:文章增加类型(普通版 / 增值版),增值版后 N 章额外付费、按章累加计价
|
||||
- **触发方式**:开个会议分析需求
|
||||
- **参与角色**:产品经理、后端开发、管理端开发工程师、小程序开发工程师、测试人员
|
||||
|
||||
---
|
||||
|
||||
## 各角色发言
|
||||
|
||||
### 【产品经理】
|
||||
|
||||
**需求理解**:
|
||||
1. **普通版**:全书 9.9 元,一次性买断,与现有 fullbook 逻辑一致。
|
||||
2. **增值版**:基础价 + 「后 N 章」(N 可配置,如 10)需额外付费;每多看一章,价格 = 已付金额 + 该章单价,按章累加。
|
||||
3. **两者关系**:普通版与增值版是**分开的、互斥的两套产品**,用户购买其一,非叠加关系。
|
||||
|
||||
**待澄清**:
|
||||
- 「后 N 章」是指全书最后 N 个 section,还是最后 N 个 chapter?
|
||||
- 增值版基础价是否仍为 9.9,还是单独定价?
|
||||
|
||||
**用户价值**:用阶梯付费降低首购门槛,提升付费转化;增值版满足深度阅读用户需求。
|
||||
|
||||
---
|
||||
|
||||
### 【后端开发】
|
||||
|
||||
**现状**:
|
||||
- `chapters` 表:`id`、`part_id`、`chapter_id`、`section_title`、`price` 等;现有按 section 购买、fullbook 9.9。
|
||||
- `orders` 表:`product_type` 含 `section`、`fullbook`、`vip`;`product_id` 存 section id 或 `fullbook`。
|
||||
|
||||
**技术方案建议**:
|
||||
1. **书/产品类型**:增加 `book_edition` 或 `product_edition` 概念:
|
||||
- `standard`:普通版,9.9 买断
|
||||
- `premium`:增值版,基础价 + 增值章节按章付费
|
||||
2. **配置**:`system_config` 增加 `premium_config`:
|
||||
- `premium_base_price`:增值版基础价
|
||||
- `premium_chapter_count`:后 N 章(section 数量或 chapter 数量需与产品约定)
|
||||
- `premium_section_ids`:或直接配置增值章节 id 列表(灵活)
|
||||
3. **接口**:
|
||||
- `GET /api/miniprogram/user/purchase-status`:需区分普通版 / 增值版购买态,返回 `editionType`、`premiumPurchasedSections` 等
|
||||
- 支付:`product_type` 扩展 `section_premium` 或沿用 `section`,`product_id` 为 section id,金额按章节 price 累加
|
||||
4. **权限**:普通版权限独立;增值版权限 = 增值版基础价已购 + 该 section 已单独付费;两者互斥。
|
||||
|
||||
---
|
||||
|
||||
### 【管理端开发工程师】
|
||||
|
||||
**管理端需求**:
|
||||
1. **书籍/版本配置**:支持选择「普通版 / 增值版」或为同一本书配置两种版本。
|
||||
2. **增值章节配置**:配置「后 N 章」的 N,或勾选具体 section 作为增值章节。
|
||||
3. **章节单价**:增值章节的单价在章节编辑中维护(现有 `chapters.price`)。
|
||||
4. **价格展示**:在书籍/章节管理列表中区分普通版、增值版及增值章节。
|
||||
|
||||
**接口依赖**:需 `GET/POST /api/db/chapters` 支持 `is_premium` 或类似标记;`/api/db/config` 或 `/api/admin/settings` 支持 premium_config。
|
||||
|
||||
---
|
||||
|
||||
### 【小程序开发工程师】
|
||||
|
||||
**C 端体验**:
|
||||
1. **选购**:目录/书籍页区分「普通版 9.9」与「增值版 基础价 + 增值章节按章付费」。
|
||||
2. **阅读**:进入增值章节时,未购则展示「该章需额外 ¥X.X 解锁」或类似提示,点击发起支付。
|
||||
3. **支付流程**:与现有一致,`product_type`、`product_id`、`amount` 由后端计算并返回。
|
||||
4. **权限**:依赖 `purchase-status` 返回的 `editionType`、`premiumPurchasedSections` 等判断是否可读。
|
||||
|
||||
**接口**:需 `miniprogram` 组下的 `purchase-status`、`pay` 支持增值版逻辑。
|
||||
|
||||
---
|
||||
|
||||
### 【测试人员】
|
||||
|
||||
**测试重点**:
|
||||
1. 普通版 9.9 买断,全书可读。
|
||||
2. 增值版:基础价购买后,后 N 章仍锁定;逐章购买,价格累加正确。
|
||||
3. 边界:N=0、N=全书、章节无单价时的降级逻辑。
|
||||
4. 三端:管理端配置 → API 返回 → 小程序展示、支付、阅读权限。
|
||||
|
||||
---
|
||||
|
||||
## 讨论过程
|
||||
|
||||
**产品经理**:建议「后 N 章」先按 section 数量实现,便于与现有 `chapters` 结构对齐;后续可扩展为按 chapter。
|
||||
|
||||
**后端开发**:同意;建议 `premium_chapter_count` 表示「最后 N 个 section」,section 顺序按 `sort_order` 或 `id` 排序。
|
||||
|
||||
**管理端开发工程师**:需在章节列表中标注「是否增值章节」,并在书籍级配置中设置 N。
|
||||
|
||||
---
|
||||
|
||||
## 会议决议
|
||||
|
||||
1. **版本类型**:支持「普通版」(9.9 买断)与「增值版」(基础价 + 后 N 章按章付费);**两者分开、互斥**,用户只能购买其一。
|
||||
2. **增值章节**:「后 N 章」指全书最后 N 个 **section**(与 chapters 表结构一致);N 为可配置参数。
|
||||
3. **计价规则**:增值版基础价可配置(默认建议 9.9);增值章节单价取自 `chapters.price`;每购一章,实付 = 该章 price。
|
||||
4. **订单**:`product_type` 保留 `section`、`fullbook`;普通版用 `fullbook`;增值版用 `fullbook_premium`(基础价)和 `section`(增值章);增值章节购买用 `product_type=section`、`product_id=section_id`。
|
||||
5. **待确认项**:增值版基础价是否固定 9.9;N 默认值。
|
||||
|
||||
---
|
||||
|
||||
## 待办事项
|
||||
|
||||
| 责任角色 | 任务 | 优先级 | 截止建议 |
|
||||
|---------|------|--------|---------|
|
||||
| 产品经理 | 输出增值版 MRD:基础价、N 默认值、与普通版关系 | 高 | 需求定稿前 |
|
||||
| 后端开发 | 设计 premium_config、扩展 purchase-status / pay | 高 | 方案评审后 |
|
||||
| 管理端开发工程师 | 增值章节配置 UI、书籍版本选择 | 中 | 接口就绪后 |
|
||||
| 小程序开发工程师 | 增值版选购与章节解锁流程、支付衔接 | 中 | 接口就绪后 |
|
||||
| 测试人员 | 编写增值版测试用例、边界场景 | 中 | 开发完成前 |
|
||||
|
||||
---
|
||||
|
||||
## 问题与作答区
|
||||
|
||||
| # | 问题 | 责任角色 | 作答 |
|
||||
|---|------|---------|------|
|
||||
| 1 | 「后 N 章」按 section 还是 chapter 计数? | 产品经理 | 决议:按 section |
|
||||
| 2 | 增值版基础价是否固定 9.9? | 产品经理 | (待补充) |
|
||||
| 3 | 普通版与增值版是否互斥?用户能否同时拥有? | 产品经理 | **已确认:分开、互斥**,用户购买其一 |
|
||||
| 4 | N 的默认值建议?(如 10) | 产品经理 | (待补充) |
|
||||
|
||||
---
|
||||
|
||||
## 各角色经验与业务理解更新
|
||||
|
||||
### 产品经理
|
||||
- 文章/书籍可区分为普通版与增值版,增值版采用「基础价 + 增值章节按章付费」模式。
|
||||
|
||||
### 后端开发
|
||||
- 增值版需新增 `premium_config`,含 `premium_chapter_count`(后 N 个 section)、`premium_base_price`;增值章节购买沿用 `section` 订单。
|
||||
|
||||
### 管理端开发工程师
|
||||
- 需支持「增值版配置」与「增值章节」的 N、单价维护。
|
||||
|
||||
### 小程序开发工程师
|
||||
- 增值版需在目录与阅读页区分普通/增值,未购增值章节时展示解锁与支付入口。
|
||||
|
||||
### 测试人员
|
||||
- 增值版需覆盖:基础价购买、逐章购买、价格累加、权限边界、配置 N=0/全书的异常场景。
|
||||
|
||||
### 团队共享
|
||||
- 增值版计价规则:基础价 + Σ(增值章节单价),按章购买、按章累加。
|
||||
|
||||
---
|
||||
|
||||
*会议纪要由助理橙子生成 | 各角色经验已同步至 `agent/{角色}/evolution/2026-02-28.md`*
|
||||
122
.cursor/meeting/2026-03-05_分支冲突后功能完整性分析.md
Normal file
122
.cursor/meeting/2026-03-05_分支冲突后功能完整性分析.md
Normal file
@@ -0,0 +1,122 @@
|
||||
# 会议纪要 - 2026-03-05 | 分支冲突后功能完整性分析
|
||||
|
||||
> 本文件由**助理橙子**在会议结束后自动生成。
|
||||
|
||||
---
|
||||
|
||||
## 基本信息
|
||||
|
||||
- **时间**:2026-03-05
|
||||
- **议题**:分支冲突后可能有功能缺失,各成员分析自身项目完整性
|
||||
- **触发方式**:开个会议
|
||||
- **参与角色**:产品经理、后端开发、管理端开发工程师、小程序开发工程师、测试人员
|
||||
|
||||
---
|
||||
|
||||
## 各角色发言
|
||||
|
||||
### 【产品经理】
|
||||
|
||||
- 需求文档(stitch_soul、个人资料页、文章类型等)已记录,需核对 `开发文档/1、需求/`、`临时需求池/` 与实现是否一致
|
||||
- 风险:分支合并后文档可能被覆盖,导致需求与实现脱节
|
||||
- 重点确认:个人资料页、增值版/普通版计价、找伙伴联系方式完善弹窗
|
||||
|
||||
### 【后端开发】
|
||||
|
||||
- soul-api 被 .gitignore 排除,当前仓库无法直接检查
|
||||
- 风险:`/api/miniprogram/orders`、`/api/db/distribution` 等接口是否已实现需在 soul-api 所在位置核对
|
||||
- 建议:在 soul-api 仓库/目录确认合并状态,对照「三端需求业务对齐」逐项核对接口
|
||||
|
||||
### 【管理端开发工程师】
|
||||
|
||||
- 21 个路由与页面一一对应,无缺失;仅调用 `/api/admin/*`、`/api/db/*`,符合边界
|
||||
- 风险:`DistributionPage` 的 `GET /api/db/distribution` 若未实现会 404
|
||||
- 建议:全功能自测,记录 404 或异常接口反馈后端
|
||||
|
||||
### 【小程序开发工程师】
|
||||
|
||||
- 21 个页面均有对应目录和文件,无缺失;全部 `/api/miniprogram/*`,符合边界
|
||||
- 小问题:app.json 第 21 行多页面写同一行,建议拆行
|
||||
- 风险:`/api/miniprogram/orders` 是否已实现;`完整的` 分支上的优化(如 5a5f0087 卡片边距)是否已并入 devlop
|
||||
- 建议:核心流程自测(登录→阅读→购买→提现→找伙伴→个人资料→VIP)
|
||||
|
||||
### 【测试人员】
|
||||
|
||||
- 三端联调需逐项验证;回归清单应覆盖登录、VIP、阅读、分销、提现、找伙伴、个人资料、导师、购买记录
|
||||
- 风险:soul-api 无法在仓库内检查;多分支(完整的、soul-content、yongpxu-soul)合并结果需确认
|
||||
- 建议:制定「分支合并后回归清单」,各端自测 + 抽检
|
||||
|
||||
---
|
||||
|
||||
## 讨论过程
|
||||
|
||||
- **乘风**:reflog 显示 devlop 曾 reset 到 58d4c0b6,后又提交 7e3d36d6;`完整的` 分支有 5a5f0087 等提交,是否已并入 devlop?
|
||||
- **小程序**:需对比 devlop 与 `完整的` 的 miniprogram 差异,确认 2026-03-03 卡片边距等优化是否保留
|
||||
- **后端**:soul-api 不在本仓库,需在 soul-api 所在位置单独确认 git 状态与合并情况
|
||||
- **管理端**:结构完整,主要风险在接口可用性,需联调确认
|
||||
|
||||
---
|
||||
|
||||
## 会议决议
|
||||
|
||||
1. **小程序端**:修正 app.json 第 21 行多页面拆行;核心流程自测;确认 `/api/miniprogram/orders` 是否可用
|
||||
2. **管理端**:全功能自测,记录 404/异常接口反馈后端
|
||||
3. **后端**:在 soul-api 所在仓库确认当前分支与合并状态;核对 orders、distribution 等接口是否已实现并挂载
|
||||
4. **产品**:核对 `开发文档/`、`临时需求池/` 与实现一致性;重点确认个人资料、增值版/普通版、找伙伴
|
||||
5. **测试**:制定「分支合并后回归清单」,覆盖登录、VIP、阅读、分销、提现、找伙伴、个人资料、导师、购买记录
|
||||
6. **待确认**:`完整的` 分支上的提交是否已全部并入 devlop;soul-api 的版本管理与合并策略
|
||||
|
||||
---
|
||||
|
||||
## 待办事项
|
||||
|
||||
| 责任角色 | 任务 | 优先级 | 截止建议 |
|
||||
|---------|------|--------|---------|
|
||||
| 小程序开发工程师 | 修正 app.json 第 21 行;核心流程自测;确认 orders 接口 | 高 | 2026-03-06 |
|
||||
| 管理端开发工程师 | 全功能自测,记录 404/异常接口 | 高 | 2026-03-06 |
|
||||
| 后端开发 | 在 soul-api 确认合并状态;核对 orders、distribution 接口 | 高 | 2026-03-06 |
|
||||
| 产品经理 | 核对需求文档与实现一致性 | 中 | 2026-03-06 |
|
||||
| 测试人员 | 制定「分支合并后回归清单」 | 中 | 2026-03-06 |
|
||||
|
||||
---
|
||||
|
||||
## 问题与作答区
|
||||
|
||||
| # | 问题 | 责任角色 | 作答 |
|
||||
|---|------|---------|------|
|
||||
| 1 | `完整的` 分支上的提交(5a5f0087 等)是否已全部并入 devlop? | 小程序开发工程师 | (待补充) |
|
||||
| 2 | soul-api 的版本管理与合并策略是什么?是否在独立仓库? | 后端开发 | (待补充) |
|
||||
| 3 | `/api/miniprogram/orders` 是否已实现并挂载到 miniprogram 组? | 后端开发 | (待补充) |
|
||||
| 4 | `/api/db/distribution` 是否已实现? | 后端开发 | (待补充) |
|
||||
|
||||
---
|
||||
|
||||
## 各角色经验与业务理解更新
|
||||
|
||||
### 产品经理
|
||||
|
||||
- 分支冲突后需优先核对需求文档与实现一致性,避免「文档在合并中丢失」导致需求脱节
|
||||
|
||||
### 后端开发
|
||||
|
||||
- soul-api 被 gitignore 时,需在 soul-api 所在位置单独确认合并状态;重点核对 orders、distribution 等接口是否已实现并挂载
|
||||
|
||||
### 管理端开发工程师
|
||||
|
||||
- 路由与页面结构完整时,主要风险在接口可用性;全功能自测可快速暴露 404 或异常接口
|
||||
|
||||
### 小程序开发工程师
|
||||
|
||||
- app.json 多页面配置建议拆行便于维护;分支合并后需做核心流程自测,确认 orders 等依赖接口可用
|
||||
|
||||
### 测试人员
|
||||
|
||||
- 分支合并后应制定「回归清单」,覆盖三端联调关键路径;soul-api 不在仓库时需与后端协作确认接口契约
|
||||
|
||||
### 团队共享
|
||||
|
||||
- 分支冲突后各端需做完整性自查:产品核对需求文档、后端核对接口、管理端/小程序核对页面与功能、测试制定回归清单
|
||||
|
||||
---
|
||||
|
||||
*会议纪要由助理橙子生成 | 各角色经验已同步至 `agent/{角色}/evolution/2026-03-05.md`*
|
||||
95
.cursor/meeting/2026-03-05_文章详情@某人加好友方案讨论.md
Normal file
95
.cursor/meeting/2026-03-05_文章详情@某人加好友方案讨论.md
Normal file
@@ -0,0 +1,95 @@
|
||||
# 会议纪要 - 2026-03-05 | 文章详情 @某人 高亮与一键加好友方案讨论
|
||||
|
||||
> 本文件由**助理橙子**在会议结束后自动生成。
|
||||
|
||||
---
|
||||
|
||||
## 基本信息
|
||||
|
||||
- **时间**:2026-03-05
|
||||
- **议题**:小程序文章详情中「@某人」高亮、点击添加好友;内容编辑时如何插入并存储用户信息(含用户 id),以及是否有更优实现方式
|
||||
- **触发方式**:开一个开发大会,讨论一下
|
||||
- **参与角色**:产品经理、后端开发、管理端开发工程师、小程序开发工程师、测试人员
|
||||
|
||||
---
|
||||
|
||||
## 各角色发言
|
||||
|
||||
### 【产品经理】
|
||||
|
||||
- 需求:文章中可出现「@某某人」,名称高亮,用户点击后执行添加该人为好友;添加好友能力以接口为准。
|
||||
- 用户价值:从内容到人的关系链沉淀,提升互动与转化。
|
||||
- 业务规则:仅支持 @ 已存在用户;展示名以昵称为准;点击统一为「发起添加好友」。
|
||||
- 验收标准:文章详情内 @ 名称高亮且可点击;点击后调用添加好友流程;管理端/编辑侧能插入 @用户 并落库(含用户 id)。
|
||||
|
||||
### 【后端开发】
|
||||
|
||||
- 添加好友接口需在 soul-api 的 **miniprogram** 路由组下提供(如 `POST /api/miniprogram/friend/add` 或 `POST /api/miniprogram/user/add-friend`),入参建议 `targetUserId`;`开发文档/api_v1.md` 当前为存客宝文档,添加好友接口应单独约定或在该文档中新增小节。
|
||||
- 内容存储推荐**方案 A**:正文存带 @ 标记的字符串,如 `@[昵称](userId)` 或 `{{@userId:昵称}}`,后端只存不解析,由前端解析;方案 B(正文 + mentions 位置表)需维护偏移量,正文变更易错位。
|
||||
- 数据模型:内容表扩展 content 存带 @ 标记的字符串即可,无需单独表。
|
||||
|
||||
### 【管理端开发工程师】
|
||||
|
||||
- 文章/章节编辑页增加「插入 @用户」:选择用户后插入到光标位置,保存时写入约定格式的 content;仅调 `/api/admin/*`、`/api/db/*`。
|
||||
- 管理端列表/预览可简单高亮或原样显示,与小程序约定同一 content 格式即可。
|
||||
|
||||
### 【小程序开发工程师】
|
||||
|
||||
- 阅读页当前为按行渲染纯文本;需将 content 解析为「段落 + 片段」(普通文本 / mention),WXML 中对 mention 渲染为可点击 `<text data-user-id>` 并高亮,点击时调用 miniprogram 添加好友接口。
|
||||
- 继续使用现有章节内容接口,保证返回的 content 含 @ 标记;添加好友调用 miniprogram 组新接口。
|
||||
|
||||
### 【测试人员】
|
||||
|
||||
- 用例:无 @ 行为不变;有 @ 高亮且点击调起添加好友并提示;重复点击、未登录、无权限等边界;管理端插入 @ 后保存再编辑,内容与用户 id 不错位。
|
||||
- 联调:小程序 ↔ 章节接口、添加好友接口;管理端 ↔ 内容保存与用户列表。回归:阅读页其他功能不受影响。
|
||||
|
||||
---
|
||||
|
||||
## 讨论过程
|
||||
|
||||
- 一致同意采用「正文内嵌 @ 标记」方案,格式统一为 `@[昵称](userId)`(或约定等价格式)。
|
||||
- 添加好友接口不混用存客宝 api_v1,在 soul-api miniprogram 组新增并在开发文档中明确。
|
||||
- 管理端负责插入 @ 并写入同一 content 格式;小程序负责解析、展示与点击加好友。
|
||||
|
||||
---
|
||||
|
||||
## 会议决议
|
||||
|
||||
1. **内容格式**:正文使用内嵌 @ 标记,格式 `@[昵称](userId)`(或团队约定的等价格式),后端/管理端/小程序统一。
|
||||
2. **小程序**:阅读页解析 content 中 @,渲染为高亮可点击;点击时调 miniprogram 添加好友接口(如 `targetUserId`),并做结果提示。
|
||||
3. **管理端**:编辑页支持「插入 @用户」,保存时写入约定格式的 content。
|
||||
4. **后端**:提供 miniprogram 添加好友接口;章节/文章接口返回的 content 支持带 @ 标记的字符串。
|
||||
5. **待确认**:添加好友接口的最终 path、入参/出参;若已有好友/关注模型需对齐。
|
||||
|
||||
---
|
||||
|
||||
## 待办事项
|
||||
|
||||
| 责任角色 | 任务 | 优先级 | 截止建议 |
|
||||
|---------|------|--------|---------|
|
||||
| 后端开发 | 在 miniprogram 组新增添加好友接口并更新开发文档 | 高 | 排期后 |
|
||||
| 管理端开发工程师 | 文章/章节编辑页支持插入 @用户并保存为约定 content 格式 | 高 | 后端接口与格式确定后 |
|
||||
| 小程序开发工程师 | 阅读页解析 @ 并高亮可点击,点击调添加好友接口 | 高 | 后端接口就绪后 |
|
||||
| 产品经理 | 确认添加好友接口 path 与业务规则(已是好友/重复请求等) | 中 | 开发前 |
|
||||
| 测试人员 | 编写 @ 展示与添加好友用例及回归清单 | 中 | 联调前 |
|
||||
|
||||
---
|
||||
|
||||
## 问题与作答区
|
||||
|
||||
| # | 问题 | 责任角色 | 作答 |
|
||||
|---|------|---------|------|
|
||||
| 1 | 添加好友接口的最终 path、入参(如 targetUserId)、出参及错误码? | 后端开发 | (待补充) |
|
||||
| 2 | 开发文档中添加好友接口放在 api_v1.md 新小节还是单独文档? | 后端/产品 | (待补充) |
|
||||
| 3 | 是否已有「好友/关注」表或接口需与本次对接? | 后端开发 | (待补充) |
|
||||
|
||||
---
|
||||
|
||||
## 各角色经验与业务理解更新
|
||||
|
||||
- 本次会议结论已同步至各角色当日经验文件(见 `agent/{角色}/evolution/2026-03-05.md`)。
|
||||
- 团队共享:内容 @ 采用「正文内嵌 `@[昵称](userId)`」方案;添加好友接口归属 miniprogram 组,与存客宝 api_v1 分离。
|
||||
|
||||
---
|
||||
|
||||
*会议纪要由助理橙子生成 | 各角色经验已同步至 `agent/{角色}/evolution/2026-03-05.md`*
|
||||
78
.cursor/meeting/2026-03-05_超级个体解锁眼睛需求分析.md
Normal file
78
.cursor/meeting/2026-03-05_超级个体解锁眼睛需求分析.md
Normal file
@@ -0,0 +1,78 @@
|
||||
# 需求分析 - 超级个体解锁眼睛交互改造
|
||||
|
||||
## 基本信息
|
||||
- **时间**:2026-03-05
|
||||
- **需求来源**:用户反馈
|
||||
- **涉及页面**:`miniprogram/pages/member-detail/member-detail`
|
||||
|
||||
---
|
||||
|
||||
## 一、需求描述
|
||||
|
||||
超级个体详情页点击「解锁眼睛」图标时,需调整交互逻辑:
|
||||
|
||||
| 原逻辑 | 新逻辑 |
|
||||
|--------|--------|
|
||||
| 弹窗「成为VIP会员并完成匹配后,即可查看完整联系方式」→ 确认跳转**找伙伴/匹配页** | **不跳转匹配页**;未登录先登录;已登录按权益处理 |
|
||||
|
||||
### 新逻辑细则
|
||||
|
||||
1. **未登录**:弹窗「请先登录」→ 确认跳转「我的」页,用户登录后再返回操作
|
||||
2. **已登录**:
|
||||
- **VIP 会员**(`hasFullBook`):直接解锁,可无限次解锁任意超级个体
|
||||
- **非 VIP**:每人 **1 次免费解锁**,第 2 次起弹窗「免费次数已用完,开通 VIP(¥1980/年)可无限解锁」→ 确认跳转 **VIP 会员页**(1980 付款页)
|
||||
|
||||
---
|
||||
|
||||
## 二、已实现修改(小程序端)
|
||||
|
||||
### 修改文件
|
||||
- `miniprogram/pages/member-detail/member-detail.js`
|
||||
|
||||
### 实现要点
|
||||
|
||||
1. **解锁状态存储**(本地 `wx.setStorageSync`)
|
||||
- Key:`member_unlocks_{userId}`
|
||||
- 值:已解锁的 `memberId` 数组
|
||||
- 用于判断是否已解锁、是否已用掉免费次数
|
||||
|
||||
2. **`unlockContact()` 流程**
|
||||
```
|
||||
点击眼睛
|
||||
→ 未登录:Modal「需要登录」→ 去登录 → switchTab 我的
|
||||
→ 已登录 + VIP:直接解锁并写入存储
|
||||
→ 已登录 + 非VIP + 首次:免费解锁并写入存储
|
||||
→ 已登录 + 非VIP + 非首次:Modal「去开通」→ navigateTo VIP 页
|
||||
```
|
||||
|
||||
3. **`enrichAndFormat` 中 `contactUnlocked` / `wechatUnlocked`**
|
||||
- 原:仅 `isMatched`(匹配过的人)
|
||||
- 现:`isMatched || localUnlocked`(本地解锁列表也视为已解锁)
|
||||
|
||||
---
|
||||
|
||||
## 三、后续可选优化(后端/管理端)
|
||||
|
||||
### 1. 后端持久化(可选)
|
||||
|
||||
当前免费次数与解锁记录存于**本地**,换设备或清缓存会丢失。若需跨设备、防作弊,可:
|
||||
|
||||
- 新增接口:`POST /api/miniprogram/member/unlock`
|
||||
- 入参:`memberId`、`userId`
|
||||
- 逻辑:校验免费次数 / VIP 权益,记录解锁关系
|
||||
- 小程序改为调用该接口,成功后更新本地展示
|
||||
|
||||
### 2. 管理端统计(可选)
|
||||
|
||||
- 统计「超级个体联系方式解锁」次数
|
||||
- 按用户、按超级个体维度统计
|
||||
|
||||
---
|
||||
|
||||
## 四、验收要点
|
||||
|
||||
- [ ] 未登录点击眼睛 → 弹窗「需要登录」→ 确认跳转「我的」
|
||||
- [ ] 已登录 + 非 VIP + 首次 → 免费解锁,展示完整联系方式
|
||||
- [ ] 已登录 + 非 VIP + 第 2 次起 → 弹窗「去开通」→ 确认跳转 VIP 页(¥1980)
|
||||
- [ ] 已登录 + VIP → 直接解锁,不限次数
|
||||
- [ ] 不跳转匹配页
|
||||
67
.cursor/meeting/README.md
Normal file
67
.cursor/meeting/README.md
Normal file
@@ -0,0 +1,67 @@
|
||||
# Soul 创业派对 - 会议记录
|
||||
|
||||
> 每次多角色会议后,由**橙子**生成独立会议纪要文件,按日期+主题命名。
|
||||
|
||||
---
|
||||
|
||||
## 命名规则
|
||||
|
||||
```
|
||||
YYYY-MM-DD_会议主题.md
|
||||
```
|
||||
|
||||
示例:
|
||||
- `2026-02-27_提现流程优化讨论.md`
|
||||
- `2026-02-27_分销功能需求评审.md`
|
||||
- `2026-03-01_会员分润方案讨论.md`
|
||||
|
||||
---
|
||||
|
||||
## 会议纪要结构
|
||||
|
||||
每份会议纪要包含以下标准结构:
|
||||
|
||||
```markdown
|
||||
# 会议纪要 - YYYY-MM-DD | 会议主题
|
||||
|
||||
## 基本信息
|
||||
- **时间**:YYYY-MM-DD HH:mm
|
||||
- **议题**:xxx
|
||||
- **参与角色**:产品经理、后端开发、管理端开发工程师、小程序开发工程师、测试人员
|
||||
|
||||
## 各角色发言
|
||||
### 【产品经理】...
|
||||
### 【后端开发】...
|
||||
### 【管理端开发工程师】...
|
||||
### 【小程序开发工程师】...
|
||||
### 【测试人员】...(验收/测试相关)
|
||||
|
||||
## 讨论过程
|
||||
(关键讨论节点记录)
|
||||
|
||||
## 会议决议
|
||||
(达成共识的结论,可直接用于开发)
|
||||
|
||||
## 待办事项
|
||||
| 责任角色 | 任务 | 截止 |
|
||||
|
||||
## 问题与作答区
|
||||
(待确认问题列表 + 作答列供后续补充,便于追溯闭环)
|
||||
|
||||
## 各角色经验与业务理解更新
|
||||
### 产品经理 / 后端开发 / 管理端开发工程师 / 小程序开发工程师
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 索引
|
||||
|
||||
| 日期 | 主题 | 参与角色 | 文件 |
|
||||
|------|------|---------|------|
|
||||
| 2026-02-27 | 开发进度同步会议 | 产品、后端、管理端、小程序 | [2026-02-27_开发进度同步会议.md](2026-02-27_开发进度同步会议.md) |
|
||||
| 2026-02-28 | 临时需求池 stitch_soul 需求评审(含页面重构专项·10 张图全覆盖) | 产品、后端、管理端、小程序、测试 | [2026-02-28_临时需求池stitch_soul需求评审.md](2026-02-28_临时需求池stitch_soul需求评审.md) |
|
||||
| 2026-02-28 | 个人资料页实现评估(profile-show / profile-edit) | 产品、后端、管理端、小程序、测试 | [2026-02-28_个人资料页实现评估.md](2026-02-28_个人资料页实现评估.md) |
|
||||
| 2026-02-28 | 文章类型(普通版/增值版)需求分析 | 产品、后端、管理端、小程序、测试 | [2026-02-28_文章类型普通版增值版需求分析.md](2026-02-28_文章类型普通版增值版需求分析.md) |
|
||||
| 2026-03-05 | 分支冲突后功能完整性分析 | 产品、后端、管理端、小程序、测试 | [2026-03-05_分支冲突后功能完整性分析.md](2026-03-05_分支冲突后功能完整性分析.md) |
|
||||
| 2026-03-05 | 超级个体解锁眼睛需求分析 | 产品、小程序 | [2026-03-05_超级个体解锁眼睛需求分析.md](2026-03-05_超级个体解锁眼睛需求分析.md) |
|
||||
| 2026-03-05 | 文章详情 @某人 高亮与一键加好友方案讨论 | 产品、后端、管理端、小程序、测试 | [2026-03-05_文章详情@某人加好友方案讨论.md](2026-03-05_文章详情@某人加好友方案讨论.md) |
|
||||
111
.cursor/meeting/_模板.md
Normal file
111
.cursor/meeting/_模板.md
Normal file
@@ -0,0 +1,111 @@
|
||||
# 会议纪要 - YYYY-MM-DD | {会议主题}
|
||||
|
||||
> 本文件由**助理橙子**在会议结束后自动生成。
|
||||
|
||||
---
|
||||
|
||||
## 基本信息
|
||||
|
||||
- **时间**:YYYY-MM-DD HH:mm
|
||||
- **议题**:{从用户消息提取}
|
||||
- **触发方式**:{语义化触发词}
|
||||
- **参与角色**:{根据议题自动判断:产品经理、后端开发、管理端开发工程师、小程序开发工程师、测试人员}
|
||||
|
||||
---
|
||||
|
||||
## 各角色发言
|
||||
|
||||
> 各角色从自身专业视角对议题发表意见。
|
||||
|
||||
### 【产品经理】
|
||||
|
||||
(从需求、用户价值、业务规则、验收标准角度发言)
|
||||
|
||||
### 【后端开发】
|
||||
|
||||
(从接口设计、路由组归属、数据模型、技术可行性角度发言)
|
||||
|
||||
### 【管理端开发工程师】
|
||||
|
||||
(从管理端功能需求、审核/配置/统计、接口依赖角度发言)
|
||||
|
||||
### 【小程序开发工程师】
|
||||
|
||||
(从 C 端用户体验、交互流程、接口依赖角度发言)
|
||||
|
||||
### 【测试人员】(验收/测试相关会议时)
|
||||
|
||||
(从测试用例、三端联调、回归清单、已知风险角度发言)
|
||||
|
||||
---
|
||||
|
||||
## 讨论过程
|
||||
|
||||
(关键交流节点,角色间的问答和碰撞)
|
||||
|
||||
---
|
||||
|
||||
## 会议决议
|
||||
|
||||
> 所有角色达成共识的结论,可直接指导开发。
|
||||
|
||||
1. **{决议点1}**:{说明}
|
||||
2. **{决议点2}**:{说明}
|
||||
3. **待确认项**:{需进一步调研或确认的内容}
|
||||
|
||||
---
|
||||
|
||||
## 待办事项
|
||||
|
||||
| 责任角色 | 任务 | 优先级 | 截止建议 |
|
||||
|---------|------|--------|---------|
|
||||
| 后端开发 | {任务} | 高/中/低 | {日期} |
|
||||
| 管理端开发工程师 | {任务} | 高/中/低 | {日期} |
|
||||
| 小程序开发工程师 | {任务} | 高/中/低 | {日期} |
|
||||
| 产品经理 | {任务} | 高/中/低 | {日期} |
|
||||
| 测试人员 | {任务} | 高/中/低 | {日期} |
|
||||
|
||||
---
|
||||
|
||||
## 问题与作答区
|
||||
|
||||
> 会议中提出的待确认问题在此列出;作答区域供后续补充答案,便于追溯闭环。
|
||||
|
||||
| # | 问题 | 责任角色 | 作答 |
|
||||
|---|------|---------|------|
|
||||
| 1 | {待确认问题1} | {谁负责回答} | (待补充) |
|
||||
| 2 | {待确认问题2} | {谁负责回答} | (待补充) |
|
||||
|
||||
---
|
||||
|
||||
## 各角色经验与业务理解更新
|
||||
|
||||
> 本次会议结束后,各角色基于讨论结果生成的经验,已同步写入各自的日期经验文件。
|
||||
|
||||
### 产品经理
|
||||
|
||||
- {从本次会议提炼的业务理解}
|
||||
|
||||
### 后端开发
|
||||
|
||||
- {从本次会议提炼的后端相关经验}
|
||||
|
||||
### 管理端开发工程师
|
||||
|
||||
- {从本次会议提炼的管理端相关经验}
|
||||
|
||||
### 小程序开发工程师
|
||||
|
||||
- {从本次会议提炼的小程序相关经验}
|
||||
|
||||
### 测试人员
|
||||
|
||||
- {从本次会议提炼的测试相关经验}
|
||||
|
||||
### 团队共享
|
||||
|
||||
- {跨角色共享的架构决策或业务规则}
|
||||
|
||||
---
|
||||
|
||||
*会议纪要由助理橙子生成 | 各角色经验已同步至 `agent/{角色}/evolution/YYYY-MM-DD.md`*
|
||||
3
.cursor/process/README.md
Normal file
3
.cursor/process/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# 工作流
|
||||
|
||||
存放项目工作流、流程图等文档。
|
||||
16
.cursor/rules/assistant-xiaofeng.mdc
Normal file
16
.cursor/rules/assistant-xiaofeng.mdc
Normal file
@@ -0,0 +1,16 @@
|
||||
---
|
||||
description: 小橙/橙子/橙橙/🍊 - 文档同步与经验升级助理
|
||||
globs: ["**"]
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
# 小橙触发器
|
||||
|
||||
当用户提及**小橙、橙子、橙橙、🍊**,或说**「讨论完毕」「记录一下」「同步到开发文档」「更新文档」「吸收经验」「升级 skills」「记录经验」「保存开发进度」「更新项目索引」「记录开发进度」「任务完成」「搞定了」「完成了」「会议结束」「散会」「会开完了」**时:
|
||||
|
||||
**必须使用 Read 工具读取 `e:\Gongsi\Mycontent\.cursor\skills\assistant-doc-sync\SKILL.md` 的完整内容**,然后严格按其流程执行。
|
||||
|
||||
### 行为摘要(供模型快速理解,完整流程以 SKILL 文件为准)
|
||||
|
||||
1. **文档同步**:从对话中提炼结论/待办/变更 → 写入 `开发文档/1、需求/需求汇总.md`、`开发文档/10、项目管理/运营与变更.md`、`临时需求池/` 等对应文档
|
||||
2. **经验入库**:提炼经验 → 写入 `agent/{角色}/evolution/YYYY-MM-DD.md` → 更新 `agent/开发助理/项目索引/{索引名}.md`(写日期)→ 更新 `agent/开发助理/经验清单.md` → 升级对应 SKILL
|
||||
11
.cursor/rules/product-manager.mdc
Normal file
11
.cursor/rules/product-manager.mdc
Normal file
@@ -0,0 +1,11 @@
|
||||
---
|
||||
description: 产品经理需求与验收。编辑需求文档时加载 SKILL-产品经理
|
||||
globs: ["开发文档/1、需求/**", "临时需求池/**", "开发文档/10、项目管理/**"]
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
# 产品经理
|
||||
|
||||
当编辑 **开发文档/1、需求/**、**临时需求池/**、**开发文档/10、项目管理/** 时,推断当前角色为**产品经理**。
|
||||
|
||||
**必须使用 Read 工具读取 `e:\Gongsi\Mycontent\.cursor\skills\product-manager\SKILL.md` 的完整内容**,然后按其规范执行需求分析、文档编写、验收标准制定。
|
||||
33
.cursor/rules/soul-admin-boundary.mdc
Normal file
33
.cursor/rules/soul-admin-boundary.mdc
Normal file
@@ -0,0 +1,33 @@
|
||||
---
|
||||
description: 管理端边界约束,防止与小程序/API 路径互窜
|
||||
globs: soul-admin/**/*
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
# 管理端开发边界(防互窜)
|
||||
|
||||
在 **soul-admin/** 下新增、优化或编辑任何代码时,必须遵守以下约束:
|
||||
|
||||
## API 路径(强制)
|
||||
|
||||
- **允许**:仅使用 soul-api 中面向管理端的路径,例如:
|
||||
- `/api/admin`、`/api/admin/logout`、`/api/admin/withdrawals`、`/api/admin/chapters`、`/api/admin/content`、`/api/admin/settings` 等;
|
||||
- `/api/db/users`、`/api/db/config/full`、`/api/db/chapters` 等;
|
||||
- `/api/orders` 等与现网一致的管理端接口。
|
||||
- **禁止**:
|
||||
- 不得调用 `/api/miniprogram/*`(小程序专属,如 miniprogram/login、miniprogram/book、miniprogram/withdraw 等)。
|
||||
- 不得在管理端实现「使用小程序登录或小程序 token」的业务逻辑。
|
||||
- **请求方式**:统一通过 `src/api/client.ts` 的 `get`、`post`、`put`、`del`、`request`;鉴权使用 `src/api/auth.ts` 的 admin_token(Bearer)。
|
||||
|
||||
## 目录与职责
|
||||
|
||||
- 仅修改 **soul-admin/** 内文件(含 src/pages、src/components、src/api、src/layouts 等)。
|
||||
- 不在此处实现小程序逻辑;不在此处编写 soul-api 的 Go 代码或 miniprogram 的 WXML/WXSS/JS。
|
||||
|
||||
## Skill 加载(必须执行)
|
||||
|
||||
**必须使用 Read 工具读取 `e:\Gongsi\Mycontent\.cursor\skills\admin-dev\SKILL.md` 的完整内容**,按其规范进行开发。该 Skill 包含代码风格、业务逻辑、API 对接细节等完整约定。
|
||||
|
||||
接口实现与路由分组的规范在 `e:\Gongsi\Mycontent\.cursor\rules\soul-api.mdc`(编辑 soul-api 时自动加载)。
|
||||
|
||||
违反上述路径或职责边界即视为「互窜」,需纠正后再提交。
|
||||
75
.cursor/rules/soul-api.mdc
Normal file
75
.cursor/rules/soul-api.mdc
Normal file
@@ -0,0 +1,75 @@
|
||||
---
|
||||
description: soul-api 路由边界 + 编码规范(合并版,防互窜 + GORM/Gin/响应约定)
|
||||
globs: soul-api/**/*
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
# soul-api 开发规范
|
||||
|
||||
> **Skill 加载**:编辑 soul-api 代码时,**必须使用 Read 工具读取 `e:\Gongsi\Mycontent\.cursor\skills\api-dev\SKILL.md` 的完整内容**,该 Skill 包含业务对接、与前端边界协同等补充约定。本规则侧重编码规范与路由边界。
|
||||
|
||||
## 1. 路由按使用方归类(强制)
|
||||
|
||||
新增或修改接口必须**先明确使用方**,再挂到对应路由组:
|
||||
|
||||
| 使用方 | 路由组 | 路径前缀 | 鉴权 |
|
||||
|--------|--------|----------|------|
|
||||
| 管理端 | `admin` / `db` | `/api/admin/…`、`/api/db/…` | `middleware.AdminAuth()` |
|
||||
| 小程序 | `miniprogram` | `/api/miniprogram/…` | 按接口需要 |
|
||||
| 两端共用 | `api` 下 + `miniprogram` 下各挂一遍 | `/api/xxx` 与 `/api/miniprogram/xxx` | 各自鉴权 |
|
||||
|
||||
即使业务逻辑相同,也必须按使用方做路径区分。禁止仅提供 `/api/vip/*` 等通用路径让两端混用。
|
||||
|
||||
### 禁止行为
|
||||
|
||||
- 禁止在 `miniprogram` 组挂仅管理端调用的接口(后台审核、DB 初始化等)。
|
||||
- 禁止在 `admin`/`db` 组挂小程序专属逻辑(wx code 登录、小程序码生成等)。
|
||||
- 禁止在 handler 内混用管理端/小程序路径语义(根据 path 分支写两套业务而不按使用方拆 handler/路由)。
|
||||
|
||||
handler 注释标明使用方,如 `// GET /api/miniprogram/withdraw/records 小程序-提现记录`。
|
||||
|
||||
管理端列表接口需包含:`user_name`/`userNickname`、`userAvatar`、`status`、`amount`。提现状态 DB 存 `pending`/`processing`/`success`/`failed`。
|
||||
|
||||
## 2. 数据访问:优先 GORM
|
||||
|
||||
- 通过 `database.DB()` 获取 `*gorm.DB`,操作集中在 `internal/model` 的模型上。
|
||||
- 常规 CRUD 必须用链式 API(`Where/First/Find/Create/Save/Updates/Delete`)。
|
||||
- 原子更新用 `gorm.Expr`,如 `Update("pending_earnings", gorm.Expr("pending_earnings + ?", delta))`。
|
||||
- 多表写入必须用 `db.Transaction(func(tx *gorm.DB) error { ... })`。
|
||||
- 用 `Preload`/`Joins` 减少 N+1;仅需单列时用 `Pluck`;重复条件抽 Scopes。
|
||||
- 禁止 handler 中手写 `db.Exec/db.Raw`,除非:复杂统计 SQL 用 GORM 表达冗长(须加注释);原子多列 SET。
|
||||
|
||||
## 3. Model 与表结构
|
||||
|
||||
- 结构体放 `internal/model`,文件名与业务一致。
|
||||
- 必须包含 `gorm` 标签(column/primaryKey/type)+ `json` 标签(小写驼峰)。
|
||||
- 不对外暴露的字段用 `json:"-"`。
|
||||
- 实现 `TableName() string`(若表名与默认不一致)。
|
||||
|
||||
## 4. 依赖物尽其用
|
||||
|
||||
- **Gin**:入参 `c.ShouldBindJSON` + `binding` 标签校验;统一 `c.JSON` 返回。
|
||||
- **配置**:仅通过 `internal/config` 的 `config.Load()` 读环境变量,不直接 `os.Getenv`。
|
||||
- **中间件**:安全头 `middleware.Secure()`,跨域 `cors`,限流 `middleware.NewRateLimiter`。
|
||||
- **微信/支付**:统一走 `internal/wechat`(PowerWeChat),handler 只做参数与结果转换。
|
||||
- **JWT**:管理端鉴权用 `internal/auth` 的 `IssueAdminJWT`/`ParseAdminJWT`/`GetAdminJWTFromRequest`。
|
||||
|
||||
## 5. 目录与包约定
|
||||
|
||||
- `cmd/server/main.go`:入口,只做初始化与启停。
|
||||
- `internal/handler`:HTTP 处理函数,绑定→校验→调 DB/wechat→写响应。逻辑复杂时抽到 `internal/service`。
|
||||
- `internal/router`:注册路由与中间件,不写业务逻辑。
|
||||
- `internal/database`:仅提供 `Init(dsn)` 与 `DB()`。
|
||||
- 新增接口流程:确定使用方 → 确定路由 Group → 实现 handler + GORM model。
|
||||
|
||||
## 6. 响应与错误
|
||||
|
||||
- 成功:`gin.H{"success": true, "data": ...}` 或 `"message": "..."`。
|
||||
- 失败:`gin.H{"success": false, "error": "..."}`。
|
||||
- 不吞错误:DB/wechat 的 `err` 必须处理并返回。
|
||||
- HTTP 状态码:业务错误可用 200 + `success: false`;未授权/禁止用 401/403。
|
||||
|
||||
## 7. 代码风格
|
||||
|
||||
- 遵循 `gofmt`;导出函数 PascalCase,内部 camelCase。
|
||||
- 公开 handler 或复杂逻辑处写清用途注释。
|
||||
39
.cursor/rules/soul-change-checklist.mdc
Normal file
39
.cursor/rules/soul-change-checklist.mdc
Normal file
@@ -0,0 +1,39 @@
|
||||
---
|
||||
description: 变更时关联层检查清单,防止漏改(前端/后端/管理端/表结构)
|
||||
globs: ["miniprogram/**/*", "soul-admin/**/*", "soul-api/**/*"]
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
# Soul 创业派对 - 变更关联检查清单(防漏改)
|
||||
|
||||
在 **miniprogram/**、**soul-admin/** 或 **soul-api/** 下做任何**修改、优化、新增**后,必须按下列项过一遍,确认关联层已同步,避免只改一端导致数据不一致或功能缺管理入口。
|
||||
|
||||
## 一、按「你改了什么」对表检查
|
||||
|
||||
| 你改的是… | 必须同时检查/修改的关联 |
|
||||
|-----------|--------------------------|
|
||||
| **前端(小程序或管理端)** 新增/改了**字段**或**接口入参/出参** | soul-api 对应接口的 request/response、model 是否已改?数据库表是否有对应列(无则加迁移/字段)? |
|
||||
| **小程序** 新增或改了一个**功能**(页面、能力、配置项) | soul-api 是否已有或需新增接口(挂到 `/api/miniprogram/...`)?**管理端**是否需要对应的**配置、审核、统计、列表**? |
|
||||
| **管理端** 新增或改了**列表/表单/配置项** | soul-api 的 admin/db 接口是否已提供对应数据或写接口?字段名与类型是否与前端一致? |
|
||||
| **soul-api** 新增/改了**接口**(路径、请求体、响应体、model) | 小程序或管理端是否有**调用处**?类型/字段是否已同步更新?若改了表结构,迁移是否已加?**路径是否按使用方区分**(小程序用 `/api/miniprogram/*`,管理端用 `/api/admin/*` 或 `/api/db/*`,禁止通用路径混用)? |
|
||||
| **soul-api** 新增/改了**表或字段** | 相关 handler、model 是否已改?是否有接口暴露给小程序/管理端?若有,前端是否已对接? |
|
||||
|
||||
## 二、按「业务功能」想三端
|
||||
|
||||
以**功能/领域**为单位(如:提现、推荐、章节权限、找伙伴、配置项),问一句:
|
||||
|
||||
- **小程序**:用户侧是否已实现/已更新?
|
||||
- **soul-api**:接口是否在正确路由组(miniprogram / admin / db)、请求响应是否一致?若两端共用,是否显式挂到 miniprogram 组(`/api/miniprogram/xxx`),禁止仅提供 `/api/xxx` 混用?
|
||||
- **管理端**:该功能是否需要**配置、审核、统计、列表**?有则需在 soul-admin 与 soul-api 的 admin/db 下补齐。
|
||||
|
||||
## 三、执行约定
|
||||
|
||||
- **每次**在 miniprogram、soul-admin、soul-api 内完成一轮修改后,**先过一遍上表 + 二**,再视为本次变更完成。
|
||||
- 若本次变更涉及多端(例如小程序新功能 + 管理端配置页),应在同一次任务内一并完成或明确记录未做项,避免漏改。
|
||||
- 更详细的检查流程:**必须使用 Read 工具读取 `e:\Gongsi\Mycontent\.cursor\skills\change-checklist\SKILL.md` 的完整内容**,按其「以领域为单位思考」的方法逐项确认。
|
||||
|
||||
## 四、聊天中触发变更检查
|
||||
|
||||
编码完成后在聊天中说**「变更完成」「检查一下」「准备提交」**,AI 会主动加载本清单 + change-checklist/SKILL.md 完成核对。**不需要正在编辑文件,直接说触发词即可。**
|
||||
|
||||
未通过上述检查即提交视为可能漏改,需补全后再提交。
|
||||
32
.cursor/rules/soul-meeting.mdc
Normal file
32
.cursor/rules/soul-meeting.mdc
Normal file
@@ -0,0 +1,32 @@
|
||||
---
|
||||
description: Soul 创业派对开发团队多角色会议触发器。开个会、团队会议、需求评审、方案讨论时加载 SKILL-团队会议
|
||||
globs: ["**"]
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
# Soul 创业派对 - 会议触发器
|
||||
|
||||
当用户表达**开会意图**时(包括但不限于以下触发词),**必须使用 Read 工具读取 `e:\Gongsi\Mycontent\.cursor\skills\team-meeting\SKILL.md` 的完整内容**,然后严格按其流程主持会议。
|
||||
|
||||
## 语义化触发词(理解意图,不必完全匹配)
|
||||
|
||||
| 触发词示例 | 类型 |
|
||||
|-----------|------|
|
||||
| 开发团队和产品经理现在开始开会 | 全员会议 |
|
||||
| 开个会 / 开会讨论 / 我们开个会 | 快速会议 |
|
||||
| 团队会议 / 多角色会议 / 开发会议 | 正式会议 |
|
||||
| 需求评审 / 技术评审 / 方案讨论 | 专项会议 |
|
||||
| 大家一起讨论 / 召集开会 / 叫大家过来 | 集体讨论 |
|
||||
| 多角色讨论 / 各角色发言 | 多视角讨论 |
|
||||
|
||||
## 会议结束触发
|
||||
|
||||
当用户说**「会议结束」「散会」「会开完了」「结束会议」**时:
|
||||
|
||||
1. 助理橙子立即执行收尾流程
|
||||
2. **生成会议纪要**:`e:\Gongsi\Mycontent\.cursor\meeting\YYYY-MM-DD_主题.md`
|
||||
3. **各角色经验入库**:`e:\Gongsi\Mycontent\.cursor\agent\{角色}\evolution\YYYY-MM-DD.md`
|
||||
4. **更新项目索引**:`agent/开发助理/项目索引/{索引名}.md` 开发进度表追加一行
|
||||
5. **更新会议记录索引**:`e:\Gongsi\Mycontent\.cursor\meeting\README.md`
|
||||
|
||||
**必须使用 Read 工具读取 `e:\Gongsi\Mycontent\.cursor\skills\assistant-doc-sync\SKILL.md` 执行收尾。**
|
||||
30
.cursor/rules/soul-miniprogram-boundary.mdc
Normal file
30
.cursor/rules/soul-miniprogram-boundary.mdc
Normal file
@@ -0,0 +1,30 @@
|
||||
---
|
||||
description: 小程序端边界约束,防止与管理端/API 路径互窜
|
||||
globs: miniprogram/**/*
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
# 小程序端开发边界(防互窜)
|
||||
|
||||
在 **miniprogram/** 下新增、优化或编辑任何代码时,必须遵守以下约束:
|
||||
|
||||
## API 路径(强制)
|
||||
|
||||
- **允许**:仅使用以 `/api/miniprogram/` 开头的接口路径(与 soul-api 的 miniprogram 路由组一致)。
|
||||
- **禁止**:
|
||||
- 不得使用 `/api/admin/*`、`/api/db/*`(管理端专属)。
|
||||
- 不得使用未在 soul-api 的 miniprogram 组下注册的路径(如仅存在于 next-project 的接口)。
|
||||
- **请求方式**:统一通过 `getApp().request(url, options)` 发起,不在页面内直接写死 baseUrl 或使用 `wx.request` 拼管理端路径。
|
||||
|
||||
## 目录与职责
|
||||
|
||||
- 仅修改 **miniprogram/** 内文件(含 pages、components、utils、app.js 等)。
|
||||
- 不在此处实现或引用管理端逻辑;不在此处编写 soul-api 的 Go 代码或 soul-admin 的 React 代码。
|
||||
|
||||
## Skill 加载(必须执行)
|
||||
|
||||
**必须使用 Read 工具读取 `e:\Gongsi\Mycontent\.cursor\skills\miniprogram-dev\SKILL.md` 的完整内容**,按其规范进行开发。该 Skill 包含代码风格、业务逻辑、API 对接细节等完整约定。
|
||||
|
||||
接口实现与路由分组的规范在 `e:\Gongsi\Mycontent\.cursor\rules\soul-api.mdc`(编辑 soul-api 时自动加载)。
|
||||
|
||||
违反上述路径或职责边界即视为「互窜」,需纠正后再提交。
|
||||
64
.cursor/rules/soul-project-boundary.mdc
Normal file
64
.cursor/rules/soul-project-boundary.mdc
Normal file
@@ -0,0 +1,64 @@
|
||||
---
|
||||
description: Soul 创业派对项目整体边界、角色推断与 Skill 加载(alwaysApply)
|
||||
globs: ["**"]
|
||||
alwaysApply: true
|
||||
---
|
||||
|
||||
# Soul 创业派对 - 项目边界
|
||||
|
||||
## 会话自检
|
||||
|
||||
仅沿用本项目 `.cursor/` 下的 rules、skills、配置;忽略与本项目无关的全局 rules/skills。
|
||||
|
||||
## 项目组成
|
||||
|
||||
| 子项目 | 目录 | 用途 | 后端对接 |
|
||||
|--------|------|------|----------|
|
||||
| 小程序 | miniprogram/ | 微信原生小程序 C 端 | soul-api |
|
||||
| 管理端 | soul-admin/ | React 管理后台 | soul-api |
|
||||
| API 后端 | soul-api/ | Go + Gin + GORM 接口服务 | - |
|
||||
| 预览/参考 | next-project/ | 仅预览,非线上 | 不依赖 |
|
||||
|
||||
## 核心原则
|
||||
|
||||
- 小程序只调 `/api/miniprogram/*`;管理端只调 `/api/admin/*`、`/api/db/*`;禁止混用。
|
||||
- 变更完成必过 soul-change-checklist.mdc;聊天中说「变更完成」「检查一下」「准备提交」时主动触发检查。
|
||||
|
||||
## 角色推断与 Skill 加载(必须执行)
|
||||
|
||||
根据**当前编辑目录**或**语义触发词**,**必须使用 Read 工具读取对应的主 Skill 文件完整内容**,然后按其规范执行开发:
|
||||
|
||||
### 按编辑目录
|
||||
|
||||
| 编辑目录 | 推断角色 | 必须 Read 的主 Skill 文件(绝对路径) |
|
||||
|----------|----------|---------------------------------------|
|
||||
| miniprogram/ | 小程序开发工程师 | `e:\Gongsi\Mycontent\.cursor\skills\miniprogram-dev\SKILL.md` |
|
||||
| soul-admin/ | 管理端开发工程师 | `e:\Gongsi\Mycontent\.cursor\skills\admin-dev\SKILL.md` |
|
||||
| soul-api/ | 后端开发 | `e:\Gongsi\Mycontent\.cursor\skills\api-dev\SKILL.md` |
|
||||
| 开发文档/1、需求/、临时需求池/ | 产品经理 | `e:\Gongsi\Mycontent\.cursor\skills\product-manager\SKILL.md` |
|
||||
| .cursor/ | 助理橙子 | `e:\Gongsi\Mycontent\.cursor\skills\assistant-doc-sync\SKILL.md` |
|
||||
|
||||
### 按语义触发词(说啥切角色,无需编辑文件)
|
||||
|
||||
用户说出以下词时,推断对应角色并 Read 其 Skill(理解意图即可,不必完全匹配):
|
||||
|
||||
| 触发词 | 推断角色 | 必须 Read 的 Skill 文件 |
|
||||
|--------|----------|-------------------------|
|
||||
| 后端、API、soul-api、接口、Go、GORM | 后端开发 | `e:\Gongsi\Mycontent\.cursor\skills\api-dev\SKILL.md` |
|
||||
| 管理端、soul-admin、React、后台管理 | 管理端开发工程师 | `e:\Gongsi\Mycontent\.cursor\skills\admin-dev\SKILL.md` |
|
||||
| 小程序、miniprogram、C 端、微信小程序 | 小程序开发工程师 | `e:\Gongsi\Mycontent\.cursor\skills\miniprogram-dev\SKILL.md` |
|
||||
| 产品、需求、验收、排期、需求文档 | 产品经理 | `e:\Gongsi\Mycontent\.cursor\skills\product-manager\SKILL.md` |
|
||||
| 测试、测试用例、回归测试、功能测试、QA | 测试人员 | `e:\Gongsi\Mycontent\.cursor\skills\testing\SKILL.md` |
|
||||
|
||||
### 按场景触发词
|
||||
|
||||
| 场景触发词 | 必须 Read 的 Skill 文件(绝对路径) |
|
||||
|------------|-------------------------------------|
|
||||
| 小橙、橙子、橙橙、🍊、讨论完毕、记录一下、记录、同步文档 | `e:\Gongsi\Mycontent\.cursor\skills\assistant-doc-sync\SKILL.md` |
|
||||
| 吸收经验、升级 skills、记录经验、保存开发进度、更新项目索引、记录开发进度、任务完成、搞定了、完成了 | `e:\Gongsi\Mycontent\.cursor\skills\assistant-doc-sync\SKILL.md` |
|
||||
| 跨端功能开发 | `e:\Gongsi\Mycontent\.cursor\skills\role-flow-control\SKILL.md` |
|
||||
| 变更完成、检查一下、准备提交 | `e:\Gongsi\Mycontent\.cursor\skills\change-checklist\SKILL.md` |
|
||||
| 开个会、开会、团队会议、乘风开会、需求评审、方案讨论、大家一起讨论 | `e:\Gongsi\Mycontent\.cursor\skills\team-meeting\SKILL.md`(老板分身/乘风主持) |
|
||||
| 会议结束、散会、会开完了 | `e:\Gongsi\Mycontent\.cursor\skills\assistant-doc-sync\SKILL.md`(会议收尾) |
|
||||
|
||||
**注意**:「必须 Read」= 使用 Read 工具读取**绝对路径**的完整文件内容后执行,不可跳过或仅凭记忆。
|
||||
82
.cursor/rules/老板分身-索引.mdc
Normal file
82
.cursor/rules/老板分身-索引.mdc
Normal file
@@ -0,0 +1,82 @@
|
||||
---
|
||||
description: 老板分身 - 最高权限智能体,协调 Soul 开发团队;编码习惯与思维模式总览
|
||||
alwaysApply: true
|
||||
---
|
||||
|
||||
# 老板分身 - 能力与约束(Soul 创业派对)
|
||||
|
||||
> **老板分身权限最高**:协调所有智能体(小程序开发工程师、管理端开发工程师、后端工程师、产品经理、开发助理等)。其他 agent 执行任务时遵循本规则;老板分身可调度、协调、指派任一角色。
|
||||
> **激活方式**:用户说「老板」「分身」「乘风」「架构」「帮我协调」时,从旁观者转为主动参与。**开会时**:用户说「开会」「开个会」「团队会议」「乘风开会」等,老板分身(乘风)作为主持人自动读取并执行 `.cursor/skills/team-meeting/SKILL.md` 中的会议协议。
|
||||
> **会话自检**:仅沿用本项目 `.cursor/` 下的 rules、skills、agent;忽略与本项目无关的全局 rules/skills。
|
||||
> **角色驱动**:Soul 角色与 agent 映射见 `config/paths.py` 的 ROLE_TO_AGENT。
|
||||
|
||||
### 领域特例优先(含合理性校验)
|
||||
|
||||
当某个 **skill** 或领域规则与通用规则冲突时,原则上以该 skill/领域规则为准。**但须先做合理性校验**:
|
||||
|
||||
- 若 skill 的规则**明显不合理**(如违背安全、可维护性、行业惯例等),应**提醒用户**并说明原因,**确认后再覆盖**
|
||||
- 若合理(如 Soul 三端路由隔离约定),可直接按 skill 执行
|
||||
|
||||
---
|
||||
|
||||
## 〇、经验自动收集(优先执行)
|
||||
|
||||
**在每次回复前判断**:本次会话是否完成了一次「问题 → 解决」的闭环?
|
||||
|
||||
### 判定条件(同时满足则触发)
|
||||
|
||||
1. 会话中出现了**技术问题**(报错、bug、实现困难、配置问题等)
|
||||
2. 问题已**解决**:用户明确表示解决(如「解决了」「可以了」「搞定了」「好了」「跑通了」)
|
||||
3. 解决过程有**可提炼价值**:有具体的问题描述、解决步骤或关键决策
|
||||
|
||||
### 触发后动作
|
||||
|
||||
1. 从对话中提取:问题描述、解决过程、关键决策、可提炼的规则方向
|
||||
2. **推断目标角色**(可多选):
|
||||
- 小程序/WXML/微信/微信原生→**小程序开发工程师**
|
||||
- 管理端/React/admin/后台管理→**管理端开发工程师**
|
||||
- 后端/Go/Gin/GORM/接口/API→**后端工程师**
|
||||
- 产品/需求/config→**产品经理**
|
||||
- 测试/自检/QA→**软件测试**
|
||||
- 架构/选型/路由约定/三端协同→**团队**
|
||||
- 无法判断→**通用**(写入开发助理)
|
||||
3. **若可写文件**:
|
||||
- **有明确目标角色**:写入 `.cursor/agent/{角色}/evolution/YYYY-MM-DD-简短描述.md`,并更新该目录下的 `索引.md`
|
||||
- **无法判断角色**:写入 `.cursor/agent/开发助理/evolution/`
|
||||
4. **若无法写文件**:输出 JSON,并提示用户双击 `agent/开发助理/script/一键-添加经验.bat`
|
||||
|
||||
### Soul 目标角色与 target_roles 取值
|
||||
|
||||
| 推断场景 | target_roles |
|
||||
|----------|--------------|
|
||||
| 小程序/WXML/微信 | `["小程序开发工程师"]` |
|
||||
| 管理端/React/admin | `["管理端开发工程师"]` |
|
||||
| 后端/Go/Gin/API | `["后端工程师"]` |
|
||||
| 产品/需求 | `["产品经理"]` |
|
||||
| 测试/QA | `["软件测试"]` |
|
||||
| 架构/三端协同 | `["团队"]` |
|
||||
| 跨端(小程序+管理端) | `["小程序开发工程师","管理端开发工程师"]` |
|
||||
|
||||
### 不触发情况
|
||||
|
||||
- 纯咨询、无实际问题
|
||||
- 问题未解决或用户未确认
|
||||
- 用户明确说「不要记录」「不用沉淀」
|
||||
|
||||
---
|
||||
|
||||
## 一、编码习惯
|
||||
|
||||
- 先理解需求,再动手写代码
|
||||
- 小步迭代,可读性优先
|
||||
- 函数保持单一职责,避免深层嵌套
|
||||
|
||||
---
|
||||
|
||||
## 二、Soul 三端分工
|
||||
|
||||
- **小程序**:只调 `/api/miniprogram/*`,禁止调 admin/db
|
||||
- **管理端**:只调 `/api/admin/*`、`/api/db/*`
|
||||
- **后端**:路由分组 miniprogram/admin/db,响应格式统一
|
||||
|
||||
跨端任务时先分解:后端任务 / 管理端任务 / 小程序任务,再分阶段执行。
|
||||
20
.cursor/scripts/db-exec/README.md
Normal file
20
.cursor/scripts/db-exec/README.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# db-exec - MySQL 直接执行脚本
|
||||
|
||||
当 MCP MySQL 因端口非 3306 无法连接时,用此脚本执行 SQL。
|
||||
|
||||
## 首次使用
|
||||
|
||||
```bash
|
||||
cd .cursor/scripts/db-exec
|
||||
npm install
|
||||
```
|
||||
|
||||
## 用法
|
||||
|
||||
```bash
|
||||
# 从项目根目录执行
|
||||
node .cursor/scripts/db-exec/run.js "SELECT 1"
|
||||
node .cursor/scripts/db-exec/run.js -f migrations/xxx.sql
|
||||
```
|
||||
|
||||
凭证自动从 `soul-api/.env` 的 `DB_DSN` 读取。
|
||||
149
.cursor/scripts/db-exec/node_modules/.package-lock.json
generated
vendored
Normal file
149
.cursor/scripts/db-exec/node_modules/.package-lock.json
generated
vendored
Normal file
@@ -0,0 +1,149 @@
|
||||
{
|
||||
"name": "soul-db-exec",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"node_modules/@types/node": {
|
||||
"version": "25.3.0",
|
||||
"resolved": "https://registry.npmmirror.com/@types/node/-/node-25.3.0.tgz",
|
||||
"integrity": "sha512-4K3bqJpXpqfg2XKGK9bpDTc6xO/xoUP/RBWS7AtRMug6zZFaRekiLzjVtAoZMquxoAbzBvy5nxQ7veS5eYzf8A==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"undici-types": "~7.18.0"
|
||||
}
|
||||
},
|
||||
"node_modules/aws-ssl-profiles": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmmirror.com/aws-ssl-profiles/-/aws-ssl-profiles-1.1.2.tgz",
|
||||
"integrity": "sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/denque": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/denque/-/denque-2.1.0.tgz",
|
||||
"integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/generate-function": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmmirror.com/generate-function/-/generate-function-2.3.1.tgz",
|
||||
"integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"is-property": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/iconv-lite": {
|
||||
"version": "0.7.2",
|
||||
"resolved": "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.7.2.tgz",
|
||||
"integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/express"
|
||||
}
|
||||
},
|
||||
"node_modules/is-property": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmmirror.com/is-property/-/is-property-1.0.2.tgz",
|
||||
"integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/long": {
|
||||
"version": "5.3.2",
|
||||
"resolved": "https://registry.npmmirror.com/long/-/long-5.3.2.tgz",
|
||||
"integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/lru.min": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmmirror.com/lru.min/-/lru.min-1.1.4.tgz",
|
||||
"integrity": "sha512-DqC6n3QQ77zdFpCMASA1a3Jlb64Hv2N2DciFGkO/4L9+q/IpIAuRlKOvCXabtRW6cQf8usbmM6BE/TOPysCdIA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"bun": ">=1.0.0",
|
||||
"deno": ">=1.30.0",
|
||||
"node": ">=8.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/wellwelwel"
|
||||
}
|
||||
},
|
||||
"node_modules/mysql2": {
|
||||
"version": "3.18.0",
|
||||
"resolved": "https://registry.npmmirror.com/mysql2/-/mysql2-3.18.0.tgz",
|
||||
"integrity": "sha512-3rupyOFks7Vq0jcjBpmg1gtgfGuCcmgrRJPEfpGzzrB/ydutupbjKkoDJGsGkrJRU6j44o2tb0McduL03/v/dQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"aws-ssl-profiles": "^1.1.2",
|
||||
"denque": "^2.1.0",
|
||||
"generate-function": "^2.3.1",
|
||||
"iconv-lite": "^0.7.2",
|
||||
"long": "^5.3.2",
|
||||
"lru.min": "^1.1.4",
|
||||
"named-placeholders": "^1.1.6",
|
||||
"sql-escaper": "^1.3.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/named-placeholders": {
|
||||
"version": "1.1.6",
|
||||
"resolved": "https://registry.npmmirror.com/named-placeholders/-/named-placeholders-1.1.6.tgz",
|
||||
"integrity": "sha512-Tz09sEL2EEuv5fFowm419c1+a/jSMiBjI9gHxVLrVdbUkkNUUfjsVYs9pVZu5oCon/kmRh9TfLEObFtkVxmY0w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"lru.min": "^1.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmmirror.com/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/sql-escaper": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmmirror.com/sql-escaper/-/sql-escaper-1.3.3.tgz",
|
||||
"integrity": "sha512-BsTCV265VpTp8tm1wyIm1xqQCS+Q9NHx2Sr+WcnUrgLrQ6yiDIvHYJV5gHxsj1lMBy2zm5twLaZao8Jd+S8JJw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"bun": ">=1.0.0",
|
||||
"deno": ">=2.0.0",
|
||||
"node": ">=12.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/mysqljs/sql-escaper?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "7.18.2",
|
||||
"resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-7.18.2.tgz",
|
||||
"integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==",
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
}
|
||||
}
|
||||
}
|
||||
21
.cursor/scripts/db-exec/node_modules/@types/node/LICENSE
generated
vendored
Normal file
21
.cursor/scripts/db-exec/node_modules/@types/node/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) Microsoft Corporation.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE
|
||||
15
.cursor/scripts/db-exec/node_modules/@types/node/README.md
generated
vendored
Normal file
15
.cursor/scripts/db-exec/node_modules/@types/node/README.md
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
# Installation
|
||||
> `npm install --save @types/node`
|
||||
|
||||
# Summary
|
||||
This package contains type definitions for node (https://nodejs.org/).
|
||||
|
||||
# Details
|
||||
Files were exported from https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/node.
|
||||
|
||||
### Additional Details
|
||||
* Last updated: Thu, 19 Feb 2026 00:56:10 GMT
|
||||
* Dependencies: [undici-types](https://npmjs.com/package/undici-types)
|
||||
|
||||
# Credits
|
||||
These definitions were written by [Microsoft TypeScript](https://github.com/Microsoft), [Alberto Schiabel](https://github.com/jkomyno), [Andrew Makarov](https://github.com/r3nya), [Benjamin Toueg](https://github.com/btoueg), [David Junger](https://github.com/touffy), [Mohsen Azimi](https://github.com/mohsen1), [Nikita Galkin](https://github.com/galkin), [Sebastian Silbermann](https://github.com/eps1lon), [Wilco Bakker](https://github.com/WilcoBakker), [Marcin Kopacz](https://github.com/chyzwar), [Trivikram Kamat](https://github.com/trivikr), [Junxiao Shi](https://github.com/yoursunny), [Ilia Baryshnikov](https://github.com/qwelias), [ExE Boss](https://github.com/ExE-Boss), [Piotr Błażejewicz](https://github.com/peterblazejewicz), [Anna Henningsen](https://github.com/addaleax), [Victor Perin](https://github.com/victorperin), [NodeJS Contributors](https://github.com/NodeJS), [Linus Unnebäck](https://github.com/LinusU), [wafuwafu13](https://github.com/wafuwafu13), [Matteo Collina](https://github.com/mcollina), [Dmitry Semigradsky](https://github.com/Semigradsky), [René](https://github.com/Renegade334), and [Yagiz Nizipli](https://github.com/anonrig).
|
||||
955
.cursor/scripts/db-exec/node_modules/@types/node/assert.d.ts
generated
vendored
Normal file
955
.cursor/scripts/db-exec/node_modules/@types/node/assert.d.ts
generated
vendored
Normal file
@@ -0,0 +1,955 @@
|
||||
/**
|
||||
* The `node:assert` module provides a set of assertion functions for verifying
|
||||
* invariants.
|
||||
* @see [source](https://github.com/nodejs/node/blob/v25.x/lib/assert.js)
|
||||
*/
|
||||
declare module "node:assert" {
|
||||
import strict = require("node:assert/strict");
|
||||
/**
|
||||
* An alias of {@link assert.ok}.
|
||||
* @since v0.5.9
|
||||
* @param value The input that is checked for being truthy.
|
||||
*/
|
||||
function assert(value: unknown, message?: string | Error): asserts value;
|
||||
const kOptions: unique symbol;
|
||||
namespace assert {
|
||||
type AssertMethodNames =
|
||||
| "deepEqual"
|
||||
| "deepStrictEqual"
|
||||
| "doesNotMatch"
|
||||
| "doesNotReject"
|
||||
| "doesNotThrow"
|
||||
| "equal"
|
||||
| "fail"
|
||||
| "ifError"
|
||||
| "match"
|
||||
| "notDeepEqual"
|
||||
| "notDeepStrictEqual"
|
||||
| "notEqual"
|
||||
| "notStrictEqual"
|
||||
| "ok"
|
||||
| "partialDeepStrictEqual"
|
||||
| "rejects"
|
||||
| "strictEqual"
|
||||
| "throws";
|
||||
interface AssertOptions {
|
||||
/**
|
||||
* If set to `'full'`, shows the full diff in assertion errors.
|
||||
* @default 'simple'
|
||||
*/
|
||||
diff?: "simple" | "full" | undefined;
|
||||
/**
|
||||
* If set to `true`, non-strict methods behave like their
|
||||
* corresponding strict methods.
|
||||
* @default true
|
||||
*/
|
||||
strict?: boolean | undefined;
|
||||
/**
|
||||
* If set to `true`, skips prototype and constructor
|
||||
* comparison in deep equality checks.
|
||||
* @since v24.9.0
|
||||
* @default false
|
||||
*/
|
||||
skipPrototype?: boolean | undefined;
|
||||
}
|
||||
interface Assert extends Pick<typeof assert, AssertMethodNames> {
|
||||
readonly [kOptions]: AssertOptions & { strict: false };
|
||||
}
|
||||
interface AssertStrict extends Pick<typeof strict, AssertMethodNames> {
|
||||
readonly [kOptions]: AssertOptions & { strict: true };
|
||||
}
|
||||
/**
|
||||
* The `Assert` class allows creating independent assertion instances with custom options.
|
||||
* @since v24.6.0
|
||||
*/
|
||||
var Assert: {
|
||||
/**
|
||||
* Creates a new assertion instance. The `diff` option controls the verbosity of diffs in assertion error messages.
|
||||
*
|
||||
* ```js
|
||||
* const { Assert } = require('node:assert');
|
||||
* const assertInstance = new Assert({ diff: 'full' });
|
||||
* assertInstance.deepStrictEqual({ a: 1 }, { a: 2 });
|
||||
* // Shows a full diff in the error message.
|
||||
* ```
|
||||
*
|
||||
* **Important**: When destructuring assertion methods from an `Assert` instance,
|
||||
* the methods lose their connection to the instance's configuration options (such
|
||||
* as `diff`, `strict`, and `skipPrototype` settings).
|
||||
* The destructured methods will fall back to default behavior instead.
|
||||
*
|
||||
* ```js
|
||||
* const myAssert = new Assert({ diff: 'full' });
|
||||
*
|
||||
* // This works as expected - uses 'full' diff
|
||||
* myAssert.strictEqual({ a: 1 }, { b: { c: 1 } });
|
||||
*
|
||||
* // This loses the 'full' diff setting - falls back to default 'simple' diff
|
||||
* const { strictEqual } = myAssert;
|
||||
* strictEqual({ a: 1 }, { b: { c: 1 } });
|
||||
* ```
|
||||
*
|
||||
* The `skipPrototype` option affects all deep equality methods:
|
||||
*
|
||||
* ```js
|
||||
* class Foo {
|
||||
* constructor(a) {
|
||||
* this.a = a;
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* class Bar {
|
||||
* constructor(a) {
|
||||
* this.a = a;
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* const foo = new Foo(1);
|
||||
* const bar = new Bar(1);
|
||||
*
|
||||
* // Default behavior - fails due to different constructors
|
||||
* const assert1 = new Assert();
|
||||
* assert1.deepStrictEqual(foo, bar); // AssertionError
|
||||
*
|
||||
* // Skip prototype comparison - passes if properties are equal
|
||||
* const assert2 = new Assert({ skipPrototype: true });
|
||||
* assert2.deepStrictEqual(foo, bar); // OK
|
||||
* ```
|
||||
*
|
||||
* When destructured, methods lose access to the instance's `this` context and revert to default assertion behavior
|
||||
* (diff: 'simple', non-strict mode).
|
||||
* To maintain custom options when using destructured methods, avoid
|
||||
* destructuring and call methods directly on the instance.
|
||||
* @since v24.6.0
|
||||
*/
|
||||
new(
|
||||
options?: AssertOptions & { strict?: true | undefined },
|
||||
): AssertStrict;
|
||||
new(
|
||||
options: AssertOptions,
|
||||
): Assert;
|
||||
};
|
||||
interface AssertionErrorOptions {
|
||||
/**
|
||||
* If provided, the error message is set to this value.
|
||||
*/
|
||||
message?: string | undefined;
|
||||
/**
|
||||
* The `actual` property on the error instance.
|
||||
*/
|
||||
actual?: unknown;
|
||||
/**
|
||||
* The `expected` property on the error instance.
|
||||
*/
|
||||
expected?: unknown;
|
||||
/**
|
||||
* The `operator` property on the error instance.
|
||||
*/
|
||||
operator?: string | undefined;
|
||||
/**
|
||||
* If provided, the generated stack trace omits frames before this function.
|
||||
*/
|
||||
stackStartFn?: Function | undefined;
|
||||
/**
|
||||
* If set to `'full'`, shows the full diff in assertion errors.
|
||||
* @default 'simple'
|
||||
*/
|
||||
diff?: "simple" | "full" | undefined;
|
||||
}
|
||||
/**
|
||||
* Indicates the failure of an assertion. All errors thrown by the `node:assert` module will be instances of the `AssertionError` class.
|
||||
*/
|
||||
class AssertionError extends Error {
|
||||
constructor(options: AssertionErrorOptions);
|
||||
/**
|
||||
* Set to the `actual` argument for methods such as {@link assert.strictEqual()}.
|
||||
*/
|
||||
actual: unknown;
|
||||
/**
|
||||
* Set to the `expected` argument for methods such as {@link assert.strictEqual()}.
|
||||
*/
|
||||
expected: unknown;
|
||||
/**
|
||||
* Indicates if the message was auto-generated (`true`) or not.
|
||||
*/
|
||||
generatedMessage: boolean;
|
||||
/**
|
||||
* Value is always `ERR_ASSERTION` to show that the error is an assertion error.
|
||||
*/
|
||||
code: "ERR_ASSERTION";
|
||||
/**
|
||||
* Set to the passed in operator value.
|
||||
*/
|
||||
operator: string;
|
||||
}
|
||||
type AssertPredicate = RegExp | (new() => object) | ((thrown: unknown) => boolean) | object | Error;
|
||||
/**
|
||||
* Throws an `AssertionError` with the provided error message or a default
|
||||
* error message. If the `message` parameter is an instance of an `Error` then
|
||||
* it will be thrown instead of the `AssertionError`.
|
||||
*
|
||||
* ```js
|
||||
* import assert from 'node:assert/strict';
|
||||
*
|
||||
* assert.fail();
|
||||
* // AssertionError [ERR_ASSERTION]: Failed
|
||||
*
|
||||
* assert.fail('boom');
|
||||
* // AssertionError [ERR_ASSERTION]: boom
|
||||
*
|
||||
* assert.fail(new TypeError('need array'));
|
||||
* // TypeError: need array
|
||||
* ```
|
||||
* @since v0.1.21
|
||||
* @param [message='Failed']
|
||||
*/
|
||||
function fail(message?: string | Error): never;
|
||||
/**
|
||||
* Tests if `value` is truthy. It is equivalent to `assert.equal(!!value, true, message)`.
|
||||
*
|
||||
* If `value` is not truthy, an `AssertionError` is thrown with a `message` property set equal to the value of the `message` parameter. If the `message` parameter is `undefined`, a default
|
||||
* error message is assigned. If the `message` parameter is an instance of an `Error` then it will be thrown instead of the `AssertionError`.
|
||||
* If no arguments are passed in at all `message` will be set to the string:`` 'No value argument passed to `assert.ok()`' ``.
|
||||
*
|
||||
* Be aware that in the `repl` the error message will be different to the one
|
||||
* thrown in a file! See below for further details.
|
||||
*
|
||||
* ```js
|
||||
* import assert from 'node:assert/strict';
|
||||
*
|
||||
* assert.ok(true);
|
||||
* // OK
|
||||
* assert.ok(1);
|
||||
* // OK
|
||||
*
|
||||
* assert.ok();
|
||||
* // AssertionError: No value argument passed to `assert.ok()`
|
||||
*
|
||||
* assert.ok(false, 'it\'s false');
|
||||
* // AssertionError: it's false
|
||||
*
|
||||
* // In the repl:
|
||||
* assert.ok(typeof 123 === 'string');
|
||||
* // AssertionError: false == true
|
||||
*
|
||||
* // In a file (e.g. test.js):
|
||||
* assert.ok(typeof 123 === 'string');
|
||||
* // AssertionError: The expression evaluated to a falsy value:
|
||||
* //
|
||||
* // assert.ok(typeof 123 === 'string')
|
||||
*
|
||||
* assert.ok(false);
|
||||
* // AssertionError: The expression evaluated to a falsy value:
|
||||
* //
|
||||
* // assert.ok(false)
|
||||
*
|
||||
* assert.ok(0);
|
||||
* // AssertionError: The expression evaluated to a falsy value:
|
||||
* //
|
||||
* // assert.ok(0)
|
||||
* ```
|
||||
*
|
||||
* ```js
|
||||
* import assert from 'node:assert/strict';
|
||||
*
|
||||
* // Using `assert()` works the same:
|
||||
* assert(0);
|
||||
* // AssertionError: The expression evaluated to a falsy value:
|
||||
* //
|
||||
* // assert(0)
|
||||
* ```
|
||||
* @since v0.1.21
|
||||
*/
|
||||
function ok(value: unknown, message?: string | Error): asserts value;
|
||||
/**
|
||||
* **Strict assertion mode**
|
||||
*
|
||||
* An alias of {@link strictEqual}.
|
||||
*
|
||||
* **Legacy assertion mode**
|
||||
*
|
||||
* > Stability: 3 - Legacy: Use {@link strictEqual} instead.
|
||||
*
|
||||
* Tests shallow, coercive equality between the `actual` and `expected` parameters
|
||||
* using the [`==` operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Equality). `NaN` is specially handled
|
||||
* and treated as being identical if both sides are `NaN`.
|
||||
*
|
||||
* ```js
|
||||
* import assert from 'node:assert';
|
||||
*
|
||||
* assert.equal(1, 1);
|
||||
* // OK, 1 == 1
|
||||
* assert.equal(1, '1');
|
||||
* // OK, 1 == '1'
|
||||
* assert.equal(NaN, NaN);
|
||||
* // OK
|
||||
*
|
||||
* assert.equal(1, 2);
|
||||
* // AssertionError: 1 == 2
|
||||
* assert.equal({ a: { b: 1 } }, { a: { b: 1 } });
|
||||
* // AssertionError: { a: { b: 1 } } == { a: { b: 1 } }
|
||||
* ```
|
||||
*
|
||||
* If the values are not equal, an `AssertionError` is thrown with a `message` property set equal to the value of the `message` parameter. If the `message` parameter is undefined, a default
|
||||
* error message is assigned. If the `message` parameter is an instance of an `Error` then it will be thrown instead of the `AssertionError`.
|
||||
* @since v0.1.21
|
||||
*/
|
||||
function equal(actual: unknown, expected: unknown, message?: string | Error): void;
|
||||
/**
|
||||
* **Strict assertion mode**
|
||||
*
|
||||
* An alias of {@link notStrictEqual}.
|
||||
*
|
||||
* **Legacy assertion mode**
|
||||
*
|
||||
* > Stability: 3 - Legacy: Use {@link notStrictEqual} instead.
|
||||
*
|
||||
* Tests shallow, coercive inequality with the [`!=` operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Inequality). `NaN` is
|
||||
* specially handled and treated as being identical if both sides are `NaN`.
|
||||
*
|
||||
* ```js
|
||||
* import assert from 'node:assert';
|
||||
*
|
||||
* assert.notEqual(1, 2);
|
||||
* // OK
|
||||
*
|
||||
* assert.notEqual(1, 1);
|
||||
* // AssertionError: 1 != 1
|
||||
*
|
||||
* assert.notEqual(1, '1');
|
||||
* // AssertionError: 1 != '1'
|
||||
* ```
|
||||
*
|
||||
* If the values are equal, an `AssertionError` is thrown with a `message` property set equal to the value of the `message` parameter. If the `message` parameter is undefined, a default error
|
||||
* message is assigned. If the `message` parameter is an instance of an `Error` then it will be thrown instead of the `AssertionError`.
|
||||
* @since v0.1.21
|
||||
*/
|
||||
function notEqual(actual: unknown, expected: unknown, message?: string | Error): void;
|
||||
/**
|
||||
* **Strict assertion mode**
|
||||
*
|
||||
* An alias of {@link deepStrictEqual}.
|
||||
*
|
||||
* **Legacy assertion mode**
|
||||
*
|
||||
* > Stability: 3 - Legacy: Use {@link deepStrictEqual} instead.
|
||||
*
|
||||
* Tests for deep equality between the `actual` and `expected` parameters. Consider
|
||||
* using {@link deepStrictEqual} instead. {@link deepEqual} can have
|
||||
* surprising results.
|
||||
*
|
||||
* _Deep equality_ means that the enumerable "own" properties of child objects
|
||||
* are also recursively evaluated by the following rules.
|
||||
* @since v0.1.21
|
||||
*/
|
||||
function deepEqual(actual: unknown, expected: unknown, message?: string | Error): void;
|
||||
/**
|
||||
* **Strict assertion mode**
|
||||
*
|
||||
* An alias of {@link notDeepStrictEqual}.
|
||||
*
|
||||
* **Legacy assertion mode**
|
||||
*
|
||||
* > Stability: 3 - Legacy: Use {@link notDeepStrictEqual} instead.
|
||||
*
|
||||
* Tests for any deep inequality. Opposite of {@link deepEqual}.
|
||||
*
|
||||
* ```js
|
||||
* import assert from 'node:assert';
|
||||
*
|
||||
* const obj1 = {
|
||||
* a: {
|
||||
* b: 1,
|
||||
* },
|
||||
* };
|
||||
* const obj2 = {
|
||||
* a: {
|
||||
* b: 2,
|
||||
* },
|
||||
* };
|
||||
* const obj3 = {
|
||||
* a: {
|
||||
* b: 1,
|
||||
* },
|
||||
* };
|
||||
* const obj4 = { __proto__: obj1 };
|
||||
*
|
||||
* assert.notDeepEqual(obj1, obj1);
|
||||
* // AssertionError: { a: { b: 1 } } notDeepEqual { a: { b: 1 } }
|
||||
*
|
||||
* assert.notDeepEqual(obj1, obj2);
|
||||
* // OK
|
||||
*
|
||||
* assert.notDeepEqual(obj1, obj3);
|
||||
* // AssertionError: { a: { b: 1 } } notDeepEqual { a: { b: 1 } }
|
||||
*
|
||||
* assert.notDeepEqual(obj1, obj4);
|
||||
* // OK
|
||||
* ```
|
||||
*
|
||||
* If the values are deeply equal, an `AssertionError` is thrown with a `message` property set equal to the value of the `message` parameter. If the `message` parameter is undefined, a default
|
||||
* error message is assigned. If the `message` parameter is an instance of an `Error` then it will be thrown
|
||||
* instead of the `AssertionError`.
|
||||
* @since v0.1.21
|
||||
*/
|
||||
function notDeepEqual(actual: unknown, expected: unknown, message?: string | Error): void;
|
||||
/**
|
||||
* Tests strict equality between the `actual` and `expected` parameters as
|
||||
* determined by [`Object.is()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is).
|
||||
*
|
||||
* ```js
|
||||
* import assert from 'node:assert/strict';
|
||||
*
|
||||
* assert.strictEqual(1, 2);
|
||||
* // AssertionError [ERR_ASSERTION]: Expected inputs to be strictly equal:
|
||||
* //
|
||||
* // 1 !== 2
|
||||
*
|
||||
* assert.strictEqual(1, 1);
|
||||
* // OK
|
||||
*
|
||||
* assert.strictEqual('Hello foobar', 'Hello World!');
|
||||
* // AssertionError [ERR_ASSERTION]: Expected inputs to be strictly equal:
|
||||
* // + actual - expected
|
||||
* //
|
||||
* // + 'Hello foobar'
|
||||
* // - 'Hello World!'
|
||||
* // ^
|
||||
*
|
||||
* const apples = 1;
|
||||
* const oranges = 2;
|
||||
* assert.strictEqual(apples, oranges, `apples ${apples} !== oranges ${oranges}`);
|
||||
* // AssertionError [ERR_ASSERTION]: apples 1 !== oranges 2
|
||||
*
|
||||
* assert.strictEqual(1, '1', new TypeError('Inputs are not identical'));
|
||||
* // TypeError: Inputs are not identical
|
||||
* ```
|
||||
*
|
||||
* If the values are not strictly equal, an `AssertionError` is thrown with a `message` property set equal to the value of the `message` parameter. If the `message` parameter is undefined, a
|
||||
* default error message is assigned. If the `message` parameter is an instance of an `Error` then it will be thrown
|
||||
* instead of the `AssertionError`.
|
||||
* @since v0.1.21
|
||||
*/
|
||||
function strictEqual<T>(actual: unknown, expected: T, message?: string | Error): asserts actual is T;
|
||||
/**
|
||||
* Tests strict inequality between the `actual` and `expected` parameters as
|
||||
* determined by [`Object.is()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is).
|
||||
*
|
||||
* ```js
|
||||
* import assert from 'node:assert/strict';
|
||||
*
|
||||
* assert.notStrictEqual(1, 2);
|
||||
* // OK
|
||||
*
|
||||
* assert.notStrictEqual(1, 1);
|
||||
* // AssertionError [ERR_ASSERTION]: Expected "actual" to be strictly unequal to:
|
||||
* //
|
||||
* // 1
|
||||
*
|
||||
* assert.notStrictEqual(1, '1');
|
||||
* // OK
|
||||
* ```
|
||||
*
|
||||
* If the values are strictly equal, an `AssertionError` is thrown with a `message` property set equal to the value of the `message` parameter. If the `message` parameter is undefined, a
|
||||
* default error message is assigned. If the `message` parameter is an instance of an `Error` then it will be thrown
|
||||
* instead of the `AssertionError`.
|
||||
* @since v0.1.21
|
||||
*/
|
||||
function notStrictEqual(actual: unknown, expected: unknown, message?: string | Error): void;
|
||||
/**
|
||||
* Tests for deep equality between the `actual` and `expected` parameters.
|
||||
* "Deep" equality means that the enumerable "own" properties of child objects
|
||||
* are recursively evaluated also by the following rules.
|
||||
* @since v1.2.0
|
||||
*/
|
||||
function deepStrictEqual<T>(actual: unknown, expected: T, message?: string | Error): asserts actual is T;
|
||||
/**
|
||||
* Tests for deep strict inequality. Opposite of {@link deepStrictEqual}.
|
||||
*
|
||||
* ```js
|
||||
* import assert from 'node:assert/strict';
|
||||
*
|
||||
* assert.notDeepStrictEqual({ a: 1 }, { a: '1' });
|
||||
* // OK
|
||||
* ```
|
||||
*
|
||||
* If the values are deeply and strictly equal, an `AssertionError` is thrown
|
||||
* with a `message` property set equal to the value of the `message` parameter. If
|
||||
* the `message` parameter is undefined, a default error message is assigned. If
|
||||
* the `message` parameter is an instance of an `Error` then it will be thrown
|
||||
* instead of the `AssertionError`.
|
||||
* @since v1.2.0
|
||||
*/
|
||||
function notDeepStrictEqual(actual: unknown, expected: unknown, message?: string | Error): void;
|
||||
/**
|
||||
* Expects the function `fn` to throw an error.
|
||||
*
|
||||
* If specified, `error` can be a [`Class`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes),
|
||||
* [`RegExp`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions), a validation function,
|
||||
* a validation object where each property will be tested for strict deep equality,
|
||||
* or an instance of error where each property will be tested for strict deep
|
||||
* equality including the non-enumerable `message` and `name` properties. When
|
||||
* using an object, it is also possible to use a regular expression, when
|
||||
* validating against a string property. See below for examples.
|
||||
*
|
||||
* If specified, `message` will be appended to the message provided by the `AssertionError` if the `fn` call fails to throw or in case the error validation
|
||||
* fails.
|
||||
*
|
||||
* Custom validation object/error instance:
|
||||
*
|
||||
* ```js
|
||||
* import assert from 'node:assert/strict';
|
||||
*
|
||||
* const err = new TypeError('Wrong value');
|
||||
* err.code = 404;
|
||||
* err.foo = 'bar';
|
||||
* err.info = {
|
||||
* nested: true,
|
||||
* baz: 'text',
|
||||
* };
|
||||
* err.reg = /abc/i;
|
||||
*
|
||||
* assert.throws(
|
||||
* () => {
|
||||
* throw err;
|
||||
* },
|
||||
* {
|
||||
* name: 'TypeError',
|
||||
* message: 'Wrong value',
|
||||
* info: {
|
||||
* nested: true,
|
||||
* baz: 'text',
|
||||
* },
|
||||
* // Only properties on the validation object will be tested for.
|
||||
* // Using nested objects requires all properties to be present. Otherwise
|
||||
* // the validation is going to fail.
|
||||
* },
|
||||
* );
|
||||
*
|
||||
* // Using regular expressions to validate error properties:
|
||||
* assert.throws(
|
||||
* () => {
|
||||
* throw err;
|
||||
* },
|
||||
* {
|
||||
* // The `name` and `message` properties are strings and using regular
|
||||
* // expressions on those will match against the string. If they fail, an
|
||||
* // error is thrown.
|
||||
* name: /^TypeError$/,
|
||||
* message: /Wrong/,
|
||||
* foo: 'bar',
|
||||
* info: {
|
||||
* nested: true,
|
||||
* // It is not possible to use regular expressions for nested properties!
|
||||
* baz: 'text',
|
||||
* },
|
||||
* // The `reg` property contains a regular expression and only if the
|
||||
* // validation object contains an identical regular expression, it is going
|
||||
* // to pass.
|
||||
* reg: /abc/i,
|
||||
* },
|
||||
* );
|
||||
*
|
||||
* // Fails due to the different `message` and `name` properties:
|
||||
* assert.throws(
|
||||
* () => {
|
||||
* const otherErr = new Error('Not found');
|
||||
* // Copy all enumerable properties from `err` to `otherErr`.
|
||||
* for (const [key, value] of Object.entries(err)) {
|
||||
* otherErr[key] = value;
|
||||
* }
|
||||
* throw otherErr;
|
||||
* },
|
||||
* // The error's `message` and `name` properties will also be checked when using
|
||||
* // an error as validation object.
|
||||
* err,
|
||||
* );
|
||||
* ```
|
||||
*
|
||||
* Validate instanceof using constructor:
|
||||
*
|
||||
* ```js
|
||||
* import assert from 'node:assert/strict';
|
||||
*
|
||||
* assert.throws(
|
||||
* () => {
|
||||
* throw new Error('Wrong value');
|
||||
* },
|
||||
* Error,
|
||||
* );
|
||||
* ```
|
||||
*
|
||||
* Validate error message using [`RegExp`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions):
|
||||
*
|
||||
* Using a regular expression runs `.toString` on the error object, and will
|
||||
* therefore also include the error name.
|
||||
*
|
||||
* ```js
|
||||
* import assert from 'node:assert/strict';
|
||||
*
|
||||
* assert.throws(
|
||||
* () => {
|
||||
* throw new Error('Wrong value');
|
||||
* },
|
||||
* /^Error: Wrong value$/,
|
||||
* );
|
||||
* ```
|
||||
*
|
||||
* Custom error validation:
|
||||
*
|
||||
* The function must return `true` to indicate all internal validations passed.
|
||||
* It will otherwise fail with an `AssertionError`.
|
||||
*
|
||||
* ```js
|
||||
* import assert from 'node:assert/strict';
|
||||
*
|
||||
* assert.throws(
|
||||
* () => {
|
||||
* throw new Error('Wrong value');
|
||||
* },
|
||||
* (err) => {
|
||||
* assert(err instanceof Error);
|
||||
* assert(/value/.test(err));
|
||||
* // Avoid returning anything from validation functions besides `true`.
|
||||
* // Otherwise, it's not clear what part of the validation failed. Instead,
|
||||
* // throw an error about the specific validation that failed (as done in this
|
||||
* // example) and add as much helpful debugging information to that error as
|
||||
* // possible.
|
||||
* return true;
|
||||
* },
|
||||
* 'unexpected error',
|
||||
* );
|
||||
* ```
|
||||
*
|
||||
* `error` cannot be a string. If a string is provided as the second
|
||||
* argument, then `error` is assumed to be omitted and the string will be used for `message` instead. This can lead to easy-to-miss mistakes. Using the same
|
||||
* message as the thrown error message is going to result in an `ERR_AMBIGUOUS_ARGUMENT` error. Please read the example below carefully if using
|
||||
* a string as the second argument gets considered:
|
||||
*
|
||||
* ```js
|
||||
* import assert from 'node:assert/strict';
|
||||
*
|
||||
* function throwingFirst() {
|
||||
* throw new Error('First');
|
||||
* }
|
||||
*
|
||||
* function throwingSecond() {
|
||||
* throw new Error('Second');
|
||||
* }
|
||||
*
|
||||
* function notThrowing() {}
|
||||
*
|
||||
* // The second argument is a string and the input function threw an Error.
|
||||
* // The first case will not throw as it does not match for the error message
|
||||
* // thrown by the input function!
|
||||
* assert.throws(throwingFirst, 'Second');
|
||||
* // In the next example the message has no benefit over the message from the
|
||||
* // error and since it is not clear if the user intended to actually match
|
||||
* // against the error message, Node.js throws an `ERR_AMBIGUOUS_ARGUMENT` error.
|
||||
* assert.throws(throwingSecond, 'Second');
|
||||
* // TypeError [ERR_AMBIGUOUS_ARGUMENT]
|
||||
*
|
||||
* // The string is only used (as message) in case the function does not throw:
|
||||
* assert.throws(notThrowing, 'Second');
|
||||
* // AssertionError [ERR_ASSERTION]: Missing expected exception: Second
|
||||
*
|
||||
* // If it was intended to match for the error message do this instead:
|
||||
* // It does not throw because the error messages match.
|
||||
* assert.throws(throwingSecond, /Second$/);
|
||||
*
|
||||
* // If the error message does not match, an AssertionError is thrown.
|
||||
* assert.throws(throwingFirst, /Second$/);
|
||||
* // AssertionError [ERR_ASSERTION]
|
||||
* ```
|
||||
*
|
||||
* Due to the confusing error-prone notation, avoid a string as the second
|
||||
* argument.
|
||||
* @since v0.1.21
|
||||
*/
|
||||
function throws(block: () => unknown, message?: string | Error): void;
|
||||
function throws(block: () => unknown, error: AssertPredicate, message?: string | Error): void;
|
||||
/**
|
||||
* Asserts that the function `fn` does not throw an error.
|
||||
*
|
||||
* Using `assert.doesNotThrow()` is actually not useful because there
|
||||
* is no benefit in catching an error and then rethrowing it. Instead, consider
|
||||
* adding a comment next to the specific code path that should not throw and keep
|
||||
* error messages as expressive as possible.
|
||||
*
|
||||
* When `assert.doesNotThrow()` is called, it will immediately call the `fn` function.
|
||||
*
|
||||
* If an error is thrown and it is the same type as that specified by the `error` parameter, then an `AssertionError` is thrown. If the error is of a
|
||||
* different type, or if the `error` parameter is undefined, the error is
|
||||
* propagated back to the caller.
|
||||
*
|
||||
* If specified, `error` can be a [`Class`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes),
|
||||
* [`RegExp`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions), or a validation
|
||||
* function. See {@link throws} for more details.
|
||||
*
|
||||
* The following, for instance, will throw the `TypeError` because there is no
|
||||
* matching error type in the assertion:
|
||||
*
|
||||
* ```js
|
||||
* import assert from 'node:assert/strict';
|
||||
*
|
||||
* assert.doesNotThrow(
|
||||
* () => {
|
||||
* throw new TypeError('Wrong value');
|
||||
* },
|
||||
* SyntaxError,
|
||||
* );
|
||||
* ```
|
||||
*
|
||||
* However, the following will result in an `AssertionError` with the message
|
||||
* 'Got unwanted exception...':
|
||||
*
|
||||
* ```js
|
||||
* import assert from 'node:assert/strict';
|
||||
*
|
||||
* assert.doesNotThrow(
|
||||
* () => {
|
||||
* throw new TypeError('Wrong value');
|
||||
* },
|
||||
* TypeError,
|
||||
* );
|
||||
* ```
|
||||
*
|
||||
* If an `AssertionError` is thrown and a value is provided for the `message` parameter, the value of `message` will be appended to the `AssertionError` message:
|
||||
*
|
||||
* ```js
|
||||
* import assert from 'node:assert/strict';
|
||||
*
|
||||
* assert.doesNotThrow(
|
||||
* () => {
|
||||
* throw new TypeError('Wrong value');
|
||||
* },
|
||||
* /Wrong value/,
|
||||
* 'Whoops',
|
||||
* );
|
||||
* // Throws: AssertionError: Got unwanted exception: Whoops
|
||||
* ```
|
||||
* @since v0.1.21
|
||||
*/
|
||||
function doesNotThrow(block: () => unknown, message?: string | Error): void;
|
||||
function doesNotThrow(block: () => unknown, error: AssertPredicate, message?: string | Error): void;
|
||||
/**
|
||||
* Throws `value` if `value` is not `undefined` or `null`. This is useful when
|
||||
* testing the `error` argument in callbacks. The stack trace contains all frames
|
||||
* from the error passed to `ifError()` including the potential new frames for `ifError()` itself.
|
||||
*
|
||||
* ```js
|
||||
* import assert from 'node:assert/strict';
|
||||
*
|
||||
* assert.ifError(null);
|
||||
* // OK
|
||||
* assert.ifError(0);
|
||||
* // AssertionError [ERR_ASSERTION]: ifError got unwanted exception: 0
|
||||
* assert.ifError('error');
|
||||
* // AssertionError [ERR_ASSERTION]: ifError got unwanted exception: 'error'
|
||||
* assert.ifError(new Error());
|
||||
* // AssertionError [ERR_ASSERTION]: ifError got unwanted exception: Error
|
||||
*
|
||||
* // Create some random error frames.
|
||||
* let err;
|
||||
* (function errorFrame() {
|
||||
* err = new Error('test error');
|
||||
* })();
|
||||
*
|
||||
* (function ifErrorFrame() {
|
||||
* assert.ifError(err);
|
||||
* })();
|
||||
* // AssertionError [ERR_ASSERTION]: ifError got unwanted exception: test error
|
||||
* // at ifErrorFrame
|
||||
* // at errorFrame
|
||||
* ```
|
||||
* @since v0.1.97
|
||||
*/
|
||||
function ifError(value: unknown): asserts value is null | undefined;
|
||||
/**
|
||||
* Awaits the `asyncFn` promise or, if `asyncFn` is a function, immediately
|
||||
* calls the function and awaits the returned promise to complete. It will then
|
||||
* check that the promise is rejected.
|
||||
*
|
||||
* If `asyncFn` is a function and it throws an error synchronously, `assert.rejects()` will return a rejected `Promise` with that error. If the
|
||||
* function does not return a promise, `assert.rejects()` will return a rejected `Promise` with an [ERR_INVALID_RETURN_VALUE](https://nodejs.org/docs/latest-v25.x/api/errors.html#err_invalid_return_value)
|
||||
* error. In both cases the error handler is skipped.
|
||||
*
|
||||
* Besides the async nature to await the completion behaves identically to {@link throws}.
|
||||
*
|
||||
* If specified, `error` can be a [`Class`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes),
|
||||
* [`RegExp`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions), a validation function,
|
||||
* an object where each property will be tested for, or an instance of error where
|
||||
* each property will be tested for including the non-enumerable `message` and `name` properties.
|
||||
*
|
||||
* If specified, `message` will be the message provided by the `{@link AssertionError}` if the `asyncFn` fails to reject.
|
||||
*
|
||||
* ```js
|
||||
* import assert from 'node:assert/strict';
|
||||
*
|
||||
* await assert.rejects(
|
||||
* async () => {
|
||||
* throw new TypeError('Wrong value');
|
||||
* },
|
||||
* {
|
||||
* name: 'TypeError',
|
||||
* message: 'Wrong value',
|
||||
* },
|
||||
* );
|
||||
* ```
|
||||
*
|
||||
* ```js
|
||||
* import assert from 'node:assert/strict';
|
||||
*
|
||||
* await assert.rejects(
|
||||
* async () => {
|
||||
* throw new TypeError('Wrong value');
|
||||
* },
|
||||
* (err) => {
|
||||
* assert.strictEqual(err.name, 'TypeError');
|
||||
* assert.strictEqual(err.message, 'Wrong value');
|
||||
* return true;
|
||||
* },
|
||||
* );
|
||||
* ```
|
||||
*
|
||||
* ```js
|
||||
* import assert from 'node:assert/strict';
|
||||
*
|
||||
* assert.rejects(
|
||||
* Promise.reject(new Error('Wrong value')),
|
||||
* Error,
|
||||
* ).then(() => {
|
||||
* // ...
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* `error` cannot be a string. If a string is provided as the second argument, then `error` is assumed to
|
||||
* be omitted and the string will be used for `message` instead. This can lead to easy-to-miss mistakes. Please read the
|
||||
* example in {@link throws} carefully if using a string as the second argument gets considered.
|
||||
* @since v10.0.0
|
||||
*/
|
||||
function rejects(block: (() => Promise<unknown>) | Promise<unknown>, message?: string | Error): Promise<void>;
|
||||
function rejects(
|
||||
block: (() => Promise<unknown>) | Promise<unknown>,
|
||||
error: AssertPredicate,
|
||||
message?: string | Error,
|
||||
): Promise<void>;
|
||||
/**
|
||||
* Awaits the `asyncFn` promise or, if `asyncFn` is a function, immediately
|
||||
* calls the function and awaits the returned promise to complete. It will then
|
||||
* check that the promise is not rejected.
|
||||
*
|
||||
* If `asyncFn` is a function and it throws an error synchronously, `assert.doesNotReject()` will return a rejected `Promise` with that error. If
|
||||
* the function does not return a promise, `assert.doesNotReject()` will return a
|
||||
* rejected `Promise` with an [ERR_INVALID_RETURN_VALUE](https://nodejs.org/docs/latest-v25.x/api/errors.html#err_invalid_return_value) error. In both cases
|
||||
* the error handler is skipped.
|
||||
*
|
||||
* Using `assert.doesNotReject()` is actually not useful because there is little
|
||||
* benefit in catching a rejection and then rejecting it again. Instead, consider
|
||||
* adding a comment next to the specific code path that should not reject and keep
|
||||
* error messages as expressive as possible.
|
||||
*
|
||||
* If specified, `error` can be a [`Class`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes),
|
||||
* [`RegExp`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions), or a validation
|
||||
* function. See {@link throws} for more details.
|
||||
*
|
||||
* Besides the async nature to await the completion behaves identically to {@link doesNotThrow}.
|
||||
*
|
||||
* ```js
|
||||
* import assert from 'node:assert/strict';
|
||||
*
|
||||
* await assert.doesNotReject(
|
||||
* async () => {
|
||||
* throw new TypeError('Wrong value');
|
||||
* },
|
||||
* SyntaxError,
|
||||
* );
|
||||
* ```
|
||||
*
|
||||
* ```js
|
||||
* import assert from 'node:assert/strict';
|
||||
*
|
||||
* assert.doesNotReject(Promise.reject(new TypeError('Wrong value')))
|
||||
* .then(() => {
|
||||
* // ...
|
||||
* });
|
||||
* ```
|
||||
* @since v10.0.0
|
||||
*/
|
||||
function doesNotReject(
|
||||
block: (() => Promise<unknown>) | Promise<unknown>,
|
||||
message?: string | Error,
|
||||
): Promise<void>;
|
||||
function doesNotReject(
|
||||
block: (() => Promise<unknown>) | Promise<unknown>,
|
||||
error: AssertPredicate,
|
||||
message?: string | Error,
|
||||
): Promise<void>;
|
||||
/**
|
||||
* Expects the `string` input to match the regular expression.
|
||||
*
|
||||
* ```js
|
||||
* import assert from 'node:assert/strict';
|
||||
*
|
||||
* assert.match('I will fail', /pass/);
|
||||
* // AssertionError [ERR_ASSERTION]: The input did not match the regular ...
|
||||
*
|
||||
* assert.match(123, /pass/);
|
||||
* // AssertionError [ERR_ASSERTION]: The "string" argument must be of type string.
|
||||
*
|
||||
* assert.match('I will pass', /pass/);
|
||||
* // OK
|
||||
* ```
|
||||
*
|
||||
* If the values do not match, or if the `string` argument is of another type than `string`, an `{@link AssertionError}` is thrown with a `message` property set equal
|
||||
* to the value of the `message` parameter. If the `message` parameter is
|
||||
* undefined, a default error message is assigned. If the `message` parameter is an
|
||||
* instance of an [Error](https://nodejs.org/docs/latest-v25.x/api/errors.html#class-error) then it will be thrown instead of the `{@link AssertionError}`.
|
||||
* @since v13.6.0, v12.16.0
|
||||
*/
|
||||
function match(value: string, regExp: RegExp, message?: string | Error): void;
|
||||
/**
|
||||
* Expects the `string` input not to match the regular expression.
|
||||
*
|
||||
* ```js
|
||||
* import assert from 'node:assert/strict';
|
||||
*
|
||||
* assert.doesNotMatch('I will fail', /fail/);
|
||||
* // AssertionError [ERR_ASSERTION]: The input was expected to not match the ...
|
||||
*
|
||||
* assert.doesNotMatch(123, /pass/);
|
||||
* // AssertionError [ERR_ASSERTION]: The "string" argument must be of type string.
|
||||
*
|
||||
* assert.doesNotMatch('I will pass', /different/);
|
||||
* // OK
|
||||
* ```
|
||||
*
|
||||
* If the values do match, or if the `string` argument is of another type than `string`, an `{@link AssertionError}` is thrown with a `message` property set equal
|
||||
* to the value of the `message` parameter. If the `message` parameter is
|
||||
* undefined, a default error message is assigned. If the `message` parameter is an
|
||||
* instance of an [Error](https://nodejs.org/docs/latest-v25.x/api/errors.html#class-error) then it will be thrown instead of the `{@link AssertionError}`.
|
||||
* @since v13.6.0, v12.16.0
|
||||
*/
|
||||
function doesNotMatch(value: string, regExp: RegExp, message?: string | Error): void;
|
||||
/**
|
||||
* Tests for partial deep equality between the `actual` and `expected` parameters.
|
||||
* "Deep" equality means that the enumerable "own" properties of child objects
|
||||
* are recursively evaluated also by the following rules. "Partial" equality means
|
||||
* that only properties that exist on the `expected` parameter are going to be
|
||||
* compared.
|
||||
*
|
||||
* This method always passes the same test cases as `assert.deepStrictEqual()`,
|
||||
* behaving as a super set of it.
|
||||
* @since v22.13.0
|
||||
*/
|
||||
function partialDeepStrictEqual(actual: unknown, expected: unknown, message?: string | Error): void;
|
||||
}
|
||||
namespace assert {
|
||||
export { strict };
|
||||
}
|
||||
export = assert;
|
||||
}
|
||||
declare module "assert" {
|
||||
import assert = require("node:assert");
|
||||
export = assert;
|
||||
}
|
||||
105
.cursor/scripts/db-exec/node_modules/@types/node/assert/strict.d.ts
generated
vendored
Normal file
105
.cursor/scripts/db-exec/node_modules/@types/node/assert/strict.d.ts
generated
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
/**
|
||||
* In strict assertion mode, non-strict methods behave like their corresponding
|
||||
* strict methods. For example, `assert.deepEqual()` will behave like
|
||||
* `assert.deepStrictEqual()`.
|
||||
*
|
||||
* In strict assertion mode, error messages for objects display a diff. In legacy
|
||||
* assertion mode, error messages for objects display the objects, often truncated.
|
||||
*
|
||||
* To use strict assertion mode:
|
||||
*
|
||||
* ```js
|
||||
* import { strict as assert } from 'node:assert';
|
||||
* ```
|
||||
*
|
||||
* ```js
|
||||
* import assert from 'node:assert/strict';
|
||||
* ```
|
||||
*
|
||||
* Example error diff:
|
||||
*
|
||||
* ```js
|
||||
* import { strict as assert } from 'node:assert';
|
||||
*
|
||||
* assert.deepEqual([[[1, 2, 3]], 4, 5], [[[1, 2, '3']], 4, 5]);
|
||||
* // AssertionError: Expected inputs to be strictly deep-equal:
|
||||
* // + actual - expected ... Lines skipped
|
||||
* //
|
||||
* // [
|
||||
* // [
|
||||
* // ...
|
||||
* // 2,
|
||||
* // + 3
|
||||
* // - '3'
|
||||
* // ],
|
||||
* // ...
|
||||
* // 5
|
||||
* // ]
|
||||
* ```
|
||||
*
|
||||
* To deactivate the colors, use the `NO_COLOR` or `NODE_DISABLE_COLORS`
|
||||
* environment variables. This will also deactivate the colors in the REPL. For
|
||||
* more on color support in terminal environments, read the tty
|
||||
* [`getColorDepth()`](https://nodejs.org/docs/latest-v25.x/api/tty.html#writestreamgetcolordepthenv) documentation.
|
||||
* @since v15.0.0
|
||||
* @see [source](https://github.com/nodejs/node/blob/v25.x/lib/assert/strict.js)
|
||||
*/
|
||||
declare module "node:assert/strict" {
|
||||
import {
|
||||
Assert,
|
||||
AssertionError,
|
||||
AssertionErrorOptions,
|
||||
AssertOptions,
|
||||
AssertPredicate,
|
||||
AssertStrict,
|
||||
deepStrictEqual,
|
||||
doesNotMatch,
|
||||
doesNotReject,
|
||||
doesNotThrow,
|
||||
fail,
|
||||
ifError,
|
||||
match,
|
||||
notDeepStrictEqual,
|
||||
notStrictEqual,
|
||||
ok,
|
||||
partialDeepStrictEqual,
|
||||
rejects,
|
||||
strictEqual,
|
||||
throws,
|
||||
} from "node:assert";
|
||||
function strict(value: unknown, message?: string | Error): asserts value;
|
||||
namespace strict {
|
||||
export {
|
||||
Assert,
|
||||
AssertionError,
|
||||
AssertionErrorOptions,
|
||||
AssertOptions,
|
||||
AssertPredicate,
|
||||
AssertStrict,
|
||||
deepStrictEqual,
|
||||
deepStrictEqual as deepEqual,
|
||||
doesNotMatch,
|
||||
doesNotReject,
|
||||
doesNotThrow,
|
||||
fail,
|
||||
ifError,
|
||||
match,
|
||||
notDeepStrictEqual,
|
||||
notDeepStrictEqual as notDeepEqual,
|
||||
notStrictEqual,
|
||||
notStrictEqual as notEqual,
|
||||
ok,
|
||||
partialDeepStrictEqual,
|
||||
rejects,
|
||||
strict,
|
||||
strictEqual,
|
||||
strictEqual as equal,
|
||||
throws,
|
||||
};
|
||||
}
|
||||
export = strict;
|
||||
}
|
||||
declare module "assert/strict" {
|
||||
import strict = require("node:assert/strict");
|
||||
export = strict;
|
||||
}
|
||||
623
.cursor/scripts/db-exec/node_modules/@types/node/async_hooks.d.ts
generated
vendored
Normal file
623
.cursor/scripts/db-exec/node_modules/@types/node/async_hooks.d.ts
generated
vendored
Normal file
@@ -0,0 +1,623 @@
|
||||
/**
|
||||
* We strongly discourage the use of the `async_hooks` API.
|
||||
* Other APIs that can cover most of its use cases include:
|
||||
*
|
||||
* * [`AsyncLocalStorage`](https://nodejs.org/docs/latest-v25.x/api/async_context.html#class-asynclocalstorage) tracks async context
|
||||
* * [`process.getActiveResourcesInfo()`](https://nodejs.org/docs/latest-v25.x/api/process.html#processgetactiveresourcesinfo) tracks active resources
|
||||
*
|
||||
* The `node:async_hooks` module provides an API to track asynchronous resources.
|
||||
* It can be accessed using:
|
||||
*
|
||||
* ```js
|
||||
* import async_hooks from 'node:async_hooks';
|
||||
* ```
|
||||
* @experimental
|
||||
* @see [source](https://github.com/nodejs/node/blob/v25.x/lib/async_hooks.js)
|
||||
*/
|
||||
declare module "node:async_hooks" {
|
||||
/**
|
||||
* ```js
|
||||
* import { executionAsyncId } from 'node:async_hooks';
|
||||
* import fs from 'node:fs';
|
||||
*
|
||||
* console.log(executionAsyncId()); // 1 - bootstrap
|
||||
* const path = '.';
|
||||
* fs.open(path, 'r', (err, fd) => {
|
||||
* console.log(executionAsyncId()); // 6 - open()
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* The ID returned from `executionAsyncId()` is related to execution timing, not
|
||||
* causality (which is covered by `triggerAsyncId()`):
|
||||
*
|
||||
* ```js
|
||||
* const server = net.createServer((conn) => {
|
||||
* // Returns the ID of the server, not of the new connection, because the
|
||||
* // callback runs in the execution scope of the server's MakeCallback().
|
||||
* async_hooks.executionAsyncId();
|
||||
*
|
||||
* }).listen(port, () => {
|
||||
* // Returns the ID of a TickObject (process.nextTick()) because all
|
||||
* // callbacks passed to .listen() are wrapped in a nextTick().
|
||||
* async_hooks.executionAsyncId();
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* Promise contexts may not get precise `executionAsyncIds` by default.
|
||||
* See the section on [promise execution tracking](https://nodejs.org/docs/latest-v25.x/api/async_hooks.html#promise-execution-tracking).
|
||||
* @since v8.1.0
|
||||
* @return The `asyncId` of the current execution context. Useful to track when something calls.
|
||||
*/
|
||||
function executionAsyncId(): number;
|
||||
/**
|
||||
* Resource objects returned by `executionAsyncResource()` are most often internal
|
||||
* Node.js handle objects with undocumented APIs. Using any functions or properties
|
||||
* on the object is likely to crash your application and should be avoided.
|
||||
*
|
||||
* Using `executionAsyncResource()` in the top-level execution context will
|
||||
* return an empty object as there is no handle or request object to use,
|
||||
* but having an object representing the top-level can be helpful.
|
||||
*
|
||||
* ```js
|
||||
* import { open } from 'node:fs';
|
||||
* import { executionAsyncId, executionAsyncResource } from 'node:async_hooks';
|
||||
*
|
||||
* console.log(executionAsyncId(), executionAsyncResource()); // 1 {}
|
||||
* open(new URL(import.meta.url), 'r', (err, fd) => {
|
||||
* console.log(executionAsyncId(), executionAsyncResource()); // 7 FSReqWrap
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* This can be used to implement continuation local storage without the
|
||||
* use of a tracking `Map` to store the metadata:
|
||||
*
|
||||
* ```js
|
||||
* import { createServer } from 'node:http';
|
||||
* import {
|
||||
* executionAsyncId,
|
||||
* executionAsyncResource,
|
||||
* createHook,
|
||||
* } from 'node:async_hooks';
|
||||
* const sym = Symbol('state'); // Private symbol to avoid pollution
|
||||
*
|
||||
* createHook({
|
||||
* init(asyncId, type, triggerAsyncId, resource) {
|
||||
* const cr = executionAsyncResource();
|
||||
* if (cr) {
|
||||
* resource[sym] = cr[sym];
|
||||
* }
|
||||
* },
|
||||
* }).enable();
|
||||
*
|
||||
* const server = createServer((req, res) => {
|
||||
* executionAsyncResource()[sym] = { state: req.url };
|
||||
* setTimeout(function() {
|
||||
* res.end(JSON.stringify(executionAsyncResource()[sym]));
|
||||
* }, 100);
|
||||
* }).listen(3000);
|
||||
* ```
|
||||
* @since v13.9.0, v12.17.0
|
||||
* @return The resource representing the current execution. Useful to store data within the resource.
|
||||
*/
|
||||
function executionAsyncResource(): object;
|
||||
/**
|
||||
* ```js
|
||||
* const server = net.createServer((conn) => {
|
||||
* // The resource that caused (or triggered) this callback to be called
|
||||
* // was that of the new connection. Thus the return value of triggerAsyncId()
|
||||
* // is the asyncId of "conn".
|
||||
* async_hooks.triggerAsyncId();
|
||||
*
|
||||
* }).listen(port, () => {
|
||||
* // Even though all callbacks passed to .listen() are wrapped in a nextTick()
|
||||
* // the callback itself exists because the call to the server's .listen()
|
||||
* // was made. So the return value would be the ID of the server.
|
||||
* async_hooks.triggerAsyncId();
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* Promise contexts may not get valid `triggerAsyncId`s by default. See
|
||||
* the section on [promise execution tracking](https://nodejs.org/docs/latest-v25.x/api/async_hooks.html#promise-execution-tracking).
|
||||
* @return The ID of the resource responsible for calling the callback that is currently being executed.
|
||||
*/
|
||||
function triggerAsyncId(): number;
|
||||
interface HookCallbacks {
|
||||
/**
|
||||
* Called when a class is constructed that has the possibility to emit an asynchronous event.
|
||||
* @param asyncId A unique ID for the async resource
|
||||
* @param type The type of the async resource
|
||||
* @param triggerAsyncId The unique ID of the async resource in whose execution context this async resource was created
|
||||
* @param resource Reference to the resource representing the async operation, needs to be released during destroy
|
||||
*/
|
||||
init?(asyncId: number, type: string, triggerAsyncId: number, resource: object): void;
|
||||
/**
|
||||
* When an asynchronous operation is initiated or completes a callback is called to notify the user.
|
||||
* The before callback is called just before said callback is executed.
|
||||
* @param asyncId the unique identifier assigned to the resource about to execute the callback.
|
||||
*/
|
||||
before?(asyncId: number): void;
|
||||
/**
|
||||
* Called immediately after the callback specified in `before` is completed.
|
||||
*
|
||||
* If an uncaught exception occurs during execution of the callback, then `after` will run after the `'uncaughtException'` event is emitted or a `domain`'s handler runs.
|
||||
* @param asyncId the unique identifier assigned to the resource which has executed the callback.
|
||||
*/
|
||||
after?(asyncId: number): void;
|
||||
/**
|
||||
* Called when a promise has resolve() called. This may not be in the same execution id
|
||||
* as the promise itself.
|
||||
* @param asyncId the unique id for the promise that was resolve()d.
|
||||
*/
|
||||
promiseResolve?(asyncId: number): void;
|
||||
/**
|
||||
* Called after the resource corresponding to asyncId is destroyed
|
||||
* @param asyncId a unique ID for the async resource
|
||||
*/
|
||||
destroy?(asyncId: number): void;
|
||||
}
|
||||
interface AsyncHook {
|
||||
/**
|
||||
* Enable the callbacks for a given AsyncHook instance. If no callbacks are provided enabling is a noop.
|
||||
*/
|
||||
enable(): this;
|
||||
/**
|
||||
* Disable the callbacks for a given AsyncHook instance from the global pool of AsyncHook callbacks to be executed. Once a hook has been disabled it will not be called again until enabled.
|
||||
*/
|
||||
disable(): this;
|
||||
}
|
||||
/**
|
||||
* Registers functions to be called for different lifetime events of each async
|
||||
* operation.
|
||||
*
|
||||
* The callbacks `init()`/`before()`/`after()`/`destroy()` are called for the
|
||||
* respective asynchronous event during a resource's lifetime.
|
||||
*
|
||||
* All callbacks are optional. For example, if only resource cleanup needs to
|
||||
* be tracked, then only the `destroy` callback needs to be passed. The
|
||||
* specifics of all functions that can be passed to `callbacks` is in the `Hook Callbacks` section.
|
||||
*
|
||||
* ```js
|
||||
* import { createHook } from 'node:async_hooks';
|
||||
*
|
||||
* const asyncHook = createHook({
|
||||
* init(asyncId, type, triggerAsyncId, resource) { },
|
||||
* destroy(asyncId) { },
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* The callbacks will be inherited via the prototype chain:
|
||||
*
|
||||
* ```js
|
||||
* class MyAsyncCallbacks {
|
||||
* init(asyncId, type, triggerAsyncId, resource) { }
|
||||
* destroy(asyncId) {}
|
||||
* }
|
||||
*
|
||||
* class MyAddedCallbacks extends MyAsyncCallbacks {
|
||||
* before(asyncId) { }
|
||||
* after(asyncId) { }
|
||||
* }
|
||||
*
|
||||
* const asyncHook = async_hooks.createHook(new MyAddedCallbacks());
|
||||
* ```
|
||||
*
|
||||
* Because promises are asynchronous resources whose lifecycle is tracked
|
||||
* via the async hooks mechanism, the `init()`, `before()`, `after()`, and`destroy()` callbacks _must not_ be async functions that return promises.
|
||||
* @since v8.1.0
|
||||
* @param callbacks The `Hook Callbacks` to register
|
||||
* @return Instance used for disabling and enabling hooks
|
||||
*/
|
||||
function createHook(callbacks: HookCallbacks): AsyncHook;
|
||||
interface AsyncResourceOptions {
|
||||
/**
|
||||
* The ID of the execution context that created this async event.
|
||||
* @default executionAsyncId()
|
||||
*/
|
||||
triggerAsyncId?: number | undefined;
|
||||
/**
|
||||
* Disables automatic `emitDestroy` when the object is garbage collected.
|
||||
* This usually does not need to be set (even if `emitDestroy` is called
|
||||
* manually), unless the resource's `asyncId` is retrieved and the
|
||||
* sensitive API's `emitDestroy` is called with it.
|
||||
* @default false
|
||||
*/
|
||||
requireManualDestroy?: boolean | undefined;
|
||||
}
|
||||
/**
|
||||
* The class `AsyncResource` is designed to be extended by the embedder's async
|
||||
* resources. Using this, users can easily trigger the lifetime events of their
|
||||
* own resources.
|
||||
*
|
||||
* The `init` hook will trigger when an `AsyncResource` is instantiated.
|
||||
*
|
||||
* The following is an overview of the `AsyncResource` API.
|
||||
*
|
||||
* ```js
|
||||
* import { AsyncResource, executionAsyncId } from 'node:async_hooks';
|
||||
*
|
||||
* // AsyncResource() is meant to be extended. Instantiating a
|
||||
* // new AsyncResource() also triggers init. If triggerAsyncId is omitted then
|
||||
* // async_hook.executionAsyncId() is used.
|
||||
* const asyncResource = new AsyncResource(
|
||||
* type, { triggerAsyncId: executionAsyncId(), requireManualDestroy: false },
|
||||
* );
|
||||
*
|
||||
* // Run a function in the execution context of the resource. This will
|
||||
* // * establish the context of the resource
|
||||
* // * trigger the AsyncHooks before callbacks
|
||||
* // * call the provided function `fn` with the supplied arguments
|
||||
* // * trigger the AsyncHooks after callbacks
|
||||
* // * restore the original execution context
|
||||
* asyncResource.runInAsyncScope(fn, thisArg, ...args);
|
||||
*
|
||||
* // Call AsyncHooks destroy callbacks.
|
||||
* asyncResource.emitDestroy();
|
||||
*
|
||||
* // Return the unique ID assigned to the AsyncResource instance.
|
||||
* asyncResource.asyncId();
|
||||
*
|
||||
* // Return the trigger ID for the AsyncResource instance.
|
||||
* asyncResource.triggerAsyncId();
|
||||
* ```
|
||||
*/
|
||||
class AsyncResource {
|
||||
/**
|
||||
* AsyncResource() is meant to be extended. Instantiating a
|
||||
* new AsyncResource() also triggers init. If triggerAsyncId is omitted then
|
||||
* async_hook.executionAsyncId() is used.
|
||||
* @param type The type of async event.
|
||||
* @param triggerAsyncId The ID of the execution context that created
|
||||
* this async event (default: `executionAsyncId()`), or an
|
||||
* AsyncResourceOptions object (since v9.3.0)
|
||||
*/
|
||||
constructor(type: string, triggerAsyncId?: number | AsyncResourceOptions);
|
||||
/**
|
||||
* Binds the given function to the current execution context.
|
||||
* @since v14.8.0, v12.19.0
|
||||
* @param fn The function to bind to the current execution context.
|
||||
* @param type An optional name to associate with the underlying `AsyncResource`.
|
||||
*/
|
||||
static bind<Func extends (this: ThisArg, ...args: any[]) => any, ThisArg>(
|
||||
fn: Func,
|
||||
type?: string,
|
||||
thisArg?: ThisArg,
|
||||
): Func;
|
||||
/**
|
||||
* Binds the given function to execute to this `AsyncResource`'s scope.
|
||||
* @since v14.8.0, v12.19.0
|
||||
* @param fn The function to bind to the current `AsyncResource`.
|
||||
*/
|
||||
bind<Func extends (...args: any[]) => any>(fn: Func): Func;
|
||||
/**
|
||||
* Call the provided function with the provided arguments in the execution context
|
||||
* of the async resource. This will establish the context, trigger the AsyncHooks
|
||||
* before callbacks, call the function, trigger the AsyncHooks after callbacks, and
|
||||
* then restore the original execution context.
|
||||
* @since v9.6.0
|
||||
* @param fn The function to call in the execution context of this async resource.
|
||||
* @param thisArg The receiver to be used for the function call.
|
||||
* @param args Optional arguments to pass to the function.
|
||||
*/
|
||||
runInAsyncScope<This, Result>(
|
||||
fn: (this: This, ...args: any[]) => Result,
|
||||
thisArg?: This,
|
||||
...args: any[]
|
||||
): Result;
|
||||
/**
|
||||
* Call all `destroy` hooks. This should only ever be called once. An error will
|
||||
* be thrown if it is called more than once. This **must** be manually called. If
|
||||
* the resource is left to be collected by the GC then the `destroy` hooks will
|
||||
* never be called.
|
||||
* @return A reference to `asyncResource`.
|
||||
*/
|
||||
emitDestroy(): this;
|
||||
/**
|
||||
* @return The unique `asyncId` assigned to the resource.
|
||||
*/
|
||||
asyncId(): number;
|
||||
/**
|
||||
* @return The same `triggerAsyncId` that is passed to the `AsyncResource` constructor.
|
||||
*/
|
||||
triggerAsyncId(): number;
|
||||
}
|
||||
interface AsyncLocalStorageOptions {
|
||||
/**
|
||||
* The default value to be used when no store is provided.
|
||||
*/
|
||||
defaultValue?: any;
|
||||
/**
|
||||
* A name for the `AsyncLocalStorage` value.
|
||||
*/
|
||||
name?: string | undefined;
|
||||
}
|
||||
/**
|
||||
* This class creates stores that stay coherent through asynchronous operations.
|
||||
*
|
||||
* While you can create your own implementation on top of the `node:async_hooks` module, `AsyncLocalStorage` should be preferred as it is a performant and memory
|
||||
* safe implementation that involves significant optimizations that are non-obvious
|
||||
* to implement.
|
||||
*
|
||||
* The following example uses `AsyncLocalStorage` to build a simple logger
|
||||
* that assigns IDs to incoming HTTP requests and includes them in messages
|
||||
* logged within each request.
|
||||
*
|
||||
* ```js
|
||||
* import http from 'node:http';
|
||||
* import { AsyncLocalStorage } from 'node:async_hooks';
|
||||
*
|
||||
* const asyncLocalStorage = new AsyncLocalStorage();
|
||||
*
|
||||
* function logWithId(msg) {
|
||||
* const id = asyncLocalStorage.getStore();
|
||||
* console.log(`${id !== undefined ? id : '-'}:`, msg);
|
||||
* }
|
||||
*
|
||||
* let idSeq = 0;
|
||||
* http.createServer((req, res) => {
|
||||
* asyncLocalStorage.run(idSeq++, () => {
|
||||
* logWithId('start');
|
||||
* // Imagine any chain of async operations here
|
||||
* setImmediate(() => {
|
||||
* logWithId('finish');
|
||||
* res.end();
|
||||
* });
|
||||
* });
|
||||
* }).listen(8080);
|
||||
*
|
||||
* http.get('http://localhost:8080');
|
||||
* http.get('http://localhost:8080');
|
||||
* // Prints:
|
||||
* // 0: start
|
||||
* // 0: finish
|
||||
* // 1: start
|
||||
* // 1: finish
|
||||
* ```
|
||||
*
|
||||
* Each instance of `AsyncLocalStorage` maintains an independent storage context.
|
||||
* Multiple instances can safely exist simultaneously without risk of interfering
|
||||
* with each other's data.
|
||||
* @since v13.10.0, v12.17.0
|
||||
*/
|
||||
class AsyncLocalStorage<T> {
|
||||
/**
|
||||
* Creates a new instance of `AsyncLocalStorage`. Store is only provided within a
|
||||
* `run()` call or after an `enterWith()` call.
|
||||
*/
|
||||
constructor(options?: AsyncLocalStorageOptions);
|
||||
/**
|
||||
* Binds the given function to the current execution context.
|
||||
* @since v19.8.0
|
||||
* @param fn The function to bind to the current execution context.
|
||||
* @return A new function that calls `fn` within the captured execution context.
|
||||
*/
|
||||
static bind<Func extends (...args: any[]) => any>(fn: Func): Func;
|
||||
/**
|
||||
* Captures the current execution context and returns a function that accepts a
|
||||
* function as an argument. Whenever the returned function is called, it
|
||||
* calls the function passed to it within the captured context.
|
||||
*
|
||||
* ```js
|
||||
* const asyncLocalStorage = new AsyncLocalStorage();
|
||||
* const runInAsyncScope = asyncLocalStorage.run(123, () => AsyncLocalStorage.snapshot());
|
||||
* const result = asyncLocalStorage.run(321, () => runInAsyncScope(() => asyncLocalStorage.getStore()));
|
||||
* console.log(result); // returns 123
|
||||
* ```
|
||||
*
|
||||
* AsyncLocalStorage.snapshot() can replace the use of AsyncResource for simple
|
||||
* async context tracking purposes, for example:
|
||||
*
|
||||
* ```js
|
||||
* class Foo {
|
||||
* #runInAsyncScope = AsyncLocalStorage.snapshot();
|
||||
*
|
||||
* get() { return this.#runInAsyncScope(() => asyncLocalStorage.getStore()); }
|
||||
* }
|
||||
*
|
||||
* const foo = asyncLocalStorage.run(123, () => new Foo());
|
||||
* console.log(asyncLocalStorage.run(321, () => foo.get())); // returns 123
|
||||
* ```
|
||||
* @since v19.8.0
|
||||
* @return A new function with the signature `(fn: (...args) : R, ...args) : R`.
|
||||
*/
|
||||
static snapshot(): <R, TArgs extends any[]>(fn: (...args: TArgs) => R, ...args: TArgs) => R;
|
||||
/**
|
||||
* Disables the instance of `AsyncLocalStorage`. All subsequent calls
|
||||
* to `asyncLocalStorage.getStore()` will return `undefined` until `asyncLocalStorage.run()` or `asyncLocalStorage.enterWith()` is called again.
|
||||
*
|
||||
* When calling `asyncLocalStorage.disable()`, all current contexts linked to the
|
||||
* instance will be exited.
|
||||
*
|
||||
* Calling `asyncLocalStorage.disable()` is required before the `asyncLocalStorage` can be garbage collected. This does not apply to stores
|
||||
* provided by the `asyncLocalStorage`, as those objects are garbage collected
|
||||
* along with the corresponding async resources.
|
||||
*
|
||||
* Use this method when the `asyncLocalStorage` is not in use anymore
|
||||
* in the current process.
|
||||
* @since v13.10.0, v12.17.0
|
||||
* @experimental
|
||||
*/
|
||||
disable(): void;
|
||||
/**
|
||||
* Returns the current store.
|
||||
* If called outside of an asynchronous context initialized by
|
||||
* calling `asyncLocalStorage.run()` or `asyncLocalStorage.enterWith()`, it
|
||||
* returns `undefined`.
|
||||
* @since v13.10.0, v12.17.0
|
||||
*/
|
||||
getStore(): T | undefined;
|
||||
/**
|
||||
* The name of the `AsyncLocalStorage` instance if provided.
|
||||
* @since v24.0.0
|
||||
*/
|
||||
readonly name: string;
|
||||
/**
|
||||
* Runs a function synchronously within a context and returns its
|
||||
* return value. The store is not accessible outside of the callback function.
|
||||
* The store is accessible to any asynchronous operations created within the
|
||||
* callback.
|
||||
*
|
||||
* The optional `args` are passed to the callback function.
|
||||
*
|
||||
* If the callback function throws an error, the error is thrown by `run()` too.
|
||||
* The stacktrace is not impacted by this call and the context is exited.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```js
|
||||
* const store = { id: 2 };
|
||||
* try {
|
||||
* asyncLocalStorage.run(store, () => {
|
||||
* asyncLocalStorage.getStore(); // Returns the store object
|
||||
* setTimeout(() => {
|
||||
* asyncLocalStorage.getStore(); // Returns the store object
|
||||
* }, 200);
|
||||
* throw new Error();
|
||||
* });
|
||||
* } catch (e) {
|
||||
* asyncLocalStorage.getStore(); // Returns undefined
|
||||
* // The error will be caught here
|
||||
* }
|
||||
* ```
|
||||
* @since v13.10.0, v12.17.0
|
||||
*/
|
||||
run<R>(store: T, callback: () => R): R;
|
||||
run<R, TArgs extends any[]>(store: T, callback: (...args: TArgs) => R, ...args: TArgs): R;
|
||||
/**
|
||||
* Runs a function synchronously outside of a context and returns its
|
||||
* return value. The store is not accessible within the callback function or
|
||||
* the asynchronous operations created within the callback. Any `getStore()` call done within the callback function will always return `undefined`.
|
||||
*
|
||||
* The optional `args` are passed to the callback function.
|
||||
*
|
||||
* If the callback function throws an error, the error is thrown by `exit()` too.
|
||||
* The stacktrace is not impacted by this call and the context is re-entered.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```js
|
||||
* // Within a call to run
|
||||
* try {
|
||||
* asyncLocalStorage.getStore(); // Returns the store object or value
|
||||
* asyncLocalStorage.exit(() => {
|
||||
* asyncLocalStorage.getStore(); // Returns undefined
|
||||
* throw new Error();
|
||||
* });
|
||||
* } catch (e) {
|
||||
* asyncLocalStorage.getStore(); // Returns the same object or value
|
||||
* // The error will be caught here
|
||||
* }
|
||||
* ```
|
||||
* @since v13.10.0, v12.17.0
|
||||
* @experimental
|
||||
*/
|
||||
exit<R, TArgs extends any[]>(callback: (...args: TArgs) => R, ...args: TArgs): R;
|
||||
/**
|
||||
* Transitions into the context for the remainder of the current
|
||||
* synchronous execution and then persists the store through any following
|
||||
* asynchronous calls.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```js
|
||||
* const store = { id: 1 };
|
||||
* // Replaces previous store with the given store object
|
||||
* asyncLocalStorage.enterWith(store);
|
||||
* asyncLocalStorage.getStore(); // Returns the store object
|
||||
* someAsyncOperation(() => {
|
||||
* asyncLocalStorage.getStore(); // Returns the same object
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* This transition will continue for the _entire_ synchronous execution.
|
||||
* This means that if, for example, the context is entered within an event
|
||||
* handler subsequent event handlers will also run within that context unless
|
||||
* specifically bound to another context with an `AsyncResource`. That is why `run()` should be preferred over `enterWith()` unless there are strong reasons
|
||||
* to use the latter method.
|
||||
*
|
||||
* ```js
|
||||
* const store = { id: 1 };
|
||||
*
|
||||
* emitter.on('my-event', () => {
|
||||
* asyncLocalStorage.enterWith(store);
|
||||
* });
|
||||
* emitter.on('my-event', () => {
|
||||
* asyncLocalStorage.getStore(); // Returns the same object
|
||||
* });
|
||||
*
|
||||
* asyncLocalStorage.getStore(); // Returns undefined
|
||||
* emitter.emit('my-event');
|
||||
* asyncLocalStorage.getStore(); // Returns the same object
|
||||
* ```
|
||||
* @since v13.11.0, v12.17.0
|
||||
* @experimental
|
||||
*/
|
||||
enterWith(store: T): void;
|
||||
}
|
||||
/**
|
||||
* @since v17.2.0, v16.14.0
|
||||
* @return A map of provider types to the corresponding numeric id.
|
||||
* This map contains all the event types that might be emitted by the `async_hooks.init()` event.
|
||||
*/
|
||||
namespace asyncWrapProviders {
|
||||
const NONE: number;
|
||||
const DIRHANDLE: number;
|
||||
const DNSCHANNEL: number;
|
||||
const ELDHISTOGRAM: number;
|
||||
const FILEHANDLE: number;
|
||||
const FILEHANDLECLOSEREQ: number;
|
||||
const FIXEDSIZEBLOBCOPY: number;
|
||||
const FSEVENTWRAP: number;
|
||||
const FSREQCALLBACK: number;
|
||||
const FSREQPROMISE: number;
|
||||
const GETADDRINFOREQWRAP: number;
|
||||
const GETNAMEINFOREQWRAP: number;
|
||||
const HEAPSNAPSHOT: number;
|
||||
const HTTP2SESSION: number;
|
||||
const HTTP2STREAM: number;
|
||||
const HTTP2PING: number;
|
||||
const HTTP2SETTINGS: number;
|
||||
const HTTPINCOMINGMESSAGE: number;
|
||||
const HTTPCLIENTREQUEST: number;
|
||||
const JSSTREAM: number;
|
||||
const JSUDPWRAP: number;
|
||||
const MESSAGEPORT: number;
|
||||
const PIPECONNECTWRAP: number;
|
||||
const PIPESERVERWRAP: number;
|
||||
const PIPEWRAP: number;
|
||||
const PROCESSWRAP: number;
|
||||
const PROMISE: number;
|
||||
const QUERYWRAP: number;
|
||||
const SHUTDOWNWRAP: number;
|
||||
const SIGNALWRAP: number;
|
||||
const STATWATCHER: number;
|
||||
const STREAMPIPE: number;
|
||||
const TCPCONNECTWRAP: number;
|
||||
const TCPSERVERWRAP: number;
|
||||
const TCPWRAP: number;
|
||||
const TTYWRAP: number;
|
||||
const UDPSENDWRAP: number;
|
||||
const UDPWRAP: number;
|
||||
const SIGINTWATCHDOG: number;
|
||||
const WORKER: number;
|
||||
const WORKERHEAPSNAPSHOT: number;
|
||||
const WRITEWRAP: number;
|
||||
const ZLIB: number;
|
||||
const CHECKPRIMEREQUEST: number;
|
||||
const PBKDF2REQUEST: number;
|
||||
const KEYPAIRGENREQUEST: number;
|
||||
const KEYGENREQUEST: number;
|
||||
const KEYEXPORTREQUEST: number;
|
||||
const CIPHERREQUEST: number;
|
||||
const DERIVEBITSREQUEST: number;
|
||||
const HASHREQUEST: number;
|
||||
const RANDOMBYTESREQUEST: number;
|
||||
const RANDOMPRIMEREQUEST: number;
|
||||
const SCRYPTREQUEST: number;
|
||||
const SIGNREQUEST: number;
|
||||
const TLSWRAP: number;
|
||||
const VERIFYREQUEST: number;
|
||||
}
|
||||
}
|
||||
declare module "async_hooks" {
|
||||
export * from "node:async_hooks";
|
||||
}
|
||||
466
.cursor/scripts/db-exec/node_modules/@types/node/buffer.buffer.d.ts
generated
vendored
Normal file
466
.cursor/scripts/db-exec/node_modules/@types/node/buffer.buffer.d.ts
generated
vendored
Normal file
@@ -0,0 +1,466 @@
|
||||
declare module "node:buffer" {
|
||||
type ImplicitArrayBuffer<T extends WithImplicitCoercion<ArrayBufferLike>> = T extends
|
||||
{ valueOf(): infer V extends ArrayBufferLike } ? V : T;
|
||||
global {
|
||||
interface BufferConstructor {
|
||||
// see buffer.d.ts for implementation shared with all TypeScript versions
|
||||
|
||||
/**
|
||||
* Allocates a new buffer containing the given {str}.
|
||||
*
|
||||
* @param str String to store in buffer.
|
||||
* @param encoding encoding to use, optional. Default is 'utf8'
|
||||
* @deprecated since v10.0.0 - Use `Buffer.from(string[, encoding])` instead.
|
||||
*/
|
||||
new(str: string, encoding?: BufferEncoding): Buffer<ArrayBuffer>;
|
||||
/**
|
||||
* Allocates a new buffer of {size} octets.
|
||||
*
|
||||
* @param size count of octets to allocate.
|
||||
* @deprecated since v10.0.0 - Use `Buffer.alloc()` instead (also see `Buffer.allocUnsafe()`).
|
||||
*/
|
||||
new(size: number): Buffer<ArrayBuffer>;
|
||||
/**
|
||||
* Allocates a new buffer containing the given {array} of octets.
|
||||
*
|
||||
* @param array The octets to store.
|
||||
* @deprecated since v10.0.0 - Use `Buffer.from(array)` instead.
|
||||
*/
|
||||
new(array: ArrayLike<number>): Buffer<ArrayBuffer>;
|
||||
/**
|
||||
* Produces a Buffer backed by the same allocated memory as
|
||||
* the given {ArrayBuffer}/{SharedArrayBuffer}.
|
||||
*
|
||||
* @param arrayBuffer The ArrayBuffer with which to share memory.
|
||||
* @deprecated since v10.0.0 - Use `Buffer.from(arrayBuffer[, byteOffset[, length]])` instead.
|
||||
*/
|
||||
new<TArrayBuffer extends ArrayBufferLike = ArrayBuffer>(arrayBuffer: TArrayBuffer): Buffer<TArrayBuffer>;
|
||||
/**
|
||||
* Allocates a new `Buffer` using an `array` of bytes in the range `0` – `255`.
|
||||
* Array entries outside that range will be truncated to fit into it.
|
||||
*
|
||||
* ```js
|
||||
* import { Buffer } from 'node:buffer';
|
||||
*
|
||||
* // Creates a new Buffer containing the UTF-8 bytes of the string 'buffer'.
|
||||
* const buf = Buffer.from([0x62, 0x75, 0x66, 0x66, 0x65, 0x72]);
|
||||
* ```
|
||||
*
|
||||
* If `array` is an `Array`-like object (that is, one with a `length` property of
|
||||
* type `number`), it is treated as if it is an array, unless it is a `Buffer` or
|
||||
* a `Uint8Array`. This means all other `TypedArray` variants get treated as an
|
||||
* `Array`. To create a `Buffer` from the bytes backing a `TypedArray`, use
|
||||
* `Buffer.copyBytesFrom()`.
|
||||
*
|
||||
* A `TypeError` will be thrown if `array` is not an `Array` or another type
|
||||
* appropriate for `Buffer.from()` variants.
|
||||
*
|
||||
* `Buffer.from(array)` and `Buffer.from(string)` may also use the internal
|
||||
* `Buffer` pool like `Buffer.allocUnsafe()` does.
|
||||
* @since v5.10.0
|
||||
*/
|
||||
from(array: WithImplicitCoercion<ArrayLike<number>>): Buffer<ArrayBuffer>;
|
||||
/**
|
||||
* This creates a view of the `ArrayBuffer` without copying the underlying
|
||||
* memory. For example, when passed a reference to the `.buffer` property of a
|
||||
* `TypedArray` instance, the newly created `Buffer` will share the same
|
||||
* allocated memory as the `TypedArray`'s underlying `ArrayBuffer`.
|
||||
*
|
||||
* ```js
|
||||
* import { Buffer } from 'node:buffer';
|
||||
*
|
||||
* const arr = new Uint16Array(2);
|
||||
*
|
||||
* arr[0] = 5000;
|
||||
* arr[1] = 4000;
|
||||
*
|
||||
* // Shares memory with `arr`.
|
||||
* const buf = Buffer.from(arr.buffer);
|
||||
*
|
||||
* console.log(buf);
|
||||
* // Prints: <Buffer 88 13 a0 0f>
|
||||
*
|
||||
* // Changing the original Uint16Array changes the Buffer also.
|
||||
* arr[1] = 6000;
|
||||
*
|
||||
* console.log(buf);
|
||||
* // Prints: <Buffer 88 13 70 17>
|
||||
* ```
|
||||
*
|
||||
* The optional `byteOffset` and `length` arguments specify a memory range within
|
||||
* the `arrayBuffer` that will be shared by the `Buffer`.
|
||||
*
|
||||
* ```js
|
||||
* import { Buffer } from 'node:buffer';
|
||||
*
|
||||
* const ab = new ArrayBuffer(10);
|
||||
* const buf = Buffer.from(ab, 0, 2);
|
||||
*
|
||||
* console.log(buf.length);
|
||||
* // Prints: 2
|
||||
* ```
|
||||
*
|
||||
* A `TypeError` will be thrown if `arrayBuffer` is not an `ArrayBuffer` or a
|
||||
* `SharedArrayBuffer` or another type appropriate for `Buffer.from()`
|
||||
* variants.
|
||||
*
|
||||
* It is important to remember that a backing `ArrayBuffer` can cover a range
|
||||
* of memory that extends beyond the bounds of a `TypedArray` view. A new
|
||||
* `Buffer` created using the `buffer` property of a `TypedArray` may extend
|
||||
* beyond the range of the `TypedArray`:
|
||||
*
|
||||
* ```js
|
||||
* import { Buffer } from 'node:buffer';
|
||||
*
|
||||
* const arrA = Uint8Array.from([0x63, 0x64, 0x65, 0x66]); // 4 elements
|
||||
* const arrB = new Uint8Array(arrA.buffer, 1, 2); // 2 elements
|
||||
* console.log(arrA.buffer === arrB.buffer); // true
|
||||
*
|
||||
* const buf = Buffer.from(arrB.buffer);
|
||||
* console.log(buf);
|
||||
* // Prints: <Buffer 63 64 65 66>
|
||||
* ```
|
||||
* @since v5.10.0
|
||||
* @param arrayBuffer An `ArrayBuffer`, `SharedArrayBuffer`, for example the
|
||||
* `.buffer` property of a `TypedArray`.
|
||||
* @param byteOffset Index of first byte to expose. **Default:** `0`.
|
||||
* @param length Number of bytes to expose. **Default:**
|
||||
* `arrayBuffer.byteLength - byteOffset`.
|
||||
*/
|
||||
from<TArrayBuffer extends WithImplicitCoercion<ArrayBufferLike>>(
|
||||
arrayBuffer: TArrayBuffer,
|
||||
byteOffset?: number,
|
||||
length?: number,
|
||||
): Buffer<ImplicitArrayBuffer<TArrayBuffer>>;
|
||||
/**
|
||||
* Creates a new `Buffer` containing `string`. The `encoding` parameter identifies
|
||||
* the character encoding to be used when converting `string` into bytes.
|
||||
*
|
||||
* ```js
|
||||
* import { Buffer } from 'node:buffer';
|
||||
*
|
||||
* const buf1 = Buffer.from('this is a tést');
|
||||
* const buf2 = Buffer.from('7468697320697320612074c3a97374', 'hex');
|
||||
*
|
||||
* console.log(buf1.toString());
|
||||
* // Prints: this is a tést
|
||||
* console.log(buf2.toString());
|
||||
* // Prints: this is a tést
|
||||
* console.log(buf1.toString('latin1'));
|
||||
* // Prints: this is a tést
|
||||
* ```
|
||||
*
|
||||
* A `TypeError` will be thrown if `string` is not a string or another type
|
||||
* appropriate for `Buffer.from()` variants.
|
||||
*
|
||||
* `Buffer.from(string)` may also use the internal `Buffer` pool like
|
||||
* `Buffer.allocUnsafe()` does.
|
||||
* @since v5.10.0
|
||||
* @param string A string to encode.
|
||||
* @param encoding The encoding of `string`. **Default:** `'utf8'`.
|
||||
*/
|
||||
from(string: WithImplicitCoercion<string>, encoding?: BufferEncoding): Buffer<ArrayBuffer>;
|
||||
from(arrayOrString: WithImplicitCoercion<ArrayLike<number> | string>): Buffer<ArrayBuffer>;
|
||||
/**
|
||||
* Creates a new Buffer using the passed {data}
|
||||
* @param values to create a new Buffer
|
||||
*/
|
||||
of(...items: number[]): Buffer<ArrayBuffer>;
|
||||
/**
|
||||
* Returns a new `Buffer` which is the result of concatenating all the `Buffer` instances in the `list` together.
|
||||
*
|
||||
* If the list has no items, or if the `totalLength` is 0, then a new zero-length `Buffer` is returned.
|
||||
*
|
||||
* If `totalLength` is not provided, it is calculated from the `Buffer` instances
|
||||
* in `list` by adding their lengths.
|
||||
*
|
||||
* If `totalLength` is provided, it is coerced to an unsigned integer. If the
|
||||
* combined length of the `Buffer`s in `list` exceeds `totalLength`, the result is
|
||||
* truncated to `totalLength`. If the combined length of the `Buffer`s in `list` is
|
||||
* less than `totalLength`, the remaining space is filled with zeros.
|
||||
*
|
||||
* ```js
|
||||
* import { Buffer } from 'node:buffer';
|
||||
*
|
||||
* // Create a single `Buffer` from a list of three `Buffer` instances.
|
||||
*
|
||||
* const buf1 = Buffer.alloc(10);
|
||||
* const buf2 = Buffer.alloc(14);
|
||||
* const buf3 = Buffer.alloc(18);
|
||||
* const totalLength = buf1.length + buf2.length + buf3.length;
|
||||
*
|
||||
* console.log(totalLength);
|
||||
* // Prints: 42
|
||||
*
|
||||
* const bufA = Buffer.concat([buf1, buf2, buf3], totalLength);
|
||||
*
|
||||
* console.log(bufA);
|
||||
* // Prints: <Buffer 00 00 00 00 ...>
|
||||
* console.log(bufA.length);
|
||||
* // Prints: 42
|
||||
* ```
|
||||
*
|
||||
* `Buffer.concat()` may also use the internal `Buffer` pool like `Buffer.allocUnsafe()` does.
|
||||
* @since v0.7.11
|
||||
* @param list List of `Buffer` or {@link Uint8Array} instances to concatenate.
|
||||
* @param totalLength Total length of the `Buffer` instances in `list` when concatenated.
|
||||
*/
|
||||
concat(list: readonly Uint8Array[], totalLength?: number): Buffer<ArrayBuffer>;
|
||||
/**
|
||||
* Copies the underlying memory of `view` into a new `Buffer`.
|
||||
*
|
||||
* ```js
|
||||
* const u16 = new Uint16Array([0, 0xffff]);
|
||||
* const buf = Buffer.copyBytesFrom(u16, 1, 1);
|
||||
* u16[1] = 0;
|
||||
* console.log(buf.length); // 2
|
||||
* console.log(buf[0]); // 255
|
||||
* console.log(buf[1]); // 255
|
||||
* ```
|
||||
* @since v19.8.0
|
||||
* @param view The {TypedArray} to copy.
|
||||
* @param [offset=0] The starting offset within `view`.
|
||||
* @param [length=view.length - offset] The number of elements from `view` to copy.
|
||||
*/
|
||||
copyBytesFrom(view: NodeJS.TypedArray, offset?: number, length?: number): Buffer<ArrayBuffer>;
|
||||
/**
|
||||
* Allocates a new `Buffer` of `size` bytes. If `fill` is `undefined`, the`Buffer` will be zero-filled.
|
||||
*
|
||||
* ```js
|
||||
* import { Buffer } from 'node:buffer';
|
||||
*
|
||||
* const buf = Buffer.alloc(5);
|
||||
*
|
||||
* console.log(buf);
|
||||
* // Prints: <Buffer 00 00 00 00 00>
|
||||
* ```
|
||||
*
|
||||
* If `size` is larger than {@link constants.MAX_LENGTH} or smaller than 0, `ERR_OUT_OF_RANGE` is thrown.
|
||||
*
|
||||
* If `fill` is specified, the allocated `Buffer` will be initialized by calling `buf.fill(fill)`.
|
||||
*
|
||||
* ```js
|
||||
* import { Buffer } from 'node:buffer';
|
||||
*
|
||||
* const buf = Buffer.alloc(5, 'a');
|
||||
*
|
||||
* console.log(buf);
|
||||
* // Prints: <Buffer 61 61 61 61 61>
|
||||
* ```
|
||||
*
|
||||
* If both `fill` and `encoding` are specified, the allocated `Buffer` will be
|
||||
* initialized by calling `buf.fill(fill, encoding)`.
|
||||
*
|
||||
* ```js
|
||||
* import { Buffer } from 'node:buffer';
|
||||
*
|
||||
* const buf = Buffer.alloc(11, 'aGVsbG8gd29ybGQ=', 'base64');
|
||||
*
|
||||
* console.log(buf);
|
||||
* // Prints: <Buffer 68 65 6c 6c 6f 20 77 6f 72 6c 64>
|
||||
* ```
|
||||
*
|
||||
* Calling `Buffer.alloc()` can be measurably slower than the alternative `Buffer.allocUnsafe()` but ensures that the newly created `Buffer` instance
|
||||
* contents will never contain sensitive data from previous allocations, including
|
||||
* data that might not have been allocated for `Buffer`s.
|
||||
*
|
||||
* A `TypeError` will be thrown if `size` is not a number.
|
||||
* @since v5.10.0
|
||||
* @param size The desired length of the new `Buffer`.
|
||||
* @param [fill=0] A value to pre-fill the new `Buffer` with.
|
||||
* @param [encoding='utf8'] If `fill` is a string, this is its encoding.
|
||||
*/
|
||||
alloc(size: number, fill?: string | Uint8Array | number, encoding?: BufferEncoding): Buffer<ArrayBuffer>;
|
||||
/**
|
||||
* Allocates a new `Buffer` of `size` bytes. If `size` is larger than {@link constants.MAX_LENGTH} or smaller than 0, `ERR_OUT_OF_RANGE` is thrown.
|
||||
*
|
||||
* The underlying memory for `Buffer` instances created in this way is _not_
|
||||
* _initialized_. The contents of the newly created `Buffer` are unknown and _may contain sensitive data_. Use `Buffer.alloc()` instead to initialize`Buffer` instances with zeroes.
|
||||
*
|
||||
* ```js
|
||||
* import { Buffer } from 'node:buffer';
|
||||
*
|
||||
* const buf = Buffer.allocUnsafe(10);
|
||||
*
|
||||
* console.log(buf);
|
||||
* // Prints (contents may vary): <Buffer a0 8b 28 3f 01 00 00 00 50 32>
|
||||
*
|
||||
* buf.fill(0);
|
||||
*
|
||||
* console.log(buf);
|
||||
* // Prints: <Buffer 00 00 00 00 00 00 00 00 00 00>
|
||||
* ```
|
||||
*
|
||||
* A `TypeError` will be thrown if `size` is not a number.
|
||||
*
|
||||
* The `Buffer` module pre-allocates an internal `Buffer` instance of
|
||||
* size `Buffer.poolSize` that is used as a pool for the fast allocation of new `Buffer` instances created using `Buffer.allocUnsafe()`, `Buffer.from(array)`,
|
||||
* and `Buffer.concat()` only when `size` is less than `Buffer.poolSize >>> 1` (floor of `Buffer.poolSize` divided by two).
|
||||
*
|
||||
* Use of this pre-allocated internal memory pool is a key difference between
|
||||
* calling `Buffer.alloc(size, fill)` vs. `Buffer.allocUnsafe(size).fill(fill)`.
|
||||
* Specifically, `Buffer.alloc(size, fill)` will _never_ use the internal `Buffer`pool, while `Buffer.allocUnsafe(size).fill(fill)`_will_ use the internal`Buffer` pool if `size` is less
|
||||
* than or equal to half `Buffer.poolSize`. The
|
||||
* difference is subtle but can be important when an application requires the
|
||||
* additional performance that `Buffer.allocUnsafe()` provides.
|
||||
* @since v5.10.0
|
||||
* @param size The desired length of the new `Buffer`.
|
||||
*/
|
||||
allocUnsafe(size: number): Buffer<ArrayBuffer>;
|
||||
/**
|
||||
* Allocates a new `Buffer` of `size` bytes. If `size` is larger than {@link constants.MAX_LENGTH} or smaller than 0, `ERR_OUT_OF_RANGE` is thrown. A zero-length `Buffer` is created if
|
||||
* `size` is 0.
|
||||
*
|
||||
* The underlying memory for `Buffer` instances created in this way is _not_
|
||||
* _initialized_. The contents of the newly created `Buffer` are unknown and _may contain sensitive data_. Use `buf.fill(0)` to initialize
|
||||
* such `Buffer` instances with zeroes.
|
||||
*
|
||||
* When using `Buffer.allocUnsafe()` to allocate new `Buffer` instances,
|
||||
* allocations under 4 KiB are sliced from a single pre-allocated `Buffer`. This
|
||||
* allows applications to avoid the garbage collection overhead of creating many
|
||||
* individually allocated `Buffer` instances. This approach improves both
|
||||
* performance and memory usage by eliminating the need to track and clean up as
|
||||
* many individual `ArrayBuffer` objects.
|
||||
*
|
||||
* However, in the case where a developer may need to retain a small chunk of
|
||||
* memory from a pool for an indeterminate amount of time, it may be appropriate
|
||||
* to create an un-pooled `Buffer` instance using `Buffer.allocUnsafeSlow()` and
|
||||
* then copying out the relevant bits.
|
||||
*
|
||||
* ```js
|
||||
* import { Buffer } from 'node:buffer';
|
||||
*
|
||||
* // Need to keep around a few small chunks of memory.
|
||||
* const store = [];
|
||||
*
|
||||
* socket.on('readable', () => {
|
||||
* let data;
|
||||
* while (null !== (data = readable.read())) {
|
||||
* // Allocate for retained data.
|
||||
* const sb = Buffer.allocUnsafeSlow(10);
|
||||
*
|
||||
* // Copy the data into the new allocation.
|
||||
* data.copy(sb, 0, 0, 10);
|
||||
*
|
||||
* store.push(sb);
|
||||
* }
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* A `TypeError` will be thrown if `size` is not a number.
|
||||
* @since v5.12.0
|
||||
* @param size The desired length of the new `Buffer`.
|
||||
*/
|
||||
allocUnsafeSlow(size: number): Buffer<ArrayBuffer>;
|
||||
}
|
||||
interface Buffer<TArrayBuffer extends ArrayBufferLike = ArrayBufferLike> extends Uint8Array<TArrayBuffer> {
|
||||
// see buffer.d.ts for implementation shared with all TypeScript versions
|
||||
|
||||
/**
|
||||
* Returns a new `Buffer` that references the same memory as the original, but
|
||||
* offset and cropped by the `start` and `end` indices.
|
||||
*
|
||||
* This method is not compatible with the `Uint8Array.prototype.slice()`,
|
||||
* which is a superclass of `Buffer`. To copy the slice, use`Uint8Array.prototype.slice()`.
|
||||
*
|
||||
* ```js
|
||||
* import { Buffer } from 'node:buffer';
|
||||
*
|
||||
* const buf = Buffer.from('buffer');
|
||||
*
|
||||
* const copiedBuf = Uint8Array.prototype.slice.call(buf);
|
||||
* copiedBuf[0]++;
|
||||
* console.log(copiedBuf.toString());
|
||||
* // Prints: cuffer
|
||||
*
|
||||
* console.log(buf.toString());
|
||||
* // Prints: buffer
|
||||
*
|
||||
* // With buf.slice(), the original buffer is modified.
|
||||
* const notReallyCopiedBuf = buf.slice();
|
||||
* notReallyCopiedBuf[0]++;
|
||||
* console.log(notReallyCopiedBuf.toString());
|
||||
* // Prints: cuffer
|
||||
* console.log(buf.toString());
|
||||
* // Also prints: cuffer (!)
|
||||
* ```
|
||||
* @since v0.3.0
|
||||
* @deprecated Use `subarray` instead.
|
||||
* @param [start=0] Where the new `Buffer` will start.
|
||||
* @param [end=buf.length] Where the new `Buffer` will end (not inclusive).
|
||||
*/
|
||||
slice(start?: number, end?: number): Buffer<ArrayBuffer>;
|
||||
/**
|
||||
* Returns a new `Buffer` that references the same memory as the original, but
|
||||
* offset and cropped by the `start` and `end` indices.
|
||||
*
|
||||
* Specifying `end` greater than `buf.length` will return the same result as
|
||||
* that of `end` equal to `buf.length`.
|
||||
*
|
||||
* This method is inherited from [`TypedArray.prototype.subarray()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/subarray).
|
||||
*
|
||||
* Modifying the new `Buffer` slice will modify the memory in the original `Buffer`because the allocated memory of the two objects overlap.
|
||||
*
|
||||
* ```js
|
||||
* import { Buffer } from 'node:buffer';
|
||||
*
|
||||
* // Create a `Buffer` with the ASCII alphabet, take a slice, and modify one byte
|
||||
* // from the original `Buffer`.
|
||||
*
|
||||
* const buf1 = Buffer.allocUnsafe(26);
|
||||
*
|
||||
* for (let i = 0; i < 26; i++) {
|
||||
* // 97 is the decimal ASCII value for 'a'.
|
||||
* buf1[i] = i + 97;
|
||||
* }
|
||||
*
|
||||
* const buf2 = buf1.subarray(0, 3);
|
||||
*
|
||||
* console.log(buf2.toString('ascii', 0, buf2.length));
|
||||
* // Prints: abc
|
||||
*
|
||||
* buf1[0] = 33;
|
||||
*
|
||||
* console.log(buf2.toString('ascii', 0, buf2.length));
|
||||
* // Prints: !bc
|
||||
* ```
|
||||
*
|
||||
* Specifying negative indexes causes the slice to be generated relative to the
|
||||
* end of `buf` rather than the beginning.
|
||||
*
|
||||
* ```js
|
||||
* import { Buffer } from 'node:buffer';
|
||||
*
|
||||
* const buf = Buffer.from('buffer');
|
||||
*
|
||||
* console.log(buf.subarray(-6, -1).toString());
|
||||
* // Prints: buffe
|
||||
* // (Equivalent to buf.subarray(0, 5).)
|
||||
*
|
||||
* console.log(buf.subarray(-6, -2).toString());
|
||||
* // Prints: buff
|
||||
* // (Equivalent to buf.subarray(0, 4).)
|
||||
*
|
||||
* console.log(buf.subarray(-5, -2).toString());
|
||||
* // Prints: uff
|
||||
* // (Equivalent to buf.subarray(1, 4).)
|
||||
* ```
|
||||
* @since v3.0.0
|
||||
* @param [start=0] Where the new `Buffer` will start.
|
||||
* @param [end=buf.length] Where the new `Buffer` will end (not inclusive).
|
||||
*/
|
||||
subarray(start?: number, end?: number): Buffer<TArrayBuffer>;
|
||||
}
|
||||
// TODO: remove globals in future version
|
||||
/**
|
||||
* @deprecated This is intended for internal use, and will be removed once `@types/node` no longer supports
|
||||
* TypeScript versions earlier than 5.7.
|
||||
*/
|
||||
type NonSharedBuffer = Buffer<ArrayBuffer>;
|
||||
/**
|
||||
* @deprecated This is intended for internal use, and will be removed once `@types/node` no longer supports
|
||||
* TypeScript versions earlier than 5.7.
|
||||
*/
|
||||
type AllowSharedBuffer = Buffer<ArrayBufferLike>;
|
||||
}
|
||||
}
|
||||
1810
.cursor/scripts/db-exec/node_modules/@types/node/buffer.d.ts
generated
vendored
Normal file
1810
.cursor/scripts/db-exec/node_modules/@types/node/buffer.d.ts
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1428
.cursor/scripts/db-exec/node_modules/@types/node/child_process.d.ts
generated
vendored
Normal file
1428
.cursor/scripts/db-exec/node_modules/@types/node/child_process.d.ts
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
486
.cursor/scripts/db-exec/node_modules/@types/node/cluster.d.ts
generated
vendored
Normal file
486
.cursor/scripts/db-exec/node_modules/@types/node/cluster.d.ts
generated
vendored
Normal file
@@ -0,0 +1,486 @@
|
||||
/**
|
||||
* Clusters of Node.js processes can be used to run multiple instances of Node.js
|
||||
* that can distribute workloads among their application threads. When process isolation
|
||||
* is not needed, use the [`worker_threads`](https://nodejs.org/docs/latest-v25.x/api/worker_threads.html)
|
||||
* module instead, which allows running multiple application threads within a single Node.js instance.
|
||||
*
|
||||
* The cluster module allows easy creation of child processes that all share
|
||||
* server ports.
|
||||
*
|
||||
* ```js
|
||||
* import cluster from 'node:cluster';
|
||||
* import http from 'node:http';
|
||||
* import { availableParallelism } from 'node:os';
|
||||
* import process from 'node:process';
|
||||
*
|
||||
* const numCPUs = availableParallelism();
|
||||
*
|
||||
* if (cluster.isPrimary) {
|
||||
* console.log(`Primary ${process.pid} is running`);
|
||||
*
|
||||
* // Fork workers.
|
||||
* for (let i = 0; i < numCPUs; i++) {
|
||||
* cluster.fork();
|
||||
* }
|
||||
*
|
||||
* cluster.on('exit', (worker, code, signal) => {
|
||||
* console.log(`worker ${worker.process.pid} died`);
|
||||
* });
|
||||
* } else {
|
||||
* // Workers can share any TCP connection
|
||||
* // In this case it is an HTTP server
|
||||
* http.createServer((req, res) => {
|
||||
* res.writeHead(200);
|
||||
* res.end('hello world\n');
|
||||
* }).listen(8000);
|
||||
*
|
||||
* console.log(`Worker ${process.pid} started`);
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* Running Node.js will now share port 8000 between the workers:
|
||||
*
|
||||
* ```console
|
||||
* $ node server.js
|
||||
* Primary 3596 is running
|
||||
* Worker 4324 started
|
||||
* Worker 4520 started
|
||||
* Worker 6056 started
|
||||
* Worker 5644 started
|
||||
* ```
|
||||
*
|
||||
* On Windows, it is not yet possible to set up a named pipe server in a worker.
|
||||
* @see [source](https://github.com/nodejs/node/blob/v25.x/lib/cluster.js)
|
||||
*/
|
||||
declare module "node:cluster" {
|
||||
import * as child_process from "node:child_process";
|
||||
import { EventEmitter, InternalEventEmitter } from "node:events";
|
||||
class Worker implements EventEmitter {
|
||||
constructor(options?: cluster.WorkerOptions);
|
||||
/**
|
||||
* Each new worker is given its own unique id, this id is stored in the `id`.
|
||||
*
|
||||
* While a worker is alive, this is the key that indexes it in `cluster.workers`.
|
||||
* @since v0.8.0
|
||||
*/
|
||||
id: number;
|
||||
/**
|
||||
* All workers are created using [`child_process.fork()`](https://nodejs.org/docs/latest-v25.x/api/child_process.html#child_processforkmodulepath-args-options), the returned object
|
||||
* from this function is stored as `.process`. In a worker, the global `process` is stored.
|
||||
*
|
||||
* See: [Child Process module](https://nodejs.org/docs/latest-v25.x/api/child_process.html#child_processforkmodulepath-args-options).
|
||||
*
|
||||
* Workers will call `process.exit(0)` if the `'disconnect'` event occurs
|
||||
* on `process` and `.exitedAfterDisconnect` is not `true`. This protects against
|
||||
* accidental disconnection.
|
||||
* @since v0.7.0
|
||||
*/
|
||||
process: child_process.ChildProcess;
|
||||
/**
|
||||
* Send a message to a worker or primary, optionally with a handle.
|
||||
*
|
||||
* In the primary, this sends a message to a specific worker. It is identical to [`ChildProcess.send()`](https://nodejs.org/docs/latest-v25.x/api/child_process.html#subprocesssendmessage-sendhandle-options-callback).
|
||||
*
|
||||
* In a worker, this sends a message to the primary. It is identical to `process.send()`.
|
||||
*
|
||||
* This example will echo back all messages from the primary:
|
||||
*
|
||||
* ```js
|
||||
* if (cluster.isPrimary) {
|
||||
* const worker = cluster.fork();
|
||||
* worker.send('hi there');
|
||||
*
|
||||
* } else if (cluster.isWorker) {
|
||||
* process.on('message', (msg) => {
|
||||
* process.send(msg);
|
||||
* });
|
||||
* }
|
||||
* ```
|
||||
* @since v0.7.0
|
||||
* @param options The `options` argument, if present, is an object used to parameterize the sending of certain types of handles.
|
||||
*/
|
||||
send(message: child_process.Serializable, callback?: (error: Error | null) => void): boolean;
|
||||
send(
|
||||
message: child_process.Serializable,
|
||||
sendHandle: child_process.SendHandle,
|
||||
callback?: (error: Error | null) => void,
|
||||
): boolean;
|
||||
send(
|
||||
message: child_process.Serializable,
|
||||
sendHandle: child_process.SendHandle,
|
||||
options?: child_process.MessageOptions,
|
||||
callback?: (error: Error | null) => void,
|
||||
): boolean;
|
||||
/**
|
||||
* This function will kill the worker. In the primary worker, it does this by
|
||||
* disconnecting the `worker.process`, and once disconnected, killing with `signal`. In the worker, it does it by killing the process with `signal`.
|
||||
*
|
||||
* The `kill()` function kills the worker process without waiting for a graceful
|
||||
* disconnect, it has the same behavior as `worker.process.kill()`.
|
||||
*
|
||||
* This method is aliased as `worker.destroy()` for backwards compatibility.
|
||||
*
|
||||
* In a worker, `process.kill()` exists, but it is not this function;
|
||||
* it is [`kill()`](https://nodejs.org/docs/latest-v25.x/api/process.html#processkillpid-signal).
|
||||
* @since v0.9.12
|
||||
* @param [signal='SIGTERM'] Name of the kill signal to send to the worker process.
|
||||
*/
|
||||
kill(signal?: string): void;
|
||||
destroy(signal?: string): void;
|
||||
/**
|
||||
* In a worker, this function will close all servers, wait for the `'close'` event
|
||||
* on those servers, and then disconnect the IPC channel.
|
||||
*
|
||||
* In the primary, an internal message is sent to the worker causing it to call `.disconnect()` on itself.
|
||||
*
|
||||
* Causes `.exitedAfterDisconnect` to be set.
|
||||
*
|
||||
* After a server is closed, it will no longer accept new connections,
|
||||
* but connections may be accepted by any other listening worker. Existing
|
||||
* connections will be allowed to close as usual. When no more connections exist,
|
||||
* see `server.close()`, the IPC channel to the worker will close allowing it
|
||||
* to die gracefully.
|
||||
*
|
||||
* The above applies _only_ to server connections, client connections are not
|
||||
* automatically closed by workers, and disconnect does not wait for them to close
|
||||
* before exiting.
|
||||
*
|
||||
* In a worker, `process.disconnect` exists, but it is not this function;
|
||||
* it is `disconnect()`.
|
||||
*
|
||||
* Because long living server connections may block workers from disconnecting, it
|
||||
* may be useful to send a message, so application specific actions may be taken to
|
||||
* close them. It also may be useful to implement a timeout, killing a worker if
|
||||
* the `'disconnect'` event has not been emitted after some time.
|
||||
*
|
||||
* ```js
|
||||
* import net from 'node:net';
|
||||
*
|
||||
* if (cluster.isPrimary) {
|
||||
* const worker = cluster.fork();
|
||||
* let timeout;
|
||||
*
|
||||
* worker.on('listening', (address) => {
|
||||
* worker.send('shutdown');
|
||||
* worker.disconnect();
|
||||
* timeout = setTimeout(() => {
|
||||
* worker.kill();
|
||||
* }, 2000);
|
||||
* });
|
||||
*
|
||||
* worker.on('disconnect', () => {
|
||||
* clearTimeout(timeout);
|
||||
* });
|
||||
*
|
||||
* } else if (cluster.isWorker) {
|
||||
* const server = net.createServer((socket) => {
|
||||
* // Connections never end
|
||||
* });
|
||||
*
|
||||
* server.listen(8000);
|
||||
*
|
||||
* process.on('message', (msg) => {
|
||||
* if (msg === 'shutdown') {
|
||||
* // Initiate graceful close of any connections to server
|
||||
* }
|
||||
* });
|
||||
* }
|
||||
* ```
|
||||
* @since v0.7.7
|
||||
* @return A reference to `worker`.
|
||||
*/
|
||||
disconnect(): this;
|
||||
/**
|
||||
* This function returns `true` if the worker is connected to its primary via its
|
||||
* IPC channel, `false` otherwise. A worker is connected to its primary after it
|
||||
* has been created. It is disconnected after the `'disconnect'` event is emitted.
|
||||
* @since v0.11.14
|
||||
*/
|
||||
isConnected(): boolean;
|
||||
/**
|
||||
* This function returns `true` if the worker's process has terminated (either
|
||||
* because of exiting or being signaled). Otherwise, it returns `false`.
|
||||
*
|
||||
* ```js
|
||||
* import cluster from 'node:cluster';
|
||||
* import http from 'node:http';
|
||||
* import { availableParallelism } from 'node:os';
|
||||
* import process from 'node:process';
|
||||
*
|
||||
* const numCPUs = availableParallelism();
|
||||
*
|
||||
* if (cluster.isPrimary) {
|
||||
* console.log(`Primary ${process.pid} is running`);
|
||||
*
|
||||
* // Fork workers.
|
||||
* for (let i = 0; i < numCPUs; i++) {
|
||||
* cluster.fork();
|
||||
* }
|
||||
*
|
||||
* cluster.on('fork', (worker) => {
|
||||
* console.log('worker is dead:', worker.isDead());
|
||||
* });
|
||||
*
|
||||
* cluster.on('exit', (worker, code, signal) => {
|
||||
* console.log('worker is dead:', worker.isDead());
|
||||
* });
|
||||
* } else {
|
||||
* // Workers can share any TCP connection. In this case, it is an HTTP server.
|
||||
* http.createServer((req, res) => {
|
||||
* res.writeHead(200);
|
||||
* res.end(`Current process\n ${process.pid}`);
|
||||
* process.kill(process.pid);
|
||||
* }).listen(8000);
|
||||
* }
|
||||
* ```
|
||||
* @since v0.11.14
|
||||
*/
|
||||
isDead(): boolean;
|
||||
/**
|
||||
* This property is `true` if the worker exited due to `.disconnect()`.
|
||||
* If the worker exited any other way, it is `false`. If the
|
||||
* worker has not exited, it is `undefined`.
|
||||
*
|
||||
* The boolean `worker.exitedAfterDisconnect` allows distinguishing between
|
||||
* voluntary and accidental exit, the primary may choose not to respawn a worker
|
||||
* based on this value.
|
||||
*
|
||||
* ```js
|
||||
* cluster.on('exit', (worker, code, signal) => {
|
||||
* if (worker.exitedAfterDisconnect === true) {
|
||||
* console.log('Oh, it was just voluntary – no need to worry');
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* // kill worker
|
||||
* worker.kill();
|
||||
* ```
|
||||
* @since v6.0.0
|
||||
*/
|
||||
exitedAfterDisconnect: boolean;
|
||||
}
|
||||
interface Worker extends InternalEventEmitter<cluster.WorkerEventMap> {}
|
||||
type _Worker = Worker;
|
||||
namespace cluster {
|
||||
interface Worker extends _Worker {}
|
||||
interface WorkerOptions {
|
||||
id?: number | undefined;
|
||||
process?: child_process.ChildProcess | undefined;
|
||||
state?: string | undefined;
|
||||
}
|
||||
interface WorkerEventMap {
|
||||
"disconnect": [];
|
||||
"error": [error: Error];
|
||||
"exit": [code: number, signal: string];
|
||||
"listening": [address: Address];
|
||||
"message": [message: any, handle: child_process.SendHandle];
|
||||
"online": [];
|
||||
}
|
||||
interface ClusterSettings {
|
||||
/**
|
||||
* List of string arguments passed to the Node.js executable.
|
||||
* @default process.execArgv
|
||||
*/
|
||||
execArgv?: string[] | undefined;
|
||||
/**
|
||||
* File path to worker file.
|
||||
* @default process.argv[1]
|
||||
*/
|
||||
exec?: string | undefined;
|
||||
/**
|
||||
* String arguments passed to worker.
|
||||
* @default process.argv.slice(2)
|
||||
*/
|
||||
args?: readonly string[] | undefined;
|
||||
/**
|
||||
* Whether or not to send output to parent's stdio.
|
||||
* @default false
|
||||
*/
|
||||
silent?: boolean | undefined;
|
||||
/**
|
||||
* Configures the stdio of forked processes. Because the cluster module relies on IPC to function, this configuration must
|
||||
* contain an `'ipc'` entry. When this option is provided, it overrides `silent`. See [`child_prcess.spawn()`](https://nodejs.org/docs/latest-v25.x/api/child_process.html#child_processspawncommand-args-options)'s
|
||||
* [`stdio`](https://nodejs.org/docs/latest-v25.x/api/child_process.html#optionsstdio).
|
||||
*/
|
||||
stdio?: any[] | undefined;
|
||||
/**
|
||||
* Sets the user identity of the process. (See [`setuid(2)`](https://man7.org/linux/man-pages/man2/setuid.2.html).)
|
||||
*/
|
||||
uid?: number | undefined;
|
||||
/**
|
||||
* Sets the group identity of the process. (See [`setgid(2)`](https://man7.org/linux/man-pages/man2/setgid.2.html).)
|
||||
*/
|
||||
gid?: number | undefined;
|
||||
/**
|
||||
* Sets inspector port of worker. This can be a number, or a function that takes no arguments and returns a number.
|
||||
* By default each worker gets its own port, incremented from the primary's `process.debugPort`.
|
||||
*/
|
||||
inspectPort?: number | (() => number) | undefined;
|
||||
/**
|
||||
* Specify the kind of serialization used for sending messages between processes. Possible values are `'json'` and `'advanced'`.
|
||||
* See [Advanced serialization for `child_process`](https://nodejs.org/docs/latest-v25.x/api/child_process.html#advanced-serialization) for more details.
|
||||
* @default false
|
||||
*/
|
||||
serialization?: "json" | "advanced" | undefined;
|
||||
/**
|
||||
* Current working directory of the worker process.
|
||||
* @default undefined (inherits from parent process)
|
||||
*/
|
||||
cwd?: string | undefined;
|
||||
/**
|
||||
* Hide the forked processes console window that would normally be created on Windows systems.
|
||||
* @default false
|
||||
*/
|
||||
windowsHide?: boolean | undefined;
|
||||
}
|
||||
interface Address {
|
||||
address: string;
|
||||
port: number;
|
||||
/**
|
||||
* The `addressType` is one of:
|
||||
*
|
||||
* * `4` (TCPv4)
|
||||
* * `6` (TCPv6)
|
||||
* * `-1` (Unix domain socket)
|
||||
* * `'udp4'` or `'udp6'` (UDPv4 or UDPv6)
|
||||
*/
|
||||
addressType: 4 | 6 | -1 | "udp4" | "udp6";
|
||||
}
|
||||
interface ClusterEventMap {
|
||||
"disconnect": [worker: Worker];
|
||||
"exit": [worker: Worker, code: number, signal: string];
|
||||
"fork": [worker: Worker];
|
||||
"listening": [worker: Worker, address: Address];
|
||||
"message": [worker: Worker, message: any, handle: child_process.SendHandle];
|
||||
"online": [worker: Worker];
|
||||
"setup": [settings: ClusterSettings];
|
||||
}
|
||||
interface Cluster extends InternalEventEmitter<ClusterEventMap> {
|
||||
/**
|
||||
* A `Worker` object contains all public information and method about a worker.
|
||||
* In the primary it can be obtained using `cluster.workers`. In a worker
|
||||
* it can be obtained using `cluster.worker`.
|
||||
* @since v0.7.0
|
||||
*/
|
||||
Worker: typeof Worker;
|
||||
disconnect(callback?: () => void): void;
|
||||
/**
|
||||
* Spawn a new worker process.
|
||||
*
|
||||
* This can only be called from the primary process.
|
||||
* @param env Key/value pairs to add to worker process environment.
|
||||
* @since v0.6.0
|
||||
*/
|
||||
fork(env?: any): Worker;
|
||||
/** @deprecated since v16.0.0 - use isPrimary. */
|
||||
readonly isMaster: boolean;
|
||||
/**
|
||||
* True if the process is a primary. This is determined by the `process.env.NODE_UNIQUE_ID`. If `process.env.NODE_UNIQUE_ID`
|
||||
* is undefined, then `isPrimary` is `true`.
|
||||
* @since v16.0.0
|
||||
*/
|
||||
readonly isPrimary: boolean;
|
||||
/**
|
||||
* True if the process is not a primary (it is the negation of `cluster.isPrimary`).
|
||||
* @since v0.6.0
|
||||
*/
|
||||
readonly isWorker: boolean;
|
||||
/**
|
||||
* The scheduling policy, either `cluster.SCHED_RR` for round-robin or `cluster.SCHED_NONE` to leave it to the operating system. This is a
|
||||
* global setting and effectively frozen once either the first worker is spawned, or [`.setupPrimary()`](https://nodejs.org/docs/latest-v25.x/api/cluster.html#clustersetupprimarysettings)
|
||||
* is called, whichever comes first.
|
||||
*
|
||||
* `SCHED_RR` is the default on all operating systems except Windows. Windows will change to `SCHED_RR` once libuv is able to effectively distribute
|
||||
* IOCP handles without incurring a large performance hit.
|
||||
*
|
||||
* `cluster.schedulingPolicy` can also be set through the `NODE_CLUSTER_SCHED_POLICY` environment variable. Valid values are `'rr'` and `'none'`.
|
||||
* @since v0.11.2
|
||||
*/
|
||||
schedulingPolicy: number;
|
||||
/**
|
||||
* After calling [`.setupPrimary()`](https://nodejs.org/docs/latest-v25.x/api/cluster.html#clustersetupprimarysettings)
|
||||
* (or [`.fork()`](https://nodejs.org/docs/latest-v25.x/api/cluster.html#clusterforkenv)) this settings object will contain
|
||||
* the settings, including the default values.
|
||||
*
|
||||
* This object is not intended to be changed or set manually.
|
||||
* @since v0.7.1
|
||||
*/
|
||||
readonly settings: ClusterSettings;
|
||||
/** @deprecated since v16.0.0 - use [`.setupPrimary()`](https://nodejs.org/docs/latest-v25.x/api/cluster.html#clustersetupprimarysettings) instead. */
|
||||
setupMaster(settings?: ClusterSettings): void;
|
||||
/**
|
||||
* `setupPrimary` is used to change the default 'fork' behavior. Once called, the settings will be present in `cluster.settings`.
|
||||
*
|
||||
* Any settings changes only affect future calls to [`.fork()`](https://nodejs.org/docs/latest-v25.x/api/cluster.html#clusterforkenv)
|
||||
* and have no effect on workers that are already running.
|
||||
*
|
||||
* The only attribute of a worker that cannot be set via `.setupPrimary()` is the `env` passed to
|
||||
* [`.fork()`](https://nodejs.org/docs/latest-v25.x/api/cluster.html#clusterforkenv).
|
||||
*
|
||||
* The defaults above apply to the first call only; the defaults for later calls are the current values at the time of
|
||||
* `cluster.setupPrimary()` is called.
|
||||
*
|
||||
* ```js
|
||||
* import cluster from 'node:cluster';
|
||||
*
|
||||
* cluster.setupPrimary({
|
||||
* exec: 'worker.js',
|
||||
* args: ['--use', 'https'],
|
||||
* silent: true,
|
||||
* });
|
||||
* cluster.fork(); // https worker
|
||||
* cluster.setupPrimary({
|
||||
* exec: 'worker.js',
|
||||
* args: ['--use', 'http'],
|
||||
* });
|
||||
* cluster.fork(); // http worker
|
||||
* ```
|
||||
*
|
||||
* This can only be called from the primary process.
|
||||
* @since v16.0.0
|
||||
*/
|
||||
setupPrimary(settings?: ClusterSettings): void;
|
||||
/**
|
||||
* A reference to the current worker object. Not available in the primary process.
|
||||
*
|
||||
* ```js
|
||||
* import cluster from 'node:cluster';
|
||||
*
|
||||
* if (cluster.isPrimary) {
|
||||
* console.log('I am primary');
|
||||
* cluster.fork();
|
||||
* cluster.fork();
|
||||
* } else if (cluster.isWorker) {
|
||||
* console.log(`I am worker #${cluster.worker.id}`);
|
||||
* }
|
||||
* ```
|
||||
* @since v0.7.0
|
||||
*/
|
||||
readonly worker?: Worker;
|
||||
/**
|
||||
* A hash that stores the active worker objects, keyed by `id` field. This makes it easy to loop through all the workers. It is only available in the primary process.
|
||||
*
|
||||
* A worker is removed from `cluster.workers` after the worker has disconnected _and_ exited. The order between these two events cannot be determined in advance. However, it
|
||||
* is guaranteed that the removal from the `cluster.workers` list happens before the last `'disconnect'` or `'exit'` event is emitted.
|
||||
*
|
||||
* ```js
|
||||
* import cluster from 'node:cluster';
|
||||
*
|
||||
* for (const worker of Object.values(cluster.workers)) {
|
||||
* worker.send('big announcement to all workers');
|
||||
* }
|
||||
* ```
|
||||
* @since v0.7.0
|
||||
*/
|
||||
readonly workers?: NodeJS.Dict<Worker>;
|
||||
readonly SCHED_NONE: number;
|
||||
readonly SCHED_RR: number;
|
||||
}
|
||||
}
|
||||
var cluster: cluster.Cluster;
|
||||
export = cluster;
|
||||
}
|
||||
declare module "cluster" {
|
||||
import cluster = require("node:cluster");
|
||||
export = cluster;
|
||||
}
|
||||
21
.cursor/scripts/db-exec/node_modules/@types/node/compatibility/iterators.d.ts
generated
vendored
Normal file
21
.cursor/scripts/db-exec/node_modules/@types/node/compatibility/iterators.d.ts
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
// Backwards-compatible iterator interfaces, augmented with iterator helper methods by lib.esnext.iterator in TypeScript 5.6.
|
||||
// The IterableIterator interface does not contain these methods, which creates assignability issues in places where IteratorObjects
|
||||
// are expected (eg. DOM-compatible APIs) if lib.esnext.iterator is loaded.
|
||||
// Also ensures that iterators returned by the Node API, which inherit from Iterator.prototype, correctly expose the iterator helper methods
|
||||
// if lib.esnext.iterator is loaded.
|
||||
// TODO: remove once this package no longer supports TS 5.5, and replace NodeJS.BuiltinIteratorReturn with BuiltinIteratorReturn.
|
||||
|
||||
// Placeholders for TS <5.6
|
||||
interface IteratorObject<T, TReturn, TNext> {}
|
||||
interface AsyncIteratorObject<T, TReturn, TNext> {}
|
||||
|
||||
declare namespace NodeJS {
|
||||
// Populate iterator methods for TS <5.6
|
||||
interface Iterator<T, TReturn, TNext> extends globalThis.Iterator<T, TReturn, TNext> {}
|
||||
interface AsyncIterator<T, TReturn, TNext> extends globalThis.AsyncIterator<T, TReturn, TNext> {}
|
||||
|
||||
// Polyfill for TS 5.6's instrinsic BuiltinIteratorReturn type, required for DOM-compatible iterators
|
||||
type BuiltinIteratorReturn = ReturnType<any[][typeof Symbol.iterator]> extends
|
||||
globalThis.Iterator<any, infer TReturn> ? TReturn
|
||||
: any;
|
||||
}
|
||||
151
.cursor/scripts/db-exec/node_modules/@types/node/console.d.ts
generated
vendored
Normal file
151
.cursor/scripts/db-exec/node_modules/@types/node/console.d.ts
generated
vendored
Normal file
@@ -0,0 +1,151 @@
|
||||
/**
|
||||
* The `node:console` module provides a simple debugging console that is similar to
|
||||
* the JavaScript console mechanism provided by web browsers.
|
||||
*
|
||||
* The module exports two specific components:
|
||||
*
|
||||
* * A `Console` class with methods such as `console.log()`, `console.error()`, and `console.warn()` that can be used to write to any Node.js stream.
|
||||
* * A global `console` instance configured to write to [`process.stdout`](https://nodejs.org/docs/latest-v25.x/api/process.html#processstdout) and
|
||||
* [`process.stderr`](https://nodejs.org/docs/latest-v25.x/api/process.html#processstderr). The global `console` can be used without importing the `node:console` module.
|
||||
*
|
||||
* _**Warning**_: The global console object's methods are neither consistently
|
||||
* synchronous like the browser APIs they resemble, nor are they consistently
|
||||
* asynchronous like all other Node.js streams. See the [`note on process I/O`](https://nodejs.org/docs/latest-v25.x/api/process.html#a-note-on-process-io) for
|
||||
* more information.
|
||||
*
|
||||
* Example using the global `console`:
|
||||
*
|
||||
* ```js
|
||||
* console.log('hello world');
|
||||
* // Prints: hello world, to stdout
|
||||
* console.log('hello %s', 'world');
|
||||
* // Prints: hello world, to stdout
|
||||
* console.error(new Error('Whoops, something bad happened'));
|
||||
* // Prints error message and stack trace to stderr:
|
||||
* // Error: Whoops, something bad happened
|
||||
* // at [eval]:5:15
|
||||
* // at Script.runInThisContext (node:vm:132:18)
|
||||
* // at Object.runInThisContext (node:vm:309:38)
|
||||
* // at node:internal/process/execution:77:19
|
||||
* // at [eval]-wrapper:6:22
|
||||
* // at evalScript (node:internal/process/execution:76:60)
|
||||
* // at node:internal/main/eval_string:23:3
|
||||
*
|
||||
* const name = 'Will Robinson';
|
||||
* console.warn(`Danger ${name}! Danger!`);
|
||||
* // Prints: Danger Will Robinson! Danger!, to stderr
|
||||
* ```
|
||||
*
|
||||
* Example using the `Console` class:
|
||||
*
|
||||
* ```js
|
||||
* const out = getStreamSomehow();
|
||||
* const err = getStreamSomehow();
|
||||
* const myConsole = new console.Console(out, err);
|
||||
*
|
||||
* myConsole.log('hello world');
|
||||
* // Prints: hello world, to out
|
||||
* myConsole.log('hello %s', 'world');
|
||||
* // Prints: hello world, to out
|
||||
* myConsole.error(new Error('Whoops, something bad happened'));
|
||||
* // Prints: [Error: Whoops, something bad happened], to err
|
||||
*
|
||||
* const name = 'Will Robinson';
|
||||
* myConsole.warn(`Danger ${name}! Danger!`);
|
||||
* // Prints: Danger Will Robinson! Danger!, to err
|
||||
* ```
|
||||
* @see [source](https://github.com/nodejs/node/blob/v25.x/lib/console.js)
|
||||
*/
|
||||
declare module "node:console" {
|
||||
import { InspectOptions } from "node:util";
|
||||
namespace console {
|
||||
interface ConsoleOptions {
|
||||
stdout: NodeJS.WritableStream;
|
||||
stderr?: NodeJS.WritableStream | undefined;
|
||||
/**
|
||||
* Ignore errors when writing to the underlying streams.
|
||||
* @default true
|
||||
*/
|
||||
ignoreErrors?: boolean | undefined;
|
||||
/**
|
||||
* Set color support for this `Console` instance. Setting to true enables coloring while inspecting
|
||||
* values. Setting to `false` disables coloring while inspecting values. Setting to `'auto'` makes color
|
||||
* support depend on the value of the `isTTY` property and the value returned by `getColorDepth()` on the
|
||||
* respective stream. This option can not be used, if `inspectOptions.colors` is set as well.
|
||||
* @default 'auto'
|
||||
*/
|
||||
colorMode?: boolean | "auto" | undefined;
|
||||
/**
|
||||
* Specifies options that are passed along to
|
||||
* [`util.inspect()`](https://nodejs.org/docs/latest-v25.x/api/util.html#utilinspectobject-options).
|
||||
*/
|
||||
inspectOptions?: InspectOptions | ReadonlyMap<NodeJS.WritableStream, InspectOptions> | undefined;
|
||||
/**
|
||||
* Set group indentation.
|
||||
* @default 2
|
||||
*/
|
||||
groupIndentation?: number | undefined;
|
||||
}
|
||||
interface Console {
|
||||
readonly Console: {
|
||||
prototype: Console;
|
||||
new(stdout: NodeJS.WritableStream, stderr?: NodeJS.WritableStream, ignoreErrors?: boolean): Console;
|
||||
new(options: ConsoleOptions): Console;
|
||||
};
|
||||
assert(condition?: unknown, ...data: any[]): void;
|
||||
clear(): void;
|
||||
count(label?: string): void;
|
||||
countReset(label?: string): void;
|
||||
debug(...data: any[]): void;
|
||||
dir(item?: any, options?: InspectOptions): void;
|
||||
dirxml(...data: any[]): void;
|
||||
error(...data: any[]): void;
|
||||
group(...data: any[]): void;
|
||||
groupCollapsed(...data: any[]): void;
|
||||
groupEnd(): void;
|
||||
info(...data: any[]): void;
|
||||
log(...data: any[]): void;
|
||||
table(tabularData?: any, properties?: string[]): void;
|
||||
time(label?: string): void;
|
||||
timeEnd(label?: string): void;
|
||||
timeLog(label?: string, ...data: any[]): void;
|
||||
trace(...data: any[]): void;
|
||||
warn(...data: any[]): void;
|
||||
/**
|
||||
* This method does not display anything unless used in the inspector. The `console.profile()`
|
||||
* method starts a JavaScript CPU profile with an optional label until {@link profileEnd}
|
||||
* is called. The profile is then added to the Profile panel of the inspector.
|
||||
*
|
||||
* ```js
|
||||
* console.profile('MyLabel');
|
||||
* // Some code
|
||||
* console.profileEnd('MyLabel');
|
||||
* // Adds the profile 'MyLabel' to the Profiles panel of the inspector.
|
||||
* ```
|
||||
* @since v8.0.0
|
||||
*/
|
||||
profile(label?: string): void;
|
||||
/**
|
||||
* This method does not display anything unless used in the inspector. Stops the current
|
||||
* JavaScript CPU profiling session if one has been started and prints the report to the
|
||||
* Profiles panel of the inspector. See {@link profile} for an example.
|
||||
*
|
||||
* If this method is called without a label, the most recently started profile is stopped.
|
||||
* @since v8.0.0
|
||||
*/
|
||||
profileEnd(label?: string): void;
|
||||
/**
|
||||
* This method does not display anything unless used in the inspector. The `console.timeStamp()`
|
||||
* method adds an event with the label `'label'` to the Timeline panel of the inspector.
|
||||
* @since v8.0.0
|
||||
*/
|
||||
timeStamp(label?: string): void;
|
||||
}
|
||||
}
|
||||
var console: console.Console;
|
||||
export = console;
|
||||
}
|
||||
declare module "console" {
|
||||
import console = require("node:console");
|
||||
export = console;
|
||||
}
|
||||
20
.cursor/scripts/db-exec/node_modules/@types/node/constants.d.ts
generated
vendored
Normal file
20
.cursor/scripts/db-exec/node_modules/@types/node/constants.d.ts
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* @deprecated The `node:constants` module is deprecated. When requiring access to constants
|
||||
* relevant to specific Node.js builtin modules, developers should instead refer
|
||||
* to the `constants` property exposed by the relevant module. For instance,
|
||||
* `require('node:fs').constants` and `require('node:os').constants`.
|
||||
*/
|
||||
declare module "node:constants" {
|
||||
const constants:
|
||||
& typeof import("node:os").constants.dlopen
|
||||
& typeof import("node:os").constants.errno
|
||||
& typeof import("node:os").constants.priority
|
||||
& typeof import("node:os").constants.signals
|
||||
& typeof import("node:fs").constants
|
||||
& typeof import("node:crypto").constants;
|
||||
export = constants;
|
||||
}
|
||||
declare module "constants" {
|
||||
import constants = require("node:constants");
|
||||
export = constants;
|
||||
}
|
||||
4065
.cursor/scripts/db-exec/node_modules/@types/node/crypto.d.ts
generated
vendored
Normal file
4065
.cursor/scripts/db-exec/node_modules/@types/node/crypto.d.ts
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
564
.cursor/scripts/db-exec/node_modules/@types/node/dgram.d.ts
generated
vendored
Normal file
564
.cursor/scripts/db-exec/node_modules/@types/node/dgram.d.ts
generated
vendored
Normal file
@@ -0,0 +1,564 @@
|
||||
/**
|
||||
* The `node:dgram` module provides an implementation of UDP datagram sockets.
|
||||
*
|
||||
* ```js
|
||||
* import dgram from 'node:dgram';
|
||||
*
|
||||
* const server = dgram.createSocket('udp4');
|
||||
*
|
||||
* server.on('error', (err) => {
|
||||
* console.error(`server error:\n${err.stack}`);
|
||||
* server.close();
|
||||
* });
|
||||
*
|
||||
* server.on('message', (msg, rinfo) => {
|
||||
* console.log(`server got: ${msg} from ${rinfo.address}:${rinfo.port}`);
|
||||
* });
|
||||
*
|
||||
* server.on('listening', () => {
|
||||
* const address = server.address();
|
||||
* console.log(`server listening ${address.address}:${address.port}`);
|
||||
* });
|
||||
*
|
||||
* server.bind(41234);
|
||||
* // Prints: server listening 0.0.0.0:41234
|
||||
* ```
|
||||
* @see [source](https://github.com/nodejs/node/blob/v25.x/lib/dgram.js)
|
||||
*/
|
||||
declare module "node:dgram" {
|
||||
import { NonSharedBuffer } from "node:buffer";
|
||||
import * as dns from "node:dns";
|
||||
import { Abortable, EventEmitter, InternalEventEmitter } from "node:events";
|
||||
import { AddressInfo, BlockList } from "node:net";
|
||||
interface RemoteInfo {
|
||||
address: string;
|
||||
family: "IPv4" | "IPv6";
|
||||
port: number;
|
||||
size: number;
|
||||
}
|
||||
interface BindOptions {
|
||||
port?: number | undefined;
|
||||
address?: string | undefined;
|
||||
exclusive?: boolean | undefined;
|
||||
fd?: number | undefined;
|
||||
}
|
||||
type SocketType = "udp4" | "udp6";
|
||||
interface SocketOptions extends Abortable {
|
||||
type: SocketType;
|
||||
reuseAddr?: boolean | undefined;
|
||||
reusePort?: boolean | undefined;
|
||||
/**
|
||||
* @default false
|
||||
*/
|
||||
ipv6Only?: boolean | undefined;
|
||||
recvBufferSize?: number | undefined;
|
||||
sendBufferSize?: number | undefined;
|
||||
lookup?:
|
||||
| ((
|
||||
hostname: string,
|
||||
options: dns.LookupOneOptions,
|
||||
callback: (err: NodeJS.ErrnoException | null, address: string, family: number) => void,
|
||||
) => void)
|
||||
| undefined;
|
||||
receiveBlockList?: BlockList | undefined;
|
||||
sendBlockList?: BlockList | undefined;
|
||||
}
|
||||
/**
|
||||
* Creates a `dgram.Socket` object. Once the socket is created, calling `socket.bind()` will instruct the socket to begin listening for datagram
|
||||
* messages. When `address` and `port` are not passed to `socket.bind()` the
|
||||
* method will bind the socket to the "all interfaces" address on a random port
|
||||
* (it does the right thing for both `udp4` and `udp6` sockets). The bound address
|
||||
* and port can be retrieved using `socket.address().address` and `socket.address().port`.
|
||||
*
|
||||
* If the `signal` option is enabled, calling `.abort()` on the corresponding `AbortController` is similar to calling `.close()` on the socket:
|
||||
*
|
||||
* ```js
|
||||
* const controller = new AbortController();
|
||||
* const { signal } = controller;
|
||||
* const server = dgram.createSocket({ type: 'udp4', signal });
|
||||
* server.on('message', (msg, rinfo) => {
|
||||
* console.log(`server got: ${msg} from ${rinfo.address}:${rinfo.port}`);
|
||||
* });
|
||||
* // Later, when you want to close the server.
|
||||
* controller.abort();
|
||||
* ```
|
||||
* @since v0.11.13
|
||||
* @param options Available options are:
|
||||
* @param callback Attached as a listener for `'message'` events. Optional.
|
||||
*/
|
||||
function createSocket(type: SocketType, callback?: (msg: NonSharedBuffer, rinfo: RemoteInfo) => void): Socket;
|
||||
function createSocket(options: SocketOptions, callback?: (msg: NonSharedBuffer, rinfo: RemoteInfo) => void): Socket;
|
||||
interface SocketEventMap {
|
||||
"close": [];
|
||||
"connect": [];
|
||||
"error": [err: Error];
|
||||
"listening": [];
|
||||
"message": [msg: NonSharedBuffer, rinfo: RemoteInfo];
|
||||
}
|
||||
/**
|
||||
* Encapsulates the datagram functionality.
|
||||
*
|
||||
* New instances of `dgram.Socket` are created using {@link createSocket}.
|
||||
* The `new` keyword is not to be used to create `dgram.Socket` instances.
|
||||
* @since v0.1.99
|
||||
*/
|
||||
class Socket implements EventEmitter {
|
||||
/**
|
||||
* Tells the kernel to join a multicast group at the given `multicastAddress` and `multicastInterface` using the `IP_ADD_MEMBERSHIP` socket option. If the `multicastInterface` argument is not
|
||||
* specified, the operating system will choose
|
||||
* one interface and will add membership to it. To add membership to every
|
||||
* available interface, call `addMembership` multiple times, once per interface.
|
||||
*
|
||||
* When called on an unbound socket, this method will implicitly bind to a random
|
||||
* port, listening on all interfaces.
|
||||
*
|
||||
* When sharing a UDP socket across multiple `cluster` workers, the`socket.addMembership()` function must be called only once or an`EADDRINUSE` error will occur:
|
||||
*
|
||||
* ```js
|
||||
* import cluster from 'node:cluster';
|
||||
* import dgram from 'node:dgram';
|
||||
*
|
||||
* if (cluster.isPrimary) {
|
||||
* cluster.fork(); // Works ok.
|
||||
* cluster.fork(); // Fails with EADDRINUSE.
|
||||
* } else {
|
||||
* const s = dgram.createSocket('udp4');
|
||||
* s.bind(1234, () => {
|
||||
* s.addMembership('224.0.0.114');
|
||||
* });
|
||||
* }
|
||||
* ```
|
||||
* @since v0.6.9
|
||||
*/
|
||||
addMembership(multicastAddress: string, multicastInterface?: string): void;
|
||||
/**
|
||||
* Returns an object containing the address information for a socket.
|
||||
* For UDP sockets, this object will contain `address`, `family`, and `port` properties.
|
||||
*
|
||||
* This method throws `EBADF` if called on an unbound socket.
|
||||
* @since v0.1.99
|
||||
*/
|
||||
address(): AddressInfo;
|
||||
/**
|
||||
* For UDP sockets, causes the `dgram.Socket` to listen for datagram
|
||||
* messages on a named `port` and optional `address`. If `port` is not
|
||||
* specified or is `0`, the operating system will attempt to bind to a
|
||||
* random port. If `address` is not specified, the operating system will
|
||||
* attempt to listen on all addresses. Once binding is complete, a `'listening'` event is emitted and the optional `callback` function is
|
||||
* called.
|
||||
*
|
||||
* Specifying both a `'listening'` event listener and passing a `callback` to the `socket.bind()` method is not harmful but not very
|
||||
* useful.
|
||||
*
|
||||
* A bound datagram socket keeps the Node.js process running to receive
|
||||
* datagram messages.
|
||||
*
|
||||
* If binding fails, an `'error'` event is generated. In rare case (e.g.
|
||||
* attempting to bind with a closed socket), an `Error` may be thrown.
|
||||
*
|
||||
* Example of a UDP server listening on port 41234:
|
||||
*
|
||||
* ```js
|
||||
* import dgram from 'node:dgram';
|
||||
*
|
||||
* const server = dgram.createSocket('udp4');
|
||||
*
|
||||
* server.on('error', (err) => {
|
||||
* console.error(`server error:\n${err.stack}`);
|
||||
* server.close();
|
||||
* });
|
||||
*
|
||||
* server.on('message', (msg, rinfo) => {
|
||||
* console.log(`server got: ${msg} from ${rinfo.address}:${rinfo.port}`);
|
||||
* });
|
||||
*
|
||||
* server.on('listening', () => {
|
||||
* const address = server.address();
|
||||
* console.log(`server listening ${address.address}:${address.port}`);
|
||||
* });
|
||||
*
|
||||
* server.bind(41234);
|
||||
* // Prints: server listening 0.0.0.0:41234
|
||||
* ```
|
||||
* @since v0.1.99
|
||||
* @param callback with no parameters. Called when binding is complete.
|
||||
*/
|
||||
bind(port?: number, address?: string, callback?: () => void): this;
|
||||
bind(port?: number, callback?: () => void): this;
|
||||
bind(callback?: () => void): this;
|
||||
bind(options: BindOptions, callback?: () => void): this;
|
||||
/**
|
||||
* Close the underlying socket and stop listening for data on it. If a callback is
|
||||
* provided, it is added as a listener for the `'close'` event.
|
||||
* @since v0.1.99
|
||||
* @param callback Called when the socket has been closed.
|
||||
*/
|
||||
close(callback?: () => void): this;
|
||||
/**
|
||||
* Associates the `dgram.Socket` to a remote address and port. Every
|
||||
* message sent by this handle is automatically sent to that destination. Also,
|
||||
* the socket will only receive messages from that remote peer.
|
||||
* Trying to call `connect()` on an already connected socket will result
|
||||
* in an `ERR_SOCKET_DGRAM_IS_CONNECTED` exception. If `address` is not
|
||||
* provided, `'127.0.0.1'` (for `udp4` sockets) or `'::1'` (for `udp6` sockets)
|
||||
* will be used by default. Once the connection is complete, a `'connect'` event
|
||||
* is emitted and the optional `callback` function is called. In case of failure,
|
||||
* the `callback` is called or, failing this, an `'error'` event is emitted.
|
||||
* @since v12.0.0
|
||||
* @param callback Called when the connection is completed or on error.
|
||||
*/
|
||||
connect(port: number, address?: string, callback?: () => void): void;
|
||||
connect(port: number, callback: () => void): void;
|
||||
/**
|
||||
* A synchronous function that disassociates a connected `dgram.Socket` from
|
||||
* its remote address. Trying to call `disconnect()` on an unbound or already
|
||||
* disconnected socket will result in an `ERR_SOCKET_DGRAM_NOT_CONNECTED` exception.
|
||||
* @since v12.0.0
|
||||
*/
|
||||
disconnect(): void;
|
||||
/**
|
||||
* Instructs the kernel to leave a multicast group at `multicastAddress` using the `IP_DROP_MEMBERSHIP` socket option. This method is automatically called by the
|
||||
* kernel when the socket is closed or the process terminates, so most apps will
|
||||
* never have reason to call this.
|
||||
*
|
||||
* If `multicastInterface` is not specified, the operating system will attempt to
|
||||
* drop membership on all valid interfaces.
|
||||
* @since v0.6.9
|
||||
*/
|
||||
dropMembership(multicastAddress: string, multicastInterface?: string): void;
|
||||
/**
|
||||
* This method throws `ERR_SOCKET_BUFFER_SIZE` if called on an unbound socket.
|
||||
* @since v8.7.0
|
||||
* @return the `SO_RCVBUF` socket receive buffer size in bytes.
|
||||
*/
|
||||
getRecvBufferSize(): number;
|
||||
/**
|
||||
* This method throws `ERR_SOCKET_BUFFER_SIZE` if called on an unbound socket.
|
||||
* @since v8.7.0
|
||||
* @return the `SO_SNDBUF` socket send buffer size in bytes.
|
||||
*/
|
||||
getSendBufferSize(): number;
|
||||
/**
|
||||
* @since v18.8.0, v16.19.0
|
||||
* @return Number of bytes queued for sending.
|
||||
*/
|
||||
getSendQueueSize(): number;
|
||||
/**
|
||||
* @since v18.8.0, v16.19.0
|
||||
* @return Number of send requests currently in the queue awaiting to be processed.
|
||||
*/
|
||||
getSendQueueCount(): number;
|
||||
/**
|
||||
* By default, binding a socket will cause it to block the Node.js process from
|
||||
* exiting as long as the socket is open. The `socket.unref()` method can be used
|
||||
* to exclude the socket from the reference counting that keeps the Node.js
|
||||
* process active. The `socket.ref()` method adds the socket back to the reference
|
||||
* counting and restores the default behavior.
|
||||
*
|
||||
* Calling `socket.ref()` multiples times will have no additional effect.
|
||||
*
|
||||
* The `socket.ref()` method returns a reference to the socket so calls can be
|
||||
* chained.
|
||||
* @since v0.9.1
|
||||
*/
|
||||
ref(): this;
|
||||
/**
|
||||
* Returns an object containing the `address`, `family`, and `port` of the remote
|
||||
* endpoint. This method throws an `ERR_SOCKET_DGRAM_NOT_CONNECTED` exception
|
||||
* if the socket is not connected.
|
||||
* @since v12.0.0
|
||||
*/
|
||||
remoteAddress(): AddressInfo;
|
||||
/**
|
||||
* Broadcasts a datagram on the socket.
|
||||
* For connectionless sockets, the destination `port` and `address` must be
|
||||
* specified. Connected sockets, on the other hand, will use their associated
|
||||
* remote endpoint, so the `port` and `address` arguments must not be set.
|
||||
*
|
||||
* The `msg` argument contains the message to be sent.
|
||||
* Depending on its type, different behavior can apply. If `msg` is a `Buffer`,
|
||||
* any `TypedArray` or a `DataView`,
|
||||
* the `offset` and `length` specify the offset within the `Buffer` where the
|
||||
* message begins and the number of bytes in the message, respectively.
|
||||
* If `msg` is a `String`, then it is automatically converted to a `Buffer` with `'utf8'` encoding. With messages that
|
||||
* contain multi-byte characters, `offset` and `length` will be calculated with
|
||||
* respect to `byte length` and not the character position.
|
||||
* If `msg` is an array, `offset` and `length` must not be specified.
|
||||
*
|
||||
* The `address` argument is a string. If the value of `address` is a host name,
|
||||
* DNS will be used to resolve the address of the host. If `address` is not
|
||||
* provided or otherwise nullish, `'127.0.0.1'` (for `udp4` sockets) or `'::1'` (for `udp6` sockets) will be used by default.
|
||||
*
|
||||
* If the socket has not been previously bound with a call to `bind`, the socket
|
||||
* is assigned a random port number and is bound to the "all interfaces" address
|
||||
* (`'0.0.0.0'` for `udp4` sockets, `'::0'` for `udp6` sockets.)
|
||||
*
|
||||
* An optional `callback` function may be specified to as a way of reporting
|
||||
* DNS errors or for determining when it is safe to reuse the `buf` object.
|
||||
* DNS lookups delay the time to send for at least one tick of the
|
||||
* Node.js event loop.
|
||||
*
|
||||
* The only way to know for sure that the datagram has been sent is by using a `callback`. If an error occurs and a `callback` is given, the error will be
|
||||
* passed as the first argument to the `callback`. If a `callback` is not given,
|
||||
* the error is emitted as an `'error'` event on the `socket` object.
|
||||
*
|
||||
* Offset and length are optional but both _must_ be set if either are used.
|
||||
* They are supported only when the first argument is a `Buffer`, a `TypedArray`,
|
||||
* or a `DataView`.
|
||||
*
|
||||
* This method throws `ERR_SOCKET_BAD_PORT` if called on an unbound socket.
|
||||
*
|
||||
* Example of sending a UDP packet to a port on `localhost`;
|
||||
*
|
||||
* ```js
|
||||
* import dgram from 'node:dgram';
|
||||
* import { Buffer } from 'node:buffer';
|
||||
*
|
||||
* const message = Buffer.from('Some bytes');
|
||||
* const client = dgram.createSocket('udp4');
|
||||
* client.send(message, 41234, 'localhost', (err) => {
|
||||
* client.close();
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* Example of sending a UDP packet composed of multiple buffers to a port on`127.0.0.1`;
|
||||
*
|
||||
* ```js
|
||||
* import dgram from 'node:dgram';
|
||||
* import { Buffer } from 'node:buffer';
|
||||
*
|
||||
* const buf1 = Buffer.from('Some ');
|
||||
* const buf2 = Buffer.from('bytes');
|
||||
* const client = dgram.createSocket('udp4');
|
||||
* client.send([buf1, buf2], 41234, (err) => {
|
||||
* client.close();
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* Sending multiple buffers might be faster or slower depending on the
|
||||
* application and operating system. Run benchmarks to
|
||||
* determine the optimal strategy on a case-by-case basis. Generally speaking,
|
||||
* however, sending multiple buffers is faster.
|
||||
*
|
||||
* Example of sending a UDP packet using a socket connected to a port on `localhost`:
|
||||
*
|
||||
* ```js
|
||||
* import dgram from 'node:dgram';
|
||||
* import { Buffer } from 'node:buffer';
|
||||
*
|
||||
* const message = Buffer.from('Some bytes');
|
||||
* const client = dgram.createSocket('udp4');
|
||||
* client.connect(41234, 'localhost', (err) => {
|
||||
* client.send(message, (err) => {
|
||||
* client.close();
|
||||
* });
|
||||
* });
|
||||
* ```
|
||||
* @since v0.1.99
|
||||
* @param msg Message to be sent.
|
||||
* @param offset Offset in the buffer where the message starts.
|
||||
* @param length Number of bytes in the message.
|
||||
* @param port Destination port.
|
||||
* @param address Destination host name or IP address.
|
||||
* @param callback Called when the message has been sent.
|
||||
*/
|
||||
send(
|
||||
msg: string | NodeJS.ArrayBufferView | readonly any[],
|
||||
port?: number,
|
||||
address?: string,
|
||||
callback?: (error: Error | null, bytes: number) => void,
|
||||
): void;
|
||||
send(
|
||||
msg: string | NodeJS.ArrayBufferView | readonly any[],
|
||||
port?: number,
|
||||
callback?: (error: Error | null, bytes: number) => void,
|
||||
): void;
|
||||
send(
|
||||
msg: string | NodeJS.ArrayBufferView | readonly any[],
|
||||
callback?: (error: Error | null, bytes: number) => void,
|
||||
): void;
|
||||
send(
|
||||
msg: string | NodeJS.ArrayBufferView,
|
||||
offset: number,
|
||||
length: number,
|
||||
port?: number,
|
||||
address?: string,
|
||||
callback?: (error: Error | null, bytes: number) => void,
|
||||
): void;
|
||||
send(
|
||||
msg: string | NodeJS.ArrayBufferView,
|
||||
offset: number,
|
||||
length: number,
|
||||
port?: number,
|
||||
callback?: (error: Error | null, bytes: number) => void,
|
||||
): void;
|
||||
send(
|
||||
msg: string | NodeJS.ArrayBufferView,
|
||||
offset: number,
|
||||
length: number,
|
||||
callback?: (error: Error | null, bytes: number) => void,
|
||||
): void;
|
||||
/**
|
||||
* Sets or clears the `SO_BROADCAST` socket option. When set to `true`, UDP
|
||||
* packets may be sent to a local interface's broadcast address.
|
||||
*
|
||||
* This method throws `EBADF` if called on an unbound socket.
|
||||
* @since v0.6.9
|
||||
*/
|
||||
setBroadcast(flag: boolean): void;
|
||||
/**
|
||||
* _All references to scope in this section are referring to [IPv6 Zone Indices](https://en.wikipedia.org/wiki/IPv6_address#Scoped_literal_IPv6_addresses), which are defined by [RFC
|
||||
* 4007](https://tools.ietf.org/html/rfc4007). In string form, an IP_
|
||||
* _with a scope index is written as `'IP%scope'` where scope is an interface name_
|
||||
* _or interface number._
|
||||
*
|
||||
* Sets the default outgoing multicast interface of the socket to a chosen
|
||||
* interface or back to system interface selection. The `multicastInterface` must
|
||||
* be a valid string representation of an IP from the socket's family.
|
||||
*
|
||||
* For IPv4 sockets, this should be the IP configured for the desired physical
|
||||
* interface. All packets sent to multicast on the socket will be sent on the
|
||||
* interface determined by the most recent successful use of this call.
|
||||
*
|
||||
* For IPv6 sockets, `multicastInterface` should include a scope to indicate the
|
||||
* interface as in the examples that follow. In IPv6, individual `send` calls can
|
||||
* also use explicit scope in addresses, so only packets sent to a multicast
|
||||
* address without specifying an explicit scope are affected by the most recent
|
||||
* successful use of this call.
|
||||
*
|
||||
* This method throws `EBADF` if called on an unbound socket.
|
||||
*
|
||||
* #### Example: IPv6 outgoing multicast interface
|
||||
*
|
||||
* On most systems, where scope format uses the interface name:
|
||||
*
|
||||
* ```js
|
||||
* const socket = dgram.createSocket('udp6');
|
||||
*
|
||||
* socket.bind(1234, () => {
|
||||
* socket.setMulticastInterface('::%eth1');
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* On Windows, where scope format uses an interface number:
|
||||
*
|
||||
* ```js
|
||||
* const socket = dgram.createSocket('udp6');
|
||||
*
|
||||
* socket.bind(1234, () => {
|
||||
* socket.setMulticastInterface('::%2');
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* #### Example: IPv4 outgoing multicast interface
|
||||
*
|
||||
* All systems use an IP of the host on the desired physical interface:
|
||||
*
|
||||
* ```js
|
||||
* const socket = dgram.createSocket('udp4');
|
||||
*
|
||||
* socket.bind(1234, () => {
|
||||
* socket.setMulticastInterface('10.0.0.2');
|
||||
* });
|
||||
* ```
|
||||
* @since v8.6.0
|
||||
*/
|
||||
setMulticastInterface(multicastInterface: string): void;
|
||||
/**
|
||||
* Sets or clears the `IP_MULTICAST_LOOP` socket option. When set to `true`,
|
||||
* multicast packets will also be received on the local interface.
|
||||
*
|
||||
* This method throws `EBADF` if called on an unbound socket.
|
||||
* @since v0.3.8
|
||||
*/
|
||||
setMulticastLoopback(flag: boolean): boolean;
|
||||
/**
|
||||
* Sets the `IP_MULTICAST_TTL` socket option. While TTL generally stands for
|
||||
* "Time to Live", in this context it specifies the number of IP hops that a
|
||||
* packet is allowed to travel through, specifically for multicast traffic. Each
|
||||
* router or gateway that forwards a packet decrements the TTL. If the TTL is
|
||||
* decremented to 0 by a router, it will not be forwarded.
|
||||
*
|
||||
* The `ttl` argument may be between 0 and 255\. The default on most systems is `1`.
|
||||
*
|
||||
* This method throws `EBADF` if called on an unbound socket.
|
||||
* @since v0.3.8
|
||||
*/
|
||||
setMulticastTTL(ttl: number): number;
|
||||
/**
|
||||
* Sets the `SO_RCVBUF` socket option. Sets the maximum socket receive buffer
|
||||
* in bytes.
|
||||
*
|
||||
* This method throws `ERR_SOCKET_BUFFER_SIZE` if called on an unbound socket.
|
||||
* @since v8.7.0
|
||||
*/
|
||||
setRecvBufferSize(size: number): void;
|
||||
/**
|
||||
* Sets the `SO_SNDBUF` socket option. Sets the maximum socket send buffer
|
||||
* in bytes.
|
||||
*
|
||||
* This method throws `ERR_SOCKET_BUFFER_SIZE` if called on an unbound socket.
|
||||
* @since v8.7.0
|
||||
*/
|
||||
setSendBufferSize(size: number): void;
|
||||
/**
|
||||
* Sets the `IP_TTL` socket option. While TTL generally stands for "Time to Live",
|
||||
* in this context it specifies the number of IP hops that a packet is allowed to
|
||||
* travel through. Each router or gateway that forwards a packet decrements the
|
||||
* TTL. If the TTL is decremented to 0 by a router, it will not be forwarded.
|
||||
* Changing TTL values is typically done for network probes or when multicasting.
|
||||
*
|
||||
* The `ttl` argument may be between 1 and 255\. The default on most systems
|
||||
* is 64.
|
||||
*
|
||||
* This method throws `EBADF` if called on an unbound socket.
|
||||
* @since v0.1.101
|
||||
*/
|
||||
setTTL(ttl: number): number;
|
||||
/**
|
||||
* By default, binding a socket will cause it to block the Node.js process from
|
||||
* exiting as long as the socket is open. The `socket.unref()` method can be used
|
||||
* to exclude the socket from the reference counting that keeps the Node.js
|
||||
* process active, allowing the process to exit even if the socket is still
|
||||
* listening.
|
||||
*
|
||||
* Calling `socket.unref()` multiple times will have no additional effect.
|
||||
*
|
||||
* The `socket.unref()` method returns a reference to the socket so calls can be
|
||||
* chained.
|
||||
* @since v0.9.1
|
||||
*/
|
||||
unref(): this;
|
||||
/**
|
||||
* Tells the kernel to join a source-specific multicast channel at the given `sourceAddress` and `groupAddress`, using the `multicastInterface` with the `IP_ADD_SOURCE_MEMBERSHIP` socket
|
||||
* option. If the `multicastInterface` argument
|
||||
* is not specified, the operating system will choose one interface and will add
|
||||
* membership to it. To add membership to every available interface, call `socket.addSourceSpecificMembership()` multiple times, once per interface.
|
||||
*
|
||||
* When called on an unbound socket, this method will implicitly bind to a random
|
||||
* port, listening on all interfaces.
|
||||
* @since v13.1.0, v12.16.0
|
||||
*/
|
||||
addSourceSpecificMembership(sourceAddress: string, groupAddress: string, multicastInterface?: string): void;
|
||||
/**
|
||||
* Instructs the kernel to leave a source-specific multicast channel at the given `sourceAddress` and `groupAddress` using the `IP_DROP_SOURCE_MEMBERSHIP` socket option. This method is
|
||||
* automatically called by the kernel when the
|
||||
* socket is closed or the process terminates, so most apps will never have
|
||||
* reason to call this.
|
||||
*
|
||||
* If `multicastInterface` is not specified, the operating system will attempt to
|
||||
* drop membership on all valid interfaces.
|
||||
* @since v13.1.0, v12.16.0
|
||||
*/
|
||||
dropSourceSpecificMembership(sourceAddress: string, groupAddress: string, multicastInterface?: string): void;
|
||||
/**
|
||||
* Calls `socket.close()` and returns a promise that fulfills when the socket has closed.
|
||||
* @since v20.5.0
|
||||
*/
|
||||
[Symbol.asyncDispose](): Promise<void>;
|
||||
}
|
||||
interface Socket extends InternalEventEmitter<SocketEventMap> {}
|
||||
}
|
||||
declare module "dgram" {
|
||||
export * from "node:dgram";
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user