Compare commits
No commits in common. "37bc43dd6ba7752fe1bd9763aeab03715f356363" and "1c2cb6f01c85477836b6153a968975e2d26f2fd7" have entirely different histories.
37bc43dd6b
...
1c2cb6f01c
@ -1,67 +0,0 @@
|
|||||||
{
|
|
||||||
"schema_version": 2,
|
|
||||||
"active_work_id": "elsa-activiti-comparison-98c09385",
|
|
||||||
"works": {
|
|
||||||
"elsa-activiti-comparison-98c09385": {
|
|
||||||
"work_id": "elsa-activiti-comparison-98c09385",
|
|
||||||
"active_plan": "G:\\Source\\repos\\XiaowenBlog\\.omo\\plans\\elsa-activiti-comparison.md",
|
|
||||||
"plan_name": "elsa-activiti-comparison",
|
|
||||||
"status": "completed",
|
|
||||||
"started_at": "2026-06-17T05:45:03.831Z",
|
|
||||||
"updated_at": "2026-06-17T05:49:39.689Z",
|
|
||||||
"session_ids": [
|
|
||||||
"opencode:ses_12bf2a096ffedupptD5XsYcF0M"
|
|
||||||
],
|
|
||||||
"session_origins": {
|
|
||||||
"opencode:ses_12bf2a096ffedupptD5XsYcF0M": "direct"
|
|
||||||
},
|
|
||||||
"agent": "atlas",
|
|
||||||
"task_sessions": {
|
|
||||||
"todo:1": {
|
|
||||||
"task_key": "todo:1",
|
|
||||||
"task_label": "1",
|
|
||||||
"task_title": "补充 Elsa-Workflows-3.md 文档内容",
|
|
||||||
"session_id": "opencode:ses_12be1628effeIb7KGhchbdKAs4",
|
|
||||||
"agent": "Sisyphus-Junior",
|
|
||||||
"category": "quick",
|
|
||||||
"updated_at": "2026-06-17T05:49:00.215Z",
|
|
||||||
"started_at": "2026-06-17T05:48:41.403Z",
|
|
||||||
"status": "completed",
|
|
||||||
"ended_at": "2026-06-17T05:49:00.215Z",
|
|
||||||
"elapsed_ms": 18812
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ended_at": "2026-06-17T05:49:39.689Z",
|
|
||||||
"elapsed_ms": 275858
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"active_plan": "G:\\Source\\repos\\XiaowenBlog\\.omo\\plans\\elsa-activiti-comparison.md",
|
|
||||||
"started_at": "2026-06-17T05:45:03.831Z",
|
|
||||||
"status": "completed",
|
|
||||||
"updated_at": "2026-06-17T05:49:39.689Z",
|
|
||||||
"session_ids": [
|
|
||||||
"opencode:ses_12bf2a096ffedupptD5XsYcF0M"
|
|
||||||
],
|
|
||||||
"session_origins": {
|
|
||||||
"opencode:ses_12bf2a096ffedupptD5XsYcF0M": "direct"
|
|
||||||
},
|
|
||||||
"plan_name": "elsa-activiti-comparison",
|
|
||||||
"task_sessions": {
|
|
||||||
"todo:1": {
|
|
||||||
"task_key": "todo:1",
|
|
||||||
"task_label": "1",
|
|
||||||
"task_title": "补充 Elsa-Workflows-3.md 文档内容",
|
|
||||||
"session_id": "opencode:ses_12be1628effeIb7KGhchbdKAs4",
|
|
||||||
"agent": "Sisyphus-Junior",
|
|
||||||
"category": "quick",
|
|
||||||
"updated_at": "2026-06-17T05:49:00.215Z",
|
|
||||||
"started_at": "2026-06-17T05:48:41.403Z",
|
|
||||||
"status": "completed",
|
|
||||||
"ended_at": "2026-06-17T05:49:00.215Z",
|
|
||||||
"elapsed_ms": 18812
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"agent": "atlas",
|
|
||||||
"ended_at": "2026-06-17T05:49:39.689Z",
|
|
||||||
"elapsed_ms": 275858
|
|
||||||
}
|
|
||||||
@ -1,173 +0,0 @@
|
|||||||
# 补充 Elsa Workflows 3 与 Activiti 5.14 对比文档
|
|
||||||
|
|
||||||
## TL;DR
|
|
||||||
|
|
||||||
> **快速摘要**: 将整理好的 Elsa Workflows 3 与 Activiti 5.14 功能对比内容补充到博客文章 `source/_posts/Elsa-Workflows-3.md` 中
|
|
||||||
>
|
|
||||||
> **交付物**:
|
|
||||||
> - 更新后的 `source/_posts/Elsa-Workflows-3.md` 文件,包含完整的对比文档
|
|
||||||
>
|
|
||||||
> **预估工作量**: Quick
|
|
||||||
> **并行执行**: NO - 单一任务
|
|
||||||
> **关键路径**: 单一任务
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 背景
|
|
||||||
|
|
||||||
### 原始需求
|
|
||||||
用户需要将之前整理的 Elsa Workflows 3 与 Activiti 5.14 的功能对比文档补充到博客文章 `source/_posts/Elsa-Workflows-3.md` 中。
|
|
||||||
|
|
||||||
### 内容来源
|
|
||||||
已在对话中整理好的对比文档,包含以下内容:
|
|
||||||
1. 核心架构差异对比表
|
|
||||||
2. 七大功能逐一对比:
|
|
||||||
- 流程定义 (Process Definition)
|
|
||||||
- 启动一个特定的流程 (Start a Specific Process)
|
|
||||||
- 获取下一流程的流程以及对应审核人列表 (Get Next Tasks and Approvers)
|
|
||||||
- 提交给下一流程至下一个审核人审核 (Submit to Next Approver)
|
|
||||||
- 获取退回到之前流程以及对应审核人列表 (Get Previous Tasks for Rollback)
|
|
||||||
- 退回到之前流程及其对应的审核人 (Rollback to Previous Task)
|
|
||||||
- 流程的完结 (Process Completion)
|
|
||||||
3. 迁移建议和设计模式推荐
|
|
||||||
4. 关键差异总结表
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 工作目标
|
|
||||||
|
|
||||||
### 核心目标
|
|
||||||
将整理好的对比文档内容写入 `source/_posts/Elsa-Workflows-3.md` 文件
|
|
||||||
|
|
||||||
### 具体交付物
|
|
||||||
- 更新后的 `source/_posts/Elsa-Workflows-3.md` 文件
|
|
||||||
|
|
||||||
### 完成定义
|
|
||||||
- [ ] 文件包含完整的对比文档内容
|
|
||||||
- [ ] 文件保持正确的 front matter 格式
|
|
||||||
- [ ] 代码示例格式正确
|
|
||||||
|
|
||||||
### 必须包含
|
|
||||||
- 完整的架构差异对比表
|
|
||||||
- 七大功能的逐一对比(含代码示例)
|
|
||||||
- 迁移建议和设计模式推荐
|
|
||||||
- 关键差异总结表
|
|
||||||
|
|
||||||
### 禁止包含
|
|
||||||
- 不得删除现有 front matter
|
|
||||||
- 不得修改文件路径或文件名
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 验证策略
|
|
||||||
|
|
||||||
### 测试决策
|
|
||||||
- **基础设施存在**: N/A
|
|
||||||
- **自动化测试**: None
|
|
||||||
- **Agent-Executed QA**: YES
|
|
||||||
|
|
||||||
### QA 策略
|
|
||||||
每个任务必须包含 agent-executed QA 场景。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 执行策略
|
|
||||||
|
|
||||||
### 并行执行波次
|
|
||||||
|
|
||||||
```
|
|
||||||
Wave 1 (立即开始 - 单一任务):
|
|
||||||
└── Task 1: 补充文档内容 [quick]
|
|
||||||
|
|
||||||
Critical Path: Task 1 → 完成
|
|
||||||
Parallel Speedup: N/A
|
|
||||||
Max Concurrent: 1
|
|
||||||
```
|
|
||||||
|
|
||||||
### 依赖矩阵
|
|
||||||
|
|
||||||
- **Task 1**: 无依赖 - 可立即开始
|
|
||||||
|
|
||||||
### Agent 调度摘要
|
|
||||||
|
|
||||||
- **Wave 1**: 1 任务 - T1 → `quick`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## TODOs
|
|
||||||
|
|
||||||
- [x] 1. 补充 Elsa-Workflows-3.md 文档内容
|
|
||||||
|
|
||||||
**What to do**:
|
|
||||||
- 读取现有文件 `source/_posts/Elsa-Workflows-3.md`(已确认只有 front matter)
|
|
||||||
- 将整理好的对比内容写入文件,保持现有 front matter 不变
|
|
||||||
- 内容应包含:
|
|
||||||
- 核心架构差异对比表
|
|
||||||
- 七大功能逐一对比(含 Java 和 C# 代码示例)
|
|
||||||
- 迁移建议和设计模式推荐
|
|
||||||
- 关键差异总结表
|
|
||||||
|
|
||||||
**Must NOT do**:
|
|
||||||
- 不得删除或修改现有 front matter
|
|
||||||
- 不得修改文件路径
|
|
||||||
|
|
||||||
**Recommended Agent Profile**:
|
|
||||||
- **Category**: `quick`
|
|
||||||
- Reason: 单一文件编辑任务,内容已准备好
|
|
||||||
- **Skills**: []
|
|
||||||
- **Skills Evaluated but Omitted**:
|
|
||||||
- `hexo`: 虽然是 Hexo 博客,但任务仅涉及内容写入,不涉及 Hexo 配置或发布
|
|
||||||
|
|
||||||
**Parallelization**:
|
|
||||||
- **Can Run In Parallel**: NO
|
|
||||||
- **Parallel Group**: Sequential
|
|
||||||
- **Blocks**: 无
|
|
||||||
- **Blocked By**: 无 (可立即开始)
|
|
||||||
|
|
||||||
**References**:
|
|
||||||
- 对话中整理的完整对比内容
|
|
||||||
- 现有文件: `source/_posts/Elsa-Workflows-3.md`(只有 front matter)
|
|
||||||
|
|
||||||
**Acceptance Criteria**:
|
|
||||||
- [ ] 文件包含完整的对比文档
|
|
||||||
- [ ] Front matter 保持不变
|
|
||||||
- [ ] 代码示例格式正确
|
|
||||||
- [ ] 内容结构清晰
|
|
||||||
|
|
||||||
**QA Scenarios**:
|
|
||||||
|
|
||||||
```
|
|
||||||
Scenario: 文件内容完整性
|
|
||||||
Tool: Bash (Read file)
|
|
||||||
Preconditions: 文件已编辑完成
|
|
||||||
Steps:
|
|
||||||
1. 读取文件内容
|
|
||||||
2. 验证包含"核心架构差异"标题
|
|
||||||
3. 验证包含"流程定义"代码示例
|
|
||||||
4. 验证包含"迁移建议"章节
|
|
||||||
5. 验证 front matter 完整
|
|
||||||
Expected Result: 文件包含所有预期内容
|
|
||||||
Failure Indicators: 缺少任何主要章节或 front matter 被修改
|
|
||||||
Evidence: .omo/evidence/task-1-content-complete.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
**Evidence to Capture**:
|
|
||||||
- [ ] task-1-content-complete.txt - 文件内容验证结果
|
|
||||||
|
|
||||||
**Commit**: NO (内容补充任务,不涉及提交)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 成功标准
|
|
||||||
|
|
||||||
### 验证命令
|
|
||||||
```bash
|
|
||||||
# 验证文件内容
|
|
||||||
cat source/_posts/Elsa-Workflows-3.md | head -100
|
|
||||||
```
|
|
||||||
|
|
||||||
### 最终检查清单
|
|
||||||
- [ ] 文件包含完整的对比文档内容
|
|
||||||
- [ ] Front matter 保持不变
|
|
||||||
- [ ] 代码示例格式正确
|
|
||||||
- [ ] 内容结构清晰易读
|
|
||||||
46
Jenkinsfile
vendored
46
Jenkinsfile
vendored
@ -1,46 +0,0 @@
|
|||||||
pipeline {
|
|
||||||
agent any
|
|
||||||
|
|
||||||
environment {
|
|
||||||
NODE_VERSION = '20'
|
|
||||||
}
|
|
||||||
|
|
||||||
stages {
|
|
||||||
stage('Checkout') {
|
|
||||||
steps {
|
|
||||||
checkout scm
|
|
||||||
sh 'git submodule update --init --recursive'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stage('Install Dependencies') {
|
|
||||||
steps {
|
|
||||||
sh 'npm install'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stage('Build') {
|
|
||||||
steps {
|
|
||||||
sh 'npm run clean'
|
|
||||||
sh 'npm run build'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stage('Deploy') {
|
|
||||||
steps {
|
|
||||||
withCredentials([gitUsernamePassword(credentialsId: 'github-credentials')]) {
|
|
||||||
sh 'npx hexo deploy'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
post {
|
|
||||||
success {
|
|
||||||
echo '博客发布成功!'
|
|
||||||
}
|
|
||||||
failure {
|
|
||||||
echo '博客发布失败!'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,540 +0,0 @@
|
|||||||
---
|
|
||||||
title: Elsa Workflows 3
|
|
||||||
date: 2026-06-17 13:21:19
|
|
||||||
tags:
|
|
||||||
---
|
|
||||||
|
|
||||||
# Elsa Workflows 3 与 Activiti 5.14 对比指南
|
|
||||||
|
|
||||||
## 核心架构差异
|
|
||||||
|
|
||||||
| 概念 | Activiti 5.14 (Java) | Elsa Workflows 3 (.NET) |
|
|
||||||
|------|---------------------|------------------------|
|
|
||||||
| **流程定义** | BPMN 2.0 XML | C# 代码 / JSON / 可视化设计器 |
|
|
||||||
| **任务模型** | 内置 UserTask 概念 | 阻塞活动 (Blocking Activity) + 书签 (Bookmark) |
|
|
||||||
| **状态管理** | HistoryService 审计日志 | 自定义审计实现 |
|
|
||||||
| **回滚支持** | 无原生支持,需自定义 | 有 Alterations API |
|
|
||||||
| **API 风格** | Java 服务注入 | .NET 依赖注入 |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 功能逐一对比
|
|
||||||
|
|
||||||
### 1. 流程定义 (Process Definition)
|
|
||||||
|
|
||||||
**Activiti 5.14:**
|
|
||||||
```java
|
|
||||||
// 使用 BPMN 2.0 XML 文件
|
|
||||||
// process.bpmn20.xml
|
|
||||||
<process id="approvalProcess" name="审批流程" isExecutable="true">
|
|
||||||
<startEvent id="start"/>
|
|
||||||
<userTask id="review" name="审核" activiti:assignee="${reviewer}"/>
|
|
||||||
<endEvent id="end"/>
|
|
||||||
<sequenceFlow sourceRef="start" targetRef="review"/>
|
|
||||||
<sequenceFlow sourceRef="review" targetRef="end"/>
|
|
||||||
</process>
|
|
||||||
|
|
||||||
// 部署流程定义
|
|
||||||
repositoryService.createDeployment()
|
|
||||||
.addClasspathResource("process.bpmn20.xml")
|
|
||||||
.deploy();
|
|
||||||
```
|
|
||||||
|
|
||||||
**Elsa Workflows 3:**
|
|
||||||
```csharp
|
|
||||||
// 方式1: C# 代码定义
|
|
||||||
public class ApprovalWorkflow : Workflow
|
|
||||||
{
|
|
||||||
public override void Build(IWorkflowBuilder builder)
|
|
||||||
{
|
|
||||||
builder
|
|
||||||
.HttpEndpoint("/start-approval", HttpMethod.Post)
|
|
||||||
.Then<WaitForApprovalActivity>(activity =>
|
|
||||||
{
|
|
||||||
activity.ApprovalMessage = new("请审核此申请");
|
|
||||||
})
|
|
||||||
.WriteHttpResponse(HttpStatusCode.OK, "流程完成");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 方式2: JSON 定义
|
|
||||||
{
|
|
||||||
"definitionId": "approval-workflow",
|
|
||||||
"name": "审批流程",
|
|
||||||
"version": 1,
|
|
||||||
"root": {
|
|
||||||
"type": "Elsa.Flowchart",
|
|
||||||
"activities": [
|
|
||||||
{
|
|
||||||
"id": "start",
|
|
||||||
"type": "Elsa.HttpEndpoint",
|
|
||||||
"path": "/start-approval"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 方式3: 使用 Elsa Studio 可视化设计器
|
|
||||||
|
|
||||||
// 发布流程定义
|
|
||||||
await workflowDefinitionsApi.SaveAsync(new SaveWorkflowDefinitionRequest
|
|
||||||
{
|
|
||||||
Model = new WorkflowDefinitionModel
|
|
||||||
{
|
|
||||||
DefinitionId = "approval-workflow",
|
|
||||||
Name = "审批流程",
|
|
||||||
IsPublished = true
|
|
||||||
},
|
|
||||||
Publish = true
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 2. 启动一个特定的流程 (Start a Specific Process)
|
|
||||||
|
|
||||||
**Activiti 5.14:**
|
|
||||||
```java
|
|
||||||
Map<String, Object> variables = new HashMap<>();
|
|
||||||
variables.put("applicant", "张三");
|
|
||||||
variables.put("amount", 5000);
|
|
||||||
|
|
||||||
ProcessInstance instance = runtimeService
|
|
||||||
.startProcessInstanceByKey("approvalProcess", variables);
|
|
||||||
|
|
||||||
String processInstanceId = instance.getId();
|
|
||||||
```
|
|
||||||
|
|
||||||
**Elsa Workflows 3:**
|
|
||||||
```csharp
|
|
||||||
// 方式1: 直接执行 (同步)
|
|
||||||
var workflowRunner = serviceProvider.GetRequiredService<IWorkflowRunner>();
|
|
||||||
var result = await workflowRunner.RunAsync<ApprovalWorkflow>(input: new Dictionary<string, object>
|
|
||||||
{
|
|
||||||
["Applicant"] = "张三",
|
|
||||||
["Amount"] = 5000
|
|
||||||
});
|
|
||||||
|
|
||||||
// 方式2: 异步调度 (推荐用于生产环境)
|
|
||||||
var dispatcher = serviceProvider.GetRequiredService<IWorkflowDispatcher>();
|
|
||||||
await dispatcher.DispatchAsync(new DispatchWorkflowInstanceRequest
|
|
||||||
{
|
|
||||||
DefinitionId = "approval-workflow",
|
|
||||||
Input = new Dictionary<string, object>
|
|
||||||
{
|
|
||||||
["Applicant"] = "张三",
|
|
||||||
["Amount"] = 5000
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 方式3: 通过 HTTP API
|
|
||||||
// POST /api/workflow-definitions/approval-workflow/dispatch
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 3. 获取下一流程的流程以及对应审核人列表 (Get Next Tasks and Approvers)
|
|
||||||
|
|
||||||
**Activiti 5.14:**
|
|
||||||
```java
|
|
||||||
// 获取当前流程实例的任务
|
|
||||||
List<Task> tasks = taskService.createTaskQuery()
|
|
||||||
.processInstanceId(processInstanceId)
|
|
||||||
.list();
|
|
||||||
|
|
||||||
for (Task task : tasks) {
|
|
||||||
System.out.println("任务名称: " + task.getName());
|
|
||||||
System.out.println("处理人: " + task.getAssignee());
|
|
||||||
System.out.println("创建时间: " + task.getCreateTime());
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取候选任务 (待认领)
|
|
||||||
List<Task> candidateTasks = taskService.createTaskQuery()
|
|
||||||
.taskCandidateUser("userId")
|
|
||||||
.list();
|
|
||||||
```
|
|
||||||
|
|
||||||
**Elsa Workflows 3:**
|
|
||||||
```csharp
|
|
||||||
// Elsa 没有内置的"任务"概念,需要通过书签(Bookmarks)实现
|
|
||||||
// 查询流程实例的书签 (类似当前待处理节点)
|
|
||||||
var bookmarks = await bookmarkFinder
|
|
||||||
.FindByWorkflowInstanceIdAsync(workflowInstanceId);
|
|
||||||
|
|
||||||
foreach (var bookmark in bookmarks)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"书签名称: {bookmark.Name}");
|
|
||||||
Console.WriteLine($"活动类型: {bookmark.ActivityTypeName}");
|
|
||||||
// 自定义: 需要从书签的 Payload 中提取审核人信息
|
|
||||||
}
|
|
||||||
|
|
||||||
// 推荐方案: 使用自定义状态管理
|
|
||||||
public class ApprovalStateTracker
|
|
||||||
{
|
|
||||||
private readonly IWorkflowInstancesApi _workflowInstancesApi;
|
|
||||||
|
|
||||||
public async Task<List<ApprovalStep>> GetNextApproversAsync(
|
|
||||||
string workflowInstanceId)
|
|
||||||
{
|
|
||||||
// 从工作流变量中获取当前步骤和审核人
|
|
||||||
var instance = await _workflowInstancesApi.GetAsync(workflowInstanceId);
|
|
||||||
var currentStep = instance.Variables["CurrentStep"];
|
|
||||||
var approvers = instance.Variables["NextApprovers"] as List<string>;
|
|
||||||
|
|
||||||
return new List<ApprovalStep>
|
|
||||||
{
|
|
||||||
new ApprovalStep
|
|
||||||
{
|
|
||||||
StepName = currentStep.ToString(),
|
|
||||||
Approvers = approvers
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 4. 提交给下一流程至下一个审核人审核 (Submit to Next Approver)
|
|
||||||
|
|
||||||
**Activiti 5.14:**
|
|
||||||
```java
|
|
||||||
// 认领任务
|
|
||||||
taskService.claim(taskId, "userId");
|
|
||||||
|
|
||||||
// 完成任务并传递变量
|
|
||||||
Map<String, Object> variables = new HashMap<>();
|
|
||||||
variables.put("approved", true);
|
|
||||||
variables.put("comment", "同意申请");
|
|
||||||
|
|
||||||
taskService.complete(taskId, variables);
|
|
||||||
```
|
|
||||||
|
|
||||||
**Elsa Workflows 3:**
|
|
||||||
```csharp
|
|
||||||
// 方式1: 通过书签ID恢复
|
|
||||||
var input = new Dictionary<string, object>
|
|
||||||
{
|
|
||||||
["Decision"] = "Approved",
|
|
||||||
["ApprovedBy"] = "manager@example.com",
|
|
||||||
["Comment"] = "同意申请"
|
|
||||||
};
|
|
||||||
|
|
||||||
var result = await workflowResumer.ResumeAsync(bookmarkId, input);
|
|
||||||
|
|
||||||
// 方式2: 通过 Stimulus (匹配书签)
|
|
||||||
var stimulus = new
|
|
||||||
{
|
|
||||||
ApprovalId = approvalId,
|
|
||||||
StepName = "ManagerReview"
|
|
||||||
};
|
|
||||||
|
|
||||||
await workflowResumer.ResumeAsync(stimulus, input);
|
|
||||||
|
|
||||||
// 方式3: 通过 HTTP API (使用令牌URL)
|
|
||||||
// POST /elsa/api/bookmarks/resume?t=ENCRYPTED_TOKEN
|
|
||||||
// Body: { "input": { "Decision": "Approved", "ApprovedBy": "manager@example.com" } }
|
|
||||||
|
|
||||||
// 自定义审核活动示例
|
|
||||||
public class WaitForApprovalActivity : Activity
|
|
||||||
{
|
|
||||||
protected override async ValueTask ExecuteAsync(
|
|
||||||
ActivityExecutionContext context)
|
|
||||||
{
|
|
||||||
var bookmarkArgs = new CreateBookmarkArgs
|
|
||||||
{
|
|
||||||
BookmarkName = "WaitForApproval",
|
|
||||||
Payload = new Dictionary<string, object>
|
|
||||||
{
|
|
||||||
["ApprovalId"] = context.Get(ApprovalId),
|
|
||||||
["CurrentStep"] = context.Get(CurrentStep)
|
|
||||||
},
|
|
||||||
Callback = OnApprovalReceivedAsync,
|
|
||||||
AutoBurn = true // 使用一次后自动销毁
|
|
||||||
};
|
|
||||||
|
|
||||||
context.CreateBookmark(bookmarkArgs);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async ValueTask OnApprovalReceivedAsync(
|
|
||||||
ActivityExecutionContext context)
|
|
||||||
{
|
|
||||||
var decision = context.WorkflowInput["Decision"];
|
|
||||||
var approvedBy = context.WorkflowInput["ApprovedBy"];
|
|
||||||
|
|
||||||
// 记录审核历史
|
|
||||||
await RecordApprovalHistoryAsync(decision, approvedBy);
|
|
||||||
|
|
||||||
// 根据决策决定下一步
|
|
||||||
if (decision.ToString() == "Approved")
|
|
||||||
{
|
|
||||||
await context.CompleteActivityWithOutcomesAsync("Approved");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await context.CompleteActivityWithOutcomesAsync("Rejected");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 5. 获取退回到之前流程以及对应审核人列表 (Get Previous Tasks for Rollback)
|
|
||||||
|
|
||||||
**Activiti 5.14:**
|
|
||||||
```java
|
|
||||||
// 获取历史任务
|
|
||||||
List<HistoricTaskInstance> historicTasks = historyService
|
|
||||||
.createHistoricTaskInstanceQuery()
|
|
||||||
.processInstanceId(processInstanceId)
|
|
||||||
.orderByHistoricTaskInstanceEndTime().desc()
|
|
||||||
.list();
|
|
||||||
|
|
||||||
for (HistoricTaskInstance task : historicTasks) {
|
|
||||||
System.out.println("任务名称: " + task.getName());
|
|
||||||
System.out.println("处理人: " + task.getAssignee());
|
|
||||||
System.out.println("开始时间: " + task.getStartTime());
|
|
||||||
System.out.println("结束时间: " + task.getEndTime());
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Elsa Workflows 3:**
|
|
||||||
```csharp
|
|
||||||
// 需要自定义审计日志实现
|
|
||||||
public class WorkflowAuditService
|
|
||||||
{
|
|
||||||
private readonly IAuditLogRepository _auditLogRepo;
|
|
||||||
|
|
||||||
public async Task<List<AuditEntry>> GetApprovalHistoryAsync(
|
|
||||||
string workflowInstanceId)
|
|
||||||
{
|
|
||||||
return await _auditLogRepo
|
|
||||||
.GetByWorkflowInstanceIdAsync(workflowInstanceId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task RecordApprovalAsync(
|
|
||||||
string workflowInstanceId,
|
|
||||||
string stepName,
|
|
||||||
string approver,
|
|
||||||
string decision,
|
|
||||||
string comment)
|
|
||||||
{
|
|
||||||
await _auditLogRepo.AddAsync(new AuditEntry
|
|
||||||
{
|
|
||||||
WorkflowInstanceId = workflowInstanceId,
|
|
||||||
StepName = stepName,
|
|
||||||
Approver = approver,
|
|
||||||
Decision = decision,
|
|
||||||
Comment = comment,
|
|
||||||
Timestamp = DateTime.UtcNow
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 在审核活动的回调中记录历史
|
|
||||||
private async ValueTask OnApprovalReceivedAsync(
|
|
||||||
ActivityExecutionContext context)
|
|
||||||
{
|
|
||||||
var decision = context.WorkflowInput["Decision"];
|
|
||||||
var approvedBy = context.WorkflowInput["ApprovedBy"];
|
|
||||||
|
|
||||||
// 记录审核历史
|
|
||||||
await _auditService.RecordApprovalAsync(
|
|
||||||
context.WorkflowExecutionContext.Id,
|
|
||||||
context.Get(CurrentStep),
|
|
||||||
approvedBy.ToString(),
|
|
||||||
decision.ToString(),
|
|
||||||
context.WorkflowInput["Comment"]?.ToString());
|
|
||||||
|
|
||||||
// 继续流程...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 6. 退回到之前流程及其对应的审核人 (Rollback to Previous Task)
|
|
||||||
|
|
||||||
**Activiti 5.14:**
|
|
||||||
```java
|
|
||||||
// 方案1: 使用流程变量 + 网关循环
|
|
||||||
// 在 BPMN 中设计回退路径
|
|
||||||
// 需要在 BPMN XML 中定义循环逻辑
|
|
||||||
|
|
||||||
// 方案2: 使用信号事件
|
|
||||||
runtimeService.signalEventReceived("rollbackSignal", variables);
|
|
||||||
|
|
||||||
// 方案3: 自定义命令 (不推荐,侵入性强)
|
|
||||||
```
|
|
||||||
|
|
||||||
**Elsa Workflows 3:**
|
|
||||||
```csharp
|
|
||||||
// 方案1: 使用 Alterations API (推荐)
|
|
||||||
await workflowAlterationService.AlterAsync(workflowInstanceId, alteration =>
|
|
||||||
{
|
|
||||||
// 修改工作流变量
|
|
||||||
alteration.SetVariable("CurrentStep", "ManagerReview");
|
|
||||||
alteration.SetVariable("NeedsRollback", true);
|
|
||||||
});
|
|
||||||
|
|
||||||
// 方案2: 取消当前书签,创建新书签
|
|
||||||
public async Task RollbackToStepAsync(
|
|
||||||
string workflowInstanceId,
|
|
||||||
string targetStep,
|
|
||||||
string targetApprover)
|
|
||||||
{
|
|
||||||
// 1. 获取当前书签
|
|
||||||
var bookmarks = await bookmarkFinder
|
|
||||||
.FindByWorkflowInstanceIdAsync(workflowInstanceId);
|
|
||||||
|
|
||||||
// 2. 取消当前书签 (通过恢复并传递回退指令)
|
|
||||||
var input = new Dictionary<string, object>
|
|
||||||
{
|
|
||||||
["Decision"] = "Rollback",
|
|
||||||
["TargetStep"] = targetStep,
|
|
||||||
["TargetApprover"] = targetApprover
|
|
||||||
};
|
|
||||||
|
|
||||||
// 3. 恢复工作流,触发回退逻辑
|
|
||||||
await workflowResumer.ResumeAsync(bookmarks.First().Id, input);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 方案3: 使用自定义回退活动
|
|
||||||
public class RollbackActivity : Activity
|
|
||||||
{
|
|
||||||
protected override async ValueTask ExecuteAsync(
|
|
||||||
ActivityExecutionContext context)
|
|
||||||
{
|
|
||||||
var targetStep = context.Get(TargetStep);
|
|
||||||
var targetApprover = context.Get(TargetApprover);
|
|
||||||
|
|
||||||
// 更新流程状态
|
|
||||||
context.SetVariable("CurrentStep", targetStep);
|
|
||||||
context.SetVariable("CurrentApprover", targetApprover);
|
|
||||||
|
|
||||||
// 记录回退历史
|
|
||||||
await RecordRollbackAsync(targetStep, targetApprover);
|
|
||||||
|
|
||||||
// 完成活动,流程将根据条件网关回到目标步骤
|
|
||||||
await context.CompleteActivityAsync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 7. 流程的完结 (Process Completion)
|
|
||||||
|
|
||||||
**Activiti 5.14:**
|
|
||||||
```java
|
|
||||||
// 方式1: 自然结束 (所有任务完成)
|
|
||||||
taskService.complete(lastTaskId);
|
|
||||||
|
|
||||||
// 方式2: 手动终止
|
|
||||||
runtimeService.deleteProcessInstance(processInstanceId, "用户取消");
|
|
||||||
|
|
||||||
// 方式3: 结束事件触发
|
|
||||||
// 在 BPMN 中定义 endEvent
|
|
||||||
```
|
|
||||||
|
|
||||||
**Elsa Workflows 3:**
|
|
||||||
```csharp
|
|
||||||
// 方式1: 自然结束 (所有活动完成)
|
|
||||||
// 当工作流执行到 End 活动时自动结束
|
|
||||||
|
|
||||||
// 方式2: 手动取消
|
|
||||||
var workflowCanceller = serviceProvider.GetRequiredService<IWorkflowCanceller>();
|
|
||||||
await workflowCanceller.CancelAsync(workflowInstanceId);
|
|
||||||
|
|
||||||
// 方式3: 通过 API
|
|
||||||
// DELETE /api/workflow-instances/{instanceId}
|
|
||||||
|
|
||||||
// 方式4: 使用 End 活动
|
|
||||||
builder
|
|
||||||
.Then<SomeActivity>()
|
|
||||||
.Then<End>() // 工作流在此结束
|
|
||||||
.WriteHttpResponse(HttpStatusCode.OK, "流程已完成");
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 迁移建议
|
|
||||||
|
|
||||||
### 设计模式推荐
|
|
||||||
|
|
||||||
对于审批流程场景,建议在 Elsa 中采用以下设计:
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public class ApprovalWorkflow : Workflow
|
|
||||||
{
|
|
||||||
public override void Build(IWorkflowBuilder builder)
|
|
||||||
{
|
|
||||||
builder
|
|
||||||
// 开始
|
|
||||||
.HttpEndpoint("/start", HttpMethod.Post)
|
|
||||||
.Then<InitializeApprovalActivity>()
|
|
||||||
|
|
||||||
// 审核循环
|
|
||||||
.Then<WaitForApprovalActivity>(activity =>
|
|
||||||
{
|
|
||||||
activity.ApprovalMessage = new("请审核");
|
|
||||||
})
|
|
||||||
.If(context => context.GetInput<string>("Decision") == "Approved",
|
|
||||||
then => then.Then<ProcessApprovedActivity>(),
|
|
||||||
@else => @else.Then<ProcessRejectedActivity>())
|
|
||||||
|
|
||||||
// 结束
|
|
||||||
.WriteHttpResponse(HttpStatusCode.OK);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 状态跟踪服务
|
|
||||||
public class ApprovalTrackingService
|
|
||||||
{
|
|
||||||
// 记录每个步骤的审核人
|
|
||||||
public async Task RecordStepAsync(
|
|
||||||
string workflowId,
|
|
||||||
ApprovalStep step)
|
|
||||||
{
|
|
||||||
// 存储到数据库
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取历史步骤 (用于回退)
|
|
||||||
public async Task<List<ApprovalStep>> GetHistoryAsync(
|
|
||||||
string workflowId)
|
|
||||||
{
|
|
||||||
// 从数据库查询
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取下一个审核人
|
|
||||||
public async Task<List<string>> GetNextApproversAsync(
|
|
||||||
string workflowId)
|
|
||||||
{
|
|
||||||
// 根据业务规则计算
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 关键差异总结
|
|
||||||
|
|
||||||
| 功能 | Activiti | Elsa | 迁移注意事项 |
|
|
||||||
|------|----------|------|-------------|
|
|
||||||
| 任务查询 | 原生支持 | 需自定义 | 需要实现状态跟踪服务 |
|
|
||||||
| 审计日志 | HistoryService | 需自定义 | 需要实现审计日志模块 |
|
|
||||||
| 回滚 | 无原生支持 | Alterations API | Elsa 有更好的扩展性 |
|
|
||||||
| 任务分配 | candidateUser/Group | 需自定义 | 需要在书签中存储分配信息 |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 总结
|
|
||||||
|
|
||||||
Elsa Workflows 3 作为 .NET 工作流引擎,虽然在任务管理方面不如 Activiti 成熟,但提供了更灵活的扩展机制。迁移过程中需要:
|
|
||||||
|
|
||||||
1. **重新设计任务模型**: 使用阻塞活动 + 书签替代内置 UserTask
|
|
||||||
2. **实现审计服务**: 自定义审核历史记录
|
|
||||||
3. **利用 Alterations API**: 实现流程回退功能
|
|
||||||
4. **设计状态管理**: 通过工作流变量跟踪审批状态
|
|
||||||
|
|
||||||
整体而言,Elsa 的架构更适合现代 .NET 应用,但需要更多的自定义实现来满足审批流程的完整需求。
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
---
|
|
||||||
title: Everything
|
|
||||||
date: 2026-06-04 10:55:44
|
|
||||||
tags:
|
|
||||||
---
|
|
||||||
File diff suppressed because it is too large
Load Diff
@ -49,61 +49,6 @@ su username
|
|||||||
exit
|
exit
|
||||||
```
|
```
|
||||||
|
|
||||||
### 收回用户 Shell 权限
|
|
||||||
|
|
||||||
限制用户登录系统,禁止其使用交互式 Shell。
|
|
||||||
|
|
||||||
#### 设置禁止登录的 Shell
|
|
||||||
|
|
||||||
```shell
|
|
||||||
# 方法一:使用 /sbin/nologin(推荐)
|
|
||||||
usermod -s /sbin/nologin username
|
|
||||||
|
|
||||||
# 方法二:使用 /bin/false
|
|
||||||
usermod -s /bin/false username
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 查看用户当前 Shell
|
|
||||||
|
|
||||||
```shell
|
|
||||||
grep username /etc/passwd
|
|
||||||
|
|
||||||
# 或
|
|
||||||
getent passwd username
|
|
||||||
```
|
|
||||||
|
|
||||||
输出示例:
|
|
||||||
|
|
||||||
```
|
|
||||||
username:x:1001:1001::/home/username:/sbin/nologin
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 各 Shell 对比
|
|
||||||
|
|
||||||
| Shell | 效果 |
|
|
||||||
| --- | --- |
|
|
||||||
| `/bin/bash` | 正常登录,可执行命令 |
|
|
||||||
| `/sbin/nologin` | 拒绝登录,提示 `This account is currently not available` |
|
|
||||||
| `/bin/false` | 拒绝登录,无提示,退出码为 1 |
|
|
||||||
| `/usr/sbin/nologin` | 与 `/sbin/nologin` 相同(部分系统软链接) |
|
|
||||||
|
|
||||||
> **适用场景**:数据库用户、服务专用账户、FTP 账户等只需运行服务不需要登录系统的用户。
|
|
||||||
|
|
||||||
#### 恢复登录权限
|
|
||||||
|
|
||||||
```shell
|
|
||||||
usermod -s /bin/bash username
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 批量收回
|
|
||||||
|
|
||||||
```shell
|
|
||||||
# 读取用户列表文件,批量设置
|
|
||||||
while read user; do
|
|
||||||
usermod -s /sbin/nologin "$user"
|
|
||||||
done < userlist.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 权限管理
|
## 权限管理
|
||||||
@ -120,65 +65,14 @@ Linux 文件有三种权限:
|
|||||||
|
|
||||||
### chmod 命令
|
### chmod 命令
|
||||||
|
|
||||||
修改文件或目录权限。
|
修改文件权限。
|
||||||
|
|
||||||
#### 基本语法
|
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
chmod [选项] 模式 文件
|
# 数字方式设置权限
|
||||||
|
chmod 755 file
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 符号模式
|
**权限数字说明**:
|
||||||
|
|
||||||
通过 `u`(所有者)、`g`(所属组)、`o`(其他用户)、`a`(所有人)配合 `+`、`-`、`=` 操作权限。
|
|
||||||
|
|
||||||
**操作符区别**:
|
|
||||||
|
|
||||||
| 操作符 | 作用 | 说明 |
|
|
||||||
|--------|------|------|
|
|
||||||
| `+` | 添加权限 | 在原有权限基础上增加,不影响已有权限 |
|
|
||||||
| `-` | 移除权限 | 从现有权限中移除,不影响未指定的权限 |
|
|
||||||
| `=` | 直接设置 | 覆盖为指定权限,其余位清零 |
|
|
||||||
|
|
||||||
```shell
|
|
||||||
# + 添加权限(累加,不影响其他位)
|
|
||||||
chmod u+x script.sh # 所有者添加执行权限
|
|
||||||
chmod a+r file.txt # 所有人添加读权限
|
|
||||||
chmod g+w,o+r file.txt # 组添加写,其他添加读
|
|
||||||
|
|
||||||
# - 移除权限(仅移除指定位,其余保留)
|
|
||||||
chmod o-w file.txt # 其他用户移除写权限
|
|
||||||
chmod g-x script.sh # 组移除执行权限
|
|
||||||
chmod a-w file.txt # 所有人移除写权限
|
|
||||||
|
|
||||||
# = 直接设置(覆盖,未指定的位全部清零)
|
|
||||||
chmod u=r file.txt # 所有者只有读权限(写和执行被清除)
|
|
||||||
chmod g=r file.txt # 组只有读权限
|
|
||||||
chmod o= file.txt # 其他用户无任何权限
|
|
||||||
chmod u=rwx,g=rx,o= file.txt # 精确控制每位权限
|
|
||||||
|
|
||||||
# + 重复添加已有权限不会报错,保持不变
|
|
||||||
chmod u+x file.txt # 如果已有执行权限,不变
|
|
||||||
chmod a+r file.txt # 如果所有人已有读权限,不变
|
|
||||||
```
|
|
||||||
|
|
||||||
> **注意**:`+` 是幂等操作,重复添加已有权限不会产生任何变化,也不会报错。`-` 同理,移除不存在的权限也不会报错。
|
|
||||||
|
|
||||||
**示例对比**:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
# 假设文件当前权限为 rw-r--r--(644)
|
|
||||||
|
|
||||||
chmod u+x file.txt # 结果:rwxr--r--(654)只给所有者加了执行
|
|
||||||
chmod u-x file.txt # 结果:rw-r--r--(644)移除执行(本来就没有,不变)
|
|
||||||
chmod u=r file.txt # 结果:r--r--r--(444)所有者变成只读,写被清掉
|
|
||||||
chmod u=rw file.txt # 结果:rw-r--r--(644)所有者读写
|
|
||||||
chmod u=rwx,g=rx,o= file.txt # 结果:rwxr-x---(750)
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 数字模式
|
|
||||||
|
|
||||||
用三位八进制数表示权限,每位对应 `u`、`g`、`o`。
|
|
||||||
|
|
||||||
| 数字 | 权限 | 说明 |
|
| 数字 | 权限 | 说明 |
|
||||||
|-----|------|------|
|
|-----|------|------|
|
||||||
@ -188,158 +82,10 @@ chmod u=rwx,g=rx,o= file.txt # 结果:rwxr-x---(750)
|
|||||||
| 4 | r-- | 只读 |
|
| 4 | r-- | 只读 |
|
||||||
| 0 | --- | 无权限 |
|
| 0 | --- | 无权限 |
|
||||||
|
|
||||||
```shell
|
**755 权限含义**:`rwxr-xr-x`
|
||||||
# rwxr-xr-x(所有者全权限,组和其他用户读执行)
|
- 所有者:读、写、执行
|
||||||
chmod 755 file.txt
|
- 所属组:读、执行
|
||||||
|
- 其他用户:读、执行
|
||||||
# rw-r--r--(所有者读写,组和其他用户只读)
|
|
||||||
chmod 644 file.txt
|
|
||||||
|
|
||||||
# rw-rw----(所有者和组读写,其他用户无权限)
|
|
||||||
chmod 660 file.txt
|
|
||||||
|
|
||||||
# rwx------(仅所有者有全部权限)
|
|
||||||
chmod 700 file.txt
|
|
||||||
|
|
||||||
# rw-rw-rw-(所有人可读写)
|
|
||||||
chmod 666 file.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 常用权限参考
|
|
||||||
|
|
||||||
| 权限值 | 含义 | 适用场景 |
|
|
||||||
|--------|------|----------|
|
|
||||||
| `755` | rwxr-xr-x | 可执行脚本、程序,公开目录 |
|
|
||||||
| `644` | rw-r--r-- | 普通文件,所有人可读 |
|
|
||||||
| `700` | rwx------ | 私有目录,仅所有者可访问 |
|
|
||||||
| `600` | rw------- | 私有文件,如 SSH 密钥 |
|
|
||||||
| `640` | rw-r----- | 服务配置文件,组可读 |
|
|
||||||
| `777` | rwxrwxrwx | 所有人可读写执行(不推荐) |
|
|
||||||
|
|
||||||
#### 常用选项
|
|
||||||
|
|
||||||
```shell
|
|
||||||
# 递归修改目录及子目录下所有文件
|
|
||||||
chmod -R 755 /var/www/html
|
|
||||||
|
|
||||||
# 仅修改目录本身的权限
|
|
||||||
chmod 755 /var/www/html
|
|
||||||
|
|
||||||
# 修改符号链接的权限(不常用)
|
|
||||||
chmod -h 755 link_file
|
|
||||||
|
|
||||||
# 显示修改过程
|
|
||||||
chmod -v 755 file.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 设置特殊权限
|
|
||||||
|
|
||||||
```shell
|
|
||||||
# SUID(4):执行时以文件所有者身份运行
|
|
||||||
chmod 4755 /usr/bin/passwd
|
|
||||||
|
|
||||||
# SGID(2):执行时以文件所属组身份运行
|
|
||||||
chmod 2755 /shared_dir
|
|
||||||
|
|
||||||
# Sticky Bit(1):目录内文件只有所有者能删除
|
|
||||||
chmod 1777 /tmp
|
|
||||||
```
|
|
||||||
|
|
||||||
**特殊权限数字对照**:
|
|
||||||
|
|
||||||
| 数字 | 权限 | 说明 |
|
|
||||||
|------|------|------|
|
|
||||||
| 4 | SUID | 执行时以所有者身份运行 |
|
|
||||||
| 2 | SGID | 执行时以组身份运行 |
|
|
||||||
| 1 | Sticky | 仅文件所有者可删除目录内文件 |
|
|
||||||
|
|
||||||
```shell
|
|
||||||
# 同时设置特殊权限和普通权限
|
|
||||||
chmod 4755 file # SUID + rwxr-xr-x
|
|
||||||
chmod 2755 dir # SGID + rwxr-xr-x
|
|
||||||
chmod 1777 /tmp # Sticky + rwxrwxrwx
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 通过八进制运算理解权限
|
|
||||||
|
|
||||||
```
|
|
||||||
用户(u) 组(g) 其他(o)
|
|
||||||
rwx r-x r--
|
|
||||||
4+2+1 4+0+1 4+0+0
|
|
||||||
7 5 4 = 754
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### chown 命令
|
|
||||||
|
|
||||||
修改文件或目录的所有者和所属组。
|
|
||||||
|
|
||||||
#### 基本语法
|
|
||||||
|
|
||||||
```shell
|
|
||||||
chown [选项] 所有者[:所属组] 文件
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 常用操作
|
|
||||||
|
|
||||||
```shell
|
|
||||||
# 修改文件所有者
|
|
||||||
chown user file.txt
|
|
||||||
|
|
||||||
# 修改文件所有者和所属组
|
|
||||||
chown user:group file.txt
|
|
||||||
|
|
||||||
# 修改文件所属组
|
|
||||||
chown :group file.txt
|
|
||||||
|
|
||||||
# 递归修改目录及子文件
|
|
||||||
chown -R user:group /var/www/html
|
|
||||||
|
|
||||||
# 仅修改所有者
|
|
||||||
chown -R user /var/www/html
|
|
||||||
|
|
||||||
# 仅修改所属组
|
|
||||||
chown -R :group /var/www/html
|
|
||||||
|
|
||||||
# 显示修改过程
|
|
||||||
chown -v user file.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 常用选项
|
|
||||||
|
|
||||||
| 选项 | 说明 |
|
|
||||||
|------|------|
|
|
||||||
| `-R` | 递归修改目录及子目录下所有文件 |
|
|
||||||
| `-v` | 显示修改过程 |
|
|
||||||
| `-c` | 仅显示更改的文件 |
|
|
||||||
| `-f` | 静默模式,忽略错误 |
|
|
||||||
| `-h` | 修改符号链接本身而非链接目标 |
|
|
||||||
|
|
||||||
#### 与 chgrp 的区别
|
|
||||||
|
|
||||||
```shell
|
|
||||||
# chown 可同时修改所有者和所属组
|
|
||||||
chown user:group file.txt
|
|
||||||
|
|
||||||
# chgrp 只能修改所属组
|
|
||||||
chgrp group file.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 实用场景
|
|
||||||
|
|
||||||
```shell
|
|
||||||
# 部署 Web 项目
|
|
||||||
chown -R nginx:nginx /var/www/html
|
|
||||||
|
|
||||||
# 将目录交给特定用户管理
|
|
||||||
chown -R user:user /home/user/projects
|
|
||||||
|
|
||||||
# 修改 SSH 密钥权限
|
|
||||||
chmod 600 ~/.ssh/id_rsa
|
|
||||||
chown root:root ~/.ssh
|
|
||||||
chmod 700 ~/.ssh
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
title: OpenCode
|
title: OpenCode
|
||||||
date: 2026-06-13 10:34:02
|
date: 2026-06-04 10:34:02
|
||||||
tags:
|
tags:
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -201,289 +201,3 @@ opencode --version
|
|||||||
```
|
```
|
||||||
|
|
||||||
如果显示版本号,则表示安装成功。
|
如果显示版本号,则表示安装成功。
|
||||||
|
|
||||||
## 迁移 OpenCode 配置
|
|
||||||
|
|
||||||
当需要在新机器上恢复 OpenCode 配置时,可以使用以下方法迁移。
|
|
||||||
|
|
||||||
### 源机器打包
|
|
||||||
|
|
||||||
在源机器上打包 OpenCode 配置文件和目录:
|
|
||||||
|
|
||||||
##### Linux/macOS
|
|
||||||
|
|
||||||
```bash
|
|
||||||
tar -czf opencode-migration.tar.gz -C ~ \
|
|
||||||
.config/opencode/opencode.json \
|
|
||||||
.config/opencode/oh-my-openagent.json \
|
|
||||||
.config/opencode/AGENTS.md \
|
|
||||||
.agents/ \
|
|
||||||
.local/share/opencode/auth.json \
|
|
||||||
.cache/oh-my-opencode/connected-providers.json
|
|
||||||
```
|
|
||||||
|
|
||||||
**打包内容说明:**
|
|
||||||
|
|
||||||
- `opencode.json`:OpenCode 主配置文件
|
|
||||||
- `oh-my-openagent.json`:Oh My OpenAgent 配置
|
|
||||||
- `AGENTS.md`:Agent 指令文件
|
|
||||||
- `~/.agents/`:自定义 Agent 和 Skill 目录
|
|
||||||
- `auth.json`:认证信息(登录状态等)
|
|
||||||
- `connected-providers.json`:已连接的 Provider 配置
|
|
||||||
|
|
||||||
### 新机器恢复
|
|
||||||
|
|
||||||
在新机器上恢复配置:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 解压配置文件到用户目录
|
|
||||||
tar -xzf opencode-migration.tar.gz -C ~/
|
|
||||||
|
|
||||||
# 进入 OpenCode 配置目录并安装依赖
|
|
||||||
cd ~/.config/opencode && npm install
|
|
||||||
```
|
|
||||||
|
|
||||||
### 迁移后验证
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 验证 OpenCode 版本
|
|
||||||
opencode --version
|
|
||||||
|
|
||||||
# 检查配置文件是否正确恢复
|
|
||||||
ls -la ~/.config/opencode/
|
|
||||||
|
|
||||||
# 测试 Agent 是否正常
|
|
||||||
opencode agent list
|
|
||||||
```
|
|
||||||
|
|
||||||
### 注意事项
|
|
||||||
|
|
||||||
- **认证信息**:`auth.json` 包含登录凭证,迁移后可能需要重新登录
|
|
||||||
- **路径差异**:如果新机器用户名不同,需要调整配置文件中的路径
|
|
||||||
- **依赖版本**:建议在新机器上使用相同或更新的 Node.js 版本
|
|
||||||
- **权限问题**:确保解压后的文件权限正确(`chmod 600 ~/.local/share/opencode/auth.json`)
|
|
||||||
|
|
||||||
### Windows 系统迁移
|
|
||||||
|
|
||||||
Windows 下的 OpenCode 配置文件路径与 Linux/macOS 不同,需要使用 PowerShell 命令进行迁移。
|
|
||||||
|
|
||||||
#### 源机器打包(PowerShell)
|
|
||||||
|
|
||||||
```powershell
|
|
||||||
# 创建临时目录存放配置文件
|
|
||||||
$tempDir = "$env:TEMP\opencode-migration"
|
|
||||||
New-Item -ItemType Directory -Path $tempDir -Force
|
|
||||||
|
|
||||||
# 复制配置文件到临时目录
|
|
||||||
Copy-Item "$env:USERPROFILE\.config\opencode\opencode.json" $tempDir -ErrorAction SilentlyContinue
|
|
||||||
Copy-Item "$env:USERPROFILE\.config\opencode\oh-my-openagent.json" $tempDir -ErrorAction SilentlyContinue
|
|
||||||
Copy-Item "$env:USERPROFILE\.config\opencode\AGENTS.md" $tempDir -ErrorAction SilentlyContinue
|
|
||||||
Copy-Item "$env:USERPROFILE\.agents" "$tempDir\.agents" -Recurse -ErrorAction SilentlyContinue
|
|
||||||
Copy-Item "$env:USERPROFILE\.local\share\opencode\auth.json" $tempDir -ErrorAction SilentlyContinue
|
|
||||||
Copy-Item "$env:USERPROFILE\.cache\oh-my-opencode\connected-providers.json" $tempDir -ErrorAction SilentlyContinue
|
|
||||||
|
|
||||||
# 压缩为 zip 文件
|
|
||||||
Compress-Archive -Path "$tempDir\*" -DestinationPath "$env:USERPROFILE\Desktop\opencode-migration.zip"
|
|
||||||
|
|
||||||
# 清理临时目录
|
|
||||||
Remove-Item -Path $tempDir -Recurse -Force
|
|
||||||
|
|
||||||
Write-Host "配置已打包到: $env:USERPROFILE\Desktop\opencode-migration.zip"
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 新机器恢复(PowerShell)
|
|
||||||
|
|
||||||
```powershell
|
|
||||||
# 解压配置文件
|
|
||||||
$zipPath = "$env:USERPROFILE\Desktop\opencode-migration.zip"
|
|
||||||
$extractPath = "$env:USERPROFILE"
|
|
||||||
|
|
||||||
Expand-Archive -Path $zipPath -DestinationPath $extractPath -Force
|
|
||||||
|
|
||||||
# 进入 OpenCode 配置目录并安装依赖
|
|
||||||
Set-Location "$env:USERPROFILE\.config\opencode"
|
|
||||||
npm install
|
|
||||||
|
|
||||||
Write-Host "配置恢复完成!"
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Windows 配置文件路径
|
|
||||||
|
|
||||||
| 文件/目录 | Windows 路径 |
|
|
||||||
| ---------- | ----------------------------------------------- |
|
|
||||||
| 主配置目录 | `%USERPROFILE%\.config\opencode\` |
|
|
||||||
| Agent 目录 | `%USERPROFILE%\.agents\` |
|
|
||||||
| 认证信息 | `%USERPROFILE%\.local\share\opencode\auth.json` |
|
|
||||||
| 缓存目录 | `%USERPROFILE%\.cache\oh-my-opencode\` |
|
|
||||||
|
|
||||||
#### 验证迁移(PowerShell)
|
|
||||||
|
|
||||||
```powershell
|
|
||||||
# 检查配置文件是否存在
|
|
||||||
Test-Path "$env:USERPROFILE\.config\opencode\opencode.json"
|
|
||||||
Test-Path "$env:USERPROFILE\.agents"
|
|
||||||
|
|
||||||
# 查看配置目录内容
|
|
||||||
Get-ChildItem "$env:USERPROFILE\.config\opencode\"
|
|
||||||
|
|
||||||
# 验证 OpenCode 版本
|
|
||||||
opencode --version
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 使用 tar 命令(Windows 10+)
|
|
||||||
|
|
||||||
Windows 10 及更高版本内置了 tar 命令,也可以使用与 Linux/macOS 相同的方式:
|
|
||||||
|
|
||||||
```powershell
|
|
||||||
# 打包
|
|
||||||
tar -czf opencode-migration.tar.gz -C $env:USERPROFILE .config/opencode/opencode.json .config/opencode/oh-my-openagent.json .config/opencode/AGENTS.md .agents .local/share/opencode/auth.json .cache/oh-my-opencode/connected-providers.json
|
|
||||||
|
|
||||||
# 解压
|
|
||||||
tar -xzf opencode-migration.tar.gz -C $env:USERPROFILE
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 注意事项
|
|
||||||
|
|
||||||
- **路径分隔符**:Windows 使用反斜杠 `\`,但 PowerShell 也支持正斜杠 `/`
|
|
||||||
- **权限**:确保对配置目录有读写权限
|
|
||||||
- **隐藏文件**:`.config`、`.agents` 等是隐藏目录,需显示隐藏文件才能看到
|
|
||||||
- **npm 依赖**:恢复后需运行 `npm install` 安装依赖
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# OpenCode 插件
|
|
||||||
|
|
||||||
## oh-my-openagent 使用教程
|
|
||||||
|
|
||||||
**Oh My OpenAgent**(简称 **OmO**)是一个开源的 AI 编程助手增强插件,前身叫 `oh-my-opencode`。
|
|
||||||
|
|
||||||
oh-my-openagent 运行在 OpenCode这个 AI 编程工具之上,把它变成一个由 **11 个专业 AI Agent** 组成的开发团队。
|
|
||||||
|
|
||||||
用一句话解释:
|
|
||||||
|
|
||||||
> **你发一个需求 → OmO 自动调度多个 AI 并行工作 → 比单个 AI 快数倍**
|
|
||||||
|
|
||||||
目前在 GitHub 上有 **54k+ Stars**,是最受欢迎的 OpenCode 插件。
|
|
||||||
|
|
||||||
- Github 地址:https://github.com/code-yeongyu/oh-my-openagent
|
|
||||||
- 官网:https://ohmyopenagent.com/zh
|
|
||||||
|
|
||||||
### 安装
|
|
||||||
|
|
||||||
将以下提示词复制粘贴到你的大模型工具( OpenCode、Claude Code、AmpCode、Cursor 等):
|
|
||||||
|
|
||||||
```
|
|
||||||
按照此链接说明安装并配置 oh-my-opencode:https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/refs/heads/dev/docs/guide/installation.md
|
|
||||||
```
|
|
||||||
|
|
||||||
执行后,它就会自己安装好,安装过程可能有 API key 的配置选项,可以选择配置,也可以不配置:
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 认识 11 位 AI 团队成员(Agent)
|
|
||||||
|
|
||||||
OmO 内置了 11 个专门的 Agent,各司其职:
|
|
||||||
|
|
||||||
### 核心 Agent
|
|
||||||
|
|
||||||
| Agent | 角色 | 默认模型 | 什么时候用 |
|
|
||||||
| :------------- | :----------------- | :-------------------- | :--------------------------------- |
|
|
||||||
| **Sisyphus** | 主协调者、全能开发 | Claude Opus | 所有任务的入口,自动调度其他 Agent |
|
|
||||||
| **Prometheus** | 战略规划师 | Claude Opus / GPT-5.4 | 复杂任务的计划制定 |
|
|
||||||
| **Atlas** | 待办任务管理 | Kimi K2.5 | 跟踪多步骤任务进度 |
|
|
||||||
|
|
||||||
### 专业 Agent
|
|
||||||
|
|
||||||
| Agent | 角色 | 默认模型 | 擅长什么 |
|
|
||||||
| :------------- | :---------------- | :------------ | :------------------------------- |
|
|
||||||
| **Hephaestus** | 深度自主工作者 | GPT-5.3-codex | 长时间、高强度的独立编码任务 |
|
|
||||||
| **Oracle** | 架构顾问/调试专家 | GPT-5.4 | 系统设计、疑难 bug 定位 |
|
|
||||||
| **Momus** | 高精度审查员 | GPT-5.4 | 代码 review、输出验证 |
|
|
||||||
| **Metis** | 计划评审 | Claude Opus | 检查 Prometheus 的计划是否有遗漏 |
|
|
||||||
|
|
||||||
### 工具型 Agent(快速、低成本)
|
|
||||||
|
|
||||||
| Agent | 角色 | 默认模型 | 为什么用便宜模型 |
|
|
||||||
| :-------------------- | :------------- | :----------------------- | :------------------------------- |
|
|
||||||
| **Explore** | 代码库快速搜索 | MiniMax / Grok Code Fast | 搜索任务不需要高智能,速度更重要 |
|
|
||||||
| **Librarian** | 文档/代码检索 | MiniMax(免费) | 文档检索不需要深度推理 |
|
|
||||||
| **Multimodal Looker** | 截图/视觉分析 | Kimi K2.5 | Kimi 擅长多模态理解 |
|
|
||||||
|
|
||||||
> 💡 **新手提示**:你不需要手动选择 Agent。Sisyphus 会根据你的任务类型自动调度合适的 Agent 组合。
|
|
||||||
|
|
||||||
## 三种工作模式
|
|
||||||
|
|
||||||
### 模式一:ultrawork(最轻松)
|
|
||||||
|
|
||||||
在提示词里加 `ultrawork` 或 `ulw`,一切自动化:
|
|
||||||
|
|
||||||
```
|
|
||||||
ultrawork 帮我把这个 React 组件改成 TypeScript
|
|
||||||
```
|
|
||||||
|
|
||||||
适合:日常开发任务,希望 AI 全自动完成的场景。
|
|
||||||
|
|
||||||
### 模式二:Prometheus 计划模式(最精准)
|
|
||||||
|
|
||||||
按 **Tab 键** 进入 Prometheus 模式。AI 会先通过问答了解你的需求,生成详细执行计划,确认后再开始执行。
|
|
||||||
|
|
||||||
流程:
|
|
||||||
|
|
||||||
1. 按 `Tab` 切换到 Prometheus 模式
|
|
||||||
2. 描述你的需求,AI 会问你一些澄清问题
|
|
||||||
3. AI 生成执行计划,你确认
|
|
||||||
4. 输入 `/start-work` 开始执行
|
|
||||||
|
|
||||||
适合:复杂功能开发、架构重构等需要精确规划的场景。
|
|
||||||
|
|
||||||
### 模式三:普通对话(最灵活)
|
|
||||||
|
|
||||||
直接输入你的问题或需求,不加任何关键词:
|
|
||||||
|
|
||||||
```
|
|
||||||
解释一下 src/auth.ts 里的 JWT 验证逻辑
|
|
||||||
```
|
|
||||||
|
|
||||||
适合:问问题、代码解释、小修改等轻量任务。
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 配置文件详解
|
|
||||||
|
|
||||||
OmO 有两个配置文件,优先级不同:
|
|
||||||
|
|
||||||
- 项目级配置(优先级更高):**.opencode/oh-my-opencode.jsonc**
|
|
||||||
- 用户级配置(全局默认):**~/.config/opencode/oh-my-opencode.jsonc**
|
|
||||||
|
|
||||||
配置文件支持注释(JSONC 格式),也支持 JSON Schema 自动补全:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json",
|
|
||||||
|
|
||||||
"agents": {
|
|
||||||
// 主协调 Agent,官方建议用 Claude Opus 系列
|
|
||||||
"sisyphus": {
|
|
||||||
"model": "anthropic/claude-opus-4-6"
|
|
||||||
},
|
|
||||||
// 架构顾问,官方建议用 GPT 系列
|
|
||||||
"Hephaestus": {
|
|
||||||
"model": "openai/gpt-5.4",
|
|
||||||
"variant": "high"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
> **新手建议**:安装完成后先不要修改配置,默认设置已经很好。
|
|
||||||
|
|
||||||
## 常用命令
|
|
||||||
|
|
||||||
在对话界面内:
|
|
||||||
|
|
||||||
| 快捷键/命令 | 说明 |
|
|
||||||
| :------------------ | :--------------------------------- |
|
|
||||||
| `Tab` | 切换到 Prometheus 计划模式 |
|
|
||||||
| `/start-work` | 在 Prometheus 模式下开始执行计划 |
|
|
||||||
| `ultrawork` / `ulw` | 在提示词里加上,激活全功能并行模式 |
|
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user