@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.js
CHANGED
|
@@ -1330,6 +1330,9 @@ function parseListing(data) {
|
|
|
1330
1330
|
short_description: stringOrNull(data.short_description),
|
|
1331
1331
|
docs_url: stringOrNull(data.docs_url),
|
|
1332
1332
|
support_contact: stringOrNull(data.support_contact),
|
|
1333
|
+
seller_display_name: stringOrNull(data.seller_display_name),
|
|
1334
|
+
seller_homepage_url: stringOrNull(data.seller_homepage_url),
|
|
1335
|
+
seller_social_url: stringOrNull(data.seller_social_url),
|
|
1333
1336
|
review_status: stringOrNull(data.review_status),
|
|
1334
1337
|
review_note: stringOrNull(data.review_note),
|
|
1335
1338
|
submission_blockers: Array.isArray(data.submission_blockers) ? data.submission_blockers.filter((item) => typeof item === "string") : [],
|
|
@@ -2511,11 +2514,15 @@ var init_client = __esm({
|
|
|
2511
2514
|
max_retries;
|
|
2512
2515
|
fetchImpl;
|
|
2513
2516
|
pendingConfirmations = /* @__PURE__ */ new Map();
|
|
2514
|
-
constructor(options) {
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
+
constructor(options = {}) {
|
|
2518
|
+
const envApiKey = typeof process !== "undefined" ? process.env?.SIGLUME_API_KEY : void 0;
|
|
2519
|
+
const resolvedApiKey = (options.api_key ?? envApiKey ?? "").trim();
|
|
2520
|
+
if (!resolvedApiKey) {
|
|
2521
|
+
throw new SiglumeClientError(
|
|
2522
|
+
"SIGLUME_API_KEY is required. Pass it as the api_key option or set the SIGLUME_API_KEY env var."
|
|
2523
|
+
);
|
|
2517
2524
|
}
|
|
2518
|
-
this.api_key =
|
|
2525
|
+
this.api_key = resolvedApiKey;
|
|
2519
2526
|
this.agent_key = options.agent_key?.trim() || void 0;
|
|
2520
2527
|
this.base_url = (options.base_url ?? DEFAULT_SIGLUME_API_BASE).replace(/\/+$/, "");
|
|
2521
2528
|
this.timeout_ms = Math.max(1, options.timeout_ms ?? 15e3);
|
|
@@ -2542,6 +2549,13 @@ var init_client = __esm({
|
|
|
2542
2549
|
if (options.runtime_validation) {
|
|
2543
2550
|
payload.runtime_validation = coerceMapping(options.runtime_validation, "runtime_validation");
|
|
2544
2551
|
}
|
|
2552
|
+
if (options.oauth_credentials) {
|
|
2553
|
+
payload.oauth_credentials = Array.isArray(options.oauth_credentials) ? {
|
|
2554
|
+
items: options.oauth_credentials.map(
|
|
2555
|
+
(item, index) => coerceMapping(item, `oauth_credentials[${index}]`)
|
|
2556
|
+
)
|
|
2557
|
+
} : coerceMapping(options.oauth_credentials, "oauth_credentials");
|
|
2558
|
+
}
|
|
2545
2559
|
if (options.metadata) {
|
|
2546
2560
|
payload.metadata = coerceMapping(options.metadata, "metadata");
|
|
2547
2561
|
}
|
|
@@ -2560,6 +2574,8 @@ var init_client = __esm({
|
|
|
2560
2574
|
"docs_url",
|
|
2561
2575
|
"documentation_url",
|
|
2562
2576
|
"support_contact",
|
|
2577
|
+
"seller_homepage_url",
|
|
2578
|
+
"seller_social_url",
|
|
2563
2579
|
"jurisdiction",
|
|
2564
2580
|
"price_model",
|
|
2565
2581
|
"price_value_minor",
|
|
@@ -2575,10 +2591,14 @@ var init_client = __esm({
|
|
|
2575
2591
|
}
|
|
2576
2592
|
const docsUrl = String(manifestPayload.docs_url ?? manifestPayload.documentation_url ?? "").trim();
|
|
2577
2593
|
const supportContact = String(manifestPayload.support_contact ?? "").trim();
|
|
2578
|
-
|
|
2594
|
+
const sellerHomepageUrl = String(manifestPayload.seller_homepage_url ?? "").trim();
|
|
2595
|
+
const sellerSocialUrl = String(manifestPayload.seller_social_url ?? "").trim();
|
|
2596
|
+
if (docsUrl || supportContact || sellerHomepageUrl || sellerSocialUrl) {
|
|
2579
2597
|
const publisherIdentity = {
|
|
2580
2598
|
documentation_url: docsUrl || null,
|
|
2581
|
-
support_contact: supportContact || null
|
|
2599
|
+
support_contact: supportContact || null,
|
|
2600
|
+
seller_homepage_url: sellerHomepageUrl || null,
|
|
2601
|
+
seller_social_url: sellerSocialUrl || null
|
|
2582
2602
|
};
|
|
2583
2603
|
payload.publisher_identity = publisherIdentity;
|
|
2584
2604
|
payload.legal = { publisher_identity: publisherIdentity };
|
|
@@ -2592,36 +2612,30 @@ var init_client = __esm({
|
|
|
2592
2612
|
return {
|
|
2593
2613
|
listing_id,
|
|
2594
2614
|
status: String(data.status ?? "draft"),
|
|
2615
|
+
registration_mode: stringOrNull(data.registration_mode),
|
|
2616
|
+
listing_status: stringOrNull(data.listing_status),
|
|
2595
2617
|
auto_manifest: toRecord(data.auto_manifest),
|
|
2596
2618
|
confidence: toRecord(data.confidence),
|
|
2597
2619
|
validation_report: toRecord(data.validation_report),
|
|
2620
|
+
oauth_status: toRecord(data.oauth_status),
|
|
2598
2621
|
review_url: stringOrNull(data.review_url),
|
|
2599
2622
|
trace_id: meta.trace_id,
|
|
2600
2623
|
request_id: meta.request_id
|
|
2601
2624
|
};
|
|
2602
2625
|
}
|
|
2603
2626
|
async confirm_registration(listing_id, options = {}) {
|
|
2604
|
-
|
|
2605
|
-
const manifestPayload = options.manifest ? coerceMapping(options.manifest, "manifest") : pending?.manifest ?? {};
|
|
2606
|
-
const toolManualPayload = options.tool_manual ? coerceMapping(options.tool_manual, "tool_manual") : pending?.tool_manual ?? {};
|
|
2607
|
-
const overrides = {};
|
|
2608
|
-
for (const fieldName of ["name", "job_to_be_done"]) {
|
|
2609
|
-
if (manifestPayload[fieldName]) {
|
|
2610
|
-
overrides[fieldName] = manifestPayload[fieldName];
|
|
2611
|
-
}
|
|
2612
|
-
}
|
|
2613
|
-
if (Object.keys(toolManualPayload).length > 0) {
|
|
2614
|
-
overrides.tool_manual = toolManualPayload;
|
|
2615
|
-
}
|
|
2627
|
+
void options;
|
|
2616
2628
|
const payload = { approved: true };
|
|
2617
|
-
if (Object.keys(overrides).length > 0) {
|
|
2618
|
-
payload.overrides = overrides;
|
|
2619
|
-
}
|
|
2620
2629
|
const [data, meta] = await this.request("POST", `/market/capabilities/${listing_id}/confirm-auto-register`, { json_body: payload });
|
|
2621
2630
|
this.pendingConfirmations.delete(listing_id);
|
|
2631
|
+
const checklist = isRecord(data.checklist) ? Object.fromEntries(
|
|
2632
|
+
Object.entries(data.checklist).map(([key, value]) => [key, Boolean(value)])
|
|
2633
|
+
) : {};
|
|
2622
2634
|
return {
|
|
2623
2635
|
listing_id: String(data.listing_id ?? listing_id),
|
|
2624
2636
|
status: String(data.status ?? ""),
|
|
2637
|
+
message: stringOrNull(data.message),
|
|
2638
|
+
checklist,
|
|
2625
2639
|
release: toRecord(data.release),
|
|
2626
2640
|
quality: parseRegistrationQuality(toRecord(data.quality)),
|
|
2627
2641
|
trace_id: meta.trace_id,
|
|
@@ -4578,7 +4592,7 @@ ${details}` : summary;
|
|
|
4578
4592
|
const headers = new Headers({
|
|
4579
4593
|
Authorization: `Bearer ${this.api_key}`,
|
|
4580
4594
|
Accept: "application/json",
|
|
4581
|
-
"User-Agent": "siglume-api-sdk-ts/0.6
|
|
4595
|
+
"User-Agent": "siglume-api-sdk-ts/0.7.6"
|
|
4582
4596
|
});
|
|
4583
4597
|
if (options.headers) {
|
|
4584
4598
|
for (const [key, value] of Object.entries(options.headers)) {
|
|
@@ -4780,7 +4794,7 @@ var init_metering = __esm({
|
|
|
4780
4794
|
fetchImpl;
|
|
4781
4795
|
constructor(options) {
|
|
4782
4796
|
this.client = new SiglumeClient(options);
|
|
4783
|
-
this.api_key =
|
|
4797
|
+
this.api_key = this.client.api_key;
|
|
4784
4798
|
this.base_url = (options.base_url ?? DEFAULT_SIGLUME_API_BASE).replace(/\/+$/, "");
|
|
4785
4799
|
this.timeout_ms = Math.max(1, options.timeout_ms ?? 15e3);
|
|
4786
4800
|
this.max_retries = Math.max(1, Math.trunc(options.max_retries ?? 3));
|
|
@@ -4826,7 +4840,7 @@ var init_metering = __esm({
|
|
|
4826
4840
|
const headers = new Headers({
|
|
4827
4841
|
Authorization: `Bearer ${this.api_key}`,
|
|
4828
4842
|
Accept: "application/json",
|
|
4829
|
-
"User-Agent": "siglume-api-sdk-ts/0.6
|
|
4843
|
+
"User-Agent": "siglume-api-sdk-ts/0.7.6"
|
|
4830
4844
|
});
|
|
4831
4845
|
let body;
|
|
4832
4846
|
if (options.json_body) {
|
|
@@ -7141,6 +7155,15 @@ async function loadProject(path = ".") {
|
|
|
7141
7155
|
const tool_manual = tool_manual_path ? JSON.parse(await readFile(tool_manual_path, "utf8")) : buildToolManualTemplate(manifest);
|
|
7142
7156
|
const runtime_validation_path = await findRuntimeValidationPath(root_dir);
|
|
7143
7157
|
const runtime_validation = runtime_validation_path ? await loadJsonObject(runtime_validation_path, "runtime_validation") : void 0;
|
|
7158
|
+
const oauth_credentials_path = await findOauthCredentialsPath(root_dir);
|
|
7159
|
+
let oauth_credentials;
|
|
7160
|
+
if (oauth_credentials_path) {
|
|
7161
|
+
const parsed = JSON.parse(await readFile(oauth_credentials_path, "utf8"));
|
|
7162
|
+
if (!isRecord(parsed) && !Array.isArray(parsed)) {
|
|
7163
|
+
throw new SiglumeProjectError("oauth_credentials must be a JSON object or array");
|
|
7164
|
+
}
|
|
7165
|
+
oauth_credentials = parsed;
|
|
7166
|
+
}
|
|
7144
7167
|
return {
|
|
7145
7168
|
root_dir,
|
|
7146
7169
|
adapter_path,
|
|
@@ -7149,9 +7172,110 @@ async function loadProject(path = ".") {
|
|
|
7149
7172
|
tool_manual_path: tool_manual_path ?? void 0,
|
|
7150
7173
|
tool_manual,
|
|
7151
7174
|
runtime_validation_path: runtime_validation_path ?? void 0,
|
|
7152
|
-
runtime_validation
|
|
7175
|
+
runtime_validation,
|
|
7176
|
+
oauth_credentials_path: oauth_credentials_path ?? void 0,
|
|
7177
|
+
oauth_credentials
|
|
7153
7178
|
};
|
|
7154
7179
|
}
|
|
7180
|
+
var OAUTH_PROVIDER_ALIASES = {
|
|
7181
|
+
x: "twitter",
|
|
7182
|
+
"x-twitter": "twitter",
|
|
7183
|
+
twitter: "twitter",
|
|
7184
|
+
slack: "slack",
|
|
7185
|
+
google: "google",
|
|
7186
|
+
gmail: "google",
|
|
7187
|
+
"google-drive": "google",
|
|
7188
|
+
"google-calendar": "google",
|
|
7189
|
+
github: "github",
|
|
7190
|
+
linear: "linear",
|
|
7191
|
+
notion: "notion"
|
|
7192
|
+
};
|
|
7193
|
+
function oauthProviderKeyFromRequirement(value) {
|
|
7194
|
+
const raw = String(value ?? "").trim().toLowerCase().replaceAll("_", "-");
|
|
7195
|
+
if (!raw) return null;
|
|
7196
|
+
if (OAUTH_PROVIDER_ALIASES[raw]) {
|
|
7197
|
+
return OAUTH_PROVIDER_ALIASES[raw];
|
|
7198
|
+
}
|
|
7199
|
+
for (const token of raw.replaceAll("/", "-").replaceAll(":", "-").split("-")) {
|
|
7200
|
+
const next = token.trim();
|
|
7201
|
+
if (OAUTH_PROVIDER_ALIASES[next]) {
|
|
7202
|
+
return OAUTH_PROVIDER_ALIASES[next];
|
|
7203
|
+
}
|
|
7204
|
+
}
|
|
7205
|
+
return null;
|
|
7206
|
+
}
|
|
7207
|
+
function requiredOauthProviders(requirements) {
|
|
7208
|
+
const providers = [];
|
|
7209
|
+
for (const item of requirements ?? []) {
|
|
7210
|
+
const providerKey = oauthProviderKeyFromRequirement(item);
|
|
7211
|
+
if (providerKey && !providers.includes(providerKey)) {
|
|
7212
|
+
providers.push(providerKey);
|
|
7213
|
+
}
|
|
7214
|
+
}
|
|
7215
|
+
return providers;
|
|
7216
|
+
}
|
|
7217
|
+
function oauthProviderRecordsMap(payload) {
|
|
7218
|
+
if (!payload) {
|
|
7219
|
+
return {};
|
|
7220
|
+
}
|
|
7221
|
+
const items = Array.isArray(payload) ? payload : Array.isArray(payload.items) ? payload.items : [payload];
|
|
7222
|
+
const resolved = {};
|
|
7223
|
+
for (const [index, item] of items.entries()) {
|
|
7224
|
+
if (!isRecord(item)) {
|
|
7225
|
+
throw new SiglumeProjectError(`oauth_credentials[${index}] must be a JSON object.`);
|
|
7226
|
+
}
|
|
7227
|
+
const providerKey = oauthProviderKeyFromRequirement(item.provider_key ?? item.provider);
|
|
7228
|
+
if (!providerKey) {
|
|
7229
|
+
throw new SiglumeProjectError(`oauth_credentials[${index}].provider_key is unsupported.`);
|
|
7230
|
+
}
|
|
7231
|
+
const clientId = String(item.client_id ?? "").trim();
|
|
7232
|
+
const clientSecret = String(item.client_secret ?? "").trim();
|
|
7233
|
+
if (!clientId || !clientSecret) {
|
|
7234
|
+
throw new SiglumeProjectError(`oauth_credentials[${index}] must include client_id and client_secret.`);
|
|
7235
|
+
}
|
|
7236
|
+
const rawScopes = item.required_scopes ?? item.scopes;
|
|
7237
|
+
let scopes = [];
|
|
7238
|
+
if (rawScopes == null) {
|
|
7239
|
+
scopes = [];
|
|
7240
|
+
} else if (!Array.isArray(rawScopes)) {
|
|
7241
|
+
throw new SiglumeProjectError(`oauth_credentials[${index}].required_scopes must be a JSON array.`);
|
|
7242
|
+
} else {
|
|
7243
|
+
scopes = rawScopes.map((scope) => String(scope ?? "").trim()).filter(Boolean);
|
|
7244
|
+
}
|
|
7245
|
+
resolved[providerKey] = {
|
|
7246
|
+
provider_key: providerKey,
|
|
7247
|
+
client_id: clientId,
|
|
7248
|
+
client_secret: clientSecret,
|
|
7249
|
+
required_scopes: scopes
|
|
7250
|
+
};
|
|
7251
|
+
}
|
|
7252
|
+
return resolved;
|
|
7253
|
+
}
|
|
7254
|
+
function canonicalOauthCredentialsPayload(payload) {
|
|
7255
|
+
const records = oauthProviderRecordsMap(payload);
|
|
7256
|
+
const providerKeys = Object.keys(records).sort();
|
|
7257
|
+
if (providerKeys.length === 0) {
|
|
7258
|
+
return void 0;
|
|
7259
|
+
}
|
|
7260
|
+
return {
|
|
7261
|
+
items: providerKeys.map((providerKey) => records[providerKey])
|
|
7262
|
+
};
|
|
7263
|
+
}
|
|
7264
|
+
function ensureRequiredOauthCredentials(project) {
|
|
7265
|
+
const requiredProviders = requiredOauthProviders(project.manifest.required_connected_accounts ?? []);
|
|
7266
|
+
if (requiredProviders.length === 0) {
|
|
7267
|
+
return;
|
|
7268
|
+
}
|
|
7269
|
+
const provided = new Set(Object.keys(oauthProviderRecordsMap(project.oauth_credentials)));
|
|
7270
|
+
const missing = requiredProviders.filter((provider) => !provided.has(provider));
|
|
7271
|
+
if (missing.length === 0) {
|
|
7272
|
+
return;
|
|
7273
|
+
}
|
|
7274
|
+
const path = project.oauth_credentials_path ?? join(project.root_dir, "oauth_credentials.json");
|
|
7275
|
+
throw new SiglumeProjectError(
|
|
7276
|
+
`${path} is required for OAuth-backed APIs. Missing provider seeds: ${missing.join(", ")}`
|
|
7277
|
+
);
|
|
7278
|
+
}
|
|
7155
7279
|
async function validateProject(path = ".", deps = {}) {
|
|
7156
7280
|
const project = await loadProject(path);
|
|
7157
7281
|
const manifest_issues = await projectValidationIssues(project);
|
|
@@ -7188,17 +7312,31 @@ function ensureManifestPublisherIdentity(project) {
|
|
|
7188
7312
|
const manifestPayload = project.manifest;
|
|
7189
7313
|
const docsUrl = String(manifestPayload.docs_url ?? manifestPayload.documentation_url ?? "").trim();
|
|
7190
7314
|
const supportContact = String(manifestPayload.support_contact ?? "").trim();
|
|
7315
|
+
const sellerHomepageUrl = String(manifestPayload.seller_homepage_url ?? "").trim();
|
|
7316
|
+
const sellerSocialUrl = String(manifestPayload.seller_social_url ?? "").trim();
|
|
7191
7317
|
const jurisdiction = String(manifestPayload.jurisdiction ?? "").trim();
|
|
7192
7318
|
const issues = [];
|
|
7193
7319
|
if (!docsUrl) {
|
|
7194
7320
|
issues.push("manifest.docs_url is required");
|
|
7195
7321
|
} else if (looksLikePlaceholder(docsUrl)) {
|
|
7196
7322
|
issues.push("manifest.docs_url must be replaced with your public documentation URL");
|
|
7323
|
+
} else if (!looksLikeHttpUrl(docsUrl)) {
|
|
7324
|
+
issues.push("manifest.docs_url must be an http(s) URL");
|
|
7325
|
+
} else if (looksLikeRootUrl(docsUrl)) {
|
|
7326
|
+
issues.push("manifest.docs_url must be a dedicated API usage page, not a root homepage URL");
|
|
7197
7327
|
}
|
|
7198
7328
|
if (!supportContact) {
|
|
7199
7329
|
issues.push("manifest.support_contact is required");
|
|
7200
7330
|
} else if (looksLikePlaceholder(supportContact)) {
|
|
7201
7331
|
issues.push("manifest.support_contact must be replaced with your real support email or support URL");
|
|
7332
|
+
} else if (!looksLikeEmail(supportContact) && !looksLikeHttpUrl(supportContact)) {
|
|
7333
|
+
issues.push("manifest.support_contact must be a real email address or http(s) support URL");
|
|
7334
|
+
}
|
|
7335
|
+
if (sellerHomepageUrl && (looksLikePlaceholder(sellerHomepageUrl) || !looksLikeHttpUrl(sellerHomepageUrl))) {
|
|
7336
|
+
issues.push("manifest.seller_homepage_url must be a real http(s) official homepage URL when provided");
|
|
7337
|
+
}
|
|
7338
|
+
if (sellerSocialUrl && (looksLikePlaceholder(sellerSocialUrl) || !looksLikeHttpUrl(sellerSocialUrl))) {
|
|
7339
|
+
issues.push("manifest.seller_social_url must be a real http(s) official social/profile URL when provided");
|
|
7202
7340
|
}
|
|
7203
7341
|
if (!jurisdiction) issues.push("manifest.jurisdiction is required");
|
|
7204
7342
|
if (issues.length > 0) {
|
|
@@ -7210,7 +7348,25 @@ ${issues.map((issue2) => `- ${issue2}`).join("\n")}`
|
|
|
7210
7348
|
}
|
|
7211
7349
|
function looksLikePlaceholder(value) {
|
|
7212
7350
|
const normalized = value.trim().toLowerCase();
|
|
7213
|
-
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");
|
|
7351
|
+
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");
|
|
7352
|
+
}
|
|
7353
|
+
function looksLikeHttpUrl(value) {
|
|
7354
|
+
try {
|
|
7355
|
+
const parsed = new URL(value.trim());
|
|
7356
|
+
return parsed.protocol === "http:" || parsed.protocol === "https:";
|
|
7357
|
+
} catch {
|
|
7358
|
+
return false;
|
|
7359
|
+
}
|
|
7360
|
+
}
|
|
7361
|
+
function looksLikeRootUrl(value) {
|
|
7362
|
+
if (!looksLikeHttpUrl(value)) return false;
|
|
7363
|
+
const parsed = new URL(value.trim());
|
|
7364
|
+
return parsed.pathname.replace(/^\/+|\/+$/g, "") === "";
|
|
7365
|
+
}
|
|
7366
|
+
function looksLikeEmail(value) {
|
|
7367
|
+
const normalized = value.trim();
|
|
7368
|
+
const domain = normalized.split("@").at(-1) ?? "";
|
|
7369
|
+
return normalized.includes("@") && !normalized.includes(" ") && domain.includes(".") && !normalized.startsWith("@");
|
|
7214
7370
|
}
|
|
7215
7371
|
function runtimePlaceholderIssues(runtimeValidation) {
|
|
7216
7372
|
const issues = [];
|
|
@@ -7270,6 +7426,9 @@ async function registrationPreflight(project, client) {
|
|
|
7270
7426
|
const manifestIssues = await projectValidationIssues(project);
|
|
7271
7427
|
const [toolManualValid, toolManualIssues] = validate_tool_manual(project.tool_manual);
|
|
7272
7428
|
const remoteQuality = await client.preview_quality_score(project.tool_manual);
|
|
7429
|
+
const requiredOauthProvidersList = requiredOauthProviders(project.manifest.required_connected_accounts ?? []);
|
|
7430
|
+
const oauthProviderRecords = oauthProviderRecordsMap(project.oauth_credentials);
|
|
7431
|
+
const missingOauthProviders = requiredOauthProvidersList.filter((provider) => !oauthProviderRecords[provider]);
|
|
7273
7432
|
const blockingToolManualIssues = toolManualIssues.filter((issue2) => issue2.severity === "error");
|
|
7274
7433
|
const errors = [
|
|
7275
7434
|
...manifestIssues.map((issue2) => String(issue2)),
|
|
@@ -7281,11 +7440,17 @@ async function registrationPreflight(project, client) {
|
|
|
7281
7440
|
if (!remoteQualityOk(remoteQuality)) {
|
|
7282
7441
|
errors.push(`remote Tool Manual quality is not publishable: ${remoteQuality.grade} (${remoteQuality.overall_score}/100)`);
|
|
7283
7442
|
}
|
|
7443
|
+
if (missingOauthProviders.length > 0) {
|
|
7444
|
+
errors.push(`oauth_credentials.json is required for OAuth-backed APIs: ${missingOauthProviders.join(", ")}`);
|
|
7445
|
+
}
|
|
7284
7446
|
const preflight = {
|
|
7285
7447
|
manifest_issues: manifestIssues,
|
|
7286
7448
|
tool_manual_valid: toolManualValid,
|
|
7287
7449
|
tool_manual_issues: toolManualIssues.map((issue2) => toJsonable(issue2)),
|
|
7288
7450
|
remote_quality: toJsonable(remoteQuality),
|
|
7451
|
+
required_oauth_providers: requiredOauthProvidersList,
|
|
7452
|
+
oauth_credentials_path: project.oauth_credentials_path ?? null,
|
|
7453
|
+
oauth_missing_providers: missingOauthProviders,
|
|
7289
7454
|
ok: errors.length === 0
|
|
7290
7455
|
};
|
|
7291
7456
|
if (errors.length > 0) {
|
|
@@ -7301,6 +7466,7 @@ async function runRegistration(path = ".", options = {}, deps = {}) {
|
|
|
7301
7466
|
ensureExplicitToolManual(project);
|
|
7302
7467
|
ensureManifestPublisherIdentity(project);
|
|
7303
7468
|
ensureRuntimeValidationReady(project);
|
|
7469
|
+
ensureRequiredOauthCredentials(project);
|
|
7304
7470
|
const client = await createClient(deps);
|
|
7305
7471
|
const preflight = await registrationPreflight(project, client);
|
|
7306
7472
|
let developerPortalPreflight = null;
|
|
@@ -7309,18 +7475,20 @@ async function runRegistration(path = ".", options = {}, deps = {}) {
|
|
|
7309
7475
|
const verifiedDestination = portal.payout_readiness?.verified_destination;
|
|
7310
7476
|
if (verifiedDestination !== true) {
|
|
7311
7477
|
throw new SiglumeProjectError(
|
|
7312
|
-
"Paid API registration requires a verified Polygon payout destination. Open https://siglume.com/owner/
|
|
7478
|
+
"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."
|
|
7313
7479
|
);
|
|
7314
7480
|
}
|
|
7315
7481
|
developerPortalPreflight = toJsonable(portal);
|
|
7316
7482
|
}
|
|
7317
7483
|
const receipt = await client.auto_register(project.manifest, project.tool_manual, {
|
|
7318
|
-
runtime_validation: project.runtime_validation
|
|
7484
|
+
runtime_validation: project.runtime_validation,
|
|
7485
|
+
oauth_credentials: canonicalOauthCredentialsPayload(project.oauth_credentials)
|
|
7319
7486
|
});
|
|
7320
7487
|
const result = {
|
|
7321
7488
|
receipt: toJsonable(receipt),
|
|
7322
7489
|
registration_preflight: preflight,
|
|
7323
|
-
runtime_validation_path: project.runtime_validation_path ?? null
|
|
7490
|
+
runtime_validation_path: project.runtime_validation_path ?? null,
|
|
7491
|
+
oauth_credentials_path: project.oauth_credentials_path ?? null
|
|
7324
7492
|
};
|
|
7325
7493
|
if (developerPortalPreflight) {
|
|
7326
7494
|
result.developer_portal_preflight = developerPortalPreflight;
|
|
@@ -7335,6 +7503,37 @@ async function runRegistration(path = ".", options = {}, deps = {}) {
|
|
|
7335
7503
|
}
|
|
7336
7504
|
return result;
|
|
7337
7505
|
}
|
|
7506
|
+
async function runPreflight(path = ".", deps = {}) {
|
|
7507
|
+
const project = await loadProject(path);
|
|
7508
|
+
ensureExplicitToolManual(project);
|
|
7509
|
+
ensureManifestPublisherIdentity(project);
|
|
7510
|
+
ensureRuntimeValidationReady(project);
|
|
7511
|
+
ensureRequiredOauthCredentials(project);
|
|
7512
|
+
const client = await createClient(deps);
|
|
7513
|
+
const preflight = await registrationPreflight(project, client);
|
|
7514
|
+
let developerPortalPreflight = null;
|
|
7515
|
+
if (String(project.manifest.price_model ?? "free").toLowerCase() !== "free") {
|
|
7516
|
+
const portal = await client.get_developer_portal();
|
|
7517
|
+
const verifiedDestination = portal.payout_readiness?.verified_destination;
|
|
7518
|
+
if (verifiedDestination !== true) {
|
|
7519
|
+
throw new SiglumeProjectError(
|
|
7520
|
+
"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."
|
|
7521
|
+
);
|
|
7522
|
+
}
|
|
7523
|
+
developerPortalPreflight = toJsonable(portal);
|
|
7524
|
+
}
|
|
7525
|
+
const result = {
|
|
7526
|
+
ok: true,
|
|
7527
|
+
adapter_path: project.adapter_path,
|
|
7528
|
+
registration_preflight: preflight,
|
|
7529
|
+
runtime_validation_path: project.runtime_validation_path ?? null,
|
|
7530
|
+
oauth_credentials_path: project.oauth_credentials_path ?? null
|
|
7531
|
+
};
|
|
7532
|
+
if (developerPortalPreflight) {
|
|
7533
|
+
result.developer_portal_preflight = developerPortalPreflight;
|
|
7534
|
+
}
|
|
7535
|
+
return result;
|
|
7536
|
+
}
|
|
7338
7537
|
async function createSupportCaseReport(options, deps = {}) {
|
|
7339
7538
|
const client = await createClient(deps);
|
|
7340
7539
|
const supportCase = await client.create_support_case(options.subject, options.body, { trace_id: options.trace_id });
|
|
@@ -7381,8 +7580,12 @@ async function writeInitTemplate(template, destination) {
|
|
|
7381
7580
|
const manifest_path = join(root, "manifest.json");
|
|
7382
7581
|
const tool_manual_path = join(root, "tool_manual.json");
|
|
7383
7582
|
const runtime_validation_path = join(root, "runtime_validation.json");
|
|
7583
|
+
const gitignore_path = join(root, ".gitignore");
|
|
7384
7584
|
const readme_path = join(root, "README.md");
|
|
7385
|
-
|
|
7585
|
+
const docs_dir = join(root, "docs");
|
|
7586
|
+
await mkdir(docs_dir, { recursive: true });
|
|
7587
|
+
const docs_usage_path = join(docs_dir, "api-usage.md");
|
|
7588
|
+
for (const filePath of [adapter_path, manifest_path, tool_manual_path, runtime_validation_path, docs_usage_path, readme_path]) {
|
|
7386
7589
|
if (existsSync(filePath)) {
|
|
7387
7590
|
throw new SiglumeProjectError(`${basename(filePath)} already exists in ${root}`);
|
|
7388
7591
|
}
|
|
@@ -7393,8 +7596,10 @@ async function writeInitTemplate(template, destination) {
|
|
|
7393
7596
|
await writeFile(manifest_path, renderJson(manifest), "utf8");
|
|
7394
7597
|
await writeFile(tool_manual_path, renderJson(toolManual), "utf8");
|
|
7395
7598
|
await writeFile(runtime_validation_path, renderJson(buildRuntimeValidationTemplate(toolManual)), "utf8");
|
|
7599
|
+
await writeFile(docs_usage_path, apiUsageDocsTemplate(manifest), "utf8");
|
|
7600
|
+
await writeOrMergeGitignore(gitignore_path);
|
|
7396
7601
|
await writeFile(readme_path, readmeTemplate(template), "utf8");
|
|
7397
|
-
return [adapter_path, manifest_path, tool_manual_path, runtime_validation_path, readme_path];
|
|
7602
|
+
return [adapter_path, manifest_path, tool_manual_path, runtime_validation_path, docs_usage_path, gitignore_path, readme_path];
|
|
7398
7603
|
}
|
|
7399
7604
|
async function listOperationCatalog(options = {}, deps = {}) {
|
|
7400
7605
|
const resolvedAgentId = String(options.agent_id ?? "").trim();
|
|
@@ -7788,25 +7993,132 @@ function operationReadmeTemplate(operation, manifest, warning) {
|
|
|
7788
7993
|
"- `stubs.ts`: mock fallback used when `SIGLUME_API_KEY` is not set",
|
|
7789
7994
|
"- `manifest.json`: reviewable manifest snapshot",
|
|
7790
7995
|
"- `tool_manual.json`: machine-generated ToolManual scaffold",
|
|
7791
|
-
"- `runtime_validation.json`: public endpoint and review-key checks used by auto-register",
|
|
7996
|
+
"- `runtime_validation.json`: local public endpoint and review-key checks used by auto-register",
|
|
7997
|
+
"- `docs/api-usage.md`: publishable API usage guide template for `docs_url`",
|
|
7998
|
+
"- `.gitignore`: keeps runtime review keys and OAuth client secrets out of Git",
|
|
7792
7999
|
"- `tests/test_adapter.ts`: smoke test for `AppTestHarness`",
|
|
7793
8000
|
"",
|
|
7794
8001
|
"Before registering, replace all generated placeholders:",
|
|
7795
|
-
"- In `adapter.ts` and `manifest.json`, replace `docs_url`
|
|
7796
|
-
"-
|
|
8002
|
+
"- In `adapter.ts` and `manifest.json`, replace `docs_url` with a dedicated public API usage guide, not a homepage.",
|
|
8003
|
+
"- Replace `support_contact` with a real support email address or public support URL.",
|
|
8004
|
+
"- Optional `seller_homepage_url` is the seller's official site and can stay blank.",
|
|
8005
|
+
"- In the local `runtime_validation.json`, replace the public URL and review-key placeholders.",
|
|
8006
|
+
"- If the API uses seller-side OAuth, create a local `oauth_credentials.json` next to the adapter.",
|
|
8007
|
+
"- Do not commit real review keys or OAuth client secrets; the generated `.gitignore` excludes those files.",
|
|
8008
|
+
"- Because `runtime_validation.json` is ignored, GitHub samples do not commit review-key values.",
|
|
7797
8009
|
"",
|
|
7798
8010
|
"## Commands",
|
|
7799
8011
|
"",
|
|
8012
|
+
"Start locally without a Siglume API key:",
|
|
8013
|
+
"",
|
|
7800
8014
|
"```bash",
|
|
7801
|
-
"siglume validate .",
|
|
7802
8015
|
"siglume test .",
|
|
7803
8016
|
"npm test -- tests/test_adapter.ts",
|
|
8017
|
+
"siglume score . --offline",
|
|
8018
|
+
"```",
|
|
8019
|
+
"",
|
|
8020
|
+
"After placeholders are replaced and `SIGLUME_API_KEY` is issued from Developer Portal -> CLI / API keys, run the server-aligned checks:",
|
|
8021
|
+
"",
|
|
8022
|
+
"```bash",
|
|
8023
|
+
"siglume validate .",
|
|
7804
8024
|
"siglume score . --remote",
|
|
8025
|
+
"siglume preflight .",
|
|
8026
|
+
"siglume register .",
|
|
8027
|
+
"# inspect the draft, then explicitly approve publish:",
|
|
7805
8028
|
"siglume register . --confirm",
|
|
7806
8029
|
"```",
|
|
7807
8030
|
""
|
|
7808
8031
|
].join("\n");
|
|
7809
8032
|
}
|
|
8033
|
+
function apiUsageDocsTemplate(manifest) {
|
|
8034
|
+
const name = String(manifest.name ?? manifest.capability_key ?? "Siglume API");
|
|
8035
|
+
const capabilityKey = String(manifest.capability_key ?? "replace-with-capability-key");
|
|
8036
|
+
const jobToBeDone = String(manifest.job_to_be_done ?? "Describe what this API lets an agent do.");
|
|
8037
|
+
const permissionClass = String(manifest.permission_class ?? "read-only");
|
|
8038
|
+
const priceModel = String(manifest.price_model ?? "free");
|
|
8039
|
+
const requiredAccounts = (manifest.required_connected_accounts ?? []).join(", ") || "none";
|
|
8040
|
+
const supportContact = String(manifest.support_contact ?? "replace-with-support-contact");
|
|
8041
|
+
return [
|
|
8042
|
+
`# ${name} API Usage Guide`,
|
|
8043
|
+
"",
|
|
8044
|
+
`This page is the dedicated public usage guide for the Siglume API listing \`${capabilityKey}\`.`,
|
|
8045
|
+
"Publish this page at an anonymous HTTP 200 URL and use that URL as `docs_url`.",
|
|
8046
|
+
"",
|
|
8047
|
+
"Do not use your company homepage as `docs_url`; keep seller/company homepages in `seller_homepage_url`.",
|
|
8048
|
+
"",
|
|
8049
|
+
"## What This API Does",
|
|
8050
|
+
"",
|
|
8051
|
+
jobToBeDone,
|
|
8052
|
+
"",
|
|
8053
|
+
"## Permission Model",
|
|
8054
|
+
"",
|
|
8055
|
+
`- Permission class: \`${permissionClass}\``,
|
|
8056
|
+
`- Price model: \`${priceModel}\``,
|
|
8057
|
+
`- Required connected accounts: \`${requiredAccounts}\``,
|
|
8058
|
+
"",
|
|
8059
|
+
"## Inputs",
|
|
8060
|
+
"",
|
|
8061
|
+
"Describe the request fields your API accepts. Keep this aligned with `tool_manual.json` and `runtime_validation.json`.",
|
|
8062
|
+
"",
|
|
8063
|
+
"## Outputs",
|
|
8064
|
+
"",
|
|
8065
|
+
"Describe the response fields your API returns. Include the fields in `runtime_validation.expected_response_fields`.",
|
|
8066
|
+
"",
|
|
8067
|
+
"## Errors And Support",
|
|
8068
|
+
"",
|
|
8069
|
+
"Explain common error messages and how an owner should recover.",
|
|
8070
|
+
"",
|
|
8071
|
+
`Support contact: ${supportContact}`,
|
|
8072
|
+
""
|
|
8073
|
+
].join("\n");
|
|
8074
|
+
}
|
|
8075
|
+
function generatedGitignore() {
|
|
8076
|
+
return [
|
|
8077
|
+
"# Local secrets and registration-only runtime checks.",
|
|
8078
|
+
".env",
|
|
8079
|
+
".env.*",
|
|
8080
|
+
"!.env.example",
|
|
8081
|
+
"runtime_validation.json",
|
|
8082
|
+
"runtime-validation.json",
|
|
8083
|
+
"oauth_credentials.json",
|
|
8084
|
+
"oauth-credentials.json",
|
|
8085
|
+
"",
|
|
8086
|
+
"# Python / test artifacts.",
|
|
8087
|
+
"__pycache__/",
|
|
8088
|
+
"*.py[cod]",
|
|
8089
|
+
".pytest_cache/",
|
|
8090
|
+
".mypy_cache/",
|
|
8091
|
+
".coverage",
|
|
8092
|
+
"htmlcov/",
|
|
8093
|
+
"dist/",
|
|
8094
|
+
"build/",
|
|
8095
|
+
"*.egg-info/",
|
|
8096
|
+
"",
|
|
8097
|
+
"# JavaScript tooling if this project also uses TypeScript helpers.",
|
|
8098
|
+
"node_modules/",
|
|
8099
|
+
"coverage/",
|
|
8100
|
+
""
|
|
8101
|
+
].join("\n");
|
|
8102
|
+
}
|
|
8103
|
+
async function writeOrMergeGitignore(filePath) {
|
|
8104
|
+
const generated = generatedGitignore();
|
|
8105
|
+
if (!existsSync(filePath)) {
|
|
8106
|
+
await writeFile(filePath, generated, "utf8");
|
|
8107
|
+
return;
|
|
8108
|
+
}
|
|
8109
|
+
const existing = await readFile(filePath, "utf8");
|
|
8110
|
+
const existingEntries = new Set(existing.split(/\r?\n/).map((line) => line.trim()));
|
|
8111
|
+
const additions = generated.split(/\r?\n/).filter((line) => line.trim() && !existingEntries.has(line.trim()));
|
|
8112
|
+
if (additions.length === 0) {
|
|
8113
|
+
return;
|
|
8114
|
+
}
|
|
8115
|
+
const prefix = existing.endsWith("\n") ? existing : `${existing}
|
|
8116
|
+
`;
|
|
8117
|
+
await writeFile(filePath, `${prefix}
|
|
8118
|
+
# Siglume generated ignores.
|
|
8119
|
+
${additions.join("\n")}
|
|
8120
|
+
`, "utf8");
|
|
8121
|
+
}
|
|
7810
8122
|
async function writeOperationTemplate(operation_key, destination, options = {}, deps = {}) {
|
|
7811
8123
|
const root = resolve(destination);
|
|
7812
8124
|
await mkdir(root, { recursive: true });
|
|
@@ -7817,9 +8129,22 @@ async function writeOperationTemplate(operation_key, destination, options = {},
|
|
|
7817
8129
|
const manifest_path = join(root, "manifest.json");
|
|
7818
8130
|
const tool_manual_path = join(root, "tool_manual.json");
|
|
7819
8131
|
const runtime_validation_path = join(root, "runtime_validation.json");
|
|
8132
|
+
const gitignore_path = join(root, ".gitignore");
|
|
7820
8133
|
const readme_path = join(root, "README.md");
|
|
7821
8134
|
const test_path = join(testsDir, "test_adapter.ts");
|
|
7822
|
-
|
|
8135
|
+
const docs_dir = join(root, "docs");
|
|
8136
|
+
await mkdir(docs_dir, { recursive: true });
|
|
8137
|
+
const docs_usage_path = join(docs_dir, "api-usage.md");
|
|
8138
|
+
for (const filePath of [
|
|
8139
|
+
adapter_path,
|
|
8140
|
+
stubs_path,
|
|
8141
|
+
manifest_path,
|
|
8142
|
+
tool_manual_path,
|
|
8143
|
+
runtime_validation_path,
|
|
8144
|
+
docs_usage_path,
|
|
8145
|
+
readme_path,
|
|
8146
|
+
test_path
|
|
8147
|
+
]) {
|
|
7823
8148
|
if (existsSync(filePath)) {
|
|
7824
8149
|
throw new SiglumeProjectError(`${basename(filePath)} already exists in ${root}`);
|
|
7825
8150
|
}
|
|
@@ -7847,10 +8172,22 @@ async function writeOperationTemplate(operation_key, destination, options = {},
|
|
|
7847
8172
|
await writeFile(manifest_path, renderJson(manifest), "utf8");
|
|
7848
8173
|
await writeFile(tool_manual_path, renderJson(tool_manual), "utf8");
|
|
7849
8174
|
await writeFile(runtime_validation_path, renderJson(buildRuntimeValidationTemplate(tool_manual)), "utf8");
|
|
8175
|
+
await writeFile(docs_usage_path, apiUsageDocsTemplate(manifest), "utf8");
|
|
8176
|
+
await writeOrMergeGitignore(gitignore_path);
|
|
7850
8177
|
await writeFile(readme_path, operationReadmeTemplate(operation, manifest, warning), "utf8");
|
|
7851
8178
|
await writeFile(test_path, operationTestSource(operation), "utf8");
|
|
7852
8179
|
return {
|
|
7853
|
-
files: [
|
|
8180
|
+
files: [
|
|
8181
|
+
adapter_path,
|
|
8182
|
+
stubs_path,
|
|
8183
|
+
manifest_path,
|
|
8184
|
+
tool_manual_path,
|
|
8185
|
+
runtime_validation_path,
|
|
8186
|
+
docs_usage_path,
|
|
8187
|
+
gitignore_path,
|
|
8188
|
+
readme_path,
|
|
8189
|
+
test_path
|
|
8190
|
+
],
|
|
7854
8191
|
operation,
|
|
7855
8192
|
report: {
|
|
7856
8193
|
tool_manual_valid,
|
|
@@ -7999,6 +8336,15 @@ async function findRuntimeValidationPath(root_dir) {
|
|
|
7999
8336
|
}
|
|
8000
8337
|
return null;
|
|
8001
8338
|
}
|
|
8339
|
+
async function findOauthCredentialsPath(root_dir) {
|
|
8340
|
+
for (const name of ["oauth_credentials.json", "oauth-credentials.json"]) {
|
|
8341
|
+
const candidate = join(root_dir, name);
|
|
8342
|
+
if (existsSync(candidate)) {
|
|
8343
|
+
return candidate;
|
|
8344
|
+
}
|
|
8345
|
+
}
|
|
8346
|
+
return null;
|
|
8347
|
+
}
|
|
8002
8348
|
async function loadJsonObject(path, label) {
|
|
8003
8349
|
let payload;
|
|
8004
8350
|
try {
|
|
@@ -8222,18 +8568,36 @@ function readmeTemplate(template) {
|
|
|
8222
8568
|
"- `adapter.ts`: your AppAdapter implementation",
|
|
8223
8569
|
"- `manifest.json`: serialized AppManifest snapshot",
|
|
8224
8570
|
"- `tool_manual.json`: editable ToolManual draft for validation and registration",
|
|
8225
|
-
"- `runtime_validation.json`: live API smoke-test contract used during registration",
|
|
8571
|
+
"- `runtime_validation.json`: local live API smoke-test contract used during registration",
|
|
8572
|
+
"- `docs/api-usage.md`: publish this page and use its public URL as `docs_url`",
|
|
8573
|
+
"- `.gitignore`: keeps runtime review keys and OAuth client secrets out of Git",
|
|
8226
8574
|
"",
|
|
8227
8575
|
"Before registering, replace all generated placeholders:",
|
|
8228
|
-
"- In `adapter.ts` and `manifest.json`, replace `docs_url`
|
|
8229
|
-
"-
|
|
8576
|
+
"- In `adapter.ts` and `manifest.json`, replace `docs_url` with a dedicated public API usage guide, not a homepage.",
|
|
8577
|
+
"- Replace `support_contact` with a real support email address or public support URL.",
|
|
8578
|
+
"- Optional `seller_homepage_url` is the seller's official site and can stay blank.",
|
|
8579
|
+
"- In the local `runtime_validation.json`, replace the public URL and review-key placeholders.",
|
|
8580
|
+
"- If the API uses seller-side OAuth, create a local `oauth_credentials.json` next to the adapter.",
|
|
8581
|
+
"- Do not commit real review keys or OAuth client secrets; the generated `.gitignore` excludes those files.",
|
|
8582
|
+
"- Because `runtime_validation.json` is ignored, GitHub samples do not commit review-key values.",
|
|
8230
8583
|
"",
|
|
8231
8584
|
"Suggested workflow:",
|
|
8232
8585
|
"",
|
|
8586
|
+
"Start locally without a Siglume API key:",
|
|
8587
|
+
"",
|
|
8233
8588
|
"```bash",
|
|
8234
|
-
"siglume validate .",
|
|
8235
8589
|
"siglume test .",
|
|
8590
|
+
"siglume score . --offline",
|
|
8591
|
+
"```",
|
|
8592
|
+
"",
|
|
8593
|
+
"After placeholders are replaced and `SIGLUME_API_KEY` is issued from Developer Portal -> CLI / API keys, run the server-aligned checks:",
|
|
8594
|
+
"",
|
|
8595
|
+
"```bash",
|
|
8596
|
+
"siglume validate .",
|
|
8236
8597
|
"siglume score . --remote",
|
|
8598
|
+
"siglume preflight .",
|
|
8599
|
+
"siglume register .",
|
|
8600
|
+
"# inspect the draft, then explicitly approve publish:",
|
|
8237
8601
|
"siglume register . --confirm",
|
|
8238
8602
|
"```",
|
|
8239
8603
|
""
|
|
@@ -8402,18 +8766,52 @@ async function runCli(argv, deps = {}) {
|
|
|
8402
8766
|
throw new SiglumeProjectError("Score failed.");
|
|
8403
8767
|
}
|
|
8404
8768
|
});
|
|
8405
|
-
program.command("
|
|
8769
|
+
program.command("preflight").option("--json", "emit machine-readable JSON", false).argument("[path]", ".", "project path").action(async (path, options) => {
|
|
8770
|
+
const report = await runPreflight(path, deps);
|
|
8771
|
+
if (options.json) {
|
|
8772
|
+
emit(stdout, renderJson(report));
|
|
8773
|
+
return;
|
|
8774
|
+
}
|
|
8775
|
+
emit(stdout, "Preflight passed.");
|
|
8776
|
+
const preflight = report.registration_preflight;
|
|
8777
|
+
if (preflight?.remote_quality) {
|
|
8778
|
+
emit(stdout, `preflight_quality: ${preflight.remote_quality.grade} (${preflight.remote_quality.overall_score}/100)`);
|
|
8779
|
+
}
|
|
8780
|
+
if (report.runtime_validation_path) emit(stdout, `runtime_validation_path: ${String(report.runtime_validation_path)}`);
|
|
8781
|
+
if (report.oauth_credentials_path) emit(stdout, `oauth_credentials_path: ${String(report.oauth_credentials_path)}`);
|
|
8782
|
+
});
|
|
8783
|
+
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) => {
|
|
8406
8784
|
const report = await runRegistration(path, { confirm: options.confirm, submit_review: options.submitReview }, deps);
|
|
8407
8785
|
if (options.json) {
|
|
8408
8786
|
emit(stdout, renderJson(report));
|
|
8409
8787
|
} else {
|
|
8410
8788
|
const receipt = report.receipt;
|
|
8411
|
-
|
|
8789
|
+
if (report.confirmation) {
|
|
8790
|
+
emit(stdout, "Listing published.");
|
|
8791
|
+
} else if (report.review) {
|
|
8792
|
+
emit(stdout, "Listing published via legacy submit-review alias.");
|
|
8793
|
+
} else if (receipt.registration_mode === "upgrade") {
|
|
8794
|
+
emit(stdout, "Upgrade staged.");
|
|
8795
|
+
} else if (receipt.registration_mode === "refresh") {
|
|
8796
|
+
emit(stdout, "Draft refreshed.");
|
|
8797
|
+
} else {
|
|
8798
|
+
emit(stdout, "Draft listing created.");
|
|
8799
|
+
}
|
|
8412
8800
|
emit(stdout, `listing_id: ${receipt.listing_id}`);
|
|
8413
|
-
emit(stdout, `
|
|
8801
|
+
emit(stdout, `receipt_status: ${receipt.status}`);
|
|
8802
|
+
if (receipt.listing_status) emit(stdout, `listing_status: ${receipt.listing_status}`);
|
|
8803
|
+
if (receipt.oauth_status) emit(stdout, `oauth_configured: ${Boolean(receipt.oauth_status.configured)}`);
|
|
8414
8804
|
if (receipt.review_url) emit(stdout, `review_url: ${receipt.review_url}`);
|
|
8415
8805
|
if (receipt.trace_id) emit(stdout, `trace_id: ${receipt.trace_id}`);
|
|
8416
8806
|
if (receipt.request_id) emit(stdout, `request_id: ${receipt.request_id}`);
|
|
8807
|
+
if (report.confirmation) {
|
|
8808
|
+
const confirmation = report.confirmation;
|
|
8809
|
+
if (confirmation.status) emit(stdout, `confirmation_status: ${confirmation.status}`);
|
|
8810
|
+
if (confirmation.release?.release_status) emit(stdout, `release_status: ${confirmation.release.release_status}`);
|
|
8811
|
+
} else if (report.review) {
|
|
8812
|
+
const review = report.review;
|
|
8813
|
+
if (review.status) emit(stdout, `publish_status: ${review.status}`);
|
|
8814
|
+
}
|
|
8417
8815
|
const preflight = report.registration_preflight;
|
|
8418
8816
|
if (preflight?.remote_quality) {
|
|
8419
8817
|
emit(stdout, `preflight_quality: ${preflight.remote_quality.grade} (${preflight.remote_quality.overall_score}/100)`);
|