@siglume/api-sdk 0.10.0 → 0.10.2

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/dist/cli/index.js CHANGED
@@ -119,18 +119,6 @@ function camelCaseFromCapabilityKey(capabilityKey) {
119
119
  }
120
120
  return `${words.map((word) => word[0].toUpperCase() + word.slice(1)).join("")}App`;
121
121
  }
122
- function buildDefaultI18n(manifestPayload) {
123
- const job = String(manifestPayload.job_to_be_done ?? "").trim();
124
- const shortDescription = String(
125
- manifestPayload.short_description ?? manifestPayload.job_to_be_done ?? manifestPayload.name ?? ""
126
- ).trim();
127
- return {
128
- job_to_be_done_en: job,
129
- job_to_be_done_ja: job,
130
- short_description_en: shortDescription,
131
- short_description_ja: shortDescription
132
- };
133
- }
134
122
  function buildRegistrationStubSource(manifestPayload, toolManualPayload) {
135
123
  const capabilityKey = String(manifestPayload.capability_key ?? "generated-registration");
136
124
  const jobToBeDone = String(
@@ -285,10 +273,8 @@ var init_webhooks = __esm({
285
273
  "subscription.cancelled",
286
274
  "subscription.paused",
287
275
  "subscription.reinstated",
288
- "refund.issued",
289
276
  "payment.succeeded",
290
277
  "payment.failed",
291
- "payment.disputed",
292
278
  "capability.published",
293
279
  "capability.delisted",
294
280
  "execution.completed",
@@ -1328,6 +1314,7 @@ function parseListing(data) {
1328
1314
  price_value_minor: Number(data.price_value_minor ?? 0),
1329
1315
  currency: String(data.currency ?? "USD"),
1330
1316
  short_description: stringOrNull(data.short_description),
1317
+ description: stringOrNull(data.description),
1331
1318
  docs_url: stringOrNull(data.docs_url),
1332
1319
  support_contact: stringOrNull(data.support_contact),
1333
1320
  seller_display_name: stringOrNull(data.seller_display_name),
@@ -1352,19 +1339,6 @@ function parseBundleMember(data) {
1352
1339
  link_id: stringOrNull(data.link_id)
1353
1340
  };
1354
1341
  }
1355
- function parseConnectedAccountProvider(data) {
1356
- return {
1357
- provider_key: String(data.provider_key ?? ""),
1358
- display_name: String(data.display_name ?? ""),
1359
- auth_type: String(data.auth_type ?? "oauth2"),
1360
- refresh_supported: Boolean(data.refresh_supported ?? false),
1361
- pkce_required: Boolean(data.pkce_required ?? false),
1362
- default_scopes: Array.isArray(data.default_scopes) ? data.default_scopes.filter((s) => typeof s === "string") : [],
1363
- available_scopes: Array.isArray(data.available_scopes) ? data.available_scopes.filter((s) => typeof s === "string") : [],
1364
- scope_separator: String(data.scope_separator ?? " "),
1365
- notes: stringOrNull(data.notes)
1366
- };
1367
- }
1368
1342
  function parseConnectedAccountLifecycle(data) {
1369
1343
  return {
1370
1344
  connected_account_id: String(data.connected_account_id ?? ""),
@@ -2406,50 +2380,6 @@ function parseMarketProposalActionResult(execution) {
2406
2380
  raw: { ...execution.raw }
2407
2381
  };
2408
2382
  }
2409
- function parseRefund(data) {
2410
- return {
2411
- refund_id: String(data.refund_id ?? data.id ?? ""),
2412
- receipt_id: String(data.receipt_id ?? ""),
2413
- owner_user_id: stringOrNull(data.owner_user_id) ?? void 0,
2414
- payment_mandate_id: stringOrNull(data.payment_mandate_id) ?? void 0,
2415
- usage_event_id: stringOrNull(data.usage_event_id) ?? void 0,
2416
- chain_receipt_id: stringOrNull(data.chain_receipt_id) ?? void 0,
2417
- amount_minor: Number(data.amount_minor ?? 0),
2418
- currency: String(data.currency ?? "USD"),
2419
- status: String(data.status ?? "issued"),
2420
- reason_code: String(data.reason_code ?? "customer-request"),
2421
- note: stringOrNull(data.note) ?? void 0,
2422
- idempotency_key: stringOrNull(data.idempotency_key) ?? void 0,
2423
- on_chain_tx_hash: stringOrNull(data.on_chain_tx_hash) ?? void 0,
2424
- metadata: toRecord(data.metadata),
2425
- idempotent_replay: Boolean(data.idempotent_replay ?? false),
2426
- created_at: stringOrNull(data.created_at) ?? void 0,
2427
- updated_at: stringOrNull(data.updated_at) ?? void 0,
2428
- raw: { ...data }
2429
- };
2430
- }
2431
- function parseDispute(data) {
2432
- return {
2433
- dispute_id: String(data.dispute_id ?? data.id ?? ""),
2434
- receipt_id: String(data.receipt_id ?? ""),
2435
- owner_user_id: stringOrNull(data.owner_user_id) ?? void 0,
2436
- payment_mandate_id: stringOrNull(data.payment_mandate_id) ?? void 0,
2437
- usage_event_id: stringOrNull(data.usage_event_id) ?? void 0,
2438
- external_dispute_id: stringOrNull(data.external_dispute_id) ?? void 0,
2439
- status: String(data.status ?? "open"),
2440
- reason_code: String(data.reason_code ?? "manual-review"),
2441
- description: stringOrNull(data.description) ?? void 0,
2442
- evidence: toRecord(data.evidence),
2443
- response_decision: stringOrNull(data.response_decision) ?? void 0,
2444
- response_note: stringOrNull(data.response_note) ?? void 0,
2445
- responded_at: stringOrNull(data.responded_at) ?? void 0,
2446
- metadata: toRecord(data.metadata),
2447
- idempotent_replay: Boolean(data.idempotent_replay ?? false),
2448
- created_at: stringOrNull(data.created_at) ?? void 0,
2449
- updated_at: stringOrNull(data.updated_at) ?? void 0,
2450
- raw: { ...data }
2451
- };
2452
- }
2453
2383
  function cloneJsonLike(value) {
2454
2384
  if (Array.isArray(value)) {
2455
2385
  return value.map((item) => cloneJsonLike(item));
@@ -2534,10 +2464,13 @@ var init_client = __esm({
2534
2464
  async auto_register(manifest, tool_manual, options = {}) {
2535
2465
  const manifestPayload = coerceMapping(manifest, "manifest");
2536
2466
  const toolManualPayload = coerceMapping(tool_manual, "tool_manual");
2467
+ const toolManualForRequest = { ...toolManualPayload };
2468
+ const embeddedInputFormSpec = toolManualForRequest.input_form_spec;
2469
+ delete toolManualForRequest.input_form_spec;
2470
+ const inputFormSpec = options.input_form_spec ?? embeddedInputFormSpec;
2537
2471
  const payload = {
2538
- i18n: buildDefaultI18n(manifestPayload),
2539
2472
  manifest: { ...manifestPayload },
2540
- tool_manual: { ...toolManualPayload }
2473
+ tool_manual: toolManualForRequest
2541
2474
  };
2542
2475
  if (options.source_url) {
2543
2476
  payload.source_url = options.source_url;
@@ -2556,14 +2489,11 @@ var init_client = __esm({
2556
2489
  )
2557
2490
  } : coerceMapping(options.oauth_credentials, "oauth_credentials");
2558
2491
  }
2559
- if (options.metadata) {
2560
- payload.metadata = coerceMapping(options.metadata, "metadata");
2561
- }
2562
2492
  if (options.source_context) {
2563
2493
  payload.source_context = coerceMapping(options.source_context, "source_context");
2564
2494
  }
2565
- if (options.input_form_spec) {
2566
- payload.input_form_spec = coerceMapping(options.input_form_spec, "input_form_spec");
2495
+ if (inputFormSpec !== void 0 && inputFormSpec !== null) {
2496
+ payload.input_form_spec = coerceMapping(inputFormSpec, "input_form_spec");
2567
2497
  }
2568
2498
  for (const fieldName of [
2569
2499
  "capability_key",
@@ -2614,7 +2544,11 @@ var init_client = __esm({
2614
2544
  if (!listing_id) {
2615
2545
  throw new SiglumeClientError("Siglume auto-register response did not include listing_id.");
2616
2546
  }
2617
- this.pendingConfirmations.set(listing_id, { manifest: manifestPayload, tool_manual: toolManualPayload });
2547
+ this.pendingConfirmations.set(listing_id, {
2548
+ manifest: manifestPayload,
2549
+ tool_manual: toRecord(payload.tool_manual),
2550
+ input_form_spec: toRecord(payload.input_form_spec)
2551
+ });
2618
2552
  return {
2619
2553
  listing_id,
2620
2554
  status: String(data.status ?? "draft"),
@@ -2762,11 +2696,6 @@ var init_client = __esm({
2762
2696
  // ----- end bundles -------------------------------------------------------
2763
2697
  // ----- Connected accounts (v0.7 track 3) ---------------------------------
2764
2698
  // `resolve()` is intentionally NOT wrapped: runtime-only, never over the wire.
2765
- async list_connected_account_providers() {
2766
- const [data] = await this.request("GET", "/me/connected-accounts/providers");
2767
- const items = Array.isArray(data.items) ? data.items : [];
2768
- return items.filter((item) => isRecord(item)).map(parseConnectedAccountProvider);
2769
- }
2770
2699
  async start_connected_account_oauth(input) {
2771
2700
  const body = {
2772
2701
  listing_id: input.listing_id,
@@ -2803,8 +2732,17 @@ var init_client = __esm({
2803
2732
  const body = {
2804
2733
  provider_key: input.provider_key,
2805
2734
  client_id: input.client_id,
2806
- client_secret: input.client_secret
2735
+ client_secret: input.client_secret,
2736
+ authorize_url: input.authorize_url,
2737
+ token_url: input.token_url
2807
2738
  };
2739
+ if (input.revoke_url !== void 0) body.revoke_url = input.revoke_url;
2740
+ if (input.display_name !== void 0) body.display_name = input.display_name;
2741
+ if (input.scope_separator !== void 0) body.scope_separator = input.scope_separator;
2742
+ if (input.token_endpoint_auth !== void 0) body.token_endpoint_auth = input.token_endpoint_auth;
2743
+ if (input.pkce_required !== void 0) body.pkce_required = input.pkce_required;
2744
+ if (input.refresh_supported !== void 0) body.refresh_supported = input.refresh_supported;
2745
+ if (input.available_scopes !== void 0) body.available_scopes = input.available_scopes;
2808
2746
  if (input.required_scopes !== void 0) body.required_scopes = input.required_scopes;
2809
2747
  const [data] = await this.request("PUT", `/market/capabilities/${listing_id}/oauth-credentials`, {
2810
2748
  json_body: body
@@ -4209,105 +4147,6 @@ ${details}` : summary;
4209
4147
  fetchNext: next_cursor ? (cursor) => this.list_support_cases({ ...options, cursor }) : void 0
4210
4148
  });
4211
4149
  }
4212
- async issue_partial_refund(options) {
4213
- const receipt_id = String(options.receipt_id ?? "").trim();
4214
- const idempotency_key = String(options.idempotency_key ?? "").trim();
4215
- if (!receipt_id) {
4216
- throw new SiglumeClientError("receipt_id is required.");
4217
- }
4218
- if (!idempotency_key) {
4219
- throw new SiglumeClientError("idempotency_key is required.");
4220
- }
4221
- if (!Number.isFinite(options.amount_minor)) {
4222
- throw new SiglumeClientError("amount_minor must be a finite number.");
4223
- }
4224
- const amount_minor = Math.trunc(options.amount_minor);
4225
- if (amount_minor <= 0) {
4226
- throw new SiglumeClientError("amount_minor must be positive.");
4227
- }
4228
- if (typeof options.original_amount_minor === "number" && amount_minor > Math.trunc(options.original_amount_minor)) {
4229
- throw new SiglumeClientError("amount_minor cannot exceed the original receipt amount.");
4230
- }
4231
- const [data] = await this.request("POST", "/market/refunds", {
4232
- json_body: {
4233
- receipt_id,
4234
- amount_minor,
4235
- reason_code: options.reason ?? "customer-request",
4236
- note: options.note,
4237
- idempotency_key
4238
- }
4239
- });
4240
- return parseRefund(data);
4241
- }
4242
- async issue_full_refund(options) {
4243
- const receipt_id = String(options.receipt_id ?? "").trim();
4244
- if (!receipt_id) {
4245
- throw new SiglumeClientError("receipt_id is required.");
4246
- }
4247
- const provided_key = String(options.idempotency_key ?? "").trim();
4248
- const idempotency_key = provided_key || `full-refund:${receipt_id}`;
4249
- const [data] = await this.request("POST", "/market/refunds", {
4250
- json_body: {
4251
- receipt_id,
4252
- reason_code: options.reason ?? "customer-request",
4253
- note: options.note,
4254
- idempotency_key
4255
- }
4256
- });
4257
- return parseRefund(data);
4258
- }
4259
- async list_refunds(options = {}) {
4260
- const [data] = await this.requestAny("GET", "/market/refunds", {
4261
- params: {
4262
- receipt_id: options.receipt_id,
4263
- limit: Math.max(1, Math.min(Math.trunc(options.limit ?? 50), 100))
4264
- }
4265
- });
4266
- if (!Array.isArray(data)) {
4267
- throw new SiglumeClientError("Expected refunds to be returned as an array.");
4268
- }
4269
- return data.filter((item) => isRecord(item)).map(parseRefund);
4270
- }
4271
- async get_refund(refund_id) {
4272
- const [data] = await this.request("GET", `/market/refunds/${refund_id}`);
4273
- return parseRefund(data);
4274
- }
4275
- async get_refunds_for_receipt(receipt_id, options = {}) {
4276
- return this.list_refunds({ receipt_id, limit: options.limit });
4277
- }
4278
- async list_disputes(options = {}) {
4279
- const [data] = await this.requestAny("GET", "/market/disputes", {
4280
- params: {
4281
- receipt_id: options.receipt_id,
4282
- limit: Math.max(1, Math.min(Math.trunc(options.limit ?? 50), 100))
4283
- }
4284
- });
4285
- if (!Array.isArray(data)) {
4286
- throw new SiglumeClientError("Expected disputes to be returned as an array.");
4287
- }
4288
- return data.filter((item) => isRecord(item)).map(parseDispute);
4289
- }
4290
- async get_dispute(dispute_id) {
4291
- const [data] = await this.request("GET", `/market/disputes/${dispute_id}`);
4292
- return parseDispute(data);
4293
- }
4294
- async respond_to_dispute(options) {
4295
- const dispute_id = String(options.dispute_id ?? "").trim();
4296
- if (!dispute_id) {
4297
- throw new SiglumeClientError("dispute_id is required.");
4298
- }
4299
- if (!isRecord(options.evidence)) {
4300
- throw new SiglumeClientError("evidence must be an object.");
4301
- }
4302
- const [data] = await this.request("POST", `/market/disputes/${dispute_id}/respond`, {
4303
- json_body: {
4304
- response: options.response,
4305
- evidence: toRecord(options.evidence),
4306
- note: options.note
4307
- }
4308
- });
4309
- return parseDispute(data);
4310
- }
4311
4150
  async create_webhook_subscription(options) {
4312
4151
  const normalizedEventTypes = options.event_types.map((item) => String(item).trim()).filter((item) => item.length > 0);
4313
4152
  if (normalizedEventTypes.length === 0) {
@@ -5816,16 +5655,24 @@ function coerceToolManual(manual) {
5816
5655
  }
5817
5656
  function checkSchemaForbiddenRecursive(schema, rootField, pushIssue, path = "") {
5818
5657
  for (const keyword of COMPOSITION_KEYWORDS) {
5819
- if (keyword in schema) {
5820
- const location = path ? `${rootField}.${path}.${keyword}` : `${rootField}.${keyword}`;
5821
- pushIssue(
5822
- issue(
5823
- "INPUT_SCHEMA",
5824
- `Composition keyword '${keyword}' is not allowed in beta${path ? ` at ${path}` : ""}`,
5825
- location
5826
- )
5827
- );
5658
+ if (!(keyword in schema)) {
5659
+ continue;
5660
+ }
5661
+ const branches = schema[keyword];
5662
+ const location = path ? `${rootField}.${path}.${keyword}` : `${rootField}.${keyword}`;
5663
+ if (!Array.isArray(branches) || branches.length === 0) {
5664
+ pushIssue(issue("INPUT_SCHEMA", `${keyword} must be a non-empty array`, location));
5665
+ continue;
5828
5666
  }
5667
+ branches.forEach((branch, index) => {
5668
+ const branchPath = path ? `${path}.${keyword}[${index}]` : `${keyword}[${index}]`;
5669
+ const branchLocation = `${rootField}.${branchPath}`;
5670
+ if (!isRecord(branch)) {
5671
+ pushIssue(issue("INPUT_SCHEMA", `${keyword}[${index}] must be an object`, branchLocation));
5672
+ return;
5673
+ }
5674
+ checkSchemaForbiddenRecursive(branch, rootField, pushIssue, branchPath);
5675
+ });
5829
5676
  }
5830
5677
  for (const forbidden of INPUT_SCHEMA_FORBIDDEN_KEYS) {
5831
5678
  if (forbidden in schema) {
@@ -7192,43 +7039,51 @@ async function loadProject(path = ".") {
7192
7039
  oauth_credentials
7193
7040
  };
7194
7041
  }
7195
- var OAUTH_PROVIDER_ALIASES = {
7196
- x: "twitter",
7197
- "x-twitter": "twitter",
7198
- twitter: "twitter",
7199
- slack: "slack",
7200
- google: "google",
7201
- gmail: "google",
7202
- "google-drive": "google",
7203
- "google-calendar": "google",
7204
- github: "github",
7205
- linear: "linear",
7206
- notion: "notion"
7207
- };
7042
+ function isPlatformManagedRequirement(value) {
7043
+ if (!isRecord(value)) return false;
7044
+ if (value.platform_managed === true) return true;
7045
+ const owner = String(
7046
+ value.managed_by ?? value.auth_managed_by ?? value.connection_owner ?? ""
7047
+ ).trim().toLowerCase().replaceAll("_", "-");
7048
+ return owner === "platform" || owner === "siglume" || owner === "siglume-platform";
7049
+ }
7208
7050
  function oauthProviderKeyFromRequirement(value) {
7209
- const raw = String(value ?? "").trim().toLowerCase().replaceAll("_", "-");
7210
- if (!raw) return null;
7211
- if (OAUTH_PROVIDER_ALIASES[raw]) {
7212
- return OAUTH_PROVIDER_ALIASES[raw];
7213
- }
7214
- for (const token of raw.replaceAll("/", "-").replaceAll(":", "-").split("-")) {
7215
- const next = token.trim();
7216
- if (OAUTH_PROVIDER_ALIASES[next]) {
7217
- return OAUTH_PROVIDER_ALIASES[next];
7051
+ if (isRecord(value)) {
7052
+ for (const key of ["provider_key", "provider", "account_type", "name"]) {
7053
+ const providerKey = oauthProviderKeyFromRequirement(value[key]);
7054
+ if (providerKey) return providerKey;
7218
7055
  }
7056
+ return null;
7219
7057
  }
7220
- return null;
7058
+ const raw = String(value ?? "").trim();
7059
+ return raw || null;
7221
7060
  }
7222
7061
  function requiredOauthProviders(requirements) {
7223
7062
  const providers = [];
7224
7063
  for (const item of requirements ?? []) {
7064
+ if (!isPlatformManagedRequirement(item)) continue;
7225
7065
  const providerKey = oauthProviderKeyFromRequirement(item);
7066
+ if (!providerKey) {
7067
+ throw new SiglumeProjectError(
7068
+ "required_connected_accounts platform-managed entries must include a provider_key"
7069
+ );
7070
+ }
7226
7071
  if (providerKey && !providers.includes(providerKey)) {
7227
7072
  providers.push(providerKey);
7228
7073
  }
7229
7074
  }
7230
7075
  return providers;
7231
7076
  }
7077
+ function connectedAccountRequirementLabel(value) {
7078
+ if (isRecord(value)) {
7079
+ for (const key of ["provider_key", "provider", "account_type", "name"]) {
7080
+ const label = String(value[key] ?? "").trim();
7081
+ if (label) return label;
7082
+ }
7083
+ return "";
7084
+ }
7085
+ return String(value ?? "").trim();
7086
+ }
7232
7087
  function oauthProviderRecordsMap(payload) {
7233
7088
  if (!payload) {
7234
7089
  return {};
@@ -7241,7 +7096,23 @@ function oauthProviderRecordsMap(payload) {
7241
7096
  }
7242
7097
  const providerKey = oauthProviderKeyFromRequirement(item.provider_key ?? item.provider);
7243
7098
  if (!providerKey) {
7244
- throw new SiglumeProjectError(`oauth_credentials[${index}].provider_key is unsupported.`);
7099
+ throw new SiglumeProjectError(`oauth_credentials[${index}].provider_key is required.`);
7100
+ }
7101
+ const authorizeUrl = String(item.authorize_url ?? item.authorization_url ?? item.auth_url ?? "").trim();
7102
+ const tokenUrl = String(item.token_url ?? "").trim();
7103
+ if (!authorizeUrl || !tokenUrl) {
7104
+ throw new SiglumeProjectError(
7105
+ `oauth_credentials[${index}] must include authorize_url and token_url.`
7106
+ );
7107
+ }
7108
+ for (const [urlKey, urlValue] of Object.entries({
7109
+ authorize_url: authorizeUrl,
7110
+ token_url: tokenUrl,
7111
+ revoke_url: String(item.revoke_url ?? "").trim()
7112
+ })) {
7113
+ if (urlValue && !urlValue.startsWith("https://")) {
7114
+ throw new SiglumeProjectError(`oauth_credentials[${index}].${urlKey} must be an https URL.`);
7115
+ }
7245
7116
  }
7246
7117
  const clientId = String(item.client_id ?? "").trim();
7247
7118
  const clientSecret = String(item.client_secret ?? "").trim();
@@ -7257,12 +7128,30 @@ function oauthProviderRecordsMap(payload) {
7257
7128
  } else {
7258
7129
  scopes = rawScopes.map((scope) => String(scope ?? "").trim()).filter(Boolean);
7259
7130
  }
7260
- resolved[providerKey] = {
7131
+ const record = {
7261
7132
  provider_key: providerKey,
7262
7133
  client_id: clientId,
7263
7134
  client_secret: clientSecret,
7264
7135
  required_scopes: scopes
7265
7136
  };
7137
+ for (const [key, value] of Object.entries({
7138
+ authorize_url: authorizeUrl,
7139
+ token_url: tokenUrl,
7140
+ revoke_url: String(item.revoke_url ?? "").trim(),
7141
+ display_name: String(item.display_name ?? "").trim(),
7142
+ scope_separator: String(item.scope_separator ?? "").trim(),
7143
+ token_endpoint_auth: String(item.token_endpoint_auth ?? "").trim()
7144
+ })) {
7145
+ if (value) record[key] = value;
7146
+ }
7147
+ for (const key of ["pkce_required", "refresh_supported"]) {
7148
+ if (typeof item[key] === "boolean") record[key] = item[key];
7149
+ }
7150
+ if (Array.isArray(item.available_scopes)) {
7151
+ const availableScopes = item.available_scopes.map((scope) => String(scope ?? "").trim()).filter(Boolean);
7152
+ if (availableScopes.length > 0) record.available_scopes = availableScopes;
7153
+ }
7154
+ resolved[providerKey] = record;
7266
7155
  }
7267
7156
  return resolved;
7268
7157
  }
@@ -7288,7 +7177,7 @@ function ensureRequiredOauthCredentials(project) {
7288
7177
  }
7289
7178
  const path = project.oauth_credentials_path ?? join(project.root_dir, "oauth_credentials.json");
7290
7179
  throw new SiglumeProjectError(
7291
- `${path} is required for OAuth-backed APIs. Missing provider seeds: ${missing.join(", ")}`
7180
+ `${path} is required for platform-managed OAuth APIs. Missing provider seeds: ${missing.join(", ")}`
7292
7181
  );
7293
7182
  }
7294
7183
  async function validateProject(path = ".", deps = {}) {
@@ -7456,7 +7345,7 @@ async function registrationPreflight(project, client) {
7456
7345
  errors.push(`remote Tool Manual quality is not publishable: ${remoteQuality.grade} (${remoteQuality.overall_score}/100)`);
7457
7346
  }
7458
7347
  if (missingOauthProviders.length > 0) {
7459
- errors.push(`oauth_credentials.json is required for OAuth-backed APIs: ${missingOauthProviders.join(", ")}`);
7348
+ errors.push(`oauth_credentials.json is required for platform-managed OAuth APIs: ${missingOauthProviders.join(", ")}`);
7460
7349
  }
7461
7350
  const preflight = {
7462
7351
  manifest_issues: manifestIssues,
@@ -7482,6 +7371,7 @@ async function runRegistration(path = ".", options = {}, deps = {}) {
7482
7371
  ensureManifestPublisherIdentity(project);
7483
7372
  ensureRuntimeValidationReady(project);
7484
7373
  ensureRequiredOauthCredentials(project);
7374
+ const canonicalOauthCredentials = canonicalOauthCredentialsPayload(project.oauth_credentials);
7485
7375
  const client = await createClient(deps);
7486
7376
  const preflight = await registrationPreflight(project, client);
7487
7377
  let developerPortalPreflight = null;
@@ -7497,7 +7387,7 @@ async function runRegistration(path = ".", options = {}, deps = {}) {
7497
7387
  }
7498
7388
  const receipt = await client.auto_register(project.manifest, project.tool_manual, {
7499
7389
  runtime_validation: project.runtime_validation,
7500
- oauth_credentials: canonicalOauthCredentialsPayload(project.oauth_credentials)
7390
+ oauth_credentials: canonicalOauthCredentials
7501
7391
  });
7502
7392
  const result = {
7503
7393
  receipt: toJsonable(receipt),
@@ -7508,7 +7398,8 @@ async function runRegistration(path = ".", options = {}, deps = {}) {
7508
7398
  if (developerPortalPreflight) {
7509
7399
  result.developer_portal_preflight = developerPortalPreflight;
7510
7400
  }
7511
- if (options.confirm) {
7401
+ const shouldConfirm = Boolean(options.confirm) || options.confirm === void 0 && !options.draft_only && !options.submit_review;
7402
+ if (shouldConfirm) {
7512
7403
  result.confirmation = toJsonable(await client.confirm_registration(receipt.listing_id));
7513
7404
  if (options.submit_review) {
7514
7405
  result.submit_review_skipped = true;
@@ -8039,8 +7930,8 @@ function operationReadmeTemplate(operation, manifest, warning) {
8039
7930
  "siglume score . --remote",
8040
7931
  "siglume preflight .",
8041
7932
  "siglume register .",
8042
- "# inspect the draft, then explicitly approve publish:",
8043
- "siglume register . --confirm",
7933
+ "# review-only staging path:",
7934
+ "siglume register . --draft-only",
8044
7935
  "```",
8045
7936
  ""
8046
7937
  ].join("\n");
@@ -8051,7 +7942,7 @@ function apiUsageDocsTemplate(manifest) {
8051
7942
  const jobToBeDone = String(manifest.job_to_be_done ?? "Describe what this API lets an agent do.");
8052
7943
  const permissionClass = String(manifest.permission_class ?? "read-only");
8053
7944
  const priceModel = String(manifest.price_model ?? "free");
8054
- const requiredAccounts = (manifest.required_connected_accounts ?? []).join(", ") || "none";
7945
+ const requiredAccounts = (manifest.required_connected_accounts ?? []).map((item) => connectedAccountRequirementLabel(item)).filter(Boolean).join(", ") || "none";
8055
7946
  const supportContact = String(manifest.support_contact ?? "replace-with-support-contact");
8056
7947
  return [
8057
7948
  `# ${name} API Usage Guide`,
@@ -8612,8 +8503,8 @@ function readmeTemplate(template) {
8612
8503
  "siglume score . --remote",
8613
8504
  "siglume preflight .",
8614
8505
  "siglume register .",
8615
- "# inspect the draft, then explicitly approve publish:",
8616
- "siglume register . --confirm",
8506
+ "# review-only staging path:",
8507
+ "siglume register . --draft-only",
8617
8508
  "```",
8618
8509
  ""
8619
8510
  ].join("\n");
@@ -8795,16 +8686,25 @@ async function runCli(argv, deps = {}) {
8795
8686
  if (report.runtime_validation_path) emit(stdout, `runtime_validation_path: ${String(report.runtime_validation_path)}`);
8796
8687
  if (report.oauth_credentials_path) emit(stdout, `oauth_credentials_path: ${String(report.oauth_credentials_path)}`);
8797
8688
  });
8798
- 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) => {
8799
- const report = await runRegistration(path, { confirm: options.confirm, submit_review: options.submitReview }, deps);
8689
+ program.command("register").option("--confirm", "explicitly confirm the registration; this is the default unless --draft-only is set", false).option("--draft-only", "create or refresh the draft without confirming publication", 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) => {
8690
+ const draftOnly = Boolean(options.draftOnly);
8691
+ if (draftOnly && options.confirm) {
8692
+ throw new SiglumeProjectError("--draft-only cannot be combined with --confirm.");
8693
+ }
8694
+ if (draftOnly && options.submitReview) {
8695
+ throw new SiglumeProjectError("--draft-only cannot be combined with --submit-review.");
8696
+ }
8697
+ const shouldConfirm = Boolean(options.confirm) || !draftOnly && !options.submitReview;
8698
+ const report = await runRegistration(path, { confirm: shouldConfirm, draft_only: draftOnly, submit_review: options.submitReview }, deps);
8800
8699
  if (options.json) {
8801
8700
  emit(stdout, renderJson(report));
8802
8701
  } else {
8803
8702
  const receipt = report.receipt;
8804
- if (report.confirmation) {
8805
- emit(stdout, "Listing published.");
8806
- } else if (report.review) {
8807
- emit(stdout, "Listing published via legacy submit-review alias.");
8703
+ const published = Boolean(report.confirmation || report.review);
8704
+ if (published && receipt.registration_mode === "upgrade") {
8705
+ emit(stdout, "Upgrade registered.");
8706
+ } else if (published) {
8707
+ emit(stdout, "Registration accepted.");
8808
8708
  } else if (receipt.registration_mode === "upgrade") {
8809
8709
  emit(stdout, "Upgrade staged.");
8810
8710
  } else if (receipt.registration_mode === "refresh") {
@@ -8821,10 +8721,12 @@ async function runCli(argv, deps = {}) {
8821
8721
  if (receipt.request_id) emit(stdout, `request_id: ${receipt.request_id}`);
8822
8722
  if (report.confirmation) {
8823
8723
  const confirmation = report.confirmation;
8724
+ emit(stdout, "Listing published.");
8824
8725
  if (confirmation.status) emit(stdout, `confirmation_status: ${confirmation.status}`);
8825
8726
  if (confirmation.release?.release_status) emit(stdout, `release_status: ${confirmation.release.release_status}`);
8826
8727
  } else if (report.review) {
8827
8728
  const review = report.review;
8729
+ emit(stdout, "Listing published via legacy submit-review alias.");
8828
8730
  if (review.status) emit(stdout, `publish_status: ${review.status}`);
8829
8731
  }
8830
8732
  const preflight = report.registration_preflight;