diff --git a/.gitignore b/.gitignore
index 3ad5eca..fa136c5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,8 +10,6 @@ data/
.env
.env.local
.DS_Store
-dashscope_key.txt
-deepseek_key.txt
__pycache__/
*.py[cod]
.env.*
diff --git a/README.md b/README.md
index d96e2e4..a3f0bc5 100644
--- a/README.md
+++ b/README.md
@@ -30,4 +30,4 @@ npm --prefix client run test -- --run
npm --prefix client run build
```
-产品、数据库与验收设计见 [docs](docs/)。标准 Skill 源文件位于 [标准Skills](标准Skills/),仅作为开发素材保留,不参与应用启动同步。
+产品、数据库与验收设计见 [docs](docs/)。内置 Skill 与资源由 Flyway 种子迁移写入数据库,无需额外导入文件。
diff --git a/dashscope_key.txt b/dashscope_key.txt
new file mode 100644
index 0000000..8247914
--- /dev/null
+++ b/dashscope_key.txt
@@ -0,0 +1 @@
+sk-ws-H.EPYDEHX.hEpq.MEYCIQCvMQg2IhYKPVDB76hcNSvgbVVQ_npnqH6s2cRjiniBKAIhAN1UmUSUg6fiJLhYt3rJXONC6YrC7BlfzYd-FPqrIiD9
diff --git a/deepseek_key.txt b/deepseek_key.txt
new file mode 100644
index 0000000..2f144b3
--- /dev/null
+++ b/deepseek_key.txt
@@ -0,0 +1 @@
+sk-8d1419754bce4306bc99854ee5ccd505
diff --git a/server/pom.xml b/server/pom.xml
index e2b3316..3011530 100644
--- a/server/pom.xml
+++ b/server/pom.xml
@@ -11,10 +11,10 @@
- cn.alphaline
+ tech.easyflowManuAgent-server
- 0.1.0-SNAPSHOT
- Smart Factory Approval Agent
+ 0.1.0
+ ManuAgent21
diff --git a/server/src/main/java/cn/alphaline/smartfactory/SmartFactoryApplication.java b/server/src/main/java/tech/easyflow/manuagent/ManuAgentApplication.java
similarity index 70%
rename from server/src/main/java/cn/alphaline/smartfactory/SmartFactoryApplication.java
rename to server/src/main/java/tech/easyflow/manuagent/ManuAgentApplication.java
index 38c82d2..e2a93f5 100644
--- a/server/src/main/java/cn/alphaline/smartfactory/SmartFactoryApplication.java
+++ b/server/src/main/java/tech/easyflow/manuagent/ManuAgentApplication.java
@@ -1,6 +1,6 @@
-package cn.alphaline.smartfactory;
+package tech.easyflow.manuagent;
-import cn.alphaline.smartfactory.config.AppProperties;
+import tech.easyflow.manuagent.config.AppProperties;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
@@ -10,7 +10,7 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
*/
@SpringBootApplication
@EnableConfigurationProperties(AppProperties.class)
-public class SmartFactoryApplication {
+public class ManuAgentApplication {
/**
* 启动 Spring Boot 应用。
@@ -18,7 +18,7 @@ public class SmartFactoryApplication {
* @param args 命令行参数
*/
public static void main(String[] args) {
- SpringApplication.run(SmartFactoryApplication.class, args);
+ SpringApplication.run(ManuAgentApplication.class, args);
}
}
diff --git a/server/src/main/java/cn/alphaline/smartfactory/agent/AgentController.java b/server/src/main/java/tech/easyflow/manuagent/agent/AgentController.java
similarity index 99%
rename from server/src/main/java/cn/alphaline/smartfactory/agent/AgentController.java
rename to server/src/main/java/tech/easyflow/manuagent/agent/AgentController.java
index fd7fa41..7136069 100644
--- a/server/src/main/java/cn/alphaline/smartfactory/agent/AgentController.java
+++ b/server/src/main/java/tech/easyflow/manuagent/agent/AgentController.java
@@ -1,4 +1,4 @@
-package cn.alphaline.smartfactory.agent;
+package tech.easyflow.manuagent.agent;
import com.fasterxml.jackson.databind.JsonNode;
import java.security.Principal;
diff --git a/server/src/main/java/cn/alphaline/smartfactory/agent/AgentEventService.java b/server/src/main/java/tech/easyflow/manuagent/agent/AgentEventService.java
similarity index 99%
rename from server/src/main/java/cn/alphaline/smartfactory/agent/AgentEventService.java
rename to server/src/main/java/tech/easyflow/manuagent/agent/AgentEventService.java
index 55d52bc..87e067f 100644
--- a/server/src/main/java/cn/alphaline/smartfactory/agent/AgentEventService.java
+++ b/server/src/main/java/tech/easyflow/manuagent/agent/AgentEventService.java
@@ -1,4 +1,4 @@
-package cn.alphaline.smartfactory.agent;
+package tech.easyflow.manuagent.agent;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
diff --git a/server/src/main/java/cn/alphaline/smartfactory/agent/AgentExecutionService.java b/server/src/main/java/tech/easyflow/manuagent/agent/AgentExecutionService.java
similarity index 98%
rename from server/src/main/java/cn/alphaline/smartfactory/agent/AgentExecutionService.java
rename to server/src/main/java/tech/easyflow/manuagent/agent/AgentExecutionService.java
index 081c026..9e5a21f 100644
--- a/server/src/main/java/cn/alphaline/smartfactory/agent/AgentExecutionService.java
+++ b/server/src/main/java/tech/easyflow/manuagent/agent/AgentExecutionService.java
@@ -1,8 +1,8 @@
-package cn.alphaline.smartfactory.agent;
+package tech.easyflow.manuagent.agent;
-import cn.alphaline.smartfactory.project.ProjectFileService;
-import cn.alphaline.smartfactory.project.ProjectService;
-import cn.alphaline.smartfactory.skill.SkillService;
+import tech.easyflow.manuagent.project.ProjectFileService;
+import tech.easyflow.manuagent.project.ProjectService;
+import tech.easyflow.manuagent.skill.SkillService;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
diff --git a/server/src/main/java/cn/alphaline/smartfactory/agent/AgentFactory.java b/server/src/main/java/tech/easyflow/manuagent/agent/AgentFactory.java
similarity index 98%
rename from server/src/main/java/cn/alphaline/smartfactory/agent/AgentFactory.java
rename to server/src/main/java/tech/easyflow/manuagent/agent/AgentFactory.java
index c4416d2..03f27c6 100644
--- a/server/src/main/java/cn/alphaline/smartfactory/agent/AgentFactory.java
+++ b/server/src/main/java/tech/easyflow/manuagent/agent/AgentFactory.java
@@ -1,8 +1,8 @@
-package cn.alphaline.smartfactory.agent;
+package tech.easyflow.manuagent.agent;
-import cn.alphaline.smartfactory.config.AppProperties;
-import cn.alphaline.smartfactory.model.ModelService;
-import cn.alphaline.smartfactory.project.ProjectFileService;
+import tech.easyflow.manuagent.config.AppProperties;
+import tech.easyflow.manuagent.model.ModelService;
+import tech.easyflow.manuagent.project.ProjectFileService;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.agentscope.core.agui.adapter.AguiAdapterConfig;
import io.agentscope.core.agui.adapter.AguiAgentAdapter;
diff --git a/server/src/main/java/cn/alphaline/smartfactory/agent/AgentOutputService.java b/server/src/main/java/tech/easyflow/manuagent/agent/AgentOutputService.java
similarity index 97%
rename from server/src/main/java/cn/alphaline/smartfactory/agent/AgentOutputService.java
rename to server/src/main/java/tech/easyflow/manuagent/agent/AgentOutputService.java
index ad45305..7e2d43a 100644
--- a/server/src/main/java/cn/alphaline/smartfactory/agent/AgentOutputService.java
+++ b/server/src/main/java/tech/easyflow/manuagent/agent/AgentOutputService.java
@@ -1,7 +1,7 @@
-package cn.alphaline.smartfactory.agent;
+package tech.easyflow.manuagent.agent;
-import cn.alphaline.smartfactory.common.ApiException;
-import cn.alphaline.smartfactory.project.ProjectFileService;
+import tech.easyflow.manuagent.common.ApiException;
+import tech.easyflow.manuagent.project.ProjectFileService;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
diff --git a/server/src/main/java/cn/alphaline/smartfactory/agent/AgentRunService.java b/server/src/main/java/tech/easyflow/manuagent/agent/AgentRunService.java
similarity index 98%
rename from server/src/main/java/cn/alphaline/smartfactory/agent/AgentRunService.java
rename to server/src/main/java/tech/easyflow/manuagent/agent/AgentRunService.java
index d5c3bea..7afc413 100644
--- a/server/src/main/java/cn/alphaline/smartfactory/agent/AgentRunService.java
+++ b/server/src/main/java/tech/easyflow/manuagent/agent/AgentRunService.java
@@ -1,10 +1,10 @@
-package cn.alphaline.smartfactory.agent;
+package tech.easyflow.manuagent.agent;
-import cn.alphaline.smartfactory.artifact.ArtifactService;
-import cn.alphaline.smartfactory.auth.UserService;
-import cn.alphaline.smartfactory.common.ApiException;
-import cn.alphaline.smartfactory.project.ProjectFileService;
-import cn.alphaline.smartfactory.project.ProjectService;
+import tech.easyflow.manuagent.artifact.ArtifactService;
+import tech.easyflow.manuagent.auth.UserService;
+import tech.easyflow.manuagent.common.ApiException;
+import tech.easyflow.manuagent.project.ProjectFileService;
+import tech.easyflow.manuagent.project.ProjectService;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
diff --git a/server/src/main/java/cn/alphaline/smartfactory/agent/AgentRunStore.java b/server/src/main/java/tech/easyflow/manuagent/agent/AgentRunStore.java
similarity index 98%
rename from server/src/main/java/cn/alphaline/smartfactory/agent/AgentRunStore.java
rename to server/src/main/java/tech/easyflow/manuagent/agent/AgentRunStore.java
index 4852eea..a18d0f7 100644
--- a/server/src/main/java/cn/alphaline/smartfactory/agent/AgentRunStore.java
+++ b/server/src/main/java/tech/easyflow/manuagent/agent/AgentRunStore.java
@@ -1,7 +1,7 @@
-package cn.alphaline.smartfactory.agent;
+package tech.easyflow.manuagent.agent;
-import cn.alphaline.smartfactory.common.ApiException;
-import cn.alphaline.smartfactory.project.ProjectService;
+import tech.easyflow.manuagent.common.ApiException;
+import tech.easyflow.manuagent.project.ProjectService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
diff --git a/server/src/main/java/cn/alphaline/smartfactory/agent/DocumentViewTool.java b/server/src/main/java/tech/easyflow/manuagent/agent/DocumentViewTool.java
similarity index 99%
rename from server/src/main/java/cn/alphaline/smartfactory/agent/DocumentViewTool.java
rename to server/src/main/java/tech/easyflow/manuagent/agent/DocumentViewTool.java
index 0a25234..dc06913 100644
--- a/server/src/main/java/cn/alphaline/smartfactory/agent/DocumentViewTool.java
+++ b/server/src/main/java/tech/easyflow/manuagent/agent/DocumentViewTool.java
@@ -1,4 +1,4 @@
-package cn.alphaline.smartfactory.agent;
+package tech.easyflow.manuagent.agent;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
diff --git a/server/src/main/java/cn/alphaline/smartfactory/agent/PagedReadFileTool.java b/server/src/main/java/tech/easyflow/manuagent/agent/PagedReadFileTool.java
similarity index 99%
rename from server/src/main/java/cn/alphaline/smartfactory/agent/PagedReadFileTool.java
rename to server/src/main/java/tech/easyflow/manuagent/agent/PagedReadFileTool.java
index 5869ae3..9d5d286 100644
--- a/server/src/main/java/cn/alphaline/smartfactory/agent/PagedReadFileTool.java
+++ b/server/src/main/java/tech/easyflow/manuagent/agent/PagedReadFileTool.java
@@ -1,4 +1,4 @@
-package cn.alphaline.smartfactory.agent;
+package tech.easyflow.manuagent.agent;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
diff --git a/server/src/main/java/cn/alphaline/smartfactory/agent/RunRecoveryService.java b/server/src/main/java/tech/easyflow/manuagent/agent/RunRecoveryService.java
similarity index 96%
rename from server/src/main/java/cn/alphaline/smartfactory/agent/RunRecoveryService.java
rename to server/src/main/java/tech/easyflow/manuagent/agent/RunRecoveryService.java
index 4a4144f..12a6e2e 100644
--- a/server/src/main/java/cn/alphaline/smartfactory/agent/RunRecoveryService.java
+++ b/server/src/main/java/tech/easyflow/manuagent/agent/RunRecoveryService.java
@@ -1,4 +1,4 @@
-package cn.alphaline.smartfactory.agent;
+package tech.easyflow.manuagent.agent;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
diff --git a/server/src/main/java/cn/alphaline/smartfactory/artifact/ArtifactController.java b/server/src/main/java/tech/easyflow/manuagent/artifact/ArtifactController.java
similarity index 97%
rename from server/src/main/java/cn/alphaline/smartfactory/artifact/ArtifactController.java
rename to server/src/main/java/tech/easyflow/manuagent/artifact/ArtifactController.java
index 394877d..65b1613 100644
--- a/server/src/main/java/cn/alphaline/smartfactory/artifact/ArtifactController.java
+++ b/server/src/main/java/tech/easyflow/manuagent/artifact/ArtifactController.java
@@ -1,4 +1,4 @@
-package cn.alphaline.smartfactory.artifact;
+package tech.easyflow.manuagent.artifact;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
diff --git a/server/src/main/java/cn/alphaline/smartfactory/artifact/ArtifactService.java b/server/src/main/java/tech/easyflow/manuagent/artifact/ArtifactService.java
similarity index 98%
rename from server/src/main/java/cn/alphaline/smartfactory/artifact/ArtifactService.java
rename to server/src/main/java/tech/easyflow/manuagent/artifact/ArtifactService.java
index b8ef34b..0f7ae27 100644
--- a/server/src/main/java/cn/alphaline/smartfactory/artifact/ArtifactService.java
+++ b/server/src/main/java/tech/easyflow/manuagent/artifact/ArtifactService.java
@@ -1,7 +1,7 @@
-package cn.alphaline.smartfactory.artifact;
+package tech.easyflow.manuagent.artifact;
-import cn.alphaline.smartfactory.common.ApiException;
-import cn.alphaline.smartfactory.project.ProjectFileService;
+import tech.easyflow.manuagent.common.ApiException;
+import tech.easyflow.manuagent.project.ProjectFileService;
import com.fasterxml.jackson.databind.JsonNode;
import java.io.IOException;
import java.io.InputStream;
diff --git a/server/src/main/java/cn/alphaline/smartfactory/artifact/DocxValidator.java b/server/src/main/java/tech/easyflow/manuagent/artifact/DocxValidator.java
similarity index 98%
rename from server/src/main/java/cn/alphaline/smartfactory/artifact/DocxValidator.java
rename to server/src/main/java/tech/easyflow/manuagent/artifact/DocxValidator.java
index fd60dd5..9645510 100644
--- a/server/src/main/java/cn/alphaline/smartfactory/artifact/DocxValidator.java
+++ b/server/src/main/java/tech/easyflow/manuagent/artifact/DocxValidator.java
@@ -1,6 +1,6 @@
-package cn.alphaline.smartfactory.artifact;
+package tech.easyflow.manuagent.artifact;
-import cn.alphaline.smartfactory.common.ApiException;
+import tech.easyflow.manuagent.common.ApiException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
diff --git a/server/src/main/java/cn/alphaline/smartfactory/auth/AuthController.java b/server/src/main/java/tech/easyflow/manuagent/auth/AuthController.java
similarity index 97%
rename from server/src/main/java/cn/alphaline/smartfactory/auth/AuthController.java
rename to server/src/main/java/tech/easyflow/manuagent/auth/AuthController.java
index 59edd2a..c123666 100644
--- a/server/src/main/java/cn/alphaline/smartfactory/auth/AuthController.java
+++ b/server/src/main/java/tech/easyflow/manuagent/auth/AuthController.java
@@ -1,4 +1,4 @@
-package cn.alphaline.smartfactory.auth;
+package tech.easyflow.manuagent.auth;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
@@ -17,7 +17,6 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
/**
diff --git a/server/src/main/java/cn/alphaline/smartfactory/auth/UserService.java b/server/src/main/java/tech/easyflow/manuagent/auth/UserService.java
similarity index 96%
rename from server/src/main/java/cn/alphaline/smartfactory/auth/UserService.java
rename to server/src/main/java/tech/easyflow/manuagent/auth/UserService.java
index a0edff8..bfdccc5 100644
--- a/server/src/main/java/cn/alphaline/smartfactory/auth/UserService.java
+++ b/server/src/main/java/tech/easyflow/manuagent/auth/UserService.java
@@ -1,7 +1,7 @@
-package cn.alphaline.smartfactory.auth;
+package tech.easyflow.manuagent.auth;
-import cn.alphaline.smartfactory.common.ApiException;
-import cn.alphaline.smartfactory.config.AppProperties;
+import tech.easyflow.manuagent.common.ApiException;
+import tech.easyflow.manuagent.config.AppProperties;
import java.util.UUID;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
diff --git a/server/src/main/java/cn/alphaline/smartfactory/common/ApiError.java b/server/src/main/java/tech/easyflow/manuagent/common/ApiError.java
similarity index 87%
rename from server/src/main/java/cn/alphaline/smartfactory/common/ApiError.java
rename to server/src/main/java/tech/easyflow/manuagent/common/ApiError.java
index 3480598..3677fda 100644
--- a/server/src/main/java/cn/alphaline/smartfactory/common/ApiError.java
+++ b/server/src/main/java/tech/easyflow/manuagent/common/ApiError.java
@@ -1,4 +1,4 @@
-package cn.alphaline.smartfactory.common;
+package tech.easyflow.manuagent.common;
import java.time.Instant;
diff --git a/server/src/main/java/cn/alphaline/smartfactory/common/ApiException.java b/server/src/main/java/tech/easyflow/manuagent/common/ApiException.java
similarity index 95%
rename from server/src/main/java/cn/alphaline/smartfactory/common/ApiException.java
rename to server/src/main/java/tech/easyflow/manuagent/common/ApiException.java
index b8ec4b4..70a7707 100644
--- a/server/src/main/java/cn/alphaline/smartfactory/common/ApiException.java
+++ b/server/src/main/java/tech/easyflow/manuagent/common/ApiException.java
@@ -1,4 +1,4 @@
-package cn.alphaline.smartfactory.common;
+package tech.easyflow.manuagent.common;
import org.springframework.http.HttpStatus;
diff --git a/server/src/main/java/cn/alphaline/smartfactory/common/GlobalExceptionHandler.java b/server/src/main/java/tech/easyflow/manuagent/common/GlobalExceptionHandler.java
similarity index 99%
rename from server/src/main/java/cn/alphaline/smartfactory/common/GlobalExceptionHandler.java
rename to server/src/main/java/tech/easyflow/manuagent/common/GlobalExceptionHandler.java
index 69426a6..a2dea98 100644
--- a/server/src/main/java/cn/alphaline/smartfactory/common/GlobalExceptionHandler.java
+++ b/server/src/main/java/tech/easyflow/manuagent/common/GlobalExceptionHandler.java
@@ -1,4 +1,4 @@
-package cn.alphaline.smartfactory.common;
+package tech.easyflow.manuagent.common;
import jakarta.validation.ConstraintViolationException;
import java.util.UUID;
diff --git a/server/src/main/java/cn/alphaline/smartfactory/common/TraceIdFilter.java b/server/src/main/java/tech/easyflow/manuagent/common/TraceIdFilter.java
similarity index 97%
rename from server/src/main/java/cn/alphaline/smartfactory/common/TraceIdFilter.java
rename to server/src/main/java/tech/easyflow/manuagent/common/TraceIdFilter.java
index 0e14796..98d526d 100644
--- a/server/src/main/java/cn/alphaline/smartfactory/common/TraceIdFilter.java
+++ b/server/src/main/java/tech/easyflow/manuagent/common/TraceIdFilter.java
@@ -1,4 +1,4 @@
-package cn.alphaline.smartfactory.common;
+package tech.easyflow.manuagent.common;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
diff --git a/server/src/main/java/cn/alphaline/smartfactory/config/AppProperties.java b/server/src/main/java/tech/easyflow/manuagent/config/AppProperties.java
similarity index 96%
rename from server/src/main/java/cn/alphaline/smartfactory/config/AppProperties.java
rename to server/src/main/java/tech/easyflow/manuagent/config/AppProperties.java
index f76d20e..a6b5d54 100644
--- a/server/src/main/java/cn/alphaline/smartfactory/config/AppProperties.java
+++ b/server/src/main/java/tech/easyflow/manuagent/config/AppProperties.java
@@ -1,4 +1,4 @@
-package cn.alphaline.smartfactory.config;
+package tech.easyflow.manuagent.config;
import java.nio.file.Path;
import java.time.Duration;
diff --git a/server/src/main/java/cn/alphaline/smartfactory/config/InfraConfig.java b/server/src/main/java/tech/easyflow/manuagent/config/InfraConfig.java
similarity index 96%
rename from server/src/main/java/cn/alphaline/smartfactory/config/InfraConfig.java
rename to server/src/main/java/tech/easyflow/manuagent/config/InfraConfig.java
index 73351f8..01c43bf 100644
--- a/server/src/main/java/cn/alphaline/smartfactory/config/InfraConfig.java
+++ b/server/src/main/java/tech/easyflow/manuagent/config/InfraConfig.java
@@ -1,4 +1,4 @@
-package cn.alphaline.smartfactory.config;
+package tech.easyflow.manuagent.config;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
diff --git a/server/src/main/java/cn/alphaline/smartfactory/config/SecurityConfig.java b/server/src/main/java/tech/easyflow/manuagent/config/SecurityConfig.java
similarity index 96%
rename from server/src/main/java/cn/alphaline/smartfactory/config/SecurityConfig.java
rename to server/src/main/java/tech/easyflow/manuagent/config/SecurityConfig.java
index 8c27c87..f72ac20 100644
--- a/server/src/main/java/cn/alphaline/smartfactory/config/SecurityConfig.java
+++ b/server/src/main/java/tech/easyflow/manuagent/config/SecurityConfig.java
@@ -1,7 +1,7 @@
-package cn.alphaline.smartfactory.config;
+package tech.easyflow.manuagent.config;
-import cn.alphaline.smartfactory.auth.UserService;
-import cn.alphaline.smartfactory.common.ApiError;
+import tech.easyflow.manuagent.auth.UserService;
+import tech.easyflow.manuagent.common.ApiError;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.time.Instant;
import java.util.UUID;
diff --git a/server/src/main/java/cn/alphaline/smartfactory/config/SkillRepositoryConfig.java b/server/src/main/java/tech/easyflow/manuagent/config/SkillRepositoryConfig.java
similarity index 95%
rename from server/src/main/java/cn/alphaline/smartfactory/config/SkillRepositoryConfig.java
rename to server/src/main/java/tech/easyflow/manuagent/config/SkillRepositoryConfig.java
index f991855..a5080a7 100644
--- a/server/src/main/java/cn/alphaline/smartfactory/config/SkillRepositoryConfig.java
+++ b/server/src/main/java/tech/easyflow/manuagent/config/SkillRepositoryConfig.java
@@ -1,4 +1,4 @@
-package cn.alphaline.smartfactory.config;
+package tech.easyflow.manuagent.config;
import io.agentscope.core.skill.repository.postgresql.PostgresSkillRepository;
import javax.sql.DataSource;
diff --git a/server/src/main/java/cn/alphaline/smartfactory/model/KeyCipher.java b/server/src/main/java/tech/easyflow/manuagent/model/KeyCipher.java
similarity index 95%
rename from server/src/main/java/cn/alphaline/smartfactory/model/KeyCipher.java
rename to server/src/main/java/tech/easyflow/manuagent/model/KeyCipher.java
index c1ff9a9..3738a35 100644
--- a/server/src/main/java/cn/alphaline/smartfactory/model/KeyCipher.java
+++ b/server/src/main/java/tech/easyflow/manuagent/model/KeyCipher.java
@@ -1,7 +1,7 @@
-package cn.alphaline.smartfactory.model;
+package tech.easyflow.manuagent.model;
-import cn.alphaline.smartfactory.common.ApiException;
-import cn.alphaline.smartfactory.config.AppProperties;
+import tech.easyflow.manuagent.common.ApiException;
+import tech.easyflow.manuagent.config.AppProperties;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
diff --git a/server/src/main/java/cn/alphaline/smartfactory/model/ModelController.java b/server/src/main/java/tech/easyflow/manuagent/model/ModelController.java
similarity index 98%
rename from server/src/main/java/cn/alphaline/smartfactory/model/ModelController.java
rename to server/src/main/java/tech/easyflow/manuagent/model/ModelController.java
index 5cb8a96..0e8dddd 100644
--- a/server/src/main/java/cn/alphaline/smartfactory/model/ModelController.java
+++ b/server/src/main/java/tech/easyflow/manuagent/model/ModelController.java
@@ -1,4 +1,4 @@
-package cn.alphaline.smartfactory.model;
+package tech.easyflow.manuagent.model;
import jakarta.validation.Valid;
import java.security.Principal;
diff --git a/server/src/main/java/cn/alphaline/smartfactory/model/ModelService.java b/server/src/main/java/tech/easyflow/manuagent/model/ModelService.java
similarity index 98%
rename from server/src/main/java/cn/alphaline/smartfactory/model/ModelService.java
rename to server/src/main/java/tech/easyflow/manuagent/model/ModelService.java
index d375519..4669940 100644
--- a/server/src/main/java/cn/alphaline/smartfactory/model/ModelService.java
+++ b/server/src/main/java/tech/easyflow/manuagent/model/ModelService.java
@@ -1,8 +1,8 @@
-package cn.alphaline.smartfactory.model;
+package tech.easyflow.manuagent.model;
-import cn.alphaline.smartfactory.auth.UserService;
-import cn.alphaline.smartfactory.common.ApiException;
-import cn.alphaline.smartfactory.config.AppProperties;
+import tech.easyflow.manuagent.auth.UserService;
+import tech.easyflow.manuagent.common.ApiException;
+import tech.easyflow.manuagent.config.AppProperties;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.net.URI;
diff --git a/server/src/main/java/cn/alphaline/smartfactory/project/ProjectController.java b/server/src/main/java/tech/easyflow/manuagent/project/ProjectController.java
similarity index 98%
rename from server/src/main/java/cn/alphaline/smartfactory/project/ProjectController.java
rename to server/src/main/java/tech/easyflow/manuagent/project/ProjectController.java
index b750eca..09ac81b 100644
--- a/server/src/main/java/cn/alphaline/smartfactory/project/ProjectController.java
+++ b/server/src/main/java/tech/easyflow/manuagent/project/ProjectController.java
@@ -1,6 +1,6 @@
-package cn.alphaline.smartfactory.project;
+package tech.easyflow.manuagent.project;
-import cn.alphaline.smartfactory.agent.AgentRunService;
+import tech.easyflow.manuagent.agent.AgentRunService;
import com.fasterxml.jackson.databind.JsonNode;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
diff --git a/server/src/main/java/cn/alphaline/smartfactory/project/ProjectFileService.java b/server/src/main/java/tech/easyflow/manuagent/project/ProjectFileService.java
similarity index 98%
rename from server/src/main/java/cn/alphaline/smartfactory/project/ProjectFileService.java
rename to server/src/main/java/tech/easyflow/manuagent/project/ProjectFileService.java
index 201577f..46c4b9d 100644
--- a/server/src/main/java/cn/alphaline/smartfactory/project/ProjectFileService.java
+++ b/server/src/main/java/tech/easyflow/manuagent/project/ProjectFileService.java
@@ -1,8 +1,8 @@
-package cn.alphaline.smartfactory.project;
+package tech.easyflow.manuagent.project;
-import cn.alphaline.smartfactory.auth.UserService;
-import cn.alphaline.smartfactory.common.ApiException;
-import cn.alphaline.smartfactory.config.AppProperties;
+import tech.easyflow.manuagent.auth.UserService;
+import tech.easyflow.manuagent.common.ApiException;
+import tech.easyflow.manuagent.config.AppProperties;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
diff --git a/server/src/main/java/cn/alphaline/smartfactory/project/ProjectService.java b/server/src/main/java/tech/easyflow/manuagent/project/ProjectService.java
similarity index 98%
rename from server/src/main/java/cn/alphaline/smartfactory/project/ProjectService.java
rename to server/src/main/java/tech/easyflow/manuagent/project/ProjectService.java
index 59c2ed8..c7d7e24 100644
--- a/server/src/main/java/cn/alphaline/smartfactory/project/ProjectService.java
+++ b/server/src/main/java/tech/easyflow/manuagent/project/ProjectService.java
@@ -1,7 +1,7 @@
-package cn.alphaline.smartfactory.project;
+package tech.easyflow.manuagent.project;
-import cn.alphaline.smartfactory.auth.UserService;
-import cn.alphaline.smartfactory.common.ApiException;
+import tech.easyflow.manuagent.auth.UserService;
+import tech.easyflow.manuagent.common.ApiException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
diff --git a/server/src/main/java/cn/alphaline/smartfactory/skill/SkillController.java b/server/src/main/java/tech/easyflow/manuagent/skill/SkillController.java
similarity index 98%
rename from server/src/main/java/cn/alphaline/smartfactory/skill/SkillController.java
rename to server/src/main/java/tech/easyflow/manuagent/skill/SkillController.java
index 0580c89..0f97a34 100644
--- a/server/src/main/java/cn/alphaline/smartfactory/skill/SkillController.java
+++ b/server/src/main/java/tech/easyflow/manuagent/skill/SkillController.java
@@ -1,4 +1,4 @@
-package cn.alphaline.smartfactory.skill;
+package tech.easyflow.manuagent.skill;
import java.security.Principal;
import java.util.List;
diff --git a/server/src/main/java/cn/alphaline/smartfactory/skill/SkillPackageReader.java b/server/src/main/java/tech/easyflow/manuagent/skill/SkillPackageReader.java
similarity index 97%
rename from server/src/main/java/cn/alphaline/smartfactory/skill/SkillPackageReader.java
rename to server/src/main/java/tech/easyflow/manuagent/skill/SkillPackageReader.java
index a36fabd..9935a29 100644
--- a/server/src/main/java/cn/alphaline/smartfactory/skill/SkillPackageReader.java
+++ b/server/src/main/java/tech/easyflow/manuagent/skill/SkillPackageReader.java
@@ -1,6 +1,6 @@
-package cn.alphaline.smartfactory.skill;
+package tech.easyflow.manuagent.skill;
-import cn.alphaline.smartfactory.common.ApiException;
+import tech.easyflow.manuagent.common.ApiException;
import io.agentscope.core.skill.AgentSkill;
import java.io.IOException;
import java.nio.ByteBuffer;
@@ -11,7 +11,6 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
-import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HexFormat;
diff --git a/server/src/main/java/cn/alphaline/smartfactory/skill/SkillService.java b/server/src/main/java/tech/easyflow/manuagent/skill/SkillService.java
similarity index 98%
rename from server/src/main/java/cn/alphaline/smartfactory/skill/SkillService.java
rename to server/src/main/java/tech/easyflow/manuagent/skill/SkillService.java
index 067dd2d..24d7fe3 100644
--- a/server/src/main/java/cn/alphaline/smartfactory/skill/SkillService.java
+++ b/server/src/main/java/tech/easyflow/manuagent/skill/SkillService.java
@@ -1,8 +1,8 @@
-package cn.alphaline.smartfactory.skill;
+package tech.easyflow.manuagent.skill;
-import cn.alphaline.smartfactory.auth.UserService;
-import cn.alphaline.smartfactory.common.ApiException;
-import cn.alphaline.smartfactory.config.AppProperties;
+import tech.easyflow.manuagent.auth.UserService;
+import tech.easyflow.manuagent.common.ApiException;
+import tech.easyflow.manuagent.config.AppProperties;
import io.agentscope.core.skill.AgentSkill;
import io.agentscope.core.skill.repository.postgresql.PostgresSkillRepository;
import java.io.IOException;
diff --git a/server/src/main/resources/application.yml b/server/src/main/resources/application.yml
index 2c9d6c1..504bb8a 100644
--- a/server/src/main/resources/application.yml
+++ b/server/src/main/resources/application.yml
@@ -1,10 +1,10 @@
spring:
application:
- name: smart-factory-approval-agent
+ name: manu-agent
datasource:
- url: ${SPRING_DATASOURCE_URL:jdbc:postgresql://localhost:54330/smart_factory_agent}
- username: ${SPRING_DATASOURCE_USERNAME:smart_factory}
- password: ${SPRING_DATASOURCE_PASSWORD:smart_factory}
+ url: jdbc:postgresql://localhost:54330/smart_factory_agent
+ username: smart_factory
+ password: smart_factory
hikari:
maximum-pool-size: 12
minimum-idle: 2
@@ -22,27 +22,27 @@ spring:
default-property-inclusion: non_null
server:
- port: ${SERVER_PORT:8080}
+ port: 8080
servlet:
session:
cookie:
http-only: true
same-site: lax
- secure: ${SESSION_COOKIE_SECURE:false}
+ secure: false
app:
- data-root: ${APP_DATA_ROOT:file:../data}
- deepseek-key-file: ${DEEPSEEK_KEY_FILE:./deepseek_key.txt}
- dashscope-key-file: ${DASHSCOPE_KEY_FILE:./dashscope_key.txt}
- master-key: ${APP_MASTER_KEY:smart-factory-local-master-key}
- admin-username: ${APP_ADMIN_USERNAME:admin}
- admin-password: ${APP_ADMIN_PASSWORD:admin123}
- model-base-url: ${APP_MODEL_BASE_URL:https://api.deepseek.com}
- model-id: ${APP_MODEL_ID:deepseek-v4-flash}
- model-context-window: ${APP_MODEL_CONTEXT_WINDOW:131072}
- sandbox-image: ${APP_SANDBOX_IMAGE:smart-factory-agent-runtime:0.1.0}
- sandbox-network: ${APP_SANDBOX_NETWORK:bridge}
- run-timeout: ${APP_RUN_TIMEOUT:60m}
+ data-root: file:../data
+ deepseek-key-file: ./deepseek_key.txt
+ dashscope-key-file: ./dashscope_key.txt
+ master-key: smart-factory-local-master-key
+ admin-username: admin
+ admin-password: admin123
+ model-base-url: https://api.deepseek.com
+ model-id: deepseek-v4-flash
+ model-context-window: 131072
+ sandbox-image: smart-factory-agent-runtime:0.1.0
+ sandbox-network: bridge
+ run-timeout: 60m
logging:
pattern:
diff --git a/server/src/main/resources/db/migration/V2__seed_skills.sql b/server/src/main/resources/db/migration/V2__seed_skills.sql
new file mode 100644
index 0000000..b2e7e7d
--- /dev/null
+++ b/server/src/main/resources/db/migration/V2__seed_skills.sql
@@ -0,0 +1,55145 @@
+-- AgentScope Skill seed exported from the verified development database.
+-- Existing Skill content and local enablement are preserved on conflict.
+INSERT INTO agentscope.agentscope_skills(name, description, skill_content, source, metadata_json) VALUES ('advanced-smart-factory-review', '评审江苏省先进级智能工厂完整申报书,按最新内控五维百分制核查结构、证据、场景、跨章节口径和致命项。适用于全书总评;不替代官方评审结论。', '---
+name: advanced-smart-factory-review
+description: 评审江苏省先进级智能工厂完整申报书,按最新内控五维百分制核查结构、证据、场景、跨章节口径和致命项。适用于全书总评;不替代官方评审结论。
+---
+
+# 江苏省先进级智能工厂完整申报书评审
+
+开始评分前必须读取 [内控评审标准 v1.4](references/advanced-review-standard.md)。用户提供更新的正式政策或内控版本时,以更新版本为准,并在报告中说明替换关系。
+
+## 输入和边界
+
+- 完整申报书及附表;保留页码、章节或表格位置以便引用。
+- 企业事实库和 KPI 锚点表;缺少时仅做书内自洽性检查。
+- 当年度申报通知、要素条件、数字化评估指标、典型场景、AI 场景和申报模板。
+
+先列出已收到与缺失的材料。证据不足时标“存疑”并说明人工需要核验的内容;不引用未实际获得的文件条款。
+
+## 评审流程
+
+1. 核验申报硬门槛和 F 级致命项。确认触发致命项时停止竞争力打分,保留事实与依据并给出否决结论;疑似模板残留按存疑处理。
+2. 按 E1 完整性、E2 先进性、E3 安全性、E4 建设内容、E5 建设成效逐个二级指标评分。
+3. 检查申报书七部分、五方面、附表 1-1 至 1-8、至少 15 个场景及生产作业 / 生产管理 / 运营管理三环节覆盖。
+4. 建立全局数值索引,对企业简介、工厂简述、各建设章节、成效表和场景卡中的同一指标做名称、范围、基期、目标期、单位和公式对账。
+5. 应用扣分封顶和四档结论;分数只作为内部横向比较参考。
+
+## 输出
+
+报告严格包含:
+
+- 结论:通过 / 补正后通过 / 重写 / 否决。
+- 总分、五维得分、扣分明细,并注明“内部评审参考分,非官方分数”。
+- 固定版本声明:“本报告基于所提供的文本版本评审;若与最终提交版存在差异,以终版为准。”
+- E1–E5 逐项得分、二级指标明细、原文证据、依据、解决建议和企业调整建议。
+- 跨章节一致性问题清单,列出同一指标的全部出现位置和冲突。
+- 按优先级排列的补正或重写指令。
+- 竞争力高 / 中 / 低及三个最优先整改项。
+
+每条问题附原文位置。报告重心放在“要点 + 证据 + 问题性质”,不以分数替代事实判断。
+', 'builtin', '{"name":"advanced-smart-factory-review","description":"评审江苏省先进级智能工厂完整申报书,按最新内控五维百分制核查结构、证据、场景、跨章节口径和致命项。适用于全书总评;不替代官方评审结论。"}') ON CONFLICT (name) DO NOTHING;
+INSERT INTO agentscope.agentscope_skills(name, description, skill_content, source, metadata_json) VALUES ('alibabacloud-bailian-rag-knowledgebase', 'Alibaba Cloud Bailian Knowledge Base Retrieval Tool. Use HTTPS API to query and retrieve knowledge base content. Use when: User needs to query knowledge base, retrieve document content, or answer questions based on knowledge base. Prerequisites: (1) Configure DashScope API Key (2) Activate Bailian Knowledge Base service.', E'---
+name: alibabacloud-bailian-rag-knowledgebase
+description: "Alibaba Cloud Bailian Knowledge Base Retrieval Tool. Use HTTPS API to query and retrieve knowledge base content. Use when: User needs to query knowledge base, retrieve document content, or answer questions based on knowledge base. Prerequisites: (1) Configure DashScope API Key (2) Activate Bailian Knowledge Base service."
+---
+
+# Bailian Knowledge Base Retrieval
+
+This Skill provides query and retrieval capabilities for Alibaba Cloud Bailian Knowledge Base via HTTPS API.
+
+## API Key Security Management
+
+Scripts automatically handle key retrieval via `api_key.py`. The Agent does not need to and should not manually extract, set, or pass API Key values.
+
+- **Key retrieval is automated**: Scripts internally call `api_key.py` to automatically obtain keys from config files/environment variables. The Agent only needs to run the script command.
+- **Never hardcode any form of key**: Including `api_key = "sk-..."`, `export DASHSCOPE_API_KEY="sk-..."`, and assigning keys in shell scripts.
+- **Never extract keys from CLI output**: The Agent must not write key values into any script, variable, or file.
+- **Never expose keys in any output**: Including generated scripts, shell commands, log files, and terminal output containing strings starting with `sk-`.
+- **Never read or print keys from config files**: Do not use `cat`, `jq`, `python -c`, or other commands to read and output API Key values.
+- **Mandatory self-check before task completion**: Run `grep -rn "sk-" /` to check all output files; if any strings starting with `sk-` are found (excluding `sk-xxx` placeholders), delete the affected files and regenerate.
+
+## 🚀 Initial Setup (Required for First-time Use)
+
+### 1. Configure API Key
+
+API Keys are managed by the unified `scripts/api_key.py` module, with the following retrieval priority:
+1. Alibaba Cloud CLI config `~/.aliyun/config.json` current profile''s `dashscope.api_key`
+2. Environment variable `DASHSCOPE_API_KEY`
+3. Auto-create and save when Alibaba Cloud CLI is available (`generate_api_key()`)
+
+```python
+# All scripts use this unified approach
+from api_key import get_api_key
+api_key = get_api_key() # Returns str, raises ValueError if not found
+```
+
+Manual environment variable configuration:
+```bash
+export DASHSCOPE_API_KEY=sk-xxx
+```
+
+| Item | Description |
+|------|-------------|
+| **Key Format** | `sk-xxx` (standard DashScope API Key) |
+| **Not Supported** | `sk-sp-xxx` (Coding Plan Key, does not support knowledge base services) |
+| **Get Key** | https://bailian.console.aliyun.com/cn-beijing/?tab=app#/api-key |
+
+### Alibaba Cloud CLI Configuration (API Key Auto-Create/Delete)
+
+The `scripts/api_key.py` module creates and deletes API Keys via `aliyun modelstudio` commands. Complete the following setup before use:
+
+**1. Update Plugins**
+
+```bash
+# Update plugins to latest version
+aliyun plugin update
+```
+
+**2. Install ModelStudio Plugin** (if not already installed)
+
+```bash
+aliyun plugin install --names aliyun-cli-modelstudio --enable-pre
+```
+
+**CLI Commands Used**:
+
+| Command | Purpose | Called From |
+|---------|---------|-------------|
+| `aliyun modelstudio list-workspaces` | Get Bailian Workspace ID | `api_key.py: _get_workspace_id()` |
+| `aliyun modelstudio create-api-key` | Create DashScope API Key | `api_key.py: generate_api_key()` |
+| `aliyun modelstudio delete-api-key` | Delete cloud API Key | `api_key.py: _delete_cloud_api_key()` |
+
+### 2. Important Prerequisite: Activate Bailian Knowledge Base Service
+
+**Before using this skill, you must first activate the knowledge base service in the Alibaba Cloud Bailian console!**
+
+1. Visit [Bailian Knowledge Base page](https://bailian.console.aliyun.com/cn-beijing/?tab=app#/knowledge-base)
+2. Click the **"Activate Now"** button
+3. Confirm activation and wait for the service to take effect (usually 1-2 minutes)
+
+## Observability (MUST follow for every aliyun command)
+
+Upon loading this skill, generate a random session ID (32-char lowercase hex string) and export it as `SKILL_SESSION_ID`. This value must remain constant for the entire skill session.
+
+Every `aliyun` CLI command and HTTPS API call must include a `User-Agent` identifier for traceability.
+
+### User-Agent Format
+
+```
+AlibabaCloud-Agent-Skills/alibabacloud-bailian-rag-knowledgebase/{session-id}
+```
+
+- `{session-id}` = value of `SKILL_SESSION_ID` environment variable (32-char lowercase hex string)
+- Scripts read it via `os.environ.get("SKILL_SESSION_ID", "")`; if empty, generate one with `secrets.token_hex(16)`
+
+### Per-Command --user-agent (CLI)
+
+Every `aliyun modelstudio` business command MUST carry `--user-agent` on the command line:
+
+```bash
+aliyun modelstudio list-workspaces --region cn-beijing \\
+ --user-agent "AlibabaCloud-Agent-Skills/alibabacloud-bailian-rag-knowledgebase/{session-id}"
+```
+
+> **Prohibited**: Do NOT set User-Agent via global configuration commands. Only per-command `--user-agent` is allowed.
+
+### HTTPS User-Agent Header
+
+All HTTPS API requests set the `User-Agent` HTTP header:
+
+```python
+"User-Agent": f"AlibabaCloud-Agent-Skills/alibabacloud-bailian-rag-knowledgebase/{session_id}"
+```
+
+### Applied Locations
+
+| Location | Mechanism |
+|----------|----------|
+| `scripts/list_indices.py` | HTTPS `User-Agent` header via `_get_user_agent()` |
+| `scripts/retrieve.py` | HTTPS `User-Agent` header via `_get_user_agent()` |
+| `scripts/api_key.py` → `_get_workspace_id()` | `aliyun modelstudio list-workspaces --user-agent ...` |
+| `scripts/api_key.py` → `generate_api_key()` | `aliyun modelstudio create-api-key --user-agent ...` |
+| `scripts/api_key.py` → `_delete_cloud_api_key()` | `aliyun modelstudio delete-api-key --user-agent ...` |
+
+## Available Scripts
+
+All scripts are located in the `scripts/` directory:
+
+| Script | Purpose | Parameters |
+|--------|---------|------------|
+| `api_key.py` | API Key management (get, create, delete) | - |
+| `list_indices.py` | Query knowledge base list | `[page_number] [page_size]` |
+| `retrieve.py` | Retrieve from specified knowledge base | `index_id query [top_n]` |
+
+## Workflow
+
+### Step 1: Query Knowledge Base List
+
+Run `scripts/list_indices.py` to get all available knowledge bases:
+
+```bash
+python3 scripts/list_indices.py
+```
+
+Return format:
+```json
+[
+ {
+ "id": "qf91w6402d",
+ "name": "Product Documentation",
+ "description": "Contains product user manuals, API documentation, etc."
+ },
+ {
+ "id": "ip93d2pyvz",
+ "name": "Customer Service Q&A",
+ "description": "FAQ, customer service scripts"
+ }
+]
+```
+
+**Pagination:** page_number starts from 1 (default), page_size defaults to 10. If current page is not fully retrieved, continue to retrieve next page:
+```bash
+python3 scripts/list_indices.py 2 10
+```
+
+### Step 2: Intelligent Knowledge Base Selection
+
+Based on the user''s question and knowledge base descriptions, select **1-3 most relevant knowledge bases** for retrieval.
+
+Selection Strategy:
+- Match keywords (keywords in question vs knowledge base name/description)
+- Prioritize knowledge bases that explicitly contain relevant fields in their descriptions
+- If uncertain, select all or let user manually select
+
+### Step 3: Execute Retrieval
+
+For each selected knowledge base, run `scripts/retrieve.py index_id query [top_n]`:
+
+```bash
+python3 scripts/retrieve.py lj3hgbq60t "java" 5
+```
+
+Parameters:
+- `index_id` (required): Knowledge base ID
+- `query` (required): Search query text
+- `top_n` (optional): Number of top results to return, default 5, max 20
+
+The retrieve API uses the following configuration:
+- `dense_similarity_top_k`: 100
+- `sparse_similarity_top_k`: 100
+- `enable_reranking`: true
+- `rerank`: qwen3-rerank-hybrid with similar mode
+
+Return format, content inside each chunk represents chunk content, doc_name represents source document, score represents match score, title represents chunk section title:
+```json
+{
+ "indexId": "lj3hgbq60t",
+ "chunks": [
+ {
+ "content": "Document chunk content...",
+ "score": 0.6040189862251282,
+ "doc_name": "example-doc.pdf",
+ "title": "Section Title"
+ }
+ ]
+}
+```
+
+### Step 4: Integrate Answer
+
+Based on retrieval results:
+1. Sort by relevance (score descending)
+2. Extract key information
+3. Organize answer in natural language
+4. Please annotate the information source at the end of the generated answer (knowledge base name; document name; section name), can reference multiple documents and sections.
+
+## Common Errors
+
+### 401 Unauthorized
+```json
+{"code": "InvalidApiKey", "message": "Invalid API-KEY"}
+```
+API Key is incorrect or not configured. Guide user to check their API Key configuration.
+
+### 403 Forbidden
+```json
+{"code": "Forbidden", "message": "Service not activated"}
+```
+User has not activated the Bailian Knowledge Base service. Guide user to activate it.
+
+## Usage Example
+
+**User:** "What authentication methods does our product support?"
+
+**Flow:**
+1. Query knowledge base → Returns 3 knowledge bases
+2. Select knowledge base → "Product Documentation" (most relevant)
+3. Retrieve → Get authentication-related document chunks
+4. Answer → "According to product documentation, OAuth2.0, SAML, and API Key authentication methods are supported..."
+
+## Notes
+
+- API Key is automatically retrieved by scripts, Agent should never handle key values directly
+- When retrieving from multiple knowledge bases, merge results and deduplicate
+- Sort retrieval results by score, prioritize high-relevance content
+
+**API Key Auto-Retrieval Flow**:
+1. Read `~/.aliyun/config.json` current profile''s `dashscope.api_key` → Return if found
+2. Read environment variable `DASHSCOPE_API_KEY` → Return if found
+3. Alibaba Cloud CLI available → Auto-create via `generate_api_key()` and save to config
+4. All above fail → Error with setup instructions
+', 'builtin', '{"name":"alibabacloud-bailian-rag-knowledgebase","description":"Alibaba Cloud Bailian Knowledge Base Retrieval Tool. Use HTTPS API to query and retrieve knowledge base content. Use when: User needs to query knowledge base, retrieve document content, or answer questions based on knowledge base. Prerequisites: (1) Configure DashScope API Key (2) Activate Bailian Knowledge Base service."}') ON CONFLICT (name) DO NOTHING;
+INSERT INTO agentscope.agentscope_skills(name, description, skill_content, source, metadata_json) VALUES ('docx', 'Comprehensive document creation, editing, and analysis with support for tracked changes, comments, formatting preservation, and text extraction. When Claude needs to work with professional documents (.docx files) for: (1) Creating new documents, (2) Modifying or editing content, (3) Working with tracked changes, (4) Adding comments, or any other document tasks', '---
+name: docx
+description: "Comprehensive document creation, editing, and analysis with support for tracked changes, comments, formatting preservation, and text extraction. When Claude needs to work with professional documents (.docx files) for: (1) Creating new documents, (2) Modifying or editing content, (3) Working with tracked changes, (4) Adding comments, or any other document tasks"
+license: Proprietary. LICENSE.txt has complete terms
+---
+
+# DOCX creation, editing, and analysis
+
+## Overview
+
+A user may ask you to create, edit, or analyze the contents of a .docx file. A .docx file is essentially a ZIP archive containing XML files and other resources that you can read or edit. You have different tools and workflows available for different tasks.
+
+## Workflow Decision Tree
+
+### Reading/Analyzing Content
+Use "Text extraction" or "Raw XML access" sections below
+
+### Creating New Document
+Use "Creating a new Word document" workflow
+
+### Editing Existing Document
+- **Your own document + simple changes**
+ Use "Basic OOXML editing" workflow
+
+- **Someone else''s document**
+ Use **"Redlining workflow"** (recommended default)
+
+- **Legal, academic, business, or government docs**
+ Use **"Redlining workflow"** (required)
+
+## Reading and analyzing content
+
+### Text extraction
+If you just need to read the text contents of a document, you should convert the document to markdown using pandoc. Pandoc provides excellent support for preserving document structure and can show tracked changes:
+
+```bash
+# Convert document to markdown with tracked changes
+pandoc --track-changes=all path-to-file.docx -o output.md
+# Options: --track-changes=accept/reject/all
+```
+
+### Raw XML access
+You need raw XML access for: comments, complex formatting, document structure, embedded media, and metadata. For any of these features, you''ll need to unpack a document and read its raw XML contents.
+
+#### Unpacking a file
+`python ooxml/scripts/unpack.py `
+
+#### Key file structures
+* `word/document.xml` - Main document contents
+* `word/comments.xml` - Comments referenced in document.xml
+* `word/media/` - Embedded images and media files
+* Tracked changes use `` (insertions) and `` (deletions) tags
+
+## Creating a new Word document
+
+When creating a new Word document from scratch, use **docx-js**, which allows you to create Word documents using JavaScript/TypeScript.
+
+### Workflow
+1. **MANDATORY - READ ENTIRE FILE**: Read [`docx-js.md`](docx-js.md) (~500 lines) completely from start to finish. **NEVER set any range limits when reading this file.** Read the full file content for detailed syntax, critical formatting rules, and best practices before proceeding with document creation.
+2. Create a JavaScript/TypeScript file using Document, Paragraph, TextRun components (You can assume all dependencies are installed, but if not, refer to the dependencies section below)
+3. Export as .docx using Packer.toBuffer()
+
+### Smart-factory delivery checks
+- Markdown table separator rows such as `|---|---|` are syntax and must never become Word table content.
+- Internal provenance codes such as `C/E/U` must not appear in the user-facing document; use readable labels such as `已确认`、`待核实`、`待确认`.
+- Missing enterprise facts must keep their visible `【待企业确认】` anchor and a Word native comment. Do not replace comments with endnotes or plain explanatory text.
+- Phrase unknown current facts as questions or requested evidence, such as `需确认是否…` or `待企业提供…`. Never assert that an unknown fact already exists and append a confirmation comment afterward; unsigned declarations must remain `待签署`.
+- Before delivery, reopen the DOCX, verify `word/comments.xml` and its anchors, and inspect at least the first-page native preview for broken Chinese glyphs, tables, or pagination.
+
+## Editing an existing Word document
+
+When editing an existing Word document, use the **Document library** (a Python library for OOXML manipulation). The library automatically handles infrastructure setup and provides methods for document manipulation. For complex scenarios, you can access the underlying DOM directly through the library.
+
+### Workflow
+1. **MANDATORY - READ ENTIRE FILE**: Read [`ooxml.md`](ooxml.md) (~600 lines) completely from start to finish. **NEVER set any range limits when reading this file.** Read the full file content for the Document library API and XML patterns for directly editing document files.
+2. Unpack the document: `python ooxml/scripts/unpack.py `
+3. Create and run a Python script using the Document library (see "Document Library" section in ooxml.md)
+4. Pack the final document: `python ooxml/scripts/pack.py `
+
+The Document library provides both high-level methods for common operations and direct DOM access for complex scenarios.
+
+## Redlining workflow for document review
+
+This workflow allows you to plan comprehensive tracked changes using markdown before implementing them in OOXML. **CRITICAL**: For complete tracked changes, you must implement ALL changes systematically.
+
+**Batching Strategy**: Group related changes into batches of 3-10 changes. This makes debugging manageable while maintaining efficiency. Test each batch before moving to the next.
+
+**Principle: Minimal, Precise Edits**
+When implementing tracked changes, only mark text that actually changes. Repeating unchanged text makes edits harder to review and appears unprofessional. Break replacements into: [unchanged text] + [deletion] + [insertion] + [unchanged text]. Preserve the original run''s RSID for unchanged text by extracting the `` element from the original and reusing it.
+
+Example - Changing "30 days" to "60 days" in a sentence:
+```python
+# BAD - Replaces entire sentence
+''The term is 30 days.The term is 60 days.''
+
+# GOOD - Only marks what changed, preserves original for unchanged text
+''The term is 3060 days.''
+```
+
+### Tracked changes workflow
+
+1. **Get markdown representation**: Convert document to markdown with tracked changes preserved:
+ ```bash
+ pandoc --track-changes=all path-to-file.docx -o current.md
+ ```
+
+2. **Identify and group changes**: Review the document and identify ALL changes needed, organizing them into logical batches:
+
+ **Location methods** (for finding changes in XML):
+ - Section/heading numbers (e.g., "Section 3.2", "Article IV")
+ - Paragraph identifiers if numbered
+ - Grep patterns with unique surrounding text
+ - Document structure (e.g., "first paragraph", "signature block")
+ - **DO NOT use markdown line numbers** - they don''t map to XML structure
+
+ **Batch organization** (group 3-10 related changes per batch):
+ - By section: "Batch 1: Section 2 amendments", "Batch 2: Section 5 updates"
+ - By type: "Batch 1: Date corrections", "Batch 2: Party name changes"
+ - By complexity: Start with simple text replacements, then tackle complex structural changes
+ - Sequential: "Batch 1: Pages 1-3", "Batch 2: Pages 4-6"
+
+3. **Read documentation and unpack**:
+ - **MANDATORY - READ ENTIRE FILE**: Read [`ooxml.md`](ooxml.md) (~600 lines) completely from start to finish. **NEVER set any range limits when reading this file.** Pay special attention to the "Document Library" and "Tracked Change Patterns" sections.
+ - **Unpack the document**: `python ooxml/scripts/unpack.py `
+ - **Note the suggested RSID**: The unpack script will suggest an RSID to use for your tracked changes. Copy this RSID for use in step 4b.
+
+4. **Implement changes in batches**: Group changes logically (by section, by type, or by proximity) and implement them together in a single script. This approach:
+ - Makes debugging easier (smaller batch = easier to isolate errors)
+ - Allows incremental progress
+ - Maintains efficiency (batch size of 3-10 changes works well)
+
+ **Suggested batch groupings:**
+ - By document section (e.g., "Section 3 changes", "Definitions", "Termination clause")
+ - By change type (e.g., "Date changes", "Party name updates", "Legal term replacements")
+ - By proximity (e.g., "Changes on pages 1-3", "Changes in first half of document")
+
+ For each batch of related changes:
+
+ **a. Map text to XML**: Grep for text in `word/document.xml` to verify how text is split across `` elements.
+
+ **b. Create and run script**: Use `get_node` to find nodes, implement changes, then `doc.save()`. See **"Document Library"** section in ooxml.md for patterns.
+
+ **Note**: Always grep `word/document.xml` immediately before writing a script to get current line numbers and verify text content. Line numbers change after each script run.
+
+5. **Pack the document**: After all batches are complete, convert the unpacked directory back to .docx:
+ ```bash
+ python ooxml/scripts/pack.py unpacked reviewed-document.docx
+ ```
+
+6. **Final verification**: Do a comprehensive check of the complete document:
+ - Convert final document to markdown:
+ ```bash
+ pandoc --track-changes=all reviewed-document.docx -o verification.md
+ ```
+ - Verify ALL changes were applied correctly:
+ ```bash
+ grep "original phrase" verification.md # Should NOT find it
+ grep "replacement phrase" verification.md # Should find it
+ ```
+ - Check that no unintended changes were introduced
+
+
+## Converting Documents to Images
+
+To visually analyze Word documents, convert them to images using a two-step process:
+
+1. **Convert DOCX to PDF**:
+ ```bash
+ soffice --headless --convert-to pdf document.docx
+ ```
+
+2. **Convert PDF pages to JPEG images**:
+ ```bash
+ pdftoppm -jpeg -r 150 document.pdf page
+ ```
+ This creates files like `page-1.jpg`, `page-2.jpg`, etc.
+
+Options:
+- `-r 150`: Sets resolution to 150 DPI (adjust for quality/size balance)
+- `-jpeg`: Output JPEG format (use `-png` for PNG if preferred)
+- `-f N`: First page to convert (e.g., `-f 2` starts from page 2)
+- `-l N`: Last page to convert (e.g., `-l 5` stops at page 5)
+- `page`: Prefix for output files
+
+Example for specific range:
+```bash
+pdftoppm -jpeg -r 150 -f 2 -l 5 document.pdf page # Converts only pages 2-5
+```
+
+## Code Style Guidelines
+**IMPORTANT**: When generating code for DOCX operations:
+- Write concise code
+- Avoid verbose variable names and redundant operations
+- Avoid unnecessary print statements
+
+## Dependencies
+
+Required dependencies (install if not available):
+
+- **pandoc**: `sudo apt-get install pandoc` (for text extraction)
+- **docx**: `npm install -g docx` (for creating new documents)
+- **LibreOffice**: `sudo apt-get install libreoffice` (for PDF conversion)
+- **Poppler**: `sudo apt-get install poppler-utils` (for pdftoppm to convert PDF to images)
+- **defusedxml**: `pip install defusedxml` (for secure XML parsing)
+', 'builtin', '{"name":"docx","description":"Comprehensive document creation, editing, and analysis with support for tracked changes, comments, formatting preservation, and text extraction. When Claude needs to work with professional documents (.docx files) for: (1) Creating new documents, (2) Modifying or editing content, (3) Working with tracked changes, (4) Adding comments, or any other document tasks"}') ON CONFLICT (name) DO NOTHING;
+INSERT INTO agentscope.agentscope_skills(name, description, skill_content, source, metadata_json) VALUES ('excellent-smart-factory-review', '评审国家卓越级智能工厂完整申报书,核查官方权重、建设实效、系统贯通、现场佐证和跨章节数据一致性。仅在获得适用年度正式评分文件后执行正式评分。', '---
+name: excellent-smart-factory-review
+description: 评审国家卓越级智能工厂完整申报书,核查官方权重、建设实效、系统贯通、现场佐证和跨章节数据一致性。仅在获得适用年度正式评分文件后执行正式评分。
+---
+
+# 国家卓越级智能工厂完整申报书评审
+
+## 适用依据
+
+评分前确认用户提供的申报年度和正式评分标准。源资产采用的权重为完整性 5、先进性 15、安全性 5、建设内容 60、建设成效 15;若适用年度文件不同,以正式文件为准并说明变化。缺少正式评分标准时只做结构与证据预审,不把结果称为官方评分。
+
+## 输入
+
+- 完整申报书、全部附件和材料清单。
+- 适用年度国家卓越级评分标准、梯度培育要素条件、场景指引、申报材料清单和导出格式要求。
+- 企业事实库、KPI 锚点表、系统架构与接口资料、现场照片和系统截图。
+
+## 评分与核查
+
+| 维度 | 分值 | 核查重点 |
+|---|---:|---|
+| E1 完整性 | 5 | 组织机制、建设和运营职责、人才保障 |
+| E2 先进性 | 15 | 筑峰强链、行业地位、荣誉和成熟度 |
+| E3 安全性 | 5 | 关键装备、工业软件、操作系统、解决方案及网络数据安全 |
+| E4 建设内容 | 60 | 五方面建设、系统级建模或数字孪生、全生命周期数据贯通和全过程优化 |
+| E5 建设成效 | 15 | 技术突破、经济成效、ROI 和可溯源的建设前后指标 |
+
+重点检查:
+
+- 卓越级成果应体现已建成实效;规划目标单独标注,不计为既有成果。
+- 所谓“数据贯通”必须有接口、中台、主数据、业务闭环或可验证的数据流证据。
+- 场景名称、建设内容和等级描述与适用年度指引一致。
+- 架构图、表格、照片和截图能支撑正文,并排查套用、错企和重复素材。
+- 全局数值按指标名称、范围、基期、目标期、单位和公式对账。
+
+## 内部扣分与结论
+
+在正式标准未规定同类扣分时,可将以下项目作为内部风险提示:无源数值、跨章节矛盾、模块串场、无出处虚夸、字数越界、已建成与规划混乱、现场佐证不足。不得把内部扣分包装为官方条款。
+
+源资产的内部竞争力档位为:85 分及以上“具备竞争力”,70–84 分“定向改写”,低于 70 分“重写”;无源数值、口径矛盾或已建成与规划混乱时至少打回。若正式文件另有结论规则,以正式文件为准。
+
+## 输出
+
+1. 依据版本、材料完整性和评审边界。
+2. 总分及 E1–E5 逐项得分、原文证据、条款依据和判定逻辑。
+3. 内部风险或正式扣分明细,清楚标注性质。
+4. 跨章节一致性问题和现场佐证问题。
+5. 按优先级排列的改写指令,以及材料侧和企业建设侧建议。
+6. 卓越级竞争力高 / 中 / 低和三个最优先整改项。
+', 'builtin', '{"name":"excellent-smart-factory-review","description":"评审国家卓越级智能工厂完整申报书,核查官方权重、建设实效、系统贯通、现场佐证和跨章节数据一致性。仅在获得适用年度正式评分文件后执行正式评分。"}') ON CONFLICT (name) DO NOTHING;
+INSERT INTO agentscope.agentscope_skills(name, description, skill_content, source, metadata_json) VALUES ('pdf', 'Comprehensive PDF manipulation toolkit for extracting text and tables, creating new PDFs, merging/splitting documents, and handling forms. When Claude needs to fill in a PDF form or programmatically process, generate, or analyze PDF documents at scale.', E'---
+name: pdf
+description: Comprehensive PDF manipulation toolkit for extracting text and tables, creating new PDFs, merging/splitting documents, and handling forms. When Claude needs to fill in a PDF form or programmatically process, generate, or analyze PDF documents at scale.
+license: Proprietary. LICENSE.txt has complete terms
+---
+
+# PDF Processing Guide
+
+## Overview
+
+This guide covers essential PDF processing operations using Python libraries and command-line tools. For advanced features, JavaScript libraries, and detailed examples, see reference.md. If you need to fill out a PDF form, read forms.md and follow its instructions.
+
+## Quick Start
+
+```python
+from pypdf import PdfReader, PdfWriter
+
+# Read a PDF
+reader = PdfReader("document.pdf")
+print(f"Pages: {len(reader.pages)}")
+
+# Extract text
+text = ""
+for page in reader.pages:
+ text += page.extract_text()
+```
+
+## Python Libraries
+
+### pypdf - Basic Operations
+
+#### Merge PDFs
+```python
+from pypdf import PdfWriter, PdfReader
+
+writer = PdfWriter()
+for pdf_file in ["doc1.pdf", "doc2.pdf", "doc3.pdf"]:
+ reader = PdfReader(pdf_file)
+ for page in reader.pages:
+ writer.add_page(page)
+
+with open("merged.pdf", "wb") as output:
+ writer.write(output)
+```
+
+#### Split PDF
+```python
+reader = PdfReader("input.pdf")
+for i, page in enumerate(reader.pages):
+ writer = PdfWriter()
+ writer.add_page(page)
+ with open(f"page_{i+1}.pdf", "wb") as output:
+ writer.write(output)
+```
+
+#### Extract Metadata
+```python
+reader = PdfReader("document.pdf")
+meta = reader.metadata
+print(f"Title: {meta.title}")
+print(f"Author: {meta.author}")
+print(f"Subject: {meta.subject}")
+print(f"Creator: {meta.creator}")
+```
+
+#### Rotate Pages
+```python
+reader = PdfReader("input.pdf")
+writer = PdfWriter()
+
+page = reader.pages[0]
+page.rotate(90) # Rotate 90 degrees clockwise
+writer.add_page(page)
+
+with open("rotated.pdf", "wb") as output:
+ writer.write(output)
+```
+
+### pdfplumber - Text and Table Extraction
+
+#### Extract Text with Layout
+```python
+import pdfplumber
+
+with pdfplumber.open("document.pdf") as pdf:
+ for page in pdf.pages:
+ text = page.extract_text()
+ print(text)
+```
+
+#### Extract Tables
+```python
+with pdfplumber.open("document.pdf") as pdf:
+ for i, page in enumerate(pdf.pages):
+ tables = page.extract_tables()
+ for j, table in enumerate(tables):
+ print(f"Table {j+1} on page {i+1}:")
+ for row in table:
+ print(row)
+```
+
+#### Advanced Table Extraction
+```python
+import pandas as pd
+
+with pdfplumber.open("document.pdf") as pdf:
+ all_tables = []
+ for page in pdf.pages:
+ tables = page.extract_tables()
+ for table in tables:
+ if table: # Check if table is not empty
+ df = pd.DataFrame(table[1:], columns=table[0])
+ all_tables.append(df)
+
+# Combine all tables
+if all_tables:
+ combined_df = pd.concat(all_tables, ignore_index=True)
+ combined_df.to_excel("extracted_tables.xlsx", index=False)
+```
+
+### reportlab - Create PDFs
+
+#### Basic PDF Creation
+```python
+from reportlab.lib.pagesizes import letter
+from reportlab.pdfgen import canvas
+
+c = canvas.Canvas("hello.pdf", pagesize=letter)
+width, height = letter
+
+# Add text
+c.drawString(100, height - 100, "Hello World!")
+c.drawString(100, height - 120, "This is a PDF created with reportlab")
+
+# Add a line
+c.line(100, height - 140, 400, height - 140)
+
+# Save
+c.save()
+```
+
+#### Create PDF with Multiple Pages
+```python
+from reportlab.lib.pagesizes import letter
+from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, PageBreak
+from reportlab.lib.styles import getSampleStyleSheet
+
+doc = SimpleDocTemplate("report.pdf", pagesize=letter)
+styles = getSampleStyleSheet()
+story = []
+
+# Add content
+title = Paragraph("Report Title", styles[''Title''])
+story.append(title)
+story.append(Spacer(1, 12))
+
+body = Paragraph("This is the body of the report. " * 20, styles[''Normal''])
+story.append(body)
+story.append(PageBreak())
+
+# Page 2
+story.append(Paragraph("Page 2", styles[''Heading1'']))
+story.append(Paragraph("Content for page 2", styles[''Normal'']))
+
+# Build PDF
+doc.build(story)
+```
+
+## Command-Line Tools
+
+### pdftotext (poppler-utils)
+```bash
+# Extract text
+pdftotext input.pdf output.txt
+
+# Extract text preserving layout
+pdftotext -layout input.pdf output.txt
+
+# Extract specific pages
+pdftotext -f 1 -l 5 input.pdf output.txt # Pages 1-5
+```
+
+### qpdf
+```bash
+# Merge PDFs
+qpdf --empty --pages file1.pdf file2.pdf -- merged.pdf
+
+# Split pages
+qpdf input.pdf --pages . 1-5 -- pages1-5.pdf
+qpdf input.pdf --pages . 6-10 -- pages6-10.pdf
+
+# Rotate pages
+qpdf input.pdf output.pdf --rotate=+90:1 # Rotate page 1 by 90 degrees
+
+# Remove password
+qpdf --password=mypassword --decrypt encrypted.pdf decrypted.pdf
+```
+
+### pdftk (if available)
+```bash
+# Merge
+pdftk file1.pdf file2.pdf cat output merged.pdf
+
+# Split
+pdftk input.pdf burst
+
+# Rotate
+pdftk input.pdf rotate 1east output rotated.pdf
+```
+
+## Common Tasks
+
+### Extract Text from Scanned PDFs
+```python
+# Requires: pip install pytesseract pdf2image
+import pytesseract
+from pdf2image import convert_from_path
+
+# Convert PDF to images
+images = convert_from_path(''scanned.pdf'')
+
+# OCR each page
+text = ""
+for i, image in enumerate(images):
+ text += f"Page {i+1}:\\n"
+ text += pytesseract.image_to_string(image)
+ text += "\\n\\n"
+
+print(text)
+```
+
+### Add Watermark
+```python
+from pypdf import PdfReader, PdfWriter
+
+# Create watermark (or load existing)
+watermark = PdfReader("watermark.pdf").pages[0]
+
+# Apply to all pages
+reader = PdfReader("document.pdf")
+writer = PdfWriter()
+
+for page in reader.pages:
+ page.merge_page(watermark)
+ writer.add_page(page)
+
+with open("watermarked.pdf", "wb") as output:
+ writer.write(output)
+```
+
+### Extract Images
+```bash
+# Using pdfimages (poppler-utils)
+pdfimages -j input.pdf output_prefix
+
+# This extracts all images as output_prefix-000.jpg, output_prefix-001.jpg, etc.
+```
+
+### Password Protection
+```python
+from pypdf import PdfReader, PdfWriter
+
+reader = PdfReader("input.pdf")
+writer = PdfWriter()
+
+for page in reader.pages:
+ writer.add_page(page)
+
+# Add password
+writer.encrypt("userpassword", "ownerpassword")
+
+with open("encrypted.pdf", "wb") as output:
+ writer.write(output)
+```
+
+## Quick Reference
+
+| Task | Best Tool | Command/Code |
+|------|-----------|--------------|
+| Merge PDFs | pypdf | `writer.add_page(page)` |
+| Split PDFs | pypdf | One page per file |
+| Extract text | pdfplumber | `page.extract_text()` |
+| Extract tables | pdfplumber | `page.extract_tables()` |
+| Create PDFs | reportlab | Canvas or Platypus |
+| Command line merge | qpdf | `qpdf --empty --pages ...` |
+| OCR scanned PDFs | pytesseract | Convert to image first |
+| Fill PDF forms | pdf-lib or pypdf (see forms.md) | See forms.md |
+
+## Next Steps
+
+- For advanced pypdfium2 usage, see reference.md
+- For JavaScript libraries (pdf-lib), see reference.md
+- If you need to fill out a PDF form, follow the instructions in forms.md
+- For troubleshooting guides, see reference.md
+', 'imported', '{"name":"pdf","description":"Comprehensive PDF manipulation toolkit for extracting text and tables, creating new PDFs, merging/splitting documents, and handling forms. When Claude needs to fill in a PDF form or programmatically process, generate, or analyze PDF documents at scale."}') ON CONFLICT (name) DO NOTHING;
+INSERT INTO agentscope.agentscope_skills(name, description, skill_content, source, metadata_json) VALUES ('pptx', 'Presentation creation, editing, and analysis. When Claude needs to work with presentations (.pptx files) for: (1) Creating new presentations, (2) Modifying or editing content, (3) Working with layouts, (4) Adding comments or speaker notes, or any other presentation tasks', '---
+name: pptx
+description: "Presentation creation, editing, and analysis. When Claude needs to work with presentations (.pptx files) for: (1) Creating new presentations, (2) Modifying or editing content, (3) Working with layouts, (4) Adding comments or speaker notes, or any other presentation tasks"
+license: Proprietary. LICENSE.txt has complete terms
+---
+
+# PPTX creation, editing, and analysis
+
+## Overview
+
+A user may ask you to create, edit, or analyze the contents of a .pptx file. A .pptx file is essentially a ZIP archive containing XML files and other resources that you can read or edit. You have different tools and workflows available for different tasks.
+
+## Reading and analyzing content
+
+### Text extraction
+If you just need to read the text contents of a presentation, you should convert the document to markdown:
+
+```bash
+# Convert document to markdown
+python -m markitdown path-to-file.pptx
+```
+
+### Raw XML access
+You need raw XML access for: comments, speaker notes, slide layouts, animations, design elements, and complex formatting. For any of these features, you''ll need to unpack a presentation and read its raw XML contents.
+
+#### Unpacking a file
+`python ooxml/scripts/unpack.py `
+
+**Note**: The unpack.py script is located at `skills/pptx/ooxml/scripts/unpack.py` relative to the project root. If the script doesn''t exist at this path, use `find . -name "unpack.py"` to locate it.
+
+#### Key file structures
+* `ppt/presentation.xml` - Main presentation metadata and slide references
+* `ppt/slides/slide{N}.xml` - Individual slide contents (slide1.xml, slide2.xml, etc.)
+* `ppt/notesSlides/notesSlide{N}.xml` - Speaker notes for each slide
+* `ppt/comments/modernComment_*.xml` - Comments for specific slides
+* `ppt/slideLayouts/` - Layout templates for slides
+* `ppt/slideMasters/` - Master slide templates
+* `ppt/theme/` - Theme and styling information
+* `ppt/media/` - Images and other media files
+
+#### Typography and color extraction
+**When given an example design to emulate**: Always analyze the presentation''s typography and colors first using the methods below:
+1. **Read theme file**: Check `ppt/theme/theme1.xml` for colors (``) and fonts (``)
+2. **Sample slide content**: Examine `ppt/slides/slide1.xml` for actual font usage (``) and colors
+3. **Search for patterns**: Use grep to find color (``, ``) and font references across all XML files
+
+## Creating a new PowerPoint presentation **without a template**
+
+When creating a new PowerPoint presentation from scratch, use the **html2pptx** workflow to convert HTML slides to PowerPoint with accurate positioning.
+
+### Design Principles
+
+**CRITICAL**: Before creating any presentation, analyze the content and choose appropriate design elements:
+1. **Consider the subject matter**: What is this presentation about? What tone, industry, or mood does it suggest?
+2. **Check for branding**: If the user mentions a company/organization, consider their brand colors and identity
+3. **Match palette to content**: Select colors that reflect the subject
+4. **State your approach**: Explain your design choices before writing code
+
+**Requirements**:
+- ✅ State your content-informed design approach BEFORE writing code
+- ✅ Use web-safe fonts only: Arial, Helvetica, Times New Roman, Georgia, Courier New, Verdana, Tahoma, Trebuchet MS, Impact
+- ✅ Create clear visual hierarchy through size, weight, and color
+- ✅ Ensure readability: strong contrast, appropriately sized text, clean alignment
+- ✅ Be consistent: repeat patterns, spacing, and visual language across slides
+
+#### Color Palette Selection
+
+**Choosing colors creatively**:
+- **Think beyond defaults**: What colors genuinely match this specific topic? Avoid autopilot choices.
+- **Consider multiple angles**: Topic, industry, mood, energy level, target audience, brand identity (if mentioned)
+- **Be adventurous**: Try unexpected combinations - a healthcare presentation doesn''t have to be green, finance doesn''t have to be navy
+- **Build your palette**: Pick 3-5 colors that work together (dominant colors + supporting tones + accent)
+- **Ensure contrast**: Text must be clearly readable on backgrounds
+
+**Example color palettes** (use these to spark creativity - choose one, adapt it, or create your own):
+
+1. **Classic Blue**: Deep navy (#1C2833), slate gray (#2E4053), silver (#AAB7B8), off-white (#F4F6F6)
+2. **Teal & Coral**: Teal (#5EA8A7), deep teal (#277884), coral (#FE4447), white (#FFFFFF)
+3. **Bold Red**: Red (#C0392B), bright red (#E74C3C), orange (#F39C12), yellow (#F1C40F), green (#2ECC71)
+4. **Warm Blush**: Mauve (#A49393), blush (#EED6D3), rose (#E8B4B8), cream (#FAF7F2)
+5. **Burgundy Luxury**: Burgundy (#5D1D2E), crimson (#951233), rust (#C15937), gold (#997929)
+6. **Deep Purple & Emerald**: Purple (#B165FB), dark blue (#181B24), emerald (#40695B), white (#FFFFFF)
+7. **Cream & Forest Green**: Cream (#FFE1C7), forest green (#40695B), white (#FCFCFC)
+8. **Pink & Purple**: Pink (#F8275B), coral (#FF574A), rose (#FF737D), purple (#3D2F68)
+9. **Lime & Plum**: Lime (#C5DE82), plum (#7C3A5F), coral (#FD8C6E), blue-gray (#98ACB5)
+10. **Black & Gold**: Gold (#BF9A4A), black (#000000), cream (#F4F6F6)
+11. **Sage & Terracotta**: Sage (#87A96B), terracotta (#E07A5F), cream (#F4F1DE), charcoal (#2C2C2C)
+12. **Charcoal & Red**: Charcoal (#292929), red (#E33737), light gray (#CCCBCB)
+13. **Vibrant Orange**: Orange (#F96D00), light gray (#F2F2F2), charcoal (#222831)
+14. **Forest Green**: Black (#191A19), green (#4E9F3D), dark green (#1E5128), white (#FFFFFF)
+15. **Retro Rainbow**: Purple (#722880), pink (#D72D51), orange (#EB5C18), amber (#F08800), gold (#DEB600)
+16. **Vintage Earthy**: Mustard (#E3B448), sage (#CBD18F), forest green (#3A6B35), cream (#F4F1DE)
+17. **Coastal Rose**: Old rose (#AD7670), beaver (#B49886), eggshell (#F3ECDC), ash gray (#BFD5BE)
+18. **Orange & Turquoise**: Light orange (#FC993E), grayish turquoise (#667C6F), white (#FCFCFC)
+
+#### Visual Details Options
+
+**Geometric Patterns**:
+- Diagonal section dividers instead of horizontal
+- Asymmetric column widths (30/70, 40/60, 25/75)
+- Rotated text headers at 90° or 270°
+- Circular/hexagonal frames for images
+- Triangular accent shapes in corners
+- Overlapping shapes for depth
+
+**Border & Frame Treatments**:
+- Thick single-color borders (10-20pt) on one side only
+- Double-line borders with contrasting colors
+- Corner brackets instead of full frames
+- L-shaped borders (top+left or bottom+right)
+- Underline accents beneath headers (3-5pt thick)
+
+**Typography Treatments**:
+- Extreme size contrast (72pt headlines vs 11pt body)
+- All-caps headers with wide letter spacing
+- Numbered sections in oversized display type
+- Monospace (Courier New) for data/stats/technical content
+- Condensed fonts (Arial Narrow) for dense information
+- Outlined text for emphasis
+
+**Chart & Data Styling**:
+- Monochrome charts with single accent color for key data
+- Horizontal bar charts instead of vertical
+- Dot plots instead of bar charts
+- Minimal gridlines or none at all
+- Data labels directly on elements (no legends)
+- Oversized numbers for key metrics
+
+**Layout Innovations**:
+- Full-bleed images with text overlays
+- Sidebar column (20-30% width) for navigation/context
+- Modular grid systems (3×3, 4×4 blocks)
+- Z-pattern or F-pattern content flow
+- Floating text boxes over colored shapes
+- Magazine-style multi-column layouts
+
+**Background Treatments**:
+- Solid color blocks occupying 40-60% of slide
+- Gradient fills (vertical or diagonal only)
+- Split backgrounds (two colors, diagonal or vertical)
+- Edge-to-edge color bands
+- Negative space as a design element
+
+### Layout Tips
+**When creating slides with charts or tables:**
+- **Two-column layout (PREFERRED)**: Use a header spanning the full width, then two columns below - text/bullets in one column and the featured content in the other. This provides better balance and makes charts/tables more readable. Use flexbox with unequal column widths (e.g., 40%/60% split) to optimize space for each content type.
+- **Full-slide layout**: Let the featured content (chart/table) take up the entire slide for maximum impact and readability
+- **NEVER vertically stack**: Do not place charts/tables below text in a single column - this causes poor readability and layout issues
+
+### Workflow
+1. **MANDATORY - READ ENTIRE FILE**: Read [`html2pptx.md`](html2pptx.md) completely from start to finish. **NEVER set any range limits when reading this file.** Read the full file content for detailed syntax, critical formatting rules, and best practices before proceeding with presentation creation.
+2. Create an HTML file for each slide with proper dimensions (e.g., 720pt × 405pt for 16:9)
+ - Use `