Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@

import com.iflytek.skillhub.controller.BaseApiController;
import com.iflytek.skillhub.domain.authoring.SkillDraft;
import com.iflytek.skillhub.domain.skill.SkillVisibility;
import com.iflytek.skillhub.domain.authoring.service.DraftSubmitService;
import com.iflytek.skillhub.domain.authoring.service.FindingFixService;
import com.iflytek.skillhub.domain.authoring.service.RuntimeBindingService;
import com.iflytek.skillhub.domain.authoring.service.SkillDraftService;
import com.iflytek.skillhub.domain.authoring.service.ValidationRunService;
import com.iflytek.skillhub.domain.authoring.validation.ValidationFinding;
import com.iflytek.skillhub.domain.authoring.validation.ValidationRun;
import com.iflytek.skillhub.dto.ApiResponse;
import com.iflytek.skillhub.dto.CreateDraftRequest;
Expand All @@ -13,6 +17,8 @@
import com.iflytek.skillhub.dto.DraftResponse;
import com.iflytek.skillhub.dto.RuntimeBindingRequest;
import com.iflytek.skillhub.dto.RuntimeBindingResponse;
import com.iflytek.skillhub.dto.SubmitDraftRequest;
import com.iflytek.skillhub.dto.SubmitDraftResponse;
import com.iflytek.skillhub.dto.SaveDraftFileRequest;
import com.iflytek.skillhub.dto.SaveDraftFileResponse;
import com.iflytek.skillhub.dto.ValidationEventResponse;
Expand Down Expand Up @@ -42,8 +48,8 @@
* SKILL.md scaffold and arbitrary resource files; runtime bindings configure
* the agent, tool allowlist and MCP servers; validation runs execute the
* structure, config and behavior layers and report findings with fix
* suggestions. The fix-apply loop and publish integration arrive with the
* next layer.
* suggestions that can be applied in one click; validated drafts submit into
* the existing SkillHub publish pipeline.
*/
@RestController
@RequestMapping({"/api/v1/authoring", "/api/web/authoring"})
Expand All @@ -52,17 +58,23 @@ public class SkillAuthoringController extends BaseApiController {
private final SkillDraftService draftService;
private final RuntimeBindingService bindingService;
private final ValidationRunService runService;
private final DraftSubmitService submitService;
private final FindingFixService fixService;
private final ValidationRunOrchestrator orchestrator;

public SkillAuthoringController(com.iflytek.skillhub.dto.ApiResponseFactory responseFactory,
SkillDraftService draftService,
RuntimeBindingService bindingService,
ValidationRunService runService,
DraftSubmitService submitService,
FindingFixService fixService,
ValidationRunOrchestrator orchestrator) {
super(responseFactory);
this.draftService = draftService;
this.bindingService = bindingService;
this.runService = runService;
this.submitService = submitService;
this.fixService = fixService;
this.orchestrator = orchestrator;
}

Expand Down Expand Up @@ -272,4 +284,49 @@ public ApiResponse<List<ValidationFindingResponse>> listFindings(
.map(ValidationFindingResponse::from)
.toList());
}

// ---------------------------------------------------------------- fix loop

@Operation(operationId = "applyFindingFix", summary = "Apply a finding's fix suggestion to the draft")
@PostMapping("/runs/{runId}/findings/{findingId}/apply")
public ApiResponse<ValidationFindingResponse> applyFindingFix(
@PathVariable Long runId,
@PathVariable Long findingId,
@RequestAttribute("userId") String userId,
@RequestAttribute(value = "platformRoles", required = false)
Set<String> platformRoles) {
FindingFixService.FixOutcome outcome = fixService.applyFix(findingId, userId, platformRoles);
return ok("response.success.updated", ValidationFindingResponse.from(outcome.finding()));
}

@Operation(operationId = "dismissFindingFix", summary = "Dismiss a finding as not applicable")
@PostMapping("/runs/{runId}/findings/{findingId}/dismiss")
public ApiResponse<ValidationFindingResponse> dismissFinding(
@PathVariable Long runId,
@PathVariable Long findingId,
@RequestAttribute("userId") String userId,
@RequestAttribute(value = "platformRoles", required = false)
Set<String> platformRoles) {
ValidationFinding finding = fixService.dismissFinding(findingId, userId, platformRoles);
return ok("response.success.updated", ValidationFindingResponse.from(finding));
}

// ---------------------------------------------------------------- submission

@Operation(operationId = "submitValidatedDraft", summary = "Submit a validated draft into the publish pipeline")
@PostMapping("/drafts/{draftId}/submit")
public ApiResponse<SubmitDraftResponse> submitDraft(@PathVariable Long draftId,
@RequestBody(required = false) SubmitDraftRequest request,
@RequestAttribute("userId") String userId,
@RequestAttribute(value = "platformRoles", required = false)
Set<String> platformRoles) {
SkillVisibility visibility = request == null || request.visibility() == null
? SkillVisibility.PRIVATE
: SkillVisibility.valueOf(request.visibility());
Set<String> roles = request == null || request.platformRoles() == null
? platformRoles
: request.platformRoles();
return ok("response.success.created",
SubmitDraftResponse.from(submitService.submit(draftId, userId, visibility, roles)));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.iflytek.skillhub.dto;

import java.util.Set;

/** Request body for submitting a validated draft into the publish pipeline. */
public record SubmitDraftRequest(
String visibility,
Set<String> platformRoles
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.iflytek.skillhub.dto;

import com.iflytek.skillhub.domain.authoring.service.DraftSubmitService;

/** Outcome of submitting a validated draft: the published skill version coordinates. */
public record SubmitDraftResponse(
Long skillId,
Long versionId,
String slug,
String version
) {

public static SubmitDraftResponse from(DraftSubmitService.SubmitOutcome outcome) {
return new SubmitDraftResponse(
outcome.skillId(), outcome.versionId(), outcome.slug(), outcome.version());
}
}
3 changes: 3 additions & 0 deletions server/skillhub-app/src/main/resources/messages.properties
Original file line number Diff line number Diff line change
Expand Up @@ -354,3 +354,6 @@ error.authoring.binding.notFound=No runtime binding configured for draft {0}
error.authoring.binding.agentType.unknown=Unknown agent runtime type: {0}
error.authoring.binding.invalid=Invalid runtime binding: {0}
error.authoring.binding.unserializable=Runtime binding could not be serialized
# authoring fix loop and submission
error.authoring.submit.notValidated=Revision {0} has no passing validation run; run validation first
error.authoring.submit.runActive=Draft {0} has an active validation run
3 changes: 3 additions & 0 deletions server/skillhub-app/src/main/resources/messages_ru.properties
Original file line number Diff line number Diff line change
Expand Up @@ -297,3 +297,6 @@ error.authoring.binding.notFound=Для черновика {0} не настро
error.authoring.binding.agentType.unknown=Неизвестный тип среды выполнения агента: {0}
error.authoring.binding.invalid=Недопустимая привязка среды выполнения: {0}
error.authoring.binding.unserializable=Привязка среды выполнения не может быть сериализована
# authoring fix loop and submission
error.authoring.submit.notValidated=У ревизии {0} нет пройденной задачи проверки; сначала выполните проверку
error.authoring.submit.runActive=У черновика {0} есть активная задача проверки
3 changes: 3 additions & 0 deletions server/skillhub-app/src/main/resources/messages_zh.properties
Original file line number Diff line number Diff line change
Expand Up @@ -356,3 +356,6 @@ error.authoring.binding.notFound=草稿 {0} 尚未配置运行时绑定
error.authoring.binding.agentType.unknown=未知的 Agent 运行时类型:{0}
error.authoring.binding.invalid=运行时绑定不合法:{0}
error.authoring.binding.unserializable=运行时绑定无法序列化
# authoring fix loop and submission
error.authoring.submit.notValidated=版本 {0} 没有通过的验证任务,请先执行验证
error.authoring.submit.runActive=草稿 {0} 有正在进行的验证任务
Loading