diff --git a/qiming-backend/app-platform-modules/app-platform-agent/app-platform-agent-core-adapter/src/main/java/com/xspaceagi/agent/core/adapter/dto/digital/DigitalEmployeeAdminWorkbenchRowDto.java b/qiming-backend/app-platform-modules/app-platform-agent/app-platform-agent-core-adapter/src/main/java/com/xspaceagi/agent/core/adapter/dto/digital/DigitalEmployeeAdminWorkbenchRowDto.java
index 022af334..f277ad83 100644
--- a/qiming-backend/app-platform-modules/app-platform-agent/app-platform-agent-core-adapter/src/main/java/com/xspaceagi/agent/core/adapter/dto/digital/DigitalEmployeeAdminWorkbenchRowDto.java
+++ b/qiming-backend/app-platform-modules/app-platform-agent/app-platform-agent-core-adapter/src/main/java/com/xspaceagi/agent/core/adapter/dto/digital/DigitalEmployeeAdminWorkbenchRowDto.java
@@ -102,6 +102,16 @@ public class DigitalEmployeeAdminWorkbenchRowDto {
private String memoryKey;
@JsonProperty("skill_id")
private String skillId;
+ @JsonProperty("skill_version")
+ private String skillVersion;
+ @JsonProperty("install_status")
+ private String installStatus;
+ @JsonProperty("permission_scope")
+ private String permissionScope;
+ @JsonProperty("policy_source")
+ private String policySource;
+ @JsonProperty("policy_status")
+ private String policyStatus;
@JsonProperty("tool_name")
private String toolName;
@JsonProperty("server_id")
diff --git a/qiming-backend/app-platform-modules/app-platform-agent/app-platform-agent-core-application/src/main/java/com/xspaceagi/agent/core/application/service/DigitalEmployeeSyncApplicationServiceImpl.java b/qiming-backend/app-platform-modules/app-platform-agent/app-platform-agent-core-application/src/main/java/com/xspaceagi/agent/core/application/service/DigitalEmployeeSyncApplicationServiceImpl.java
index 8bb00195..82e8e93f 100644
--- a/qiming-backend/app-platform-modules/app-platform-agent/app-platform-agent-core-application/src/main/java/com/xspaceagi/agent/core/application/service/DigitalEmployeeSyncApplicationServiceImpl.java
+++ b/qiming-backend/app-platform-modules/app-platform-agent/app-platform-agent-core-application/src/main/java/com/xspaceagi/agent/core/application/service/DigitalEmployeeSyncApplicationServiceImpl.java
@@ -1093,6 +1093,11 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye
.memoryId(firstString(businessView.get("memory_id"), businessView.get("memoryId"), payload.get("memory_id"), payload.get("memoryId"), "memory".equals(record.getEntityType()) ? record.getEntityId() : null))
.memoryKey(firstString(businessView.get("memory_key"), businessView.get("memoryKey"), businessView.get("key"), payload.get("memory_key"), payload.get("memoryKey"), payload.get("key")))
.skillId(firstString(businessView.get("skill_id"), businessView.get("skillId"), payload.get("skill_id"), payload.get("skillId")))
+ .skillVersion(firstString(businessView.get("skill_version"), businessView.get("skillVersion"), businessView.get("version"), payload.get("skill_version"), payload.get("skillVersion"), payload.get("version")))
+ .installStatus(firstString(businessView.get("install_status"), businessView.get("installStatus"), payload.get("install_status"), payload.get("installStatus")))
+ .permissionScope(firstString(businessView.get("permission_scope"), businessView.get("permissionScope"), payload.get("permission_scope"), payload.get("permissionScope")))
+ .policySource(firstString(businessView.get("policy_source"), businessView.get("policySource"), businessView.get("source"), payload.get("policy_source"), payload.get("policySource"), payload.get("source")))
+ .policyStatus(firstString(businessView.get("policy_status"), businessView.get("policyStatus"), payload.get("policy_status"), payload.get("policyStatus")))
.toolName(firstString(businessView.get("tool_name"), businessView.get("toolName"), payload.get("tool_name"), payload.get("toolName")))
.serverId(firstString(businessView.get("server_id"), businessView.get("serverId"), payload.get("server_id"), payload.get("serverId")))
.policyKind(firstString(businessView.get("policy_kind"), businessView.get("policyKind"), payload.get("policy_kind"), payload.get("policyKind")))
@@ -1236,11 +1241,17 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye
String kind = firstString(row.getKind());
return StringUtils.equals(category, "skill")
|| StringUtils.equals(category, "skill_call_audit")
+ || StringUtils.equals(category, "skill_catalog")
+ || StringUtils.equals(category, "skill_policy")
|| startsWithAny(kind, "skill_call_")
+ || startsWithAny(kind, "skill_catalog", "skill_policy")
|| StringUtils.equals(category, "tool_call_audit")
|| StringUtils.equals(category, "sandbox_audit")
|| StringUtils.equals(category, "token_cost")
|| StringUtils.isNotBlank(row.getSkillId())
+ || StringUtils.isNotBlank(row.getSkillVersion())
+ || StringUtils.isNotBlank(row.getInstallStatus())
+ || StringUtils.isNotBlank(row.getPermissionScope())
|| StringUtils.isNotBlank(row.getToolName())
|| StringUtils.isNotBlank(row.getServerId());
}
diff --git a/qiming-backend/app-platform-modules/app-platform-agent/app-platform-agent-core-application/src/test/java/com/xspaceagi/agent/core/application/service/DigitalEmployeeSyncApplicationServiceImplTest.java b/qiming-backend/app-platform-modules/app-platform-agent/app-platform-agent-core-application/src/test/java/com/xspaceagi/agent/core/application/service/DigitalEmployeeSyncApplicationServiceImplTest.java
index 6102af74..397ad7ba 100644
--- a/qiming-backend/app-platform-modules/app-platform-agent/app-platform-agent-core-application/src/test/java/com/xspaceagi/agent/core/application/service/DigitalEmployeeSyncApplicationServiceImplTest.java
+++ b/qiming-backend/app-platform-modules/app-platform-agent/app-platform-agent-core-application/src/test/java/com/xspaceagi/agent/core/application/service/DigitalEmployeeSyncApplicationServiceImplTest.java
@@ -461,6 +461,67 @@ class DigitalEmployeeSyncApplicationServiceImplTest {
assertThat(result.getRecords().get(2).getBusinessView()).containsEntry("total_tokens", 180);
}
+ @Test
+ void queryAdminWorkbenchSkillAuditsReturnsVersionPermissionAndPolicyRowsOnly() {
+ when(repository.queryBusinessRecords(eq(101L), eq(null), eq(null), eq(null), eq(null), eq(null), eq(null), eq(null), eq(1L), eq(20L)))
+ .thenReturn(page(List.of(
+ record("outbox-skill-catalog", "event", "event-skill-catalog-1", 101L, new Date(10_000),
+ Map.of(
+ "entity_type", "event",
+ "category", "skill_catalog",
+ "kind", "skill_catalog_snapshot",
+ "status", "enabled",
+ "title", "Browser skill installed",
+ "summary", "浏览器技能已安装",
+ "skill_id", "skill-web",
+ "skill_version", "1.2.3",
+ "install_status", "installed",
+ "permission_scope", "browser.open,browser.screenshot",
+ "policy_source", "local"
+ ),
+ Map.of("id", "event-skill-catalog-1", "kind", "skill_catalog_snapshot")),
+ record("outbox-skill-policy", "event", "event-skill-policy-1", 101L, new Date(11_000),
+ Map.of(
+ "entity_type", "event",
+ "category", "skill_policy",
+ "kind", "skill_policy_snapshot",
+ "status", "remote_disabled",
+ "title", "Browser skill policy",
+ "skill_id", "skill-web",
+ "skill_version", "1.2.3",
+ "policy_source", "remote",
+ "policy_status", "disabled",
+ "permission_scope", "browser.open"
+ ),
+ Map.of("id", "event-skill-policy-1", "kind", "skill_policy_snapshot")),
+ record("outbox-notification", "notification", "notification-1", 101L, new Date(12_000),
+ Map.of("entity_type", "notification", "title", "普通通知", "status", "unread"),
+ Map.of("id", "notification-1", "status", "unread")),
+ record("outbox-approval", "approval", "approval-1", 101L, new Date(13_000),
+ Map.of("entity_type", "approval", "title", "审批", "status", "pending"),
+ Map.of("id", "approval-1", "status", "pending")),
+ record("outbox-route", "event", "event-route-1", 101L, new Date(14_000),
+ Map.of("entity_type", "event", "kind", "route_decision_blocked", "title", "路由阻断", "status", "blocked"),
+ Map.of("id", "event-route-1", "kind", "route_decision_blocked"))
+ )));
+
+ DigitalEmployeeAdminWorkbenchPageDto result = service.queryAdminWorkbench(
+ "skill_audits", null, null, null, null, null, null, null, null, null, null, null, 1L, 20L
+ );
+
+ assertThat(result.getTotal()).isEqualTo(2);
+ assertThat(result.getRecords()).extracting(DigitalEmployeeAdminWorkbenchRowDto::getEntityId)
+ .containsExactly("event-skill-catalog-1", "event-skill-policy-1");
+ assertThat(result.getRecords().get(0).getView()).isEqualTo("skill_audits");
+ assertThat(result.getRecords().get(0).getSkillId()).isEqualTo("skill-web");
+ assertThat(result.getRecords().get(0).getSkillVersion()).isEqualTo("1.2.3");
+ assertThat(result.getRecords().get(0).getInstallStatus()).isEqualTo("installed");
+ assertThat(result.getRecords().get(0).getPermissionScope()).isEqualTo("browser.open,browser.screenshot");
+ assertThat(result.getRecords().get(0).getPolicySource()).isEqualTo("local");
+ assertThat(result.getRecords().get(1).getPolicySource()).isEqualTo("remote");
+ assertThat(result.getRecords().get(1).getPolicyStatus()).isEqualTo("disabled");
+ }
+
@Test
void queryAdminWorkbenchPolicyCenterReturnsPolicySnapshotRowsOnly() {
when(repository.queryBusinessRecords(eq(101L), eq(null), eq(null), eq(null), eq(null), eq(null), eq(null), eq(null), eq(1L), eq(20L)))
diff --git a/qiming/src/pages/SystemManagement/Content/DigitalEmployeeOps/index.tsx b/qiming/src/pages/SystemManagement/Content/DigitalEmployeeOps/index.tsx
index d2db5e4e..b5445fc8 100644
--- a/qiming/src/pages/SystemManagement/Content/DigitalEmployeeOps/index.tsx
+++ b/qiming/src/pages/SystemManagement/Content/DigitalEmployeeOps/index.tsx
@@ -128,6 +128,10 @@ function renderSummary(record: DigitalEmployeeAdminWorkbenchRow) {
record.daily_report_fact_id && `ReportFact ${record.daily_report_fact_id}`,
record.memory_id && `Memory ${record.memory_id}`,
record.skill_id && `Skill ${record.skill_id}`,
+ record.skill_version && `Version ${record.skill_version}`,
+ record.install_status && `Install ${record.install_status}`,
+ record.permission_scope && `Scope ${record.permission_scope}`,
+ record.policy_source && `PolicySource ${record.policy_source}`,
record.tool_name && `Tool ${record.tool_name}`,
record.schedule_id && `Schedule ${record.schedule_id}`,
record.job_id && `Job ${record.job_id}`,
@@ -835,6 +839,8 @@ const DigitalEmployeeOps: React.FC = () => {
detailRecord.memory_id && `Memory ${detailRecord.memory_id}`,
detailRecord.memory_key && `MemoryKey ${detailRecord.memory_key}`,
detailRecord.skill_id && `Skill ${detailRecord.skill_id}`,
+ detailRecord.skill_version && `Version ${detailRecord.skill_version}`,
+ detailRecord.policy_source && `PolicySource ${detailRecord.policy_source}`,
detailRecord.tool_name && `Tool ${detailRecord.tool_name}`,
detailRecord.server_id && `Server ${detailRecord.server_id}`,
detailRecord.schedule_id && `Schedule ${detailRecord.schedule_id}`,
@@ -977,9 +983,14 @@ const DigitalEmployeeOps: React.FC = () => {
技能审计:
{detailRecord.skill_id || detailRecord.tool_name || detailRecord.category || '--'}
{detailRecord.status && ` · ${detailRecord.status}`}
+ {detailRecord.skill_version && ` · 版本 ${detailRecord.skill_version}`}
+ {detailRecord.install_status && ` · 安装状态 ${detailRecord.install_status}`}
+ {detailRecord.permission_scope && ` · 权限范围 ${detailRecord.permission_scope}`}
+ {detailRecord.policy_source && ` · 策略来源 ${detailRecord.policy_source}`}
+ {detailRecord.policy_status && ` · 策略状态 ${detailRecord.policy_status}`}
{' '}
- · 只消费调用审计和安全摘要,不安装技能、不变更权限范围。
+ · 展示版本、安装状态、权限范围和策略来源,只消费调用审计和安全摘要,不安装技能、不变更权限范围。
)}
diff --git a/qiming/src/types/interfaces/systemManage.ts b/qiming/src/types/interfaces/systemManage.ts
index 8d44e281..9a1eca6f 100644
--- a/qiming/src/types/interfaces/systemManage.ts
+++ b/qiming/src/types/interfaces/systemManage.ts
@@ -628,6 +628,11 @@ export interface DigitalEmployeeAdminWorkbenchRow {
memory_id?: string;
memory_key?: string;
skill_id?: string;
+ skill_version?: string;
+ install_status?: string;
+ permission_scope?: string;
+ policy_source?: string;
+ policy_status?: string;
tool_name?: string;
server_id?: string;
policy_kind?: string;
diff --git a/qimingclaw/crates/agent-electron-client/scripts/check-digital-employee.js b/qimingclaw/crates/agent-electron-client/scripts/check-digital-employee.js
index aa8cbf1e..57ffbbab 100644
--- a/qimingclaw/crates/agent-electron-client/scripts/check-digital-employee.js
+++ b/qimingclaw/crates/agent-electron-client/scripts/check-digital-employee.js
@@ -1585,19 +1585,29 @@ function checkDigitalAdminMemorySkillWorkbench() {
[dto, "memory_id", "backend memory id row field"],
[dto, "memory_key", "backend memory key row field"],
[dto, "skill_id", "backend skill id row field"],
+ [dto, "skill_version", "backend skill version row field"],
+ [dto, "install_status", "backend skill install status row field"],
+ [dto, "permission_scope", "backend skill permission scope row field"],
+ [dto, "policy_source", "backend skill policy source row field"],
[dto, "tool_name", "backend tool name row field"],
[dto, "server_id", "backend server id row field"],
[test, "queryAdminWorkbenchMemoryGovernanceReturnsMemoryRowsOnly", "backend memory governance test"],
[test, "queryAdminWorkbenchSkillAuditsReturnsSkillAndToolAuditRowsOnly", "backend skill audits test"],
+ [test, "queryAdminWorkbenchSkillAuditsReturnsVersionPermissionAndPolicyRowsOnly", "backend skill version permission test"],
[qimingTypes, "memory_governance", "qiming memory governance view type"],
[qimingTypes, "skill_audits", "qiming skill audits view type"],
+ [qimingTypes, "skill_version", "qiming skill version field"],
+ [qimingTypes, "permission_scope", "qiming skill permission scope field"],
[qimingOps, "记忆治理", "qiming memory governance tab"],
[qimingOps, "技能审计", "qiming skill audits tab"],
+ [qimingOps, "权限范围", "qiming skill permission scope copy"],
+ [qimingOps, "策略来源", "qiming skill policy source copy"],
[qimingOps, "批量归档", "qiming memory archive action"],
[qimingOps, "批量恢复", "qiming memory restore action"],
[qimingOps, "重复候选", "qiming memory duplicate copy"],
[docs, "正式管理端记忆治理预览", "docs memory governance absorption"],
[docs, "正式管理端技能审计预览", "docs skill audit absorption"],
+ [docs, "正式管理端技能版本权限预览", "docs skill version permission absorption"],
];
const missing = requiredSnippets
.filter(([content, snippet]) => !content.includes(snippet))
diff --git a/qimingclaw/docs/digital-employee-frontend-integration-plan.md b/qimingclaw/docs/digital-employee-frontend-integration-plan.md
index 0c10bd3f..2c27ae47 100644
--- a/qimingclaw/docs/digital-employee-frontend-integration-plan.md
+++ b/qimingclaw/docs/digital-employee-frontend-integration-plan.md
@@ -578,8 +578,8 @@ GET /api/digital-employee/approvals
- 建议:先沉淀安全重启审计和人工确认体验,再评估更细粒度的服务恢复策略。
6. **技能生命周期与策略**
- - 已吸收:ACP / MCP / GUI / file server 能力已投射到 Skill Catalog,技能库不再使用 demo fallback;Skill Library 启用/禁用已写入 qimingclaw 本地 `digital_employee_skill_policies_v1.local_skills`,管理端下发策略写入 `remote_skills`,远端禁用优先生效且不会被本地按钮覆盖;入口路由候选技能会按有效策略过滤;MCP 注入 Agent 前会应用有效技能策略,ACP permission / tool update 会写入 `skill_call_allowed` / `skill_call_rejected` / `skill_call_observed` 审计事件,`policy_snapshot` 会包含本地/远端策略命中字段;embedded 已提供 `/api/digital-employee/skill-call-audits` 只读投影、`POST /api/skill/policies/pull` 手动拉取入口,技能调用策略与审计已开始闭环。管理端调用审计视图已开始吸收,embedded 新增“技能审计”入口,将 skill call audit、tool_call_audit、sandbox_audit 和 token_cost 统一成可筛选列表,技能库可按 skill id 跳转聚焦。正式管理端技能审计预览已开始吸收,qiming-backend 新增 `skill_audits` 运营台视图聚合 skill call、tool、sandbox 和 token/cost 安全摘要,qiming“数字员工运营台”的“技能审计”tab 只开放标记复核和忽略意图,不安装技能、不变更权限范围。
- - 缺口:仍缺少技能安装、版本管理和细粒度权限范围。
+ - 已吸收:ACP / MCP / GUI / file server 能力已投射到 Skill Catalog,技能库不再使用 demo fallback;Skill Library 启用/禁用已写入 qimingclaw 本地 `digital_employee_skill_policies_v1.local_skills`,管理端下发策略写入 `remote_skills`,远端禁用优先生效且不会被本地按钮覆盖;入口路由候选技能会按有效策略过滤;MCP 注入 Agent 前会应用有效技能策略,ACP permission / tool update 会写入 `skill_call_allowed` / `skill_call_rejected` / `skill_call_observed` 审计事件,`policy_snapshot` 会包含本地/远端策略命中字段;embedded 已提供 `/api/digital-employee/skill-call-audits` 只读投影、`POST /api/skill/policies/pull` 手动拉取入口,技能调用策略与审计已开始闭环。管理端调用审计视图已开始吸收,embedded 新增“技能审计”入口,将 skill call audit、tool_call_audit、sandbox_audit 和 token_cost 统一成可筛选列表,技能库可按 skill id 跳转聚焦。正式管理端技能审计预览已开始吸收,qiming-backend 新增 `skill_audits` 运营台视图聚合 skill call、tool、sandbox 和 token/cost 安全摘要,qiming“数字员工运营台”的“技能审计”tab 只开放标记复核和忽略意图,不安装技能、不变更权限范围。正式管理端技能版本权限预览已开始吸收,`skill_audits` 继续聚合 skill catalog / skill policy snapshot,qiming 详情可展示技能版本、安装状态、权限范围、策略来源和策略状态,用于解释权限命中但不开放安装或权限编辑。
+ - 缺口:仍缺少真实技能安装、版本升级管理和细粒度权限范围编辑。
- 建议:下一轮围绕管理端审计消费、技能安装和权限范围,把本地调用审计推进到更完整的跨端治理闭环。
7. **产物交付闭环**