diff --git a/pkg/registrybroker/skills_status.go b/pkg/registrybroker/skills_status.go index 840a8e7..299ccdd 100644 --- a/pkg/registrybroker/skills_status.go +++ b/pkg/registrybroker/skills_status.go @@ -2,6 +2,7 @@ package registrybroker import ( "context" + "fmt" "net/http" "net/url" "strings" @@ -49,26 +50,46 @@ func (c *RegistryBrokerClient) GetSkillStatusByRepo( return response, err } -func (c *RegistryBrokerClient) UploadSkillPreviewFromGithubOIDC( +func (c *RegistryBrokerClient) QuoteSkillPublishPreview( ctx context.Context, - token string, - report *SkillPreviewReport, -) (SkillPreviewRecord, error) { - if err := ensureNonEmpty(token, "token"); err != nil { - return SkillPreviewRecord{}, err + request *SkillQuotePreviewRequest, +) (SkillQuotePreviewResponse, error) { + if request == nil { + return SkillQuotePreviewResponse{}, fmt.Errorf("request is required") } - if report == nil { - return SkillPreviewRecord{}, ensureNonEmpty("", "report") + if request.FileCount <= 0 { + return SkillQuotePreviewResponse{}, fmt.Errorf("fileCount must be greater than 0") } - var response SkillPreviewRecord + if request.TotalBytes <= 0 { + return SkillQuotePreviewResponse{}, fmt.Errorf("totalBytes must be greater than 0") + } + var response SkillQuotePreviewResponse err := c.requestTypedJSON( ctx, http.MethodPost, - "/skills/preview/github-oidc", - report, - map[string]string{ - "authorization": "Bearer " + token, - }, + "/skills/quote-preview", + request, + nil, + &response, + ) + return response, err +} + +func (c *RegistryBrokerClient) GetSkillConversionSignalsByRepo( + ctx context.Context, + request SkillPreviewByRepoRequest, +) (SkillConversionSignalsResponse, error) { + query, err := skillPreviewRepoQuery(request) + if err != nil { + return SkillConversionSignalsResponse{}, err + } + var response SkillConversionSignalsResponse + err = c.requestTypedJSON( + ctx, + http.MethodGet, + pathWithQuery("/skills/conversion-signals/by-repo", query), + nil, + nil, &response, ) return response, err @@ -135,6 +156,39 @@ func (c *RegistryBrokerClient) GetSkillPreviewByID( return response, err } +func (c *RegistryBrokerClient) UploadSkillPreviewFromGithubOIDC( + ctx context.Context, + token string, + report *SkillPreviewReport, +) (SkillPreviewRecord, error) { + if err := ensureNonEmpty(token, "token"); err != nil { + return SkillPreviewRecord{}, err + } + if report == nil { + return SkillPreviewRecord{}, ensureNonEmpty("", "report") + } + var response SkillPreviewRecord + err := c.requestTypedJSON( + ctx, + http.MethodPost, + "/skills/preview/github-oidc", + report, + map[string]string{ + "authorization": "Bearer " + strings.TrimSpace(token), + }, + &response, + ) + return response, err +} + +func (c *RegistryBrokerClient) UploadSkillPreviewFromGitHubOIDC( + ctx context.Context, + token string, + report *SkillPreviewReport, +) (SkillPreviewRecord, error) { + return c.UploadSkillPreviewFromGithubOIDC(ctx, token, report) +} + func skillPreviewRepoQuery(request SkillPreviewByRepoRequest) (url.Values, error) { if err := ensureNonEmpty(request.Repo, "repo"); err != nil { return nil, err diff --git a/pkg/registrybroker/skills_status_live_test.go b/pkg/registrybroker/skills_status_live_test.go new file mode 100644 index 0000000..dce0cf9 --- /dev/null +++ b/pkg/registrybroker/skills_status_live_test.go @@ -0,0 +1,47 @@ +package registrybroker + +import ( + "context" + "os" + "testing" +) + +func TestLiveSkillGrowthEndpoints(t *testing.T) { + if os.Getenv("HASHNET_LIVE_TESTS") != "1" { + t.Skip("set HASHNET_LIVE_TESTS=1 to run live registry broker checks") + } + + client, err := NewRegistryBrokerClient(RegistryBrokerClientOptions{ + BaseURL: "https://hol.org/registry/api/v1", + }) + if err != nil { + t.Fatalf("failed to create client: %v", err) + } + + quote, err := client.QuoteSkillPublishPreview(context.Background(), &SkillQuotePreviewRequest{ + FileCount: 2, + TotalBytes: 3072, + Name: "registry-broker", + Version: "1.2.3", + RepoURL: "https://github.com/hashgraph-online/registry-broker-skill", + SkillDir: ".", + }) + if err != nil { + t.Fatalf("quote skill publish preview failed: %v", err) + } + if quote.EstimatedCredits.Min <= 0 || quote.EstimatedCredits.Max <= 0 { + t.Fatalf("unexpected quote response %#v", quote) + } + + signals, err := client.GetSkillConversionSignalsByRepo(context.Background(), SkillPreviewByRepoRequest{ + Repo: "https://github.com/hashgraph-online/registry-broker-skills", + SkillDir: ".", + Ref: "refs/heads/main", + }) + if err != nil { + t.Fatalf("get skill conversion signals by repo failed: %v", err) + } + if signals.TrustTier == "" { + t.Fatalf("expected trust tier in live response") + } +} diff --git a/pkg/registrybroker/skills_status_test.go b/pkg/registrybroker/skills_status_test.go index 44012a3..9de9d50 100644 --- a/pkg/registrybroker/skills_status_test.go +++ b/pkg/registrybroker/skills_status_test.go @@ -4,12 +4,9 @@ import ( "context" "net/http" "net/http/httptest" - "strings" "testing" ) -const previewID = "preview-1" - func TestGetSkillStatusParsesLifecycleSignals(t *testing.T) { t.Parallel() @@ -21,10 +18,10 @@ func TestGetSkillStatusParsesLifecycleSignals(t *testing.T) { t.Fatalf("unexpected path %s", request.URL.Path) } if request.URL.Query().Get("name") != "registry-broker" { - t.Fatalf("unexpected name query %s", request.URL.Query().Get("name")) + t.Fatalf("unexpected name query %#v", request.URL.Query().Get("name")) } if request.URL.Query().Get("version") != "1.2.3" { - t.Fatalf("unexpected version query %s", request.URL.Query().Get("version")) + t.Fatalf("unexpected version query %#v", request.URL.Query().Get("version")) } writer.Header().Set("content-type", "application/json") _, _ = writer.Write([]byte(`{ @@ -43,10 +40,9 @@ func TestGetSkillStatusParsesLifecycleSignals(t *testing.T) { { "kind": "share_status", "priority": 1, - "id": "share-skill", + "id": "share", "label": "Share status", - "description": "Share the canonical page", - "url": "https://hol.org/registry/skills/registry-broker" + "description": "Share the canonical page" } ], "verificationSignals": { @@ -62,27 +58,6 @@ func TestGetSkillStatusParsesLifecycleSignals(t *testing.T) { "previewAvailable": true, "previewAuthoritative": false }, - "publisher": { - "cliPackageUrl": "https://www.npmjs.com/package/skill-publish", - "cliCommand": "npx skill-publish", - "actionMarketplaceUrl": "https://github.com/marketplace/actions/skill-publish", - "repositoryUrl": "https://github.com/hashgraph-online/skill-publish", - "quickstartCommands": [], - "templatePresets": [] - }, - "preview": { - "previewId": "preview-1", - "repoUrl": "https://github.com/hashgraph-online/registry-broker-skill", - "repoOwner": "hashgraph-online", - "repoName": "registry-broker-skill", - "commitSha": "abc123", - "ref": "refs/pull/5/head", - "eventName": "pull_request", - "skillDir": ".", - "generatedAt": "2026-04-04T10:00:00.000Z", - "expiresAt": "2026-04-11T10:00:00.000Z", - "statusUrl": "https://hol.org/registry/skills/preview/preview-1" - }, "statusUrl": "https://hol.org/registry/skills/registry-broker?version=1.2.3" }`)) })) @@ -103,15 +78,9 @@ func TestGetSkillStatusParsesLifecycleSignals(t *testing.T) { if err != nil { t.Fatalf("get skill status failed: %v", err) } - if status.TrustTier != "verified" { + if status.TrustTier != SkillTrustTier("verified") { t.Fatalf("unexpected trust tier %#v", status.TrustTier) } - if !status.VerificationSignals.PreviewValidated { - t.Fatalf("expected preview validated signal") - } - if status.Preview == nil || status.Preview.PreviewID != previewID { - t.Fatalf("expected preview metadata %#v", status.Preview) - } if len(status.NextSteps) != 1 || status.NextSteps[0].Kind != "share_status" { t.Fatalf("unexpected next steps %#v", status.NextSteps) } @@ -122,93 +91,176 @@ func TestSkillPreviewEndpointsUseCanonicalPaths(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) { writer.Header().Set("content-type", "application/json") - switch { - case request.Method == http.MethodGet && request.URL.Path == "/api/v1/skills/preview": - if request.URL.Query().Get("name") != "registry-broker" { - t.Fatalf("unexpected preview name query %s", request.URL.Query().Get("name")) + switch request.URL.Path { + case "/api/v1/skills/status/by-repo": + if request.URL.Query().Get("repo") != "https://github.com/hashgraph-online/registry-broker-skill" { + t.Fatalf("unexpected repo query %#v", request.URL.Query().Get("repo")) + } + if request.URL.Query().Get("skillDir") != "." { + t.Fatalf("unexpected skillDir query %#v", request.URL.Query().Get("skillDir")) + } + if request.URL.Query().Get("ref") != "refs/heads/main" { + t.Fatalf("unexpected ref query %#v", request.URL.Query().Get("ref")) } _, _ = writer.Write([]byte(`{ - "found": true, - "authoritative": false, - "preview": { - "id": "record-1", - "previewId": "preview-1", - "source": "github-oidc", - "report": { - "schema_version": "skill-preview.v1", - "tool_version": "1.0.0", - "preview_id": "preview-1", - "repo_url": "https://github.com/hashgraph-online/registry-broker-skill", - "repo_owner": "hashgraph-online", - "repo_name": "registry-broker-skill", - "default_branch": "main", - "commit_sha": "abc123", - "ref": "refs/pull/5/head", - "event_name": "pull_request", - "workflow_run_url": "https://github.com/hashgraph-online/registry-broker-skill/actions/runs/1", - "skill_dir": ".", - "name": "registry-broker", - "version": "1.2.3", - "validation_status": "passed", - "findings": [], - "package_summary": {"files": 2}, - "suggested_next_steps": [], - "generated_at": "2026-04-04T10:00:00.000Z" + "name":"registry-broker", + "version":"1.2.3", + "published":false, + "verifiedDomain":false, + "trustTier":"validated", + "badgeMetric":"tier", + "checks":{"repoCommitIntegrity":true,"manifestIntegrity":true,"domainProof":false}, + "nextSteps":[], + "verificationSignals":{"publisherBound":false,"domainProof":false,"verifiedDomain":false,"previewValidated":true}, + "provenanceSignals":{"repoCommitIntegrity":true,"manifestIntegrity":true,"canonicalRelease":false,"previewAvailable":true,"previewAuthoritative":false}, + "statusUrl":"https://hol.org/registry/skills/preview/preview-1" + }`)) + case "/api/v1/skills/conversion-signals/by-repo": + _, _ = writer.Write([]byte(`{ + "repoUrl":"https://github.com/hashgraph-online/registry-broker-skill", + "skillDir":".", + "trustTier":"validated", + "actionInstalled":true, + "previewUploaded":true, + "previewId":"preview-1", + "published":false, + "verified":false, + "publishReady":true, + "publishBlockedByMissingAuth":false, + "statusUrl":"https://hol.org/registry/skills/preview/preview-1", + "purchaseUrl":"https://hol.org/registry/skills/publish", + "publishUrl":"https://hol.org/registry/skills/submit", + "verificationUrl":"https://hol.org/registry/skills/registry-broker?tab=verification", + "nextSteps":[] + }`)) + case "/api/v1/skills/quote-preview": + if request.Method != http.MethodPost { + t.Fatalf("expected POST, got %s", request.Method) + } + _, _ = writer.Write([]byte(`{ + "estimatedCredits":{"min":589,"max":678}, + "estimatedHbar":{"min":4.11,"max":4.73}, + "pricingVersion":"2026-04-05", + "assumptions":["2 files","3 KB total"], + "purchaseUrl":"https://hol.org/registry/skills/publish", + "publishUrl":"https://hol.org/registry/skills/submit", + "verificationUrl":"https://hol.org/registry/skills/registry-broker?tab=verification" + }`)) + case "/api/v1/skills/preview": + _, _ = writer.Write([]byte(`{ + "found":true, + "authoritative":false, + "preview":{ + "id":"record-1", + "previewId":"preview-1", + "source":"github-oidc", + "report":{ + "schema_version":"skill-preview.v1", + "tool_version":"1.0.0", + "preview_id":"preview-1", + "repo_url":"https://github.com/hashgraph-online/registry-broker-skill", + "repo_owner":"hashgraph-online", + "repo_name":"registry-broker-skill", + "default_branch":"main", + "commit_sha":"abc123", + "ref":"refs/pull/5/head", + "event_name":"pull_request", + "workflow_run_url":"https://github.com/hashgraph-online/registry-broker-skill/actions/runs/1", + "skill_dir":".", + "name":"registry-broker", + "version":"1.2.3", + "validation_status":"passed", + "findings":[], + "package_summary":{"files":2}, + "suggested_next_steps":[], + "generated_at":"2026-04-04T10:00:00.000Z" }, - "generatedAt": "2026-04-04T10:00:00.000Z", - "expiresAt": "2026-04-11T10:00:00.000Z", - "statusUrl": "https://hol.org/registry/skills/preview/preview-1", - "authoritative": false + "generatedAt":"2026-04-04T10:00:00.000Z", + "expiresAt":"2026-04-11T10:00:00.000Z", + "statusUrl":"https://hol.org/registry/skills/preview/preview-1", + "authoritative":false }, - "statusUrl": "https://hol.org/registry/skills/preview/preview-1", - "expiresAt": "2026-04-11T10:00:00.000Z" + "statusUrl":"https://hol.org/registry/skills/preview/preview-1", + "expiresAt":"2026-04-11T10:00:00.000Z" }`)) - case request.Method == http.MethodGet && request.URL.Path == "/api/v1/skills/preview/by-repo": - if request.URL.Query().Get("repo") != "hashgraph-online/registry-broker-skill" { - t.Fatalf("unexpected preview repo query %s", request.URL.Query().Get("repo")) - } - if request.URL.Query().Get("skillDir") != "." { - t.Fatalf("unexpected preview skillDir query %s", request.URL.Query().Get("skillDir")) - } - _, _ = writer.Write([]byte(`{"found": false, "authoritative": false, "preview": null, "statusUrl": null, "expiresAt": null}`)) - case request.Method == http.MethodGet && request.URL.Path == "/api/v1/skills/preview/preview-1": - _, _ = writer.Write([]byte(`{"found": true, "authoritative": false, "preview": {"id":"record-1","previewId":"preview-1","source":"github-oidc","report":{"schema_version":"skill-preview.v1","tool_version":"1.0.0","preview_id":"preview-1","repo_url":"https://github.com/hashgraph-online/registry-broker-skill","repo_owner":"hashgraph-online","repo_name":"registry-broker-skill","default_branch":"main","commit_sha":"abc123","ref":"refs/pull/5/head","event_name":"pull_request","workflow_run_url":"https://github.com/hashgraph-online/registry-broker-skill/actions/runs/1","skill_dir":".","name":"registry-broker","version":"1.2.3","validation_status":"passed","findings":[],"package_summary":{"files":2},"suggested_next_steps":[],"generated_at":"2026-04-04T10:00:00.000Z"},"generatedAt":"2026-04-04T10:00:00.000Z","expiresAt":"2026-04-11T10:00:00.000Z","statusUrl":"https://hol.org/registry/skills/preview/preview-1","authoritative":false},"statusUrl":"https://hol.org/registry/skills/preview/preview-1","expiresAt":"2026-04-11T10:00:00.000Z"}`)) - case request.Method == http.MethodPost && request.URL.Path == "/api/v1/skills/preview/github-oidc": - if !strings.HasPrefix(request.Header.Get("Authorization"), "Bearer github-token") { - t.Fatalf("expected bearer token, got %q", request.Header.Get("Authorization")) + case "/api/v1/skills/preview/by-repo": + _, _ = writer.Write([]byte(`{ + "found":false, + "authoritative":false + }`)) + case "/api/v1/skills/preview/preview-1": + _, _ = writer.Write([]byte(`{ + "found":true, + "authoritative":false, + "preview":{ + "id":"record-1", + "previewId":"preview-1", + "source":"github-oidc", + "report":{ + "schema_version":"skill-preview.v1", + "tool_version":"1.0.0", + "preview_id":"preview-1", + "repo_url":"https://github.com/hashgraph-online/registry-broker-skill", + "repo_owner":"hashgraph-online", + "repo_name":"registry-broker-skill", + "default_branch":"main", + "commit_sha":"abc123", + "ref":"refs/pull/5/head", + "event_name":"pull_request", + "workflow_run_url":"https://github.com/hashgraph-online/registry-broker-skill/actions/runs/1", + "skill_dir":".", + "name":"registry-broker", + "version":"1.2.3", + "validation_status":"passed", + "findings":[], + "package_summary":{"files":2}, + "suggested_next_steps":[], + "generated_at":"2026-04-04T10:00:00.000Z" + }, + "generatedAt":"2026-04-04T10:00:00.000Z", + "expiresAt":"2026-04-11T10:00:00.000Z", + "statusUrl":"https://hol.org/registry/skills/preview/preview-1", + "authoritative":false + }, + "statusUrl":"https://hol.org/registry/skills/preview/preview-1", + "expiresAt":"2026-04-11T10:00:00.000Z" + }`)) + case "/api/v1/skills/preview/github-oidc": + if request.Header.Get("authorization") != "Bearer github-token" { + t.Fatalf("unexpected authorization header %#v", request.Header.Get("authorization")) } _, _ = writer.Write([]byte(`{ - "id": "record-1", - "previewId": "preview-1", - "source": "github-oidc", - "report": { - "schema_version": "skill-preview.v1", - "tool_version": "1.0.0", - "preview_id": "preview-1", - "repo_url": "https://github.com/hashgraph-online/registry-broker-skill", - "repo_owner": "hashgraph-online", - "repo_name": "registry-broker-skill", - "default_branch": "main", - "commit_sha": "abc123", - "ref": "refs/pull/5/head", - "event_name": "pull_request", - "workflow_run_url": "https://github.com/hashgraph-online/registry-broker-skill/actions/runs/1", - "skill_dir": ".", - "name": "registry-broker", - "version": "1.2.3", - "validation_status": "passed", - "findings": [], - "package_summary": {"files": 2}, - "suggested_next_steps": [], - "generated_at": "2026-04-04T10:00:00.000Z" + "id":"record-1", + "previewId":"preview-1", + "source":"github-oidc", + "report":{ + "schema_version":"skill-preview.v1", + "tool_version":"1.0.0", + "preview_id":"preview-1", + "repo_url":"https://github.com/hashgraph-online/registry-broker-skill", + "repo_owner":"hashgraph-online", + "repo_name":"registry-broker-skill", + "default_branch":"main", + "commit_sha":"abc123", + "ref":"refs/pull/5/head", + "event_name":"pull_request", + "workflow_run_url":"https://github.com/hashgraph-online/registry-broker-skill/actions/runs/1", + "skill_dir":".", + "name":"registry-broker", + "version":"1.2.3", + "validation_status":"passed", + "findings":[], + "package_summary":{"files":2}, + "suggested_next_steps":[], + "generated_at":"2026-04-04T10:00:00.000Z" }, - "generatedAt": "2026-04-04T10:00:00.000Z", - "expiresAt": "2026-04-11T10:00:00.000Z", - "statusUrl": "https://hol.org/registry/skills/preview/preview-1", - "authoritative": false + "generatedAt":"2026-04-04T10:00:00.000Z", + "expiresAt":"2026-04-11T10:00:00.000Z", + "statusUrl":"https://hol.org/registry/skills/preview/preview-1", + "authoritative":false }`)) default: - t.Fatalf("unexpected %s %s", request.Method, request.URL.Path) + t.Fatalf("unexpected path %s", request.URL.Path) } })) defer server.Close() @@ -221,6 +273,45 @@ func TestSkillPreviewEndpointsUseCanonicalPaths(t *testing.T) { t.Fatalf("failed to create client: %v", err) } + statusByRepo, err := client.GetSkillStatusByRepo(context.Background(), SkillPreviewByRepoRequest{ + Repo: "https://github.com/hashgraph-online/registry-broker-skill", + SkillDir: ".", + Ref: "refs/heads/main", + }) + if err != nil { + t.Fatalf("get skill status by repo failed: %v", err) + } + if statusByRepo.TrustTier != "validated" { + t.Fatalf("unexpected trust tier %#v", statusByRepo.TrustTier) + } + + signals, err := client.GetSkillConversionSignalsByRepo(context.Background(), SkillPreviewByRepoRequest{ + Repo: "https://github.com/hashgraph-online/registry-broker-skill", + SkillDir: ".", + Ref: "refs/heads/main", + }) + if err != nil { + t.Fatalf("get skill conversion signals failed: %v", err) + } + if !signals.PublishReady { + t.Fatalf("expected publish to be ready") + } + + quote, err := client.QuoteSkillPublishPreview(context.Background(), &SkillQuotePreviewRequest{ + FileCount: 2, + TotalBytes: 3072, + Name: "registry-broker", + Version: "1.2.3", + RepoURL: "https://github.com/hashgraph-online/registry-broker-skill", + SkillDir: ".", + }) + if err != nil { + t.Fatalf("quote skill publish preview failed: %v", err) + } + if quote.EstimatedCredits.Min != 589 || quote.EstimatedCredits.Max != 678 { + t.Fatalf("unexpected estimated credits %#v", quote.EstimatedCredits) + } + preview, err := client.GetSkillPreview( context.Background(), SkillPreviewLookupRequest{Name: "registry-broker", Version: "1.2.3"}, @@ -228,61 +319,54 @@ func TestSkillPreviewEndpointsUseCanonicalPaths(t *testing.T) { if err != nil { t.Fatalf("get skill preview failed: %v", err) } - if !preview.Found || preview.Preview == nil || preview.Preview.PreviewID != previewID { - t.Fatalf("unexpected preview %#v", preview) + if preview.Preview == nil || preview.Preview.PreviewID != "preview-1" { + t.Fatalf("unexpected preview %#v", preview.Preview) } - byRepo, err := client.GetSkillPreviewByRepo( - context.Background(), - SkillPreviewByRepoRequest{ - Repo: "hashgraph-online/registry-broker-skill", - SkillDir: ".", - }, - ) + previewByRepo, err := client.GetSkillPreviewByRepo(context.Background(), SkillPreviewByRepoRequest{ + Repo: "https://github.com/hashgraph-online/registry-broker-skill", + SkillDir: ".", + }) if err != nil { t.Fatalf("get skill preview by repo failed: %v", err) } - if byRepo.Found { - t.Fatalf("expected preview by repo to be absent %#v", byRepo) + if previewByRepo.Found { + t.Fatalf("expected preview lookup by repo to be absent") } - byID, err := client.GetSkillPreviewByID(context.Background(), previewID) + previewByID, err := client.GetSkillPreviewByID(context.Background(), "preview-1") if err != nil { t.Fatalf("get skill preview by id failed: %v", err) } - if byID.Preview == nil || byID.Preview.ID != "record-1" { - t.Fatalf("unexpected preview by id %#v", byID) + if previewByID.Preview == nil || previewByID.Preview.ID != "record-1" { + t.Fatalf("unexpected preview by id %#v", previewByID.Preview) } - uploaded, err := client.UploadSkillPreviewFromGithubOIDC( - context.Background(), - "github-token", - &SkillPreviewReport{ - SchemaVersion: "skill-preview.v1", - ToolVersion: "1.0.0", - PreviewID: previewID, - RepoURL: "https://github.com/hashgraph-online/registry-broker-skill", - RepoOwner: "hashgraph-online", - RepoName: "registry-broker-skill", - DefaultBranch: "main", - CommitSHA: "abc123", - Ref: "refs/pull/5/head", - EventName: "pull_request", - WorkflowRunURL: "https://github.com/hashgraph-online/registry-broker-skill/actions/runs/1", - SkillDir: ".", - Name: "registry-broker", - Version: "1.2.3", - ValidationStatus: "passed", - Findings: []any{}, - PackageSummary: JSONObject{"files": 2}, - SuggestedNextSteps: []SkillPreviewSuggestedNextStep{}, - GeneratedAt: "2026-04-04T10:00:00.000Z", - }, - ) + uploadedPreview, err := client.UploadSkillPreviewFromGitHubOIDC(context.Background(), "github-token", &SkillPreviewReport{ + SchemaVersion: "skill-preview.v1", + ToolVersion: "1.0.0", + PreviewID: "preview-1", + RepoURL: "https://github.com/hashgraph-online/registry-broker-skill", + RepoOwner: "hashgraph-online", + RepoName: "registry-broker-skill", + DefaultBranch: "main", + CommitSHA: "abc123", + Ref: "refs/pull/5/head", + EventName: "pull_request", + WorkflowRunURL: "https://github.com/hashgraph-online/registry-broker-skill/actions/runs/1", + SkillDir: ".", + Name: "registry-broker", + Version: "1.2.3", + ValidationStatus: "passed", + Findings: []any{}, + PackageSummary: JSONObject{"files": 2}, + SuggestedNextSteps: []SkillPreviewSuggestedNextStep{}, + GeneratedAt: "2026-04-04T10:00:00.000Z", + }) if err != nil { t.Fatalf("upload skill preview failed: %v", err) } - if uploaded.Source != "github-oidc" || uploaded.PreviewID != previewID { - t.Fatalf("unexpected uploaded preview %#v", uploaded) + if uploadedPreview.ID != "record-1" { + t.Fatalf("unexpected uploaded preview %#v", uploadedPreview) } } diff --git a/pkg/registrybroker/skills_status_types.go b/pkg/registrybroker/skills_status_types.go index 56e98b5..02f6792 100644 --- a/pkg/registrybroker/skills_status_types.go +++ b/pkg/registrybroker/skills_status_types.go @@ -128,3 +128,47 @@ type SkillStatusResponse struct { Preview *SkillStatusPreviewMetadata `json:"preview,omitempty"` StatusURL *string `json:"statusUrl,omitempty"` } + +type SkillQuotePreviewRequest struct { + FileCount int `json:"fileCount"` + TotalBytes int `json:"totalBytes"` + Name string `json:"name,omitempty"` + Version string `json:"version,omitempty"` + RepoURL string `json:"repoUrl,omitempty"` + SkillDir string `json:"skillDir,omitempty"` +} + +type SkillQuotePreviewRange struct { + Min int `json:"min"` + Max int `json:"max"` +} + +type SkillQuotePreviewResponse struct { + EstimatedCredits SkillQuotePreviewRange `json:"estimatedCredits"` + EstimatedHbar JSONObject `json:"estimatedHbar,omitempty"` + PricingVersion string `json:"pricingVersion"` + Assumptions []string `json:"assumptions,omitempty"` + PurchaseURL string `json:"purchaseUrl,omitempty"` + PublishURL string `json:"publishUrl,omitempty"` + VerificationURL string `json:"verificationUrl,omitempty"` +} + +type SkillConversionSignalsResponse struct { + RepoURL string `json:"repoUrl"` + SkillDir string `json:"skillDir"` + TrustTier SkillTrustTier `json:"trustTier"` + ActionInstalled bool `json:"actionInstalled"` + PreviewUploaded bool `json:"previewUploaded"` + PreviewID string `json:"previewId,omitempty"` + LastValidateSuccessAt string `json:"lastValidateSuccessAt,omitempty"` + StalePreviewAgeDays int `json:"stalePreviewAgeDays,omitempty"` + Published bool `json:"published"` + Verified bool `json:"verified"` + PublishReady bool `json:"publishReady"` + PublishBlockedByMissingAuth bool `json:"publishBlockedByMissingAuth"` + StatusURL string `json:"statusUrl,omitempty"` + PurchaseURL string `json:"purchaseUrl,omitempty"` + PublishURL string `json:"publishUrl,omitempty"` + VerificationURL string `json:"verificationUrl,omitempty"` + NextSteps []SkillStatusNextStep `json:"nextSteps,omitempty"` +}