@siglume/api-sdk 0.7.5 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +34 -3
- package/dist/bin/siglume.cjs +442 -44
- package/dist/bin/siglume.cjs.map +1 -1
- package/dist/bin/siglume.js +442 -44
- package/dist/bin/siglume.js.map +1 -1
- package/dist/cli/index.cjs +442 -44
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.d.cts +11 -0
- package/dist/cli/index.d.ts +11 -0
- package/dist/cli/index.js +442 -44
- package/dist/cli/index.js.map +1 -1
- package/dist/index.cjs +40 -26
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -2
- package/dist/index.d.ts +14 -2
- package/dist/index.js +40 -26
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.cjs
CHANGED
|
@@ -1352,6 +1352,9 @@ function parseListing(data) {
|
|
|
1352
1352
|
short_description: stringOrNull(data.short_description),
|
|
1353
1353
|
docs_url: stringOrNull(data.docs_url),
|
|
1354
1354
|
support_contact: stringOrNull(data.support_contact),
|
|
1355
|
+
seller_display_name: stringOrNull(data.seller_display_name),
|
|
1356
|
+
seller_homepage_url: stringOrNull(data.seller_homepage_url),
|
|
1357
|
+
seller_social_url: stringOrNull(data.seller_social_url),
|
|
1355
1358
|
review_status: stringOrNull(data.review_status),
|
|
1356
1359
|
review_note: stringOrNull(data.review_note),
|
|
1357
1360
|
submission_blockers: Array.isArray(data.submission_blockers) ? data.submission_blockers.filter((item) => typeof item === "string") : [],
|
|
@@ -2533,11 +2536,15 @@ var init_client = __esm({
|
|
|
2533
2536
|
max_retries;
|
|
2534
2537
|
fetchImpl;
|
|
2535
2538
|
pendingConfirmations = /* @__PURE__ */ new Map();
|
|
2536
|
-
constructor(options) {
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
+
constructor(options = {}) {
|
|
2540
|
+
const envApiKey = typeof process !== "undefined" ? process.env?.SIGLUME_API_KEY : void 0;
|
|
2541
|
+
const resolvedApiKey = (options.api_key ?? envApiKey ?? "").trim();
|
|
2542
|
+
if (!resolvedApiKey) {
|
|
2543
|
+
throw new SiglumeClientError(
|
|
2544
|
+
"SIGLUME_API_KEY is required. Pass it as the api_key option or set the SIGLUME_API_KEY env var."
|
|
2545
|
+
);
|
|
2539
2546
|
}
|
|
2540
|
-
this.api_key =
|
|
2547
|
+
this.api_key = resolvedApiKey;
|
|
2541
2548
|
this.agent_key = options.agent_key?.trim() || void 0;
|
|
2542
2549
|
this.base_url = (options.base_url ?? DEFAULT_SIGLUME_API_BASE).replace(/\/+$/, "");
|
|
2543
2550
|
this.timeout_ms = Math.max(1, options.timeout_ms ?? 15e3);
|
|
@@ -2564,6 +2571,13 @@ var init_client = __esm({
|
|
|
2564
2571
|
if (options.runtime_validation) {
|
|
2565
2572
|
payload.runtime_validation = coerceMapping(options.runtime_validation, "runtime_validation");
|
|
2566
2573
|
}
|
|
2574
|
+
if (options.oauth_credentials) {
|
|
2575
|
+
payload.oauth_credentials = Array.isArray(options.oauth_credentials) ? {
|
|
2576
|
+
items: options.oauth_credentials.map(
|
|
2577
|
+
(item, index) => coerceMapping(item, `oauth_credentials[${index}]`)
|
|
2578
|
+
)
|
|
2579
|
+
} : coerceMapping(options.oauth_credentials, "oauth_credentials");
|
|
2580
|
+
}
|
|
2567
2581
|
if (options.metadata) {
|
|
2568
2582
|
payload.metadata = coerceMapping(options.metadata, "metadata");
|
|
2569
2583
|
}
|
|
@@ -2582,6 +2596,8 @@ var init_client = __esm({
|
|
|
2582
2596
|
"docs_url",
|
|
2583
2597
|
"documentation_url",
|
|
2584
2598
|
"support_contact",
|
|
2599
|
+
"seller_homepage_url",
|
|
2600
|
+
"seller_social_url",
|
|
2585
2601
|
"jurisdiction",
|
|
2586
2602
|
"price_model",
|
|
2587
2603
|
"price_value_minor",
|
|
@@ -2597,10 +2613,14 @@ var init_client = __esm({
|
|
|
2597
2613
|
}
|
|
2598
2614
|
const docsUrl = String(manifestPayload.docs_url ?? manifestPayload.documentation_url ?? "").trim();
|
|
2599
2615
|
const supportContact = String(manifestPayload.support_contact ?? "").trim();
|
|
2600
|
-
|
|
2616
|
+
const sellerHomepageUrl = String(manifestPayload.seller_homepage_url ?? "").trim();
|
|
2617
|
+
const sellerSocialUrl = String(manifestPayload.seller_social_url ?? "").trim();
|
|
2618
|
+
if (docsUrl || supportContact || sellerHomepageUrl || sellerSocialUrl) {
|
|
2601
2619
|
const publisherIdentity = {
|
|
2602
2620
|
documentation_url: docsUrl || null,
|
|
2603
|
-
support_contact: supportContact || null
|
|
2621
|
+
support_contact: supportContact || null,
|
|
2622
|
+
seller_homepage_url: sellerHomepageUrl || null,
|
|
2623
|
+
seller_social_url: sellerSocialUrl || null
|
|
2604
2624
|
};
|
|
2605
2625
|
payload.publisher_identity = publisherIdentity;
|
|
2606
2626
|
payload.legal = { publisher_identity: publisherIdentity };
|
|
@@ -2614,36 +2634,30 @@ var init_client = __esm({
|
|
|
2614
2634
|
return {
|
|
2615
2635
|
listing_id,
|
|
2616
2636
|
status: String(data.status ?? "draft"),
|
|
2637
|
+
registration_mode: stringOrNull(data.registration_mode),
|
|
2638
|
+
listing_status: stringOrNull(data.listing_status),
|
|
2617
2639
|
auto_manifest: toRecord(data.auto_manifest),
|
|
2618
2640
|
confidence: toRecord(data.confidence),
|
|
2619
2641
|
validation_report: toRecord(data.validation_report),
|
|
2642
|
+
oauth_status: toRecord(data.oauth_status),
|
|
2620
2643
|
review_url: stringOrNull(data.review_url),
|
|
2621
2644
|
trace_id: meta.trace_id,
|
|
2622
2645
|
request_id: meta.request_id
|
|
2623
2646
|
};
|
|
2624
2647
|
}
|
|
2625
2648
|
async confirm_registration(listing_id, options = {}) {
|
|
2626
|
-
|
|
2627
|
-
const manifestPayload = options.manifest ? coerceMapping(options.manifest, "manifest") : pending?.manifest ?? {};
|
|
2628
|
-
const toolManualPayload = options.tool_manual ? coerceMapping(options.tool_manual, "tool_manual") : pending?.tool_manual ?? {};
|
|
2629
|
-
const overrides = {};
|
|
2630
|
-
for (const fieldName of ["name", "job_to_be_done"]) {
|
|
2631
|
-
if (manifestPayload[fieldName]) {
|
|
2632
|
-
overrides[fieldName] = manifestPayload[fieldName];
|
|
2633
|
-
}
|
|
2634
|
-
}
|
|
2635
|
-
if (Object.keys(toolManualPayload).length > 0) {
|
|
2636
|
-
overrides.tool_manual = toolManualPayload;
|
|
2637
|
-
}
|
|
2649
|
+
void options;
|
|
2638
2650
|
const payload = { approved: true };
|
|
2639
|
-
if (Object.keys(overrides).length > 0) {
|
|
2640
|
-
payload.overrides = overrides;
|
|
2641
|
-
}
|
|
2642
2651
|
const [data, meta] = await this.request("POST", `/market/capabilities/${listing_id}/confirm-auto-register`, { json_body: payload });
|
|
2643
2652
|
this.pendingConfirmations.delete(listing_id);
|
|
2653
|
+
const checklist = isRecord(data.checklist) ? Object.fromEntries(
|
|
2654
|
+
Object.entries(data.checklist).map(([key, value]) => [key, Boolean(value)])
|
|
2655
|
+
) : {};
|
|
2644
2656
|
return {
|
|
2645
2657
|
listing_id: String(data.listing_id ?? listing_id),
|
|
2646
2658
|
status: String(data.status ?? ""),
|
|
2659
|
+
message: stringOrNull(data.message),
|
|
2660
|
+
checklist,
|
|
2647
2661
|
release: toRecord(data.release),
|
|
2648
2662
|
quality: parseRegistrationQuality(toRecord(data.quality)),
|
|
2649
2663
|
trace_id: meta.trace_id,
|
|
@@ -4600,7 +4614,7 @@ ${details}` : summary;
|
|
|
4600
4614
|
const headers = new Headers({
|
|
4601
4615
|
Authorization: `Bearer ${this.api_key}`,
|
|
4602
4616
|
Accept: "application/json",
|
|
4603
|
-
"User-Agent": "siglume-api-sdk-ts/0.6
|
|
4617
|
+
"User-Agent": "siglume-api-sdk-ts/0.7.6"
|
|
4604
4618
|
});
|
|
4605
4619
|
if (options.headers) {
|
|
4606
4620
|
for (const [key, value] of Object.entries(options.headers)) {
|
|
@@ -4802,7 +4816,7 @@ var init_metering = __esm({
|
|
|
4802
4816
|
fetchImpl;
|
|
4803
4817
|
constructor(options) {
|
|
4804
4818
|
this.client = new SiglumeClient(options);
|
|
4805
|
-
this.api_key =
|
|
4819
|
+
this.api_key = this.client.api_key;
|
|
4806
4820
|
this.base_url = (options.base_url ?? DEFAULT_SIGLUME_API_BASE).replace(/\/+$/, "");
|
|
4807
4821
|
this.timeout_ms = Math.max(1, options.timeout_ms ?? 15e3);
|
|
4808
4822
|
this.max_retries = Math.max(1, Math.trunc(options.max_retries ?? 3));
|
|
@@ -4848,7 +4862,7 @@ var init_metering = __esm({
|
|
|
4848
4862
|
const headers = new Headers({
|
|
4849
4863
|
Authorization: `Bearer ${this.api_key}`,
|
|
4850
4864
|
Accept: "application/json",
|
|
4851
|
-
"User-Agent": "siglume-api-sdk-ts/0.6
|
|
4865
|
+
"User-Agent": "siglume-api-sdk-ts/0.7.6"
|
|
4852
4866
|
});
|
|
4853
4867
|
let body;
|
|
4854
4868
|
if (options.json_body) {
|
|
@@ -7168,6 +7182,15 @@ async function loadProject(path = ".") {
|
|
|
7168
7182
|
const tool_manual = tool_manual_path ? JSON.parse(await (0, import_promises.readFile)(tool_manual_path, "utf8")) : buildToolManualTemplate(manifest);
|
|
7169
7183
|
const runtime_validation_path = await findRuntimeValidationPath(root_dir);
|
|
7170
7184
|
const runtime_validation = runtime_validation_path ? await loadJsonObject(runtime_validation_path, "runtime_validation") : void 0;
|
|
7185
|
+
const oauth_credentials_path = await findOauthCredentialsPath(root_dir);
|
|
7186
|
+
let oauth_credentials;
|
|
7187
|
+
if (oauth_credentials_path) {
|
|
7188
|
+
const parsed = JSON.parse(await (0, import_promises.readFile)(oauth_credentials_path, "utf8"));
|
|
7189
|
+
if (!isRecord(parsed) && !Array.isArray(parsed)) {
|
|
7190
|
+
throw new SiglumeProjectError("oauth_credentials must be a JSON object or array");
|
|
7191
|
+
}
|
|
7192
|
+
oauth_credentials = parsed;
|
|
7193
|
+
}
|
|
7171
7194
|
return {
|
|
7172
7195
|
root_dir,
|
|
7173
7196
|
adapter_path,
|
|
@@ -7176,9 +7199,110 @@ async function loadProject(path = ".") {
|
|
|
7176
7199
|
tool_manual_path: tool_manual_path ?? void 0,
|
|
7177
7200
|
tool_manual,
|
|
7178
7201
|
runtime_validation_path: runtime_validation_path ?? void 0,
|
|
7179
|
-
runtime_validation
|
|
7202
|
+
runtime_validation,
|
|
7203
|
+
oauth_credentials_path: oauth_credentials_path ?? void 0,
|
|
7204
|
+
oauth_credentials
|
|
7180
7205
|
};
|
|
7181
7206
|
}
|
|
7207
|
+
var OAUTH_PROVIDER_ALIASES = {
|
|
7208
|
+
x: "twitter",
|
|
7209
|
+
"x-twitter": "twitter",
|
|
7210
|
+
twitter: "twitter",
|
|
7211
|
+
slack: "slack",
|
|
7212
|
+
google: "google",
|
|
7213
|
+
gmail: "google",
|
|
7214
|
+
"google-drive": "google",
|
|
7215
|
+
"google-calendar": "google",
|
|
7216
|
+
github: "github",
|
|
7217
|
+
linear: "linear",
|
|
7218
|
+
notion: "notion"
|
|
7219
|
+
};
|
|
7220
|
+
function oauthProviderKeyFromRequirement(value) {
|
|
7221
|
+
const raw = String(value ?? "").trim().toLowerCase().replaceAll("_", "-");
|
|
7222
|
+
if (!raw) return null;
|
|
7223
|
+
if (OAUTH_PROVIDER_ALIASES[raw]) {
|
|
7224
|
+
return OAUTH_PROVIDER_ALIASES[raw];
|
|
7225
|
+
}
|
|
7226
|
+
for (const token of raw.replaceAll("/", "-").replaceAll(":", "-").split("-")) {
|
|
7227
|
+
const next = token.trim();
|
|
7228
|
+
if (OAUTH_PROVIDER_ALIASES[next]) {
|
|
7229
|
+
return OAUTH_PROVIDER_ALIASES[next];
|
|
7230
|
+
}
|
|
7231
|
+
}
|
|
7232
|
+
return null;
|
|
7233
|
+
}
|
|
7234
|
+
function requiredOauthProviders(requirements) {
|
|
7235
|
+
const providers = [];
|
|
7236
|
+
for (const item of requirements ?? []) {
|
|
7237
|
+
const providerKey = oauthProviderKeyFromRequirement(item);
|
|
7238
|
+
if (providerKey && !providers.includes(providerKey)) {
|
|
7239
|
+
providers.push(providerKey);
|
|
7240
|
+
}
|
|
7241
|
+
}
|
|
7242
|
+
return providers;
|
|
7243
|
+
}
|
|
7244
|
+
function oauthProviderRecordsMap(payload) {
|
|
7245
|
+
if (!payload) {
|
|
7246
|
+
return {};
|
|
7247
|
+
}
|
|
7248
|
+
const items = Array.isArray(payload) ? payload : Array.isArray(payload.items) ? payload.items : [payload];
|
|
7249
|
+
const resolved = {};
|
|
7250
|
+
for (const [index, item] of items.entries()) {
|
|
7251
|
+
if (!isRecord(item)) {
|
|
7252
|
+
throw new SiglumeProjectError(`oauth_credentials[${index}] must be a JSON object.`);
|
|
7253
|
+
}
|
|
7254
|
+
const providerKey = oauthProviderKeyFromRequirement(item.provider_key ?? item.provider);
|
|
7255
|
+
if (!providerKey) {
|
|
7256
|
+
throw new SiglumeProjectError(`oauth_credentials[${index}].provider_key is unsupported.`);
|
|
7257
|
+
}
|
|
7258
|
+
const clientId = String(item.client_id ?? "").trim();
|
|
7259
|
+
const clientSecret = String(item.client_secret ?? "").trim();
|
|
7260
|
+
if (!clientId || !clientSecret) {
|
|
7261
|
+
throw new SiglumeProjectError(`oauth_credentials[${index}] must include client_id and client_secret.`);
|
|
7262
|
+
}
|
|
7263
|
+
const rawScopes = item.required_scopes ?? item.scopes;
|
|
7264
|
+
let scopes = [];
|
|
7265
|
+
if (rawScopes == null) {
|
|
7266
|
+
scopes = [];
|
|
7267
|
+
} else if (!Array.isArray(rawScopes)) {
|
|
7268
|
+
throw new SiglumeProjectError(`oauth_credentials[${index}].required_scopes must be a JSON array.`);
|
|
7269
|
+
} else {
|
|
7270
|
+
scopes = rawScopes.map((scope) => String(scope ?? "").trim()).filter(Boolean);
|
|
7271
|
+
}
|
|
7272
|
+
resolved[providerKey] = {
|
|
7273
|
+
provider_key: providerKey,
|
|
7274
|
+
client_id: clientId,
|
|
7275
|
+
client_secret: clientSecret,
|
|
7276
|
+
required_scopes: scopes
|
|
7277
|
+
};
|
|
7278
|
+
}
|
|
7279
|
+
return resolved;
|
|
7280
|
+
}
|
|
7281
|
+
function canonicalOauthCredentialsPayload(payload) {
|
|
7282
|
+
const records = oauthProviderRecordsMap(payload);
|
|
7283
|
+
const providerKeys = Object.keys(records).sort();
|
|
7284
|
+
if (providerKeys.length === 0) {
|
|
7285
|
+
return void 0;
|
|
7286
|
+
}
|
|
7287
|
+
return {
|
|
7288
|
+
items: providerKeys.map((providerKey) => records[providerKey])
|
|
7289
|
+
};
|
|
7290
|
+
}
|
|
7291
|
+
function ensureRequiredOauthCredentials(project) {
|
|
7292
|
+
const requiredProviders = requiredOauthProviders(project.manifest.required_connected_accounts ?? []);
|
|
7293
|
+
if (requiredProviders.length === 0) {
|
|
7294
|
+
return;
|
|
7295
|
+
}
|
|
7296
|
+
const provided = new Set(Object.keys(oauthProviderRecordsMap(project.oauth_credentials)));
|
|
7297
|
+
const missing = requiredProviders.filter((provider) => !provided.has(provider));
|
|
7298
|
+
if (missing.length === 0) {
|
|
7299
|
+
return;
|
|
7300
|
+
}
|
|
7301
|
+
const path = project.oauth_credentials_path ?? (0, import_node_path.join)(project.root_dir, "oauth_credentials.json");
|
|
7302
|
+
throw new SiglumeProjectError(
|
|
7303
|
+
`${path} is required for OAuth-backed APIs. Missing provider seeds: ${missing.join(", ")}`
|
|
7304
|
+
);
|
|
7305
|
+
}
|
|
7182
7306
|
async function validateProject(path = ".", deps = {}) {
|
|
7183
7307
|
const project = await loadProject(path);
|
|
7184
7308
|
const manifest_issues = await projectValidationIssues(project);
|
|
@@ -7215,17 +7339,31 @@ function ensureManifestPublisherIdentity(project) {
|
|
|
7215
7339
|
const manifestPayload = project.manifest;
|
|
7216
7340
|
const docsUrl = String(manifestPayload.docs_url ?? manifestPayload.documentation_url ?? "").trim();
|
|
7217
7341
|
const supportContact = String(manifestPayload.support_contact ?? "").trim();
|
|
7342
|
+
const sellerHomepageUrl = String(manifestPayload.seller_homepage_url ?? "").trim();
|
|
7343
|
+
const sellerSocialUrl = String(manifestPayload.seller_social_url ?? "").trim();
|
|
7218
7344
|
const jurisdiction = String(manifestPayload.jurisdiction ?? "").trim();
|
|
7219
7345
|
const issues = [];
|
|
7220
7346
|
if (!docsUrl) {
|
|
7221
7347
|
issues.push("manifest.docs_url is required");
|
|
7222
7348
|
} else if (looksLikePlaceholder(docsUrl)) {
|
|
7223
7349
|
issues.push("manifest.docs_url must be replaced with your public documentation URL");
|
|
7350
|
+
} else if (!looksLikeHttpUrl(docsUrl)) {
|
|
7351
|
+
issues.push("manifest.docs_url must be an http(s) URL");
|
|
7352
|
+
} else if (looksLikeRootUrl(docsUrl)) {
|
|
7353
|
+
issues.push("manifest.docs_url must be a dedicated API usage page, not a root homepage URL");
|
|
7224
7354
|
}
|
|
7225
7355
|
if (!supportContact) {
|
|
7226
7356
|
issues.push("manifest.support_contact is required");
|
|
7227
7357
|
} else if (looksLikePlaceholder(supportContact)) {
|
|
7228
7358
|
issues.push("manifest.support_contact must be replaced with your real support email or support URL");
|
|
7359
|
+
} else if (!looksLikeEmail(supportContact) && !looksLikeHttpUrl(supportContact)) {
|
|
7360
|
+
issues.push("manifest.support_contact must be a real email address or http(s) support URL");
|
|
7361
|
+
}
|
|
7362
|
+
if (sellerHomepageUrl && (looksLikePlaceholder(sellerHomepageUrl) || !looksLikeHttpUrl(sellerHomepageUrl))) {
|
|
7363
|
+
issues.push("manifest.seller_homepage_url must be a real http(s) official homepage URL when provided");
|
|
7364
|
+
}
|
|
7365
|
+
if (sellerSocialUrl && (looksLikePlaceholder(sellerSocialUrl) || !looksLikeHttpUrl(sellerSocialUrl))) {
|
|
7366
|
+
issues.push("manifest.seller_social_url must be a real http(s) official social/profile URL when provided");
|
|
7229
7367
|
}
|
|
7230
7368
|
if (!jurisdiction) issues.push("manifest.jurisdiction is required");
|
|
7231
7369
|
if (issues.length > 0) {
|
|
@@ -7237,7 +7375,25 @@ ${issues.map((issue2) => `- ${issue2}`).join("\n")}`
|
|
|
7237
7375
|
}
|
|
7238
7376
|
function looksLikePlaceholder(value) {
|
|
7239
7377
|
const normalized = value.trim().toLowerCase();
|
|
7240
|
-
return !normalized || normalized.includes("example.com") || normalized.startsWith("replace-with-") || normalized.startsWith("your-") || normalized.includes("your-domain") || normalized.includes("localhost") || normalized.includes("127.0.0.1") || normalized.includes("0.0.0.0");
|
|
7378
|
+
return !normalized || normalized.includes("example.com") || normalized.includes("example.net") || normalized.includes("example.org") || normalized.startsWith("replace-with-") || normalized.startsWith("your-") || normalized.includes("your-domain") || normalized.includes("localhost") || normalized.includes("127.0.0.1") || normalized.includes("0.0.0.0");
|
|
7379
|
+
}
|
|
7380
|
+
function looksLikeHttpUrl(value) {
|
|
7381
|
+
try {
|
|
7382
|
+
const parsed = new URL(value.trim());
|
|
7383
|
+
return parsed.protocol === "http:" || parsed.protocol === "https:";
|
|
7384
|
+
} catch {
|
|
7385
|
+
return false;
|
|
7386
|
+
}
|
|
7387
|
+
}
|
|
7388
|
+
function looksLikeRootUrl(value) {
|
|
7389
|
+
if (!looksLikeHttpUrl(value)) return false;
|
|
7390
|
+
const parsed = new URL(value.trim());
|
|
7391
|
+
return parsed.pathname.replace(/^\/+|\/+$/g, "") === "";
|
|
7392
|
+
}
|
|
7393
|
+
function looksLikeEmail(value) {
|
|
7394
|
+
const normalized = value.trim();
|
|
7395
|
+
const domain = normalized.split("@").at(-1) ?? "";
|
|
7396
|
+
return normalized.includes("@") && !normalized.includes(" ") && domain.includes(".") && !normalized.startsWith("@");
|
|
7241
7397
|
}
|
|
7242
7398
|
function runtimePlaceholderIssues(runtimeValidation) {
|
|
7243
7399
|
const issues = [];
|
|
@@ -7297,6 +7453,9 @@ async function registrationPreflight(project, client) {
|
|
|
7297
7453
|
const manifestIssues = await projectValidationIssues(project);
|
|
7298
7454
|
const [toolManualValid, toolManualIssues] = validate_tool_manual(project.tool_manual);
|
|
7299
7455
|
const remoteQuality = await client.preview_quality_score(project.tool_manual);
|
|
7456
|
+
const requiredOauthProvidersList = requiredOauthProviders(project.manifest.required_connected_accounts ?? []);
|
|
7457
|
+
const oauthProviderRecords = oauthProviderRecordsMap(project.oauth_credentials);
|
|
7458
|
+
const missingOauthProviders = requiredOauthProvidersList.filter((provider) => !oauthProviderRecords[provider]);
|
|
7300
7459
|
const blockingToolManualIssues = toolManualIssues.filter((issue2) => issue2.severity === "error");
|
|
7301
7460
|
const errors = [
|
|
7302
7461
|
...manifestIssues.map((issue2) => String(issue2)),
|
|
@@ -7308,11 +7467,17 @@ async function registrationPreflight(project, client) {
|
|
|
7308
7467
|
if (!remoteQualityOk(remoteQuality)) {
|
|
7309
7468
|
errors.push(`remote Tool Manual quality is not publishable: ${remoteQuality.grade} (${remoteQuality.overall_score}/100)`);
|
|
7310
7469
|
}
|
|
7470
|
+
if (missingOauthProviders.length > 0) {
|
|
7471
|
+
errors.push(`oauth_credentials.json is required for OAuth-backed APIs: ${missingOauthProviders.join(", ")}`);
|
|
7472
|
+
}
|
|
7311
7473
|
const preflight = {
|
|
7312
7474
|
manifest_issues: manifestIssues,
|
|
7313
7475
|
tool_manual_valid: toolManualValid,
|
|
7314
7476
|
tool_manual_issues: toolManualIssues.map((issue2) => toJsonable(issue2)),
|
|
7315
7477
|
remote_quality: toJsonable(remoteQuality),
|
|
7478
|
+
required_oauth_providers: requiredOauthProvidersList,
|
|
7479
|
+
oauth_credentials_path: project.oauth_credentials_path ?? null,
|
|
7480
|
+
oauth_missing_providers: missingOauthProviders,
|
|
7316
7481
|
ok: errors.length === 0
|
|
7317
7482
|
};
|
|
7318
7483
|
if (errors.length > 0) {
|
|
@@ -7328,6 +7493,7 @@ async function runRegistration(path = ".", options = {}, deps = {}) {
|
|
|
7328
7493
|
ensureExplicitToolManual(project);
|
|
7329
7494
|
ensureManifestPublisherIdentity(project);
|
|
7330
7495
|
ensureRuntimeValidationReady(project);
|
|
7496
|
+
ensureRequiredOauthCredentials(project);
|
|
7331
7497
|
const client = await createClient(deps);
|
|
7332
7498
|
const preflight = await registrationPreflight(project, client);
|
|
7333
7499
|
let developerPortalPreflight = null;
|
|
@@ -7336,18 +7502,20 @@ async function runRegistration(path = ".", options = {}, deps = {}) {
|
|
|
7336
7502
|
const verifiedDestination = portal.payout_readiness?.verified_destination;
|
|
7337
7503
|
if (verifiedDestination !== true) {
|
|
7338
7504
|
throw new SiglumeProjectError(
|
|
7339
|
-
"Paid API registration requires a verified Polygon payout destination. Open https://siglume.com/owner/
|
|
7505
|
+
"Paid API registration requires a verified Polygon payout destination. Open https://siglume.com/owner/credits/payout and confirm the embedded-wallet payout token, or call GET /v1/market/developer/portal until payout_readiness.verified_destination is true."
|
|
7340
7506
|
);
|
|
7341
7507
|
}
|
|
7342
7508
|
developerPortalPreflight = toJsonable(portal);
|
|
7343
7509
|
}
|
|
7344
7510
|
const receipt = await client.auto_register(project.manifest, project.tool_manual, {
|
|
7345
|
-
runtime_validation: project.runtime_validation
|
|
7511
|
+
runtime_validation: project.runtime_validation,
|
|
7512
|
+
oauth_credentials: canonicalOauthCredentialsPayload(project.oauth_credentials)
|
|
7346
7513
|
});
|
|
7347
7514
|
const result = {
|
|
7348
7515
|
receipt: toJsonable(receipt),
|
|
7349
7516
|
registration_preflight: preflight,
|
|
7350
|
-
runtime_validation_path: project.runtime_validation_path ?? null
|
|
7517
|
+
runtime_validation_path: project.runtime_validation_path ?? null,
|
|
7518
|
+
oauth_credentials_path: project.oauth_credentials_path ?? null
|
|
7351
7519
|
};
|
|
7352
7520
|
if (developerPortalPreflight) {
|
|
7353
7521
|
result.developer_portal_preflight = developerPortalPreflight;
|
|
@@ -7362,6 +7530,37 @@ async function runRegistration(path = ".", options = {}, deps = {}) {
|
|
|
7362
7530
|
}
|
|
7363
7531
|
return result;
|
|
7364
7532
|
}
|
|
7533
|
+
async function runPreflight(path = ".", deps = {}) {
|
|
7534
|
+
const project = await loadProject(path);
|
|
7535
|
+
ensureExplicitToolManual(project);
|
|
7536
|
+
ensureManifestPublisherIdentity(project);
|
|
7537
|
+
ensureRuntimeValidationReady(project);
|
|
7538
|
+
ensureRequiredOauthCredentials(project);
|
|
7539
|
+
const client = await createClient(deps);
|
|
7540
|
+
const preflight = await registrationPreflight(project, client);
|
|
7541
|
+
let developerPortalPreflight = null;
|
|
7542
|
+
if (String(project.manifest.price_model ?? "free").toLowerCase() !== "free") {
|
|
7543
|
+
const portal = await client.get_developer_portal();
|
|
7544
|
+
const verifiedDestination = portal.payout_readiness?.verified_destination;
|
|
7545
|
+
if (verifiedDestination !== true) {
|
|
7546
|
+
throw new SiglumeProjectError(
|
|
7547
|
+
"Paid API registration requires a verified Polygon payout destination. Open https://siglume.com/owner/credits/payout and confirm the embedded-wallet payout token, or call GET /v1/market/developer/portal until payout_readiness.verified_destination is true."
|
|
7548
|
+
);
|
|
7549
|
+
}
|
|
7550
|
+
developerPortalPreflight = toJsonable(portal);
|
|
7551
|
+
}
|
|
7552
|
+
const result = {
|
|
7553
|
+
ok: true,
|
|
7554
|
+
adapter_path: project.adapter_path,
|
|
7555
|
+
registration_preflight: preflight,
|
|
7556
|
+
runtime_validation_path: project.runtime_validation_path ?? null,
|
|
7557
|
+
oauth_credentials_path: project.oauth_credentials_path ?? null
|
|
7558
|
+
};
|
|
7559
|
+
if (developerPortalPreflight) {
|
|
7560
|
+
result.developer_portal_preflight = developerPortalPreflight;
|
|
7561
|
+
}
|
|
7562
|
+
return result;
|
|
7563
|
+
}
|
|
7365
7564
|
async function createSupportCaseReport(options, deps = {}) {
|
|
7366
7565
|
const client = await createClient(deps);
|
|
7367
7566
|
const supportCase = await client.create_support_case(options.subject, options.body, { trace_id: options.trace_id });
|
|
@@ -7408,8 +7607,12 @@ async function writeInitTemplate(template, destination) {
|
|
|
7408
7607
|
const manifest_path = (0, import_node_path.join)(root, "manifest.json");
|
|
7409
7608
|
const tool_manual_path = (0, import_node_path.join)(root, "tool_manual.json");
|
|
7410
7609
|
const runtime_validation_path = (0, import_node_path.join)(root, "runtime_validation.json");
|
|
7610
|
+
const gitignore_path = (0, import_node_path.join)(root, ".gitignore");
|
|
7411
7611
|
const readme_path = (0, import_node_path.join)(root, "README.md");
|
|
7412
|
-
|
|
7612
|
+
const docs_dir = (0, import_node_path.join)(root, "docs");
|
|
7613
|
+
await (0, import_promises.mkdir)(docs_dir, { recursive: true });
|
|
7614
|
+
const docs_usage_path = (0, import_node_path.join)(docs_dir, "api-usage.md");
|
|
7615
|
+
for (const filePath of [adapter_path, manifest_path, tool_manual_path, runtime_validation_path, docs_usage_path, readme_path]) {
|
|
7413
7616
|
if ((0, import_node_fs.existsSync)(filePath)) {
|
|
7414
7617
|
throw new SiglumeProjectError(`${(0, import_node_path.basename)(filePath)} already exists in ${root}`);
|
|
7415
7618
|
}
|
|
@@ -7420,8 +7623,10 @@ async function writeInitTemplate(template, destination) {
|
|
|
7420
7623
|
await (0, import_promises.writeFile)(manifest_path, renderJson(manifest), "utf8");
|
|
7421
7624
|
await (0, import_promises.writeFile)(tool_manual_path, renderJson(toolManual), "utf8");
|
|
7422
7625
|
await (0, import_promises.writeFile)(runtime_validation_path, renderJson(buildRuntimeValidationTemplate(toolManual)), "utf8");
|
|
7626
|
+
await (0, import_promises.writeFile)(docs_usage_path, apiUsageDocsTemplate(manifest), "utf8");
|
|
7627
|
+
await writeOrMergeGitignore(gitignore_path);
|
|
7423
7628
|
await (0, import_promises.writeFile)(readme_path, readmeTemplate(template), "utf8");
|
|
7424
|
-
return [adapter_path, manifest_path, tool_manual_path, runtime_validation_path, readme_path];
|
|
7629
|
+
return [adapter_path, manifest_path, tool_manual_path, runtime_validation_path, docs_usage_path, gitignore_path, readme_path];
|
|
7425
7630
|
}
|
|
7426
7631
|
async function listOperationCatalog(options = {}, deps = {}) {
|
|
7427
7632
|
const resolvedAgentId = String(options.agent_id ?? "").trim();
|
|
@@ -7815,25 +8020,132 @@ function operationReadmeTemplate(operation, manifest, warning) {
|
|
|
7815
8020
|
"- `stubs.ts`: mock fallback used when `SIGLUME_API_KEY` is not set",
|
|
7816
8021
|
"- `manifest.json`: reviewable manifest snapshot",
|
|
7817
8022
|
"- `tool_manual.json`: machine-generated ToolManual scaffold",
|
|
7818
|
-
"- `runtime_validation.json`: public endpoint and review-key checks used by auto-register",
|
|
8023
|
+
"- `runtime_validation.json`: local public endpoint and review-key checks used by auto-register",
|
|
8024
|
+
"- `docs/api-usage.md`: publishable API usage guide template for `docs_url`",
|
|
8025
|
+
"- `.gitignore`: keeps runtime review keys and OAuth client secrets out of Git",
|
|
7819
8026
|
"- `tests/test_adapter.ts`: smoke test for `AppTestHarness`",
|
|
7820
8027
|
"",
|
|
7821
8028
|
"Before registering, replace all generated placeholders:",
|
|
7822
|
-
"- In `adapter.ts` and `manifest.json`, replace `docs_url`
|
|
7823
|
-
"-
|
|
8029
|
+
"- In `adapter.ts` and `manifest.json`, replace `docs_url` with a dedicated public API usage guide, not a homepage.",
|
|
8030
|
+
"- Replace `support_contact` with a real support email address or public support URL.",
|
|
8031
|
+
"- Optional `seller_homepage_url` is the seller's official site and can stay blank.",
|
|
8032
|
+
"- In the local `runtime_validation.json`, replace the public URL and review-key placeholders.",
|
|
8033
|
+
"- If the API uses seller-side OAuth, create a local `oauth_credentials.json` next to the adapter.",
|
|
8034
|
+
"- Do not commit real review keys or OAuth client secrets; the generated `.gitignore` excludes those files.",
|
|
8035
|
+
"- Because `runtime_validation.json` is ignored, GitHub samples do not commit review-key values.",
|
|
7824
8036
|
"",
|
|
7825
8037
|
"## Commands",
|
|
7826
8038
|
"",
|
|
8039
|
+
"Start locally without a Siglume API key:",
|
|
8040
|
+
"",
|
|
7827
8041
|
"```bash",
|
|
7828
|
-
"siglume validate .",
|
|
7829
8042
|
"siglume test .",
|
|
7830
8043
|
"npm test -- tests/test_adapter.ts",
|
|
8044
|
+
"siglume score . --offline",
|
|
8045
|
+
"```",
|
|
8046
|
+
"",
|
|
8047
|
+
"After placeholders are replaced and `SIGLUME_API_KEY` is issued from Developer Portal -> CLI / API keys, run the server-aligned checks:",
|
|
8048
|
+
"",
|
|
8049
|
+
"```bash",
|
|
8050
|
+
"siglume validate .",
|
|
7831
8051
|
"siglume score . --remote",
|
|
8052
|
+
"siglume preflight .",
|
|
8053
|
+
"siglume register .",
|
|
8054
|
+
"# inspect the draft, then explicitly approve publish:",
|
|
7832
8055
|
"siglume register . --confirm",
|
|
7833
8056
|
"```",
|
|
7834
8057
|
""
|
|
7835
8058
|
].join("\n");
|
|
7836
8059
|
}
|
|
8060
|
+
function apiUsageDocsTemplate(manifest) {
|
|
8061
|
+
const name = String(manifest.name ?? manifest.capability_key ?? "Siglume API");
|
|
8062
|
+
const capabilityKey = String(manifest.capability_key ?? "replace-with-capability-key");
|
|
8063
|
+
const jobToBeDone = String(manifest.job_to_be_done ?? "Describe what this API lets an agent do.");
|
|
8064
|
+
const permissionClass = String(manifest.permission_class ?? "read-only");
|
|
8065
|
+
const priceModel = String(manifest.price_model ?? "free");
|
|
8066
|
+
const requiredAccounts = (manifest.required_connected_accounts ?? []).join(", ") || "none";
|
|
8067
|
+
const supportContact = String(manifest.support_contact ?? "replace-with-support-contact");
|
|
8068
|
+
return [
|
|
8069
|
+
`# ${name} API Usage Guide`,
|
|
8070
|
+
"",
|
|
8071
|
+
`This page is the dedicated public usage guide for the Siglume API listing \`${capabilityKey}\`.`,
|
|
8072
|
+
"Publish this page at an anonymous HTTP 200 URL and use that URL as `docs_url`.",
|
|
8073
|
+
"",
|
|
8074
|
+
"Do not use your company homepage as `docs_url`; keep seller/company homepages in `seller_homepage_url`.",
|
|
8075
|
+
"",
|
|
8076
|
+
"## What This API Does",
|
|
8077
|
+
"",
|
|
8078
|
+
jobToBeDone,
|
|
8079
|
+
"",
|
|
8080
|
+
"## Permission Model",
|
|
8081
|
+
"",
|
|
8082
|
+
`- Permission class: \`${permissionClass}\``,
|
|
8083
|
+
`- Price model: \`${priceModel}\``,
|
|
8084
|
+
`- Required connected accounts: \`${requiredAccounts}\``,
|
|
8085
|
+
"",
|
|
8086
|
+
"## Inputs",
|
|
8087
|
+
"",
|
|
8088
|
+
"Describe the request fields your API accepts. Keep this aligned with `tool_manual.json` and `runtime_validation.json`.",
|
|
8089
|
+
"",
|
|
8090
|
+
"## Outputs",
|
|
8091
|
+
"",
|
|
8092
|
+
"Describe the response fields your API returns. Include the fields in `runtime_validation.expected_response_fields`.",
|
|
8093
|
+
"",
|
|
8094
|
+
"## Errors And Support",
|
|
8095
|
+
"",
|
|
8096
|
+
"Explain common error messages and how an owner should recover.",
|
|
8097
|
+
"",
|
|
8098
|
+
`Support contact: ${supportContact}`,
|
|
8099
|
+
""
|
|
8100
|
+
].join("\n");
|
|
8101
|
+
}
|
|
8102
|
+
function generatedGitignore() {
|
|
8103
|
+
return [
|
|
8104
|
+
"# Local secrets and registration-only runtime checks.",
|
|
8105
|
+
".env",
|
|
8106
|
+
".env.*",
|
|
8107
|
+
"!.env.example",
|
|
8108
|
+
"runtime_validation.json",
|
|
8109
|
+
"runtime-validation.json",
|
|
8110
|
+
"oauth_credentials.json",
|
|
8111
|
+
"oauth-credentials.json",
|
|
8112
|
+
"",
|
|
8113
|
+
"# Python / test artifacts.",
|
|
8114
|
+
"__pycache__/",
|
|
8115
|
+
"*.py[cod]",
|
|
8116
|
+
".pytest_cache/",
|
|
8117
|
+
".mypy_cache/",
|
|
8118
|
+
".coverage",
|
|
8119
|
+
"htmlcov/",
|
|
8120
|
+
"dist/",
|
|
8121
|
+
"build/",
|
|
8122
|
+
"*.egg-info/",
|
|
8123
|
+
"",
|
|
8124
|
+
"# JavaScript tooling if this project also uses TypeScript helpers.",
|
|
8125
|
+
"node_modules/",
|
|
8126
|
+
"coverage/",
|
|
8127
|
+
""
|
|
8128
|
+
].join("\n");
|
|
8129
|
+
}
|
|
8130
|
+
async function writeOrMergeGitignore(filePath) {
|
|
8131
|
+
const generated = generatedGitignore();
|
|
8132
|
+
if (!(0, import_node_fs.existsSync)(filePath)) {
|
|
8133
|
+
await (0, import_promises.writeFile)(filePath, generated, "utf8");
|
|
8134
|
+
return;
|
|
8135
|
+
}
|
|
8136
|
+
const existing = await (0, import_promises.readFile)(filePath, "utf8");
|
|
8137
|
+
const existingEntries = new Set(existing.split(/\r?\n/).map((line) => line.trim()));
|
|
8138
|
+
const additions = generated.split(/\r?\n/).filter((line) => line.trim() && !existingEntries.has(line.trim()));
|
|
8139
|
+
if (additions.length === 0) {
|
|
8140
|
+
return;
|
|
8141
|
+
}
|
|
8142
|
+
const prefix = existing.endsWith("\n") ? existing : `${existing}
|
|
8143
|
+
`;
|
|
8144
|
+
await (0, import_promises.writeFile)(filePath, `${prefix}
|
|
8145
|
+
# Siglume generated ignores.
|
|
8146
|
+
${additions.join("\n")}
|
|
8147
|
+
`, "utf8");
|
|
8148
|
+
}
|
|
7837
8149
|
async function writeOperationTemplate(operation_key, destination, options = {}, deps = {}) {
|
|
7838
8150
|
const root = (0, import_node_path.resolve)(destination);
|
|
7839
8151
|
await (0, import_promises.mkdir)(root, { recursive: true });
|
|
@@ -7844,9 +8156,22 @@ async function writeOperationTemplate(operation_key, destination, options = {},
|
|
|
7844
8156
|
const manifest_path = (0, import_node_path.join)(root, "manifest.json");
|
|
7845
8157
|
const tool_manual_path = (0, import_node_path.join)(root, "tool_manual.json");
|
|
7846
8158
|
const runtime_validation_path = (0, import_node_path.join)(root, "runtime_validation.json");
|
|
8159
|
+
const gitignore_path = (0, import_node_path.join)(root, ".gitignore");
|
|
7847
8160
|
const readme_path = (0, import_node_path.join)(root, "README.md");
|
|
7848
8161
|
const test_path = (0, import_node_path.join)(testsDir, "test_adapter.ts");
|
|
7849
|
-
|
|
8162
|
+
const docs_dir = (0, import_node_path.join)(root, "docs");
|
|
8163
|
+
await (0, import_promises.mkdir)(docs_dir, { recursive: true });
|
|
8164
|
+
const docs_usage_path = (0, import_node_path.join)(docs_dir, "api-usage.md");
|
|
8165
|
+
for (const filePath of [
|
|
8166
|
+
adapter_path,
|
|
8167
|
+
stubs_path,
|
|
8168
|
+
manifest_path,
|
|
8169
|
+
tool_manual_path,
|
|
8170
|
+
runtime_validation_path,
|
|
8171
|
+
docs_usage_path,
|
|
8172
|
+
readme_path,
|
|
8173
|
+
test_path
|
|
8174
|
+
]) {
|
|
7850
8175
|
if ((0, import_node_fs.existsSync)(filePath)) {
|
|
7851
8176
|
throw new SiglumeProjectError(`${(0, import_node_path.basename)(filePath)} already exists in ${root}`);
|
|
7852
8177
|
}
|
|
@@ -7874,10 +8199,22 @@ async function writeOperationTemplate(operation_key, destination, options = {},
|
|
|
7874
8199
|
await (0, import_promises.writeFile)(manifest_path, renderJson(manifest), "utf8");
|
|
7875
8200
|
await (0, import_promises.writeFile)(tool_manual_path, renderJson(tool_manual), "utf8");
|
|
7876
8201
|
await (0, import_promises.writeFile)(runtime_validation_path, renderJson(buildRuntimeValidationTemplate(tool_manual)), "utf8");
|
|
8202
|
+
await (0, import_promises.writeFile)(docs_usage_path, apiUsageDocsTemplate(manifest), "utf8");
|
|
8203
|
+
await writeOrMergeGitignore(gitignore_path);
|
|
7877
8204
|
await (0, import_promises.writeFile)(readme_path, operationReadmeTemplate(operation, manifest, warning), "utf8");
|
|
7878
8205
|
await (0, import_promises.writeFile)(test_path, operationTestSource(operation), "utf8");
|
|
7879
8206
|
return {
|
|
7880
|
-
files: [
|
|
8207
|
+
files: [
|
|
8208
|
+
adapter_path,
|
|
8209
|
+
stubs_path,
|
|
8210
|
+
manifest_path,
|
|
8211
|
+
tool_manual_path,
|
|
8212
|
+
runtime_validation_path,
|
|
8213
|
+
docs_usage_path,
|
|
8214
|
+
gitignore_path,
|
|
8215
|
+
readme_path,
|
|
8216
|
+
test_path
|
|
8217
|
+
],
|
|
7881
8218
|
operation,
|
|
7882
8219
|
report: {
|
|
7883
8220
|
tool_manual_valid,
|
|
@@ -8026,6 +8363,15 @@ async function findRuntimeValidationPath(root_dir) {
|
|
|
8026
8363
|
}
|
|
8027
8364
|
return null;
|
|
8028
8365
|
}
|
|
8366
|
+
async function findOauthCredentialsPath(root_dir) {
|
|
8367
|
+
for (const name of ["oauth_credentials.json", "oauth-credentials.json"]) {
|
|
8368
|
+
const candidate = (0, import_node_path.join)(root_dir, name);
|
|
8369
|
+
if ((0, import_node_fs.existsSync)(candidate)) {
|
|
8370
|
+
return candidate;
|
|
8371
|
+
}
|
|
8372
|
+
}
|
|
8373
|
+
return null;
|
|
8374
|
+
}
|
|
8029
8375
|
async function loadJsonObject(path, label) {
|
|
8030
8376
|
let payload;
|
|
8031
8377
|
try {
|
|
@@ -8249,18 +8595,36 @@ function readmeTemplate(template) {
|
|
|
8249
8595
|
"- `adapter.ts`: your AppAdapter implementation",
|
|
8250
8596
|
"- `manifest.json`: serialized AppManifest snapshot",
|
|
8251
8597
|
"- `tool_manual.json`: editable ToolManual draft for validation and registration",
|
|
8252
|
-
"- `runtime_validation.json`: live API smoke-test contract used during registration",
|
|
8598
|
+
"- `runtime_validation.json`: local live API smoke-test contract used during registration",
|
|
8599
|
+
"- `docs/api-usage.md`: publish this page and use its public URL as `docs_url`",
|
|
8600
|
+
"- `.gitignore`: keeps runtime review keys and OAuth client secrets out of Git",
|
|
8253
8601
|
"",
|
|
8254
8602
|
"Before registering, replace all generated placeholders:",
|
|
8255
|
-
"- In `adapter.ts` and `manifest.json`, replace `docs_url`
|
|
8256
|
-
"-
|
|
8603
|
+
"- In `adapter.ts` and `manifest.json`, replace `docs_url` with a dedicated public API usage guide, not a homepage.",
|
|
8604
|
+
"- Replace `support_contact` with a real support email address or public support URL.",
|
|
8605
|
+
"- Optional `seller_homepage_url` is the seller's official site and can stay blank.",
|
|
8606
|
+
"- In the local `runtime_validation.json`, replace the public URL and review-key placeholders.",
|
|
8607
|
+
"- If the API uses seller-side OAuth, create a local `oauth_credentials.json` next to the adapter.",
|
|
8608
|
+
"- Do not commit real review keys or OAuth client secrets; the generated `.gitignore` excludes those files.",
|
|
8609
|
+
"- Because `runtime_validation.json` is ignored, GitHub samples do not commit review-key values.",
|
|
8257
8610
|
"",
|
|
8258
8611
|
"Suggested workflow:",
|
|
8259
8612
|
"",
|
|
8613
|
+
"Start locally without a Siglume API key:",
|
|
8614
|
+
"",
|
|
8260
8615
|
"```bash",
|
|
8261
|
-
"siglume validate .",
|
|
8262
8616
|
"siglume test .",
|
|
8617
|
+
"siglume score . --offline",
|
|
8618
|
+
"```",
|
|
8619
|
+
"",
|
|
8620
|
+
"After placeholders are replaced and `SIGLUME_API_KEY` is issued from Developer Portal -> CLI / API keys, run the server-aligned checks:",
|
|
8621
|
+
"",
|
|
8622
|
+
"```bash",
|
|
8623
|
+
"siglume validate .",
|
|
8263
8624
|
"siglume score . --remote",
|
|
8625
|
+
"siglume preflight .",
|
|
8626
|
+
"siglume register .",
|
|
8627
|
+
"# inspect the draft, then explicitly approve publish:",
|
|
8264
8628
|
"siglume register . --confirm",
|
|
8265
8629
|
"```",
|
|
8266
8630
|
""
|
|
@@ -8429,18 +8793,52 @@ async function runCli(argv, deps = {}) {
|
|
|
8429
8793
|
throw new SiglumeProjectError("Score failed.");
|
|
8430
8794
|
}
|
|
8431
8795
|
});
|
|
8432
|
-
program.command("
|
|
8796
|
+
program.command("preflight").option("--json", "emit machine-readable JSON", false).argument("[path]", ".", "project path").action(async (path, options) => {
|
|
8797
|
+
const report = await runPreflight(path, deps);
|
|
8798
|
+
if (options.json) {
|
|
8799
|
+
emit(stdout, renderJson(report));
|
|
8800
|
+
return;
|
|
8801
|
+
}
|
|
8802
|
+
emit(stdout, "Preflight passed.");
|
|
8803
|
+
const preflight = report.registration_preflight;
|
|
8804
|
+
if (preflight?.remote_quality) {
|
|
8805
|
+
emit(stdout, `preflight_quality: ${preflight.remote_quality.grade} (${preflight.remote_quality.overall_score}/100)`);
|
|
8806
|
+
}
|
|
8807
|
+
if (report.runtime_validation_path) emit(stdout, `runtime_validation_path: ${String(report.runtime_validation_path)}`);
|
|
8808
|
+
if (report.oauth_credentials_path) emit(stdout, `oauth_credentials_path: ${String(report.oauth_credentials_path)}`);
|
|
8809
|
+
});
|
|
8810
|
+
program.command("register").option("--confirm", "confirm the draft registration immediately and publish it when the self-serve checks pass", false).option("--submit-review", "legacy alias: publish immediately if your environment still routes through submit-review", false).option("--json", "emit machine-readable JSON", false).argument("[path]", ".", "project path").action(async (path, options) => {
|
|
8433
8811
|
const report = await runRegistration(path, { confirm: options.confirm, submit_review: options.submitReview }, deps);
|
|
8434
8812
|
if (options.json) {
|
|
8435
8813
|
emit(stdout, renderJson(report));
|
|
8436
8814
|
} else {
|
|
8437
8815
|
const receipt = report.receipt;
|
|
8438
|
-
|
|
8816
|
+
if (report.confirmation) {
|
|
8817
|
+
emit(stdout, "Listing published.");
|
|
8818
|
+
} else if (report.review) {
|
|
8819
|
+
emit(stdout, "Listing published via legacy submit-review alias.");
|
|
8820
|
+
} else if (receipt.registration_mode === "upgrade") {
|
|
8821
|
+
emit(stdout, "Upgrade staged.");
|
|
8822
|
+
} else if (receipt.registration_mode === "refresh") {
|
|
8823
|
+
emit(stdout, "Draft refreshed.");
|
|
8824
|
+
} else {
|
|
8825
|
+
emit(stdout, "Draft listing created.");
|
|
8826
|
+
}
|
|
8439
8827
|
emit(stdout, `listing_id: ${receipt.listing_id}`);
|
|
8440
|
-
emit(stdout, `
|
|
8828
|
+
emit(stdout, `receipt_status: ${receipt.status}`);
|
|
8829
|
+
if (receipt.listing_status) emit(stdout, `listing_status: ${receipt.listing_status}`);
|
|
8830
|
+
if (receipt.oauth_status) emit(stdout, `oauth_configured: ${Boolean(receipt.oauth_status.configured)}`);
|
|
8441
8831
|
if (receipt.review_url) emit(stdout, `review_url: ${receipt.review_url}`);
|
|
8442
8832
|
if (receipt.trace_id) emit(stdout, `trace_id: ${receipt.trace_id}`);
|
|
8443
8833
|
if (receipt.request_id) emit(stdout, `request_id: ${receipt.request_id}`);
|
|
8834
|
+
if (report.confirmation) {
|
|
8835
|
+
const confirmation = report.confirmation;
|
|
8836
|
+
if (confirmation.status) emit(stdout, `confirmation_status: ${confirmation.status}`);
|
|
8837
|
+
if (confirmation.release?.release_status) emit(stdout, `release_status: ${confirmation.release.release_status}`);
|
|
8838
|
+
} else if (report.review) {
|
|
8839
|
+
const review = report.review;
|
|
8840
|
+
if (review.status) emit(stdout, `publish_status: ${review.status}`);
|
|
8841
|
+
}
|
|
8444
8842
|
const preflight = report.registration_preflight;
|
|
8445
8843
|
if (preflight?.remote_quality) {
|
|
8446
8844
|
emit(stdout, `preflight_quality: ${preflight.remote_quality.grade} (${preflight.remote_quality.overall_score}/100)`);
|