@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/bin/siglume.cjs
CHANGED
|
@@ -1351,6 +1351,9 @@ function parseListing(data) {
|
|
|
1351
1351
|
short_description: stringOrNull(data.short_description),
|
|
1352
1352
|
docs_url: stringOrNull(data.docs_url),
|
|
1353
1353
|
support_contact: stringOrNull(data.support_contact),
|
|
1354
|
+
seller_display_name: stringOrNull(data.seller_display_name),
|
|
1355
|
+
seller_homepage_url: stringOrNull(data.seller_homepage_url),
|
|
1356
|
+
seller_social_url: stringOrNull(data.seller_social_url),
|
|
1354
1357
|
review_status: stringOrNull(data.review_status),
|
|
1355
1358
|
review_note: stringOrNull(data.review_note),
|
|
1356
1359
|
submission_blockers: Array.isArray(data.submission_blockers) ? data.submission_blockers.filter((item) => typeof item === "string") : [],
|
|
@@ -2532,11 +2535,15 @@ var init_client = __esm({
|
|
|
2532
2535
|
max_retries;
|
|
2533
2536
|
fetchImpl;
|
|
2534
2537
|
pendingConfirmations = /* @__PURE__ */ new Map();
|
|
2535
|
-
constructor(options) {
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
+
constructor(options = {}) {
|
|
2539
|
+
const envApiKey = typeof process !== "undefined" ? process.env?.SIGLUME_API_KEY : void 0;
|
|
2540
|
+
const resolvedApiKey = (options.api_key ?? envApiKey ?? "").trim();
|
|
2541
|
+
if (!resolvedApiKey) {
|
|
2542
|
+
throw new SiglumeClientError(
|
|
2543
|
+
"SIGLUME_API_KEY is required. Pass it as the api_key option or set the SIGLUME_API_KEY env var."
|
|
2544
|
+
);
|
|
2538
2545
|
}
|
|
2539
|
-
this.api_key =
|
|
2546
|
+
this.api_key = resolvedApiKey;
|
|
2540
2547
|
this.agent_key = options.agent_key?.trim() || void 0;
|
|
2541
2548
|
this.base_url = (options.base_url ?? DEFAULT_SIGLUME_API_BASE).replace(/\/+$/, "");
|
|
2542
2549
|
this.timeout_ms = Math.max(1, options.timeout_ms ?? 15e3);
|
|
@@ -2563,6 +2570,13 @@ var init_client = __esm({
|
|
|
2563
2570
|
if (options.runtime_validation) {
|
|
2564
2571
|
payload.runtime_validation = coerceMapping(options.runtime_validation, "runtime_validation");
|
|
2565
2572
|
}
|
|
2573
|
+
if (options.oauth_credentials) {
|
|
2574
|
+
payload.oauth_credentials = Array.isArray(options.oauth_credentials) ? {
|
|
2575
|
+
items: options.oauth_credentials.map(
|
|
2576
|
+
(item, index) => coerceMapping(item, `oauth_credentials[${index}]`)
|
|
2577
|
+
)
|
|
2578
|
+
} : coerceMapping(options.oauth_credentials, "oauth_credentials");
|
|
2579
|
+
}
|
|
2566
2580
|
if (options.metadata) {
|
|
2567
2581
|
payload.metadata = coerceMapping(options.metadata, "metadata");
|
|
2568
2582
|
}
|
|
@@ -2581,6 +2595,8 @@ var init_client = __esm({
|
|
|
2581
2595
|
"docs_url",
|
|
2582
2596
|
"documentation_url",
|
|
2583
2597
|
"support_contact",
|
|
2598
|
+
"seller_homepage_url",
|
|
2599
|
+
"seller_social_url",
|
|
2584
2600
|
"jurisdiction",
|
|
2585
2601
|
"price_model",
|
|
2586
2602
|
"price_value_minor",
|
|
@@ -2596,10 +2612,14 @@ var init_client = __esm({
|
|
|
2596
2612
|
}
|
|
2597
2613
|
const docsUrl = String(manifestPayload.docs_url ?? manifestPayload.documentation_url ?? "").trim();
|
|
2598
2614
|
const supportContact = String(manifestPayload.support_contact ?? "").trim();
|
|
2599
|
-
|
|
2615
|
+
const sellerHomepageUrl = String(manifestPayload.seller_homepage_url ?? "").trim();
|
|
2616
|
+
const sellerSocialUrl = String(manifestPayload.seller_social_url ?? "").trim();
|
|
2617
|
+
if (docsUrl || supportContact || sellerHomepageUrl || sellerSocialUrl) {
|
|
2600
2618
|
const publisherIdentity = {
|
|
2601
2619
|
documentation_url: docsUrl || null,
|
|
2602
|
-
support_contact: supportContact || null
|
|
2620
|
+
support_contact: supportContact || null,
|
|
2621
|
+
seller_homepage_url: sellerHomepageUrl || null,
|
|
2622
|
+
seller_social_url: sellerSocialUrl || null
|
|
2603
2623
|
};
|
|
2604
2624
|
payload.publisher_identity = publisherIdentity;
|
|
2605
2625
|
payload.legal = { publisher_identity: publisherIdentity };
|
|
@@ -2613,36 +2633,30 @@ var init_client = __esm({
|
|
|
2613
2633
|
return {
|
|
2614
2634
|
listing_id,
|
|
2615
2635
|
status: String(data.status ?? "draft"),
|
|
2636
|
+
registration_mode: stringOrNull(data.registration_mode),
|
|
2637
|
+
listing_status: stringOrNull(data.listing_status),
|
|
2616
2638
|
auto_manifest: toRecord(data.auto_manifest),
|
|
2617
2639
|
confidence: toRecord(data.confidence),
|
|
2618
2640
|
validation_report: toRecord(data.validation_report),
|
|
2641
|
+
oauth_status: toRecord(data.oauth_status),
|
|
2619
2642
|
review_url: stringOrNull(data.review_url),
|
|
2620
2643
|
trace_id: meta.trace_id,
|
|
2621
2644
|
request_id: meta.request_id
|
|
2622
2645
|
};
|
|
2623
2646
|
}
|
|
2624
2647
|
async confirm_registration(listing_id, options = {}) {
|
|
2625
|
-
|
|
2626
|
-
const manifestPayload = options.manifest ? coerceMapping(options.manifest, "manifest") : pending?.manifest ?? {};
|
|
2627
|
-
const toolManualPayload = options.tool_manual ? coerceMapping(options.tool_manual, "tool_manual") : pending?.tool_manual ?? {};
|
|
2628
|
-
const overrides = {};
|
|
2629
|
-
for (const fieldName of ["name", "job_to_be_done"]) {
|
|
2630
|
-
if (manifestPayload[fieldName]) {
|
|
2631
|
-
overrides[fieldName] = manifestPayload[fieldName];
|
|
2632
|
-
}
|
|
2633
|
-
}
|
|
2634
|
-
if (Object.keys(toolManualPayload).length > 0) {
|
|
2635
|
-
overrides.tool_manual = toolManualPayload;
|
|
2636
|
-
}
|
|
2648
|
+
void options;
|
|
2637
2649
|
const payload = { approved: true };
|
|
2638
|
-
if (Object.keys(overrides).length > 0) {
|
|
2639
|
-
payload.overrides = overrides;
|
|
2640
|
-
}
|
|
2641
2650
|
const [data, meta] = await this.request("POST", `/market/capabilities/${listing_id}/confirm-auto-register`, { json_body: payload });
|
|
2642
2651
|
this.pendingConfirmations.delete(listing_id);
|
|
2652
|
+
const checklist = isRecord(data.checklist) ? Object.fromEntries(
|
|
2653
|
+
Object.entries(data.checklist).map(([key, value]) => [key, Boolean(value)])
|
|
2654
|
+
) : {};
|
|
2643
2655
|
return {
|
|
2644
2656
|
listing_id: String(data.listing_id ?? listing_id),
|
|
2645
2657
|
status: String(data.status ?? ""),
|
|
2658
|
+
message: stringOrNull(data.message),
|
|
2659
|
+
checklist,
|
|
2646
2660
|
release: toRecord(data.release),
|
|
2647
2661
|
quality: parseRegistrationQuality(toRecord(data.quality)),
|
|
2648
2662
|
trace_id: meta.trace_id,
|
|
@@ -4599,7 +4613,7 @@ ${details}` : summary;
|
|
|
4599
4613
|
const headers = new Headers({
|
|
4600
4614
|
Authorization: `Bearer ${this.api_key}`,
|
|
4601
4615
|
Accept: "application/json",
|
|
4602
|
-
"User-Agent": "siglume-api-sdk-ts/0.6
|
|
4616
|
+
"User-Agent": "siglume-api-sdk-ts/0.7.6"
|
|
4603
4617
|
});
|
|
4604
4618
|
if (options.headers) {
|
|
4605
4619
|
for (const [key, value] of Object.entries(options.headers)) {
|
|
@@ -4801,7 +4815,7 @@ var init_metering = __esm({
|
|
|
4801
4815
|
fetchImpl;
|
|
4802
4816
|
constructor(options) {
|
|
4803
4817
|
this.client = new SiglumeClient(options);
|
|
4804
|
-
this.api_key =
|
|
4818
|
+
this.api_key = this.client.api_key;
|
|
4805
4819
|
this.base_url = (options.base_url ?? DEFAULT_SIGLUME_API_BASE).replace(/\/+$/, "");
|
|
4806
4820
|
this.timeout_ms = Math.max(1, options.timeout_ms ?? 15e3);
|
|
4807
4821
|
this.max_retries = Math.max(1, Math.trunc(options.max_retries ?? 3));
|
|
@@ -4847,7 +4861,7 @@ var init_metering = __esm({
|
|
|
4847
4861
|
const headers = new Headers({
|
|
4848
4862
|
Authorization: `Bearer ${this.api_key}`,
|
|
4849
4863
|
Accept: "application/json",
|
|
4850
|
-
"User-Agent": "siglume-api-sdk-ts/0.6
|
|
4864
|
+
"User-Agent": "siglume-api-sdk-ts/0.7.6"
|
|
4851
4865
|
});
|
|
4852
4866
|
let body;
|
|
4853
4867
|
if (options.json_body) {
|
|
@@ -7162,6 +7176,15 @@ async function loadProject(path = ".") {
|
|
|
7162
7176
|
const tool_manual = tool_manual_path ? JSON.parse(await (0, import_promises.readFile)(tool_manual_path, "utf8")) : buildToolManualTemplate(manifest);
|
|
7163
7177
|
const runtime_validation_path = await findRuntimeValidationPath(root_dir);
|
|
7164
7178
|
const runtime_validation = runtime_validation_path ? await loadJsonObject(runtime_validation_path, "runtime_validation") : void 0;
|
|
7179
|
+
const oauth_credentials_path = await findOauthCredentialsPath(root_dir);
|
|
7180
|
+
let oauth_credentials;
|
|
7181
|
+
if (oauth_credentials_path) {
|
|
7182
|
+
const parsed = JSON.parse(await (0, import_promises.readFile)(oauth_credentials_path, "utf8"));
|
|
7183
|
+
if (!isRecord(parsed) && !Array.isArray(parsed)) {
|
|
7184
|
+
throw new SiglumeProjectError("oauth_credentials must be a JSON object or array");
|
|
7185
|
+
}
|
|
7186
|
+
oauth_credentials = parsed;
|
|
7187
|
+
}
|
|
7165
7188
|
return {
|
|
7166
7189
|
root_dir,
|
|
7167
7190
|
adapter_path,
|
|
@@ -7170,9 +7193,110 @@ async function loadProject(path = ".") {
|
|
|
7170
7193
|
tool_manual_path: tool_manual_path ?? void 0,
|
|
7171
7194
|
tool_manual,
|
|
7172
7195
|
runtime_validation_path: runtime_validation_path ?? void 0,
|
|
7173
|
-
runtime_validation
|
|
7196
|
+
runtime_validation,
|
|
7197
|
+
oauth_credentials_path: oauth_credentials_path ?? void 0,
|
|
7198
|
+
oauth_credentials
|
|
7174
7199
|
};
|
|
7175
7200
|
}
|
|
7201
|
+
var OAUTH_PROVIDER_ALIASES = {
|
|
7202
|
+
x: "twitter",
|
|
7203
|
+
"x-twitter": "twitter",
|
|
7204
|
+
twitter: "twitter",
|
|
7205
|
+
slack: "slack",
|
|
7206
|
+
google: "google",
|
|
7207
|
+
gmail: "google",
|
|
7208
|
+
"google-drive": "google",
|
|
7209
|
+
"google-calendar": "google",
|
|
7210
|
+
github: "github",
|
|
7211
|
+
linear: "linear",
|
|
7212
|
+
notion: "notion"
|
|
7213
|
+
};
|
|
7214
|
+
function oauthProviderKeyFromRequirement(value) {
|
|
7215
|
+
const raw = String(value ?? "").trim().toLowerCase().replaceAll("_", "-");
|
|
7216
|
+
if (!raw) return null;
|
|
7217
|
+
if (OAUTH_PROVIDER_ALIASES[raw]) {
|
|
7218
|
+
return OAUTH_PROVIDER_ALIASES[raw];
|
|
7219
|
+
}
|
|
7220
|
+
for (const token of raw.replaceAll("/", "-").replaceAll(":", "-").split("-")) {
|
|
7221
|
+
const next = token.trim();
|
|
7222
|
+
if (OAUTH_PROVIDER_ALIASES[next]) {
|
|
7223
|
+
return OAUTH_PROVIDER_ALIASES[next];
|
|
7224
|
+
}
|
|
7225
|
+
}
|
|
7226
|
+
return null;
|
|
7227
|
+
}
|
|
7228
|
+
function requiredOauthProviders(requirements) {
|
|
7229
|
+
const providers = [];
|
|
7230
|
+
for (const item of requirements ?? []) {
|
|
7231
|
+
const providerKey = oauthProviderKeyFromRequirement(item);
|
|
7232
|
+
if (providerKey && !providers.includes(providerKey)) {
|
|
7233
|
+
providers.push(providerKey);
|
|
7234
|
+
}
|
|
7235
|
+
}
|
|
7236
|
+
return providers;
|
|
7237
|
+
}
|
|
7238
|
+
function oauthProviderRecordsMap(payload) {
|
|
7239
|
+
if (!payload) {
|
|
7240
|
+
return {};
|
|
7241
|
+
}
|
|
7242
|
+
const items = Array.isArray(payload) ? payload : Array.isArray(payload.items) ? payload.items : [payload];
|
|
7243
|
+
const resolved = {};
|
|
7244
|
+
for (const [index, item] of items.entries()) {
|
|
7245
|
+
if (!isRecord(item)) {
|
|
7246
|
+
throw new SiglumeProjectError(`oauth_credentials[${index}] must be a JSON object.`);
|
|
7247
|
+
}
|
|
7248
|
+
const providerKey = oauthProviderKeyFromRequirement(item.provider_key ?? item.provider);
|
|
7249
|
+
if (!providerKey) {
|
|
7250
|
+
throw new SiglumeProjectError(`oauth_credentials[${index}].provider_key is unsupported.`);
|
|
7251
|
+
}
|
|
7252
|
+
const clientId = String(item.client_id ?? "").trim();
|
|
7253
|
+
const clientSecret = String(item.client_secret ?? "").trim();
|
|
7254
|
+
if (!clientId || !clientSecret) {
|
|
7255
|
+
throw new SiglumeProjectError(`oauth_credentials[${index}] must include client_id and client_secret.`);
|
|
7256
|
+
}
|
|
7257
|
+
const rawScopes = item.required_scopes ?? item.scopes;
|
|
7258
|
+
let scopes = [];
|
|
7259
|
+
if (rawScopes == null) {
|
|
7260
|
+
scopes = [];
|
|
7261
|
+
} else if (!Array.isArray(rawScopes)) {
|
|
7262
|
+
throw new SiglumeProjectError(`oauth_credentials[${index}].required_scopes must be a JSON array.`);
|
|
7263
|
+
} else {
|
|
7264
|
+
scopes = rawScopes.map((scope) => String(scope ?? "").trim()).filter(Boolean);
|
|
7265
|
+
}
|
|
7266
|
+
resolved[providerKey] = {
|
|
7267
|
+
provider_key: providerKey,
|
|
7268
|
+
client_id: clientId,
|
|
7269
|
+
client_secret: clientSecret,
|
|
7270
|
+
required_scopes: scopes
|
|
7271
|
+
};
|
|
7272
|
+
}
|
|
7273
|
+
return resolved;
|
|
7274
|
+
}
|
|
7275
|
+
function canonicalOauthCredentialsPayload(payload) {
|
|
7276
|
+
const records = oauthProviderRecordsMap(payload);
|
|
7277
|
+
const providerKeys = Object.keys(records).sort();
|
|
7278
|
+
if (providerKeys.length === 0) {
|
|
7279
|
+
return void 0;
|
|
7280
|
+
}
|
|
7281
|
+
return {
|
|
7282
|
+
items: providerKeys.map((providerKey) => records[providerKey])
|
|
7283
|
+
};
|
|
7284
|
+
}
|
|
7285
|
+
function ensureRequiredOauthCredentials(project) {
|
|
7286
|
+
const requiredProviders = requiredOauthProviders(project.manifest.required_connected_accounts ?? []);
|
|
7287
|
+
if (requiredProviders.length === 0) {
|
|
7288
|
+
return;
|
|
7289
|
+
}
|
|
7290
|
+
const provided = new Set(Object.keys(oauthProviderRecordsMap(project.oauth_credentials)));
|
|
7291
|
+
const missing = requiredProviders.filter((provider) => !provided.has(provider));
|
|
7292
|
+
if (missing.length === 0) {
|
|
7293
|
+
return;
|
|
7294
|
+
}
|
|
7295
|
+
const path = project.oauth_credentials_path ?? (0, import_node_path.join)(project.root_dir, "oauth_credentials.json");
|
|
7296
|
+
throw new SiglumeProjectError(
|
|
7297
|
+
`${path} is required for OAuth-backed APIs. Missing provider seeds: ${missing.join(", ")}`
|
|
7298
|
+
);
|
|
7299
|
+
}
|
|
7176
7300
|
async function validateProject(path = ".", deps = {}) {
|
|
7177
7301
|
const project = await loadProject(path);
|
|
7178
7302
|
const manifest_issues = await projectValidationIssues(project);
|
|
@@ -7209,17 +7333,31 @@ function ensureManifestPublisherIdentity(project) {
|
|
|
7209
7333
|
const manifestPayload = project.manifest;
|
|
7210
7334
|
const docsUrl = String(manifestPayload.docs_url ?? manifestPayload.documentation_url ?? "").trim();
|
|
7211
7335
|
const supportContact = String(manifestPayload.support_contact ?? "").trim();
|
|
7336
|
+
const sellerHomepageUrl = String(manifestPayload.seller_homepage_url ?? "").trim();
|
|
7337
|
+
const sellerSocialUrl = String(manifestPayload.seller_social_url ?? "").trim();
|
|
7212
7338
|
const jurisdiction = String(manifestPayload.jurisdiction ?? "").trim();
|
|
7213
7339
|
const issues = [];
|
|
7214
7340
|
if (!docsUrl) {
|
|
7215
7341
|
issues.push("manifest.docs_url is required");
|
|
7216
7342
|
} else if (looksLikePlaceholder(docsUrl)) {
|
|
7217
7343
|
issues.push("manifest.docs_url must be replaced with your public documentation URL");
|
|
7344
|
+
} else if (!looksLikeHttpUrl(docsUrl)) {
|
|
7345
|
+
issues.push("manifest.docs_url must be an http(s) URL");
|
|
7346
|
+
} else if (looksLikeRootUrl(docsUrl)) {
|
|
7347
|
+
issues.push("manifest.docs_url must be a dedicated API usage page, not a root homepage URL");
|
|
7218
7348
|
}
|
|
7219
7349
|
if (!supportContact) {
|
|
7220
7350
|
issues.push("manifest.support_contact is required");
|
|
7221
7351
|
} else if (looksLikePlaceholder(supportContact)) {
|
|
7222
7352
|
issues.push("manifest.support_contact must be replaced with your real support email or support URL");
|
|
7353
|
+
} else if (!looksLikeEmail(supportContact) && !looksLikeHttpUrl(supportContact)) {
|
|
7354
|
+
issues.push("manifest.support_contact must be a real email address or http(s) support URL");
|
|
7355
|
+
}
|
|
7356
|
+
if (sellerHomepageUrl && (looksLikePlaceholder(sellerHomepageUrl) || !looksLikeHttpUrl(sellerHomepageUrl))) {
|
|
7357
|
+
issues.push("manifest.seller_homepage_url must be a real http(s) official homepage URL when provided");
|
|
7358
|
+
}
|
|
7359
|
+
if (sellerSocialUrl && (looksLikePlaceholder(sellerSocialUrl) || !looksLikeHttpUrl(sellerSocialUrl))) {
|
|
7360
|
+
issues.push("manifest.seller_social_url must be a real http(s) official social/profile URL when provided");
|
|
7223
7361
|
}
|
|
7224
7362
|
if (!jurisdiction) issues.push("manifest.jurisdiction is required");
|
|
7225
7363
|
if (issues.length > 0) {
|
|
@@ -7231,7 +7369,25 @@ ${issues.map((issue2) => `- ${issue2}`).join("\n")}`
|
|
|
7231
7369
|
}
|
|
7232
7370
|
function looksLikePlaceholder(value) {
|
|
7233
7371
|
const normalized = value.trim().toLowerCase();
|
|
7234
|
-
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");
|
|
7372
|
+
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");
|
|
7373
|
+
}
|
|
7374
|
+
function looksLikeHttpUrl(value) {
|
|
7375
|
+
try {
|
|
7376
|
+
const parsed = new URL(value.trim());
|
|
7377
|
+
return parsed.protocol === "http:" || parsed.protocol === "https:";
|
|
7378
|
+
} catch {
|
|
7379
|
+
return false;
|
|
7380
|
+
}
|
|
7381
|
+
}
|
|
7382
|
+
function looksLikeRootUrl(value) {
|
|
7383
|
+
if (!looksLikeHttpUrl(value)) return false;
|
|
7384
|
+
const parsed = new URL(value.trim());
|
|
7385
|
+
return parsed.pathname.replace(/^\/+|\/+$/g, "") === "";
|
|
7386
|
+
}
|
|
7387
|
+
function looksLikeEmail(value) {
|
|
7388
|
+
const normalized = value.trim();
|
|
7389
|
+
const domain = normalized.split("@").at(-1) ?? "";
|
|
7390
|
+
return normalized.includes("@") && !normalized.includes(" ") && domain.includes(".") && !normalized.startsWith("@");
|
|
7235
7391
|
}
|
|
7236
7392
|
function runtimePlaceholderIssues(runtimeValidation) {
|
|
7237
7393
|
const issues = [];
|
|
@@ -7291,6 +7447,9 @@ async function registrationPreflight(project, client) {
|
|
|
7291
7447
|
const manifestIssues = await projectValidationIssues(project);
|
|
7292
7448
|
const [toolManualValid, toolManualIssues] = validate_tool_manual(project.tool_manual);
|
|
7293
7449
|
const remoteQuality = await client.preview_quality_score(project.tool_manual);
|
|
7450
|
+
const requiredOauthProvidersList = requiredOauthProviders(project.manifest.required_connected_accounts ?? []);
|
|
7451
|
+
const oauthProviderRecords = oauthProviderRecordsMap(project.oauth_credentials);
|
|
7452
|
+
const missingOauthProviders = requiredOauthProvidersList.filter((provider) => !oauthProviderRecords[provider]);
|
|
7294
7453
|
const blockingToolManualIssues = toolManualIssues.filter((issue2) => issue2.severity === "error");
|
|
7295
7454
|
const errors = [
|
|
7296
7455
|
...manifestIssues.map((issue2) => String(issue2)),
|
|
@@ -7302,11 +7461,17 @@ async function registrationPreflight(project, client) {
|
|
|
7302
7461
|
if (!remoteQualityOk(remoteQuality)) {
|
|
7303
7462
|
errors.push(`remote Tool Manual quality is not publishable: ${remoteQuality.grade} (${remoteQuality.overall_score}/100)`);
|
|
7304
7463
|
}
|
|
7464
|
+
if (missingOauthProviders.length > 0) {
|
|
7465
|
+
errors.push(`oauth_credentials.json is required for OAuth-backed APIs: ${missingOauthProviders.join(", ")}`);
|
|
7466
|
+
}
|
|
7305
7467
|
const preflight = {
|
|
7306
7468
|
manifest_issues: manifestIssues,
|
|
7307
7469
|
tool_manual_valid: toolManualValid,
|
|
7308
7470
|
tool_manual_issues: toolManualIssues.map((issue2) => toJsonable(issue2)),
|
|
7309
7471
|
remote_quality: toJsonable(remoteQuality),
|
|
7472
|
+
required_oauth_providers: requiredOauthProvidersList,
|
|
7473
|
+
oauth_credentials_path: project.oauth_credentials_path ?? null,
|
|
7474
|
+
oauth_missing_providers: missingOauthProviders,
|
|
7310
7475
|
ok: errors.length === 0
|
|
7311
7476
|
};
|
|
7312
7477
|
if (errors.length > 0) {
|
|
@@ -7322,6 +7487,7 @@ async function runRegistration(path = ".", options = {}, deps = {}) {
|
|
|
7322
7487
|
ensureExplicitToolManual(project);
|
|
7323
7488
|
ensureManifestPublisherIdentity(project);
|
|
7324
7489
|
ensureRuntimeValidationReady(project);
|
|
7490
|
+
ensureRequiredOauthCredentials(project);
|
|
7325
7491
|
const client = await createClient(deps);
|
|
7326
7492
|
const preflight = await registrationPreflight(project, client);
|
|
7327
7493
|
let developerPortalPreflight = null;
|
|
@@ -7330,18 +7496,20 @@ async function runRegistration(path = ".", options = {}, deps = {}) {
|
|
|
7330
7496
|
const verifiedDestination = portal.payout_readiness?.verified_destination;
|
|
7331
7497
|
if (verifiedDestination !== true) {
|
|
7332
7498
|
throw new SiglumeProjectError(
|
|
7333
|
-
"Paid API registration requires a verified Polygon payout destination. Open https://siglume.com/owner/
|
|
7499
|
+
"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."
|
|
7334
7500
|
);
|
|
7335
7501
|
}
|
|
7336
7502
|
developerPortalPreflight = toJsonable(portal);
|
|
7337
7503
|
}
|
|
7338
7504
|
const receipt = await client.auto_register(project.manifest, project.tool_manual, {
|
|
7339
|
-
runtime_validation: project.runtime_validation
|
|
7505
|
+
runtime_validation: project.runtime_validation,
|
|
7506
|
+
oauth_credentials: canonicalOauthCredentialsPayload(project.oauth_credentials)
|
|
7340
7507
|
});
|
|
7341
7508
|
const result = {
|
|
7342
7509
|
receipt: toJsonable(receipt),
|
|
7343
7510
|
registration_preflight: preflight,
|
|
7344
|
-
runtime_validation_path: project.runtime_validation_path ?? null
|
|
7511
|
+
runtime_validation_path: project.runtime_validation_path ?? null,
|
|
7512
|
+
oauth_credentials_path: project.oauth_credentials_path ?? null
|
|
7345
7513
|
};
|
|
7346
7514
|
if (developerPortalPreflight) {
|
|
7347
7515
|
result.developer_portal_preflight = developerPortalPreflight;
|
|
@@ -7356,6 +7524,37 @@ async function runRegistration(path = ".", options = {}, deps = {}) {
|
|
|
7356
7524
|
}
|
|
7357
7525
|
return result;
|
|
7358
7526
|
}
|
|
7527
|
+
async function runPreflight(path = ".", deps = {}) {
|
|
7528
|
+
const project = await loadProject(path);
|
|
7529
|
+
ensureExplicitToolManual(project);
|
|
7530
|
+
ensureManifestPublisherIdentity(project);
|
|
7531
|
+
ensureRuntimeValidationReady(project);
|
|
7532
|
+
ensureRequiredOauthCredentials(project);
|
|
7533
|
+
const client = await createClient(deps);
|
|
7534
|
+
const preflight = await registrationPreflight(project, client);
|
|
7535
|
+
let developerPortalPreflight = null;
|
|
7536
|
+
if (String(project.manifest.price_model ?? "free").toLowerCase() !== "free") {
|
|
7537
|
+
const portal = await client.get_developer_portal();
|
|
7538
|
+
const verifiedDestination = portal.payout_readiness?.verified_destination;
|
|
7539
|
+
if (verifiedDestination !== true) {
|
|
7540
|
+
throw new SiglumeProjectError(
|
|
7541
|
+
"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."
|
|
7542
|
+
);
|
|
7543
|
+
}
|
|
7544
|
+
developerPortalPreflight = toJsonable(portal);
|
|
7545
|
+
}
|
|
7546
|
+
const result = {
|
|
7547
|
+
ok: true,
|
|
7548
|
+
adapter_path: project.adapter_path,
|
|
7549
|
+
registration_preflight: preflight,
|
|
7550
|
+
runtime_validation_path: project.runtime_validation_path ?? null,
|
|
7551
|
+
oauth_credentials_path: project.oauth_credentials_path ?? null
|
|
7552
|
+
};
|
|
7553
|
+
if (developerPortalPreflight) {
|
|
7554
|
+
result.developer_portal_preflight = developerPortalPreflight;
|
|
7555
|
+
}
|
|
7556
|
+
return result;
|
|
7557
|
+
}
|
|
7359
7558
|
async function createSupportCaseReport(options, deps = {}) {
|
|
7360
7559
|
const client = await createClient(deps);
|
|
7361
7560
|
const supportCase = await client.create_support_case(options.subject, options.body, { trace_id: options.trace_id });
|
|
@@ -7402,8 +7601,12 @@ async function writeInitTemplate(template, destination) {
|
|
|
7402
7601
|
const manifest_path = (0, import_node_path.join)(root, "manifest.json");
|
|
7403
7602
|
const tool_manual_path = (0, import_node_path.join)(root, "tool_manual.json");
|
|
7404
7603
|
const runtime_validation_path = (0, import_node_path.join)(root, "runtime_validation.json");
|
|
7604
|
+
const gitignore_path = (0, import_node_path.join)(root, ".gitignore");
|
|
7405
7605
|
const readme_path = (0, import_node_path.join)(root, "README.md");
|
|
7406
|
-
|
|
7606
|
+
const docs_dir = (0, import_node_path.join)(root, "docs");
|
|
7607
|
+
await (0, import_promises.mkdir)(docs_dir, { recursive: true });
|
|
7608
|
+
const docs_usage_path = (0, import_node_path.join)(docs_dir, "api-usage.md");
|
|
7609
|
+
for (const filePath of [adapter_path, manifest_path, tool_manual_path, runtime_validation_path, docs_usage_path, readme_path]) {
|
|
7407
7610
|
if ((0, import_node_fs.existsSync)(filePath)) {
|
|
7408
7611
|
throw new SiglumeProjectError(`${(0, import_node_path.basename)(filePath)} already exists in ${root}`);
|
|
7409
7612
|
}
|
|
@@ -7414,8 +7617,10 @@ async function writeInitTemplate(template, destination) {
|
|
|
7414
7617
|
await (0, import_promises.writeFile)(manifest_path, renderJson(manifest), "utf8");
|
|
7415
7618
|
await (0, import_promises.writeFile)(tool_manual_path, renderJson(toolManual), "utf8");
|
|
7416
7619
|
await (0, import_promises.writeFile)(runtime_validation_path, renderJson(buildRuntimeValidationTemplate(toolManual)), "utf8");
|
|
7620
|
+
await (0, import_promises.writeFile)(docs_usage_path, apiUsageDocsTemplate(manifest), "utf8");
|
|
7621
|
+
await writeOrMergeGitignore(gitignore_path);
|
|
7417
7622
|
await (0, import_promises.writeFile)(readme_path, readmeTemplate(template), "utf8");
|
|
7418
|
-
return [adapter_path, manifest_path, tool_manual_path, runtime_validation_path, readme_path];
|
|
7623
|
+
return [adapter_path, manifest_path, tool_manual_path, runtime_validation_path, docs_usage_path, gitignore_path, readme_path];
|
|
7419
7624
|
}
|
|
7420
7625
|
async function listOperationCatalog(options = {}, deps = {}) {
|
|
7421
7626
|
const resolvedAgentId = String(options.agent_id ?? "").trim();
|
|
@@ -7809,25 +8014,132 @@ function operationReadmeTemplate(operation, manifest, warning) {
|
|
|
7809
8014
|
"- `stubs.ts`: mock fallback used when `SIGLUME_API_KEY` is not set",
|
|
7810
8015
|
"- `manifest.json`: reviewable manifest snapshot",
|
|
7811
8016
|
"- `tool_manual.json`: machine-generated ToolManual scaffold",
|
|
7812
|
-
"- `runtime_validation.json`: public endpoint and review-key checks used by auto-register",
|
|
8017
|
+
"- `runtime_validation.json`: local public endpoint and review-key checks used by auto-register",
|
|
8018
|
+
"- `docs/api-usage.md`: publishable API usage guide template for `docs_url`",
|
|
8019
|
+
"- `.gitignore`: keeps runtime review keys and OAuth client secrets out of Git",
|
|
7813
8020
|
"- `tests/test_adapter.ts`: smoke test for `AppTestHarness`",
|
|
7814
8021
|
"",
|
|
7815
8022
|
"Before registering, replace all generated placeholders:",
|
|
7816
|
-
"- In `adapter.ts` and `manifest.json`, replace `docs_url`
|
|
7817
|
-
"-
|
|
8023
|
+
"- In `adapter.ts` and `manifest.json`, replace `docs_url` with a dedicated public API usage guide, not a homepage.",
|
|
8024
|
+
"- Replace `support_contact` with a real support email address or public support URL.",
|
|
8025
|
+
"- Optional `seller_homepage_url` is the seller's official site and can stay blank.",
|
|
8026
|
+
"- In the local `runtime_validation.json`, replace the public URL and review-key placeholders.",
|
|
8027
|
+
"- If the API uses seller-side OAuth, create a local `oauth_credentials.json` next to the adapter.",
|
|
8028
|
+
"- Do not commit real review keys or OAuth client secrets; the generated `.gitignore` excludes those files.",
|
|
8029
|
+
"- Because `runtime_validation.json` is ignored, GitHub samples do not commit review-key values.",
|
|
7818
8030
|
"",
|
|
7819
8031
|
"## Commands",
|
|
7820
8032
|
"",
|
|
8033
|
+
"Start locally without a Siglume API key:",
|
|
8034
|
+
"",
|
|
7821
8035
|
"```bash",
|
|
7822
|
-
"siglume validate .",
|
|
7823
8036
|
"siglume test .",
|
|
7824
8037
|
"npm test -- tests/test_adapter.ts",
|
|
8038
|
+
"siglume score . --offline",
|
|
8039
|
+
"```",
|
|
8040
|
+
"",
|
|
8041
|
+
"After placeholders are replaced and `SIGLUME_API_KEY` is issued from Developer Portal -> CLI / API keys, run the server-aligned checks:",
|
|
8042
|
+
"",
|
|
8043
|
+
"```bash",
|
|
8044
|
+
"siglume validate .",
|
|
7825
8045
|
"siglume score . --remote",
|
|
8046
|
+
"siglume preflight .",
|
|
8047
|
+
"siglume register .",
|
|
8048
|
+
"# inspect the draft, then explicitly approve publish:",
|
|
7826
8049
|
"siglume register . --confirm",
|
|
7827
8050
|
"```",
|
|
7828
8051
|
""
|
|
7829
8052
|
].join("\n");
|
|
7830
8053
|
}
|
|
8054
|
+
function apiUsageDocsTemplate(manifest) {
|
|
8055
|
+
const name = String(manifest.name ?? manifest.capability_key ?? "Siglume API");
|
|
8056
|
+
const capabilityKey = String(manifest.capability_key ?? "replace-with-capability-key");
|
|
8057
|
+
const jobToBeDone = String(manifest.job_to_be_done ?? "Describe what this API lets an agent do.");
|
|
8058
|
+
const permissionClass = String(manifest.permission_class ?? "read-only");
|
|
8059
|
+
const priceModel = String(manifest.price_model ?? "free");
|
|
8060
|
+
const requiredAccounts = (manifest.required_connected_accounts ?? []).join(", ") || "none";
|
|
8061
|
+
const supportContact = String(manifest.support_contact ?? "replace-with-support-contact");
|
|
8062
|
+
return [
|
|
8063
|
+
`# ${name} API Usage Guide`,
|
|
8064
|
+
"",
|
|
8065
|
+
`This page is the dedicated public usage guide for the Siglume API listing \`${capabilityKey}\`.`,
|
|
8066
|
+
"Publish this page at an anonymous HTTP 200 URL and use that URL as `docs_url`.",
|
|
8067
|
+
"",
|
|
8068
|
+
"Do not use your company homepage as `docs_url`; keep seller/company homepages in `seller_homepage_url`.",
|
|
8069
|
+
"",
|
|
8070
|
+
"## What This API Does",
|
|
8071
|
+
"",
|
|
8072
|
+
jobToBeDone,
|
|
8073
|
+
"",
|
|
8074
|
+
"## Permission Model",
|
|
8075
|
+
"",
|
|
8076
|
+
`- Permission class: \`${permissionClass}\``,
|
|
8077
|
+
`- Price model: \`${priceModel}\``,
|
|
8078
|
+
`- Required connected accounts: \`${requiredAccounts}\``,
|
|
8079
|
+
"",
|
|
8080
|
+
"## Inputs",
|
|
8081
|
+
"",
|
|
8082
|
+
"Describe the request fields your API accepts. Keep this aligned with `tool_manual.json` and `runtime_validation.json`.",
|
|
8083
|
+
"",
|
|
8084
|
+
"## Outputs",
|
|
8085
|
+
"",
|
|
8086
|
+
"Describe the response fields your API returns. Include the fields in `runtime_validation.expected_response_fields`.",
|
|
8087
|
+
"",
|
|
8088
|
+
"## Errors And Support",
|
|
8089
|
+
"",
|
|
8090
|
+
"Explain common error messages and how an owner should recover.",
|
|
8091
|
+
"",
|
|
8092
|
+
`Support contact: ${supportContact}`,
|
|
8093
|
+
""
|
|
8094
|
+
].join("\n");
|
|
8095
|
+
}
|
|
8096
|
+
function generatedGitignore() {
|
|
8097
|
+
return [
|
|
8098
|
+
"# Local secrets and registration-only runtime checks.",
|
|
8099
|
+
".env",
|
|
8100
|
+
".env.*",
|
|
8101
|
+
"!.env.example",
|
|
8102
|
+
"runtime_validation.json",
|
|
8103
|
+
"runtime-validation.json",
|
|
8104
|
+
"oauth_credentials.json",
|
|
8105
|
+
"oauth-credentials.json",
|
|
8106
|
+
"",
|
|
8107
|
+
"# Python / test artifacts.",
|
|
8108
|
+
"__pycache__/",
|
|
8109
|
+
"*.py[cod]",
|
|
8110
|
+
".pytest_cache/",
|
|
8111
|
+
".mypy_cache/",
|
|
8112
|
+
".coverage",
|
|
8113
|
+
"htmlcov/",
|
|
8114
|
+
"dist/",
|
|
8115
|
+
"build/",
|
|
8116
|
+
"*.egg-info/",
|
|
8117
|
+
"",
|
|
8118
|
+
"# JavaScript tooling if this project also uses TypeScript helpers.",
|
|
8119
|
+
"node_modules/",
|
|
8120
|
+
"coverage/",
|
|
8121
|
+
""
|
|
8122
|
+
].join("\n");
|
|
8123
|
+
}
|
|
8124
|
+
async function writeOrMergeGitignore(filePath) {
|
|
8125
|
+
const generated = generatedGitignore();
|
|
8126
|
+
if (!(0, import_node_fs.existsSync)(filePath)) {
|
|
8127
|
+
await (0, import_promises.writeFile)(filePath, generated, "utf8");
|
|
8128
|
+
return;
|
|
8129
|
+
}
|
|
8130
|
+
const existing = await (0, import_promises.readFile)(filePath, "utf8");
|
|
8131
|
+
const existingEntries = new Set(existing.split(/\r?\n/).map((line) => line.trim()));
|
|
8132
|
+
const additions = generated.split(/\r?\n/).filter((line) => line.trim() && !existingEntries.has(line.trim()));
|
|
8133
|
+
if (additions.length === 0) {
|
|
8134
|
+
return;
|
|
8135
|
+
}
|
|
8136
|
+
const prefix = existing.endsWith("\n") ? existing : `${existing}
|
|
8137
|
+
`;
|
|
8138
|
+
await (0, import_promises.writeFile)(filePath, `${prefix}
|
|
8139
|
+
# Siglume generated ignores.
|
|
8140
|
+
${additions.join("\n")}
|
|
8141
|
+
`, "utf8");
|
|
8142
|
+
}
|
|
7831
8143
|
async function writeOperationTemplate(operation_key, destination, options = {}, deps = {}) {
|
|
7832
8144
|
const root = (0, import_node_path.resolve)(destination);
|
|
7833
8145
|
await (0, import_promises.mkdir)(root, { recursive: true });
|
|
@@ -7838,9 +8150,22 @@ async function writeOperationTemplate(operation_key, destination, options = {},
|
|
|
7838
8150
|
const manifest_path = (0, import_node_path.join)(root, "manifest.json");
|
|
7839
8151
|
const tool_manual_path = (0, import_node_path.join)(root, "tool_manual.json");
|
|
7840
8152
|
const runtime_validation_path = (0, import_node_path.join)(root, "runtime_validation.json");
|
|
8153
|
+
const gitignore_path = (0, import_node_path.join)(root, ".gitignore");
|
|
7841
8154
|
const readme_path = (0, import_node_path.join)(root, "README.md");
|
|
7842
8155
|
const test_path = (0, import_node_path.join)(testsDir, "test_adapter.ts");
|
|
7843
|
-
|
|
8156
|
+
const docs_dir = (0, import_node_path.join)(root, "docs");
|
|
8157
|
+
await (0, import_promises.mkdir)(docs_dir, { recursive: true });
|
|
8158
|
+
const docs_usage_path = (0, import_node_path.join)(docs_dir, "api-usage.md");
|
|
8159
|
+
for (const filePath of [
|
|
8160
|
+
adapter_path,
|
|
8161
|
+
stubs_path,
|
|
8162
|
+
manifest_path,
|
|
8163
|
+
tool_manual_path,
|
|
8164
|
+
runtime_validation_path,
|
|
8165
|
+
docs_usage_path,
|
|
8166
|
+
readme_path,
|
|
8167
|
+
test_path
|
|
8168
|
+
]) {
|
|
7844
8169
|
if ((0, import_node_fs.existsSync)(filePath)) {
|
|
7845
8170
|
throw new SiglumeProjectError(`${(0, import_node_path.basename)(filePath)} already exists in ${root}`);
|
|
7846
8171
|
}
|
|
@@ -7868,10 +8193,22 @@ async function writeOperationTemplate(operation_key, destination, options = {},
|
|
|
7868
8193
|
await (0, import_promises.writeFile)(manifest_path, renderJson(manifest), "utf8");
|
|
7869
8194
|
await (0, import_promises.writeFile)(tool_manual_path, renderJson(tool_manual), "utf8");
|
|
7870
8195
|
await (0, import_promises.writeFile)(runtime_validation_path, renderJson(buildRuntimeValidationTemplate(tool_manual)), "utf8");
|
|
8196
|
+
await (0, import_promises.writeFile)(docs_usage_path, apiUsageDocsTemplate(manifest), "utf8");
|
|
8197
|
+
await writeOrMergeGitignore(gitignore_path);
|
|
7871
8198
|
await (0, import_promises.writeFile)(readme_path, operationReadmeTemplate(operation, manifest, warning), "utf8");
|
|
7872
8199
|
await (0, import_promises.writeFile)(test_path, operationTestSource(operation), "utf8");
|
|
7873
8200
|
return {
|
|
7874
|
-
files: [
|
|
8201
|
+
files: [
|
|
8202
|
+
adapter_path,
|
|
8203
|
+
stubs_path,
|
|
8204
|
+
manifest_path,
|
|
8205
|
+
tool_manual_path,
|
|
8206
|
+
runtime_validation_path,
|
|
8207
|
+
docs_usage_path,
|
|
8208
|
+
gitignore_path,
|
|
8209
|
+
readme_path,
|
|
8210
|
+
test_path
|
|
8211
|
+
],
|
|
7875
8212
|
operation,
|
|
7876
8213
|
report: {
|
|
7877
8214
|
tool_manual_valid,
|
|
@@ -8020,6 +8357,15 @@ async function findRuntimeValidationPath(root_dir) {
|
|
|
8020
8357
|
}
|
|
8021
8358
|
return null;
|
|
8022
8359
|
}
|
|
8360
|
+
async function findOauthCredentialsPath(root_dir) {
|
|
8361
|
+
for (const name of ["oauth_credentials.json", "oauth-credentials.json"]) {
|
|
8362
|
+
const candidate = (0, import_node_path.join)(root_dir, name);
|
|
8363
|
+
if ((0, import_node_fs.existsSync)(candidate)) {
|
|
8364
|
+
return candidate;
|
|
8365
|
+
}
|
|
8366
|
+
}
|
|
8367
|
+
return null;
|
|
8368
|
+
}
|
|
8023
8369
|
async function loadJsonObject(path, label) {
|
|
8024
8370
|
let payload;
|
|
8025
8371
|
try {
|
|
@@ -8243,18 +8589,36 @@ function readmeTemplate(template) {
|
|
|
8243
8589
|
"- `adapter.ts`: your AppAdapter implementation",
|
|
8244
8590
|
"- `manifest.json`: serialized AppManifest snapshot",
|
|
8245
8591
|
"- `tool_manual.json`: editable ToolManual draft for validation and registration",
|
|
8246
|
-
"- `runtime_validation.json`: live API smoke-test contract used during registration",
|
|
8592
|
+
"- `runtime_validation.json`: local live API smoke-test contract used during registration",
|
|
8593
|
+
"- `docs/api-usage.md`: publish this page and use its public URL as `docs_url`",
|
|
8594
|
+
"- `.gitignore`: keeps runtime review keys and OAuth client secrets out of Git",
|
|
8247
8595
|
"",
|
|
8248
8596
|
"Before registering, replace all generated placeholders:",
|
|
8249
|
-
"- In `adapter.ts` and `manifest.json`, replace `docs_url`
|
|
8250
|
-
"-
|
|
8597
|
+
"- In `adapter.ts` and `manifest.json`, replace `docs_url` with a dedicated public API usage guide, not a homepage.",
|
|
8598
|
+
"- Replace `support_contact` with a real support email address or public support URL.",
|
|
8599
|
+
"- Optional `seller_homepage_url` is the seller's official site and can stay blank.",
|
|
8600
|
+
"- In the local `runtime_validation.json`, replace the public URL and review-key placeholders.",
|
|
8601
|
+
"- If the API uses seller-side OAuth, create a local `oauth_credentials.json` next to the adapter.",
|
|
8602
|
+
"- Do not commit real review keys or OAuth client secrets; the generated `.gitignore` excludes those files.",
|
|
8603
|
+
"- Because `runtime_validation.json` is ignored, GitHub samples do not commit review-key values.",
|
|
8251
8604
|
"",
|
|
8252
8605
|
"Suggested workflow:",
|
|
8253
8606
|
"",
|
|
8607
|
+
"Start locally without a Siglume API key:",
|
|
8608
|
+
"",
|
|
8254
8609
|
"```bash",
|
|
8255
|
-
"siglume validate .",
|
|
8256
8610
|
"siglume test .",
|
|
8611
|
+
"siglume score . --offline",
|
|
8612
|
+
"```",
|
|
8613
|
+
"",
|
|
8614
|
+
"After placeholders are replaced and `SIGLUME_API_KEY` is issued from Developer Portal -> CLI / API keys, run the server-aligned checks:",
|
|
8615
|
+
"",
|
|
8616
|
+
"```bash",
|
|
8617
|
+
"siglume validate .",
|
|
8257
8618
|
"siglume score . --remote",
|
|
8619
|
+
"siglume preflight .",
|
|
8620
|
+
"siglume register .",
|
|
8621
|
+
"# inspect the draft, then explicitly approve publish:",
|
|
8258
8622
|
"siglume register . --confirm",
|
|
8259
8623
|
"```",
|
|
8260
8624
|
""
|
|
@@ -8423,18 +8787,52 @@ async function runCli(argv, deps = {}) {
|
|
|
8423
8787
|
throw new SiglumeProjectError("Score failed.");
|
|
8424
8788
|
}
|
|
8425
8789
|
});
|
|
8426
|
-
program.command("
|
|
8790
|
+
program.command("preflight").option("--json", "emit machine-readable JSON", false).argument("[path]", ".", "project path").action(async (path, options) => {
|
|
8791
|
+
const report = await runPreflight(path, deps);
|
|
8792
|
+
if (options.json) {
|
|
8793
|
+
emit(stdout, renderJson(report));
|
|
8794
|
+
return;
|
|
8795
|
+
}
|
|
8796
|
+
emit(stdout, "Preflight passed.");
|
|
8797
|
+
const preflight = report.registration_preflight;
|
|
8798
|
+
if (preflight?.remote_quality) {
|
|
8799
|
+
emit(stdout, `preflight_quality: ${preflight.remote_quality.grade} (${preflight.remote_quality.overall_score}/100)`);
|
|
8800
|
+
}
|
|
8801
|
+
if (report.runtime_validation_path) emit(stdout, `runtime_validation_path: ${String(report.runtime_validation_path)}`);
|
|
8802
|
+
if (report.oauth_credentials_path) emit(stdout, `oauth_credentials_path: ${String(report.oauth_credentials_path)}`);
|
|
8803
|
+
});
|
|
8804
|
+
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) => {
|
|
8427
8805
|
const report = await runRegistration(path, { confirm: options.confirm, submit_review: options.submitReview }, deps);
|
|
8428
8806
|
if (options.json) {
|
|
8429
8807
|
emit(stdout, renderJson(report));
|
|
8430
8808
|
} else {
|
|
8431
8809
|
const receipt = report.receipt;
|
|
8432
|
-
|
|
8810
|
+
if (report.confirmation) {
|
|
8811
|
+
emit(stdout, "Listing published.");
|
|
8812
|
+
} else if (report.review) {
|
|
8813
|
+
emit(stdout, "Listing published via legacy submit-review alias.");
|
|
8814
|
+
} else if (receipt.registration_mode === "upgrade") {
|
|
8815
|
+
emit(stdout, "Upgrade staged.");
|
|
8816
|
+
} else if (receipt.registration_mode === "refresh") {
|
|
8817
|
+
emit(stdout, "Draft refreshed.");
|
|
8818
|
+
} else {
|
|
8819
|
+
emit(stdout, "Draft listing created.");
|
|
8820
|
+
}
|
|
8433
8821
|
emit(stdout, `listing_id: ${receipt.listing_id}`);
|
|
8434
|
-
emit(stdout, `
|
|
8822
|
+
emit(stdout, `receipt_status: ${receipt.status}`);
|
|
8823
|
+
if (receipt.listing_status) emit(stdout, `listing_status: ${receipt.listing_status}`);
|
|
8824
|
+
if (receipt.oauth_status) emit(stdout, `oauth_configured: ${Boolean(receipt.oauth_status.configured)}`);
|
|
8435
8825
|
if (receipt.review_url) emit(stdout, `review_url: ${receipt.review_url}`);
|
|
8436
8826
|
if (receipt.trace_id) emit(stdout, `trace_id: ${receipt.trace_id}`);
|
|
8437
8827
|
if (receipt.request_id) emit(stdout, `request_id: ${receipt.request_id}`);
|
|
8828
|
+
if (report.confirmation) {
|
|
8829
|
+
const confirmation = report.confirmation;
|
|
8830
|
+
if (confirmation.status) emit(stdout, `confirmation_status: ${confirmation.status}`);
|
|
8831
|
+
if (confirmation.release?.release_status) emit(stdout, `release_status: ${confirmation.release.release_status}`);
|
|
8832
|
+
} else if (report.review) {
|
|
8833
|
+
const review = report.review;
|
|
8834
|
+
if (review.status) emit(stdout, `publish_status: ${review.status}`);
|
|
8835
|
+
}
|
|
8438
8836
|
const preflight = report.registration_preflight;
|
|
8439
8837
|
if (preflight?.remote_quality) {
|
|
8440
8838
|
emit(stdout, `preflight_quality: ${preflight.remote_quality.grade} (${preflight.remote_quality.overall_score}/100)`);
|