1mod http;
2mod index;
3mod install;
4mod local;
5mod package_files;
6mod payload;
7mod refs;
8pub(crate) mod scopes;
9mod source_authority;
10mod trust_anchor;
11mod types;
12
13use runx_contracts::{JsonNumber, JsonObject, JsonValue};
14
15pub use http::{
16 AcquireOptions, DefaultRuntimeHttpTransport, HttpMethod, HttpRequest, HttpResponse,
17 RegistryClient, RegistryClientError, RuntimeHttpError, RuntimeHttpHeader, Transport,
18};
19pub use index::{
20 GithubRepoRef, IndexError, IndexGithubRepoOptions, IndexResponse, IndexWarning, IndexedListing,
21 IndexedRepo, index_github_repo, parse_github_repo_ref,
22};
23pub use install::{
24 InstallCandidate, InstallError, InstallLocalSkillOptions, InstallLocalSkillResult,
25 InstallStatus, install_local_skill,
26};
27pub use local::{
28 CreateRegistrySkillVersionResult, FileRegistryStore, IngestSkillOptions, LocalRegistryClient,
29 LocalRegistryError, PublishSkillMarkdownOptions, PutVersionOptions, RegistryResolveOptions,
30 RegistrySearchOptions, RegistrySkillVersionPayload, build_registry_skill_version,
31 build_skill_id, create_file_registry_store, create_local_registry_client,
32 create_registry_skill_version, ingest_skill_markdown, normalize_registry_skill_version,
33 publish_skill_markdown, read_registry_skill, resolve_registry_skill, resolve_runx_link,
34 runx_link_for_version, search_registry, search_registry_with_options, slugify, split_skill_id,
35};
36pub use refs::{
37 ParsedRegistryRef, RegistryResolveError, materialization_cache_path,
38 materialization_digest_marker, parse_registry_ref, safe_skill_package_parts,
39};
40pub use source_authority::{
41 RUNX_REGISTRY_SOURCE_AUTHORITY_ENV, RegistryManifestSourceAuthority,
42 is_official_runx_registry_url, registry_manifest_source_authority_from_env,
43 registry_manifest_source_authority_from_registry_dir,
44 registry_manifest_source_authority_from_registry_url, registry_manifest_source_key,
45};
46pub use trust_anchor::{
47 REGISTRY_SIGNED_MANIFEST_SCHEMA, RUNX_REGISTRY_MANIFEST_TRUST_KEY_ENV,
48 RUNX_REGISTRY_MANIFEST_TRUST_KEY_ID_ENV, RUNX_REGISTRY_MANIFEST_TRUST_OWNER_ENV,
49 RegistryManifestKeyError, RegistryManifestTrustEnvError, RegistryManifestTrustScope,
50 RegistryManifestVerificationFailure, TrustedRegistryManifestKey,
51 default_trusted_registry_manifest_keys, registry_manifest_key_allows,
52 trusted_registry_manifest_keys_from_env, trusted_registry_manifest_keys_from_env_with_source,
53 verify_registry_signed_manifest,
54};
55pub use types::{
56 AcquiredRegistrySkill, ProfileMode, PublishSkillMarkdownResult, PublishStatus,
57 RegistryAttestation, RegistryLinkResolution, RegistryManifestSignature, RegistryManifestSigner,
58 RegistryPackageFile, RegistryPublishHarnessReport, RegistryPublisher, RegistrySearchResult,
59 RegistrySignedManifest, RegistrySkill, RegistrySkillDetail, RegistrySkillResolution,
60 RegistrySkillVersion, RegistrySourceMetadata, ResolvedRegistryRef, TrustSignal, TrustTier,
61};
62
63#[derive(Clone, Copy, Debug)]
64pub struct RegistryInstallMetadataInput<'a> {
65 pub candidate: &'a InstallCandidate,
66 pub install: &'a InstallLocalSkillResult,
67 pub acquisition: Option<&'a AcquiredRegistrySkill>,
68}
69
70#[must_use]
71pub fn registry_install_receipt_metadata(input: RegistryInstallMetadataInput<'_>) -> JsonObject {
72 let mut metadata = JsonObject::new();
73 insert_string(&mut metadata, "ref", &input.candidate.r#ref);
74 insert_optional_string(&mut metadata, "skill_id", input.install.skill_id.as_deref());
75 insert_optional_string(&mut metadata, "version", input.install.version.as_deref());
76 insert_string(&mut metadata, "digest", &input.install.digest);
77 insert_optional_string(
78 &mut metadata,
79 "profile_digest",
80 input.install.profile_digest.as_deref(),
81 );
82 insert_optional_string(
83 &mut metadata,
84 "package_digest",
85 input.candidate.package_digest.as_deref(),
86 );
87 insert_optional_string(
88 &mut metadata,
89 "trust_tier",
90 input.install.trust_tier.as_ref().map(trust_tier_value),
91 );
92 if let Some(acquisition) = input.acquisition {
93 metadata.insert(
94 "publisher".to_owned(),
95 JsonValue::Object(publisher_metadata(&acquisition.publisher)),
96 );
97 metadata.insert(
98 "install_count".to_owned(),
99 JsonValue::Number(JsonNumber::U64(acquisition.install_count)),
100 );
101 }
102 insert_string(&mut metadata, "source_label", &input.install.source_label);
103 insert_string(
104 &mut metadata,
105 "destination",
106 &input.install.destination.display().to_string(),
107 );
108 insert_string(
109 &mut metadata,
110 "status",
111 match input.install.status {
112 InstallStatus::Installed => "installed",
113 InstallStatus::Unchanged => "unchanged",
114 },
115 );
116 metadata
117}
118
119fn publisher_metadata(publisher: &RegistryPublisher) -> JsonObject {
120 let mut metadata = JsonObject::new();
121 insert_string(&mut metadata, "kind", &publisher.kind);
122 insert_string(&mut metadata, "id", &publisher.id);
123 insert_optional_string(&mut metadata, "handle", publisher.handle.as_deref());
124 insert_optional_string(
125 &mut metadata,
126 "display_name",
127 publisher.display_name.as_deref(),
128 );
129 metadata
130}
131
132fn insert_string(metadata: &mut JsonObject, key: &str, value: &str) {
133 metadata.insert(key.to_owned(), JsonValue::String(value.to_owned()));
134}
135
136fn insert_optional_string(metadata: &mut JsonObject, key: &str, value: Option<&str>) {
137 if let Some(value) = value.filter(|value| !value.trim().is_empty()) {
138 insert_string(metadata, key, value);
139 }
140}
141
142fn trust_tier_value(value: &TrustTier) -> &'static str {
143 match value {
144 TrustTier::FirstParty => "first_party",
145 TrustTier::Verified => "verified",
146 TrustTier::Community => "community",
147 }
148}