@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.
@@ -141,18 +141,6 @@ function camelCaseFromCapabilityKey(capabilityKey) {
141
141
  }
142
142
  return `${words.map((word) => word[0].toUpperCase() + word.slice(1)).join("")}App`;
143
143
  }
144
- function buildDefaultI18n(manifestPayload) {
145
- const job = String(manifestPayload.job_to_be_done ?? "").trim();
146
- const shortDescription = String(
147
- manifestPayload.short_description ?? manifestPayload.job_to_be_done ?? manifestPayload.name ?? ""
148
- ).trim();
149
- return {
150
- job_to_be_done_en: job,
151
- job_to_be_done_ja: job,
152
- short_description_en: shortDescription,
153
- short_description_ja: shortDescription
154
- };
155
- }
156
144
  function buildRegistrationStubSource(manifestPayload, toolManualPayload) {
157
145
  const capabilityKey = String(manifestPayload.capability_key ?? "generated-registration");
158
146
  const jobToBeDone = String(
@@ -307,10 +295,8 @@ var init_webhooks = __esm({
307
295
  "subscription.cancelled",
308
296
  "subscription.paused",
309
297
  "subscription.reinstated",
310
- "refund.issued",
311
298
  "payment.succeeded",
312
299
  "payment.failed",
313
- "payment.disputed",
314
300
  "capability.published",
315
301
  "capability.delisted",
316
302
  "execution.completed",
@@ -1350,6 +1336,7 @@ function parseListing(data) {
1350
1336
  price_value_minor: Number(data.price_value_minor ?? 0),
1351
1337
  currency: String(data.currency ?? "USD"),
1352
1338
  short_description: stringOrNull(data.short_description),
1339
+ description: stringOrNull(data.description),
1353
1340
  docs_url: stringOrNull(data.docs_url),
1354
1341
  support_contact: stringOrNull(data.support_contact),
1355
1342
  seller_display_name: stringOrNull(data.seller_display_name),
@@ -1374,19 +1361,6 @@ function parseBundleMember(data) {
1374
1361
  link_id: stringOrNull(data.link_id)
1375
1362
  };
1376
1363
  }
1377
- function parseConnectedAccountProvider(data) {
1378
- return {
1379
- provider_key: String(data.provider_key ?? ""),
1380
- display_name: String(data.display_name ?? ""),
1381
- auth_type: String(data.auth_type ?? "oauth2"),
1382
- refresh_supported: Boolean(data.refresh_supported ?? false),
1383
- pkce_required: Boolean(data.pkce_required ?? false),
1384
- default_scopes: Array.isArray(data.default_scopes) ? data.default_scopes.filter((s) => typeof s === "string") : [],
1385
- available_scopes: Array.isArray(data.available_scopes) ? data.available_scopes.filter((s) => typeof s === "string") : [],
1386
- scope_separator: String(data.scope_separator ?? " "),
1387
- notes: stringOrNull(data.notes)
1388
- };
1389
- }
1390
1364
  function parseConnectedAccountLifecycle(data) {
1391
1365
  return {
1392
1366
  connected_account_id: String(data.connected_account_id ?? ""),
@@ -2428,50 +2402,6 @@ function parseMarketProposalActionResult(execution) {
2428
2402
  raw: { ...execution.raw }
2429
2403
  };
2430
2404
  }
2431
- function parseRefund(data) {
2432
- return {
2433
- refund_id: String(data.refund_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
- chain_receipt_id: stringOrNull(data.chain_receipt_id) ?? void 0,
2439
- amount_minor: Number(data.amount_minor ?? 0),
2440
- currency: String(data.currency ?? "USD"),
2441
- status: String(data.status ?? "issued"),
2442
- reason_code: String(data.reason_code ?? "customer-request"),
2443
- note: stringOrNull(data.note) ?? void 0,
2444
- idempotency_key: stringOrNull(data.idempotency_key) ?? void 0,
2445
- on_chain_tx_hash: stringOrNull(data.on_chain_tx_hash) ?? 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
- function parseDispute(data) {
2454
- return {
2455
- dispute_id: String(data.dispute_id ?? data.id ?? ""),
2456
- receipt_id: String(data.receipt_id ?? ""),
2457
- owner_user_id: stringOrNull(data.owner_user_id) ?? void 0,
2458
- payment_mandate_id: stringOrNull(data.payment_mandate_id) ?? void 0,
2459
- usage_event_id: stringOrNull(data.usage_event_id) ?? void 0,
2460
- external_dispute_id: stringOrNull(data.external_dispute_id) ?? void 0,
2461
- status: String(data.status ?? "open"),
2462
- reason_code: String(data.reason_code ?? "manual-review"),
2463
- description: stringOrNull(data.description) ?? void 0,
2464
- evidence: toRecord(data.evidence),
2465
- response_decision: stringOrNull(data.response_decision) ?? void 0,
2466
- response_note: stringOrNull(data.response_note) ?? void 0,
2467
- responded_at: stringOrNull(data.responded_at) ?? void 0,
2468
- metadata: toRecord(data.metadata),
2469
- idempotent_replay: Boolean(data.idempotent_replay ?? false),
2470
- created_at: stringOrNull(data.created_at) ?? void 0,
2471
- updated_at: stringOrNull(data.updated_at) ?? void 0,
2472
- raw: { ...data }
2473
- };
2474
- }
2475
2405
  function cloneJsonLike(value) {
2476
2406
  if (Array.isArray(value)) {
2477
2407
  return value.map((item) => cloneJsonLike(item));
@@ -2556,10 +2486,13 @@ var init_client = __esm({
2556
2486
  async auto_register(manifest, tool_manual, options = {}) {
2557
2487
  const manifestPayload = coerceMapping(manifest, "manifest");
2558
2488
  const toolManualPayload = coerceMapping(tool_manual, "tool_manual");
2489
+ const toolManualForRequest = { ...toolManualPayload };
2490
+ const embeddedInputFormSpec = toolManualForRequest.input_form_spec;
2491
+ delete toolManualForRequest.input_form_spec;
2492
+ const inputFormSpec = options.input_form_spec ?? embeddedInputFormSpec;
2559
2493
  const payload = {
2560
- i18n: buildDefaultI18n(manifestPayload),
2561
2494
  manifest: { ...manifestPayload },
2562
- tool_manual: { ...toolManualPayload }
2495
+ tool_manual: toolManualForRequest
2563
2496
  };
2564
2497
  if (options.source_url) {
2565
2498
  payload.source_url = options.source_url;
@@ -2578,14 +2511,11 @@ var init_client = __esm({
2578
2511
  )
2579
2512
  } : coerceMapping(options.oauth_credentials, "oauth_credentials");
2580
2513
  }
2581
- if (options.metadata) {
2582
- payload.metadata = coerceMapping(options.metadata, "metadata");
2583
- }
2584
2514
  if (options.source_context) {
2585
2515
  payload.source_context = coerceMapping(options.source_context, "source_context");
2586
2516
  }
2587
- if (options.input_form_spec) {
2588
- payload.input_form_spec = coerceMapping(options.input_form_spec, "input_form_spec");
2517
+ if (inputFormSpec !== void 0 && inputFormSpec !== null) {
2518
+ payload.input_form_spec = coerceMapping(inputFormSpec, "input_form_spec");
2589
2519
  }
2590
2520
  for (const fieldName of [
2591
2521
  "capability_key",
@@ -2636,7 +2566,11 @@ var init_client = __esm({
2636
2566
  if (!listing_id) {
2637
2567
  throw new SiglumeClientError("Siglume auto-register response did not include listing_id.");
2638
2568
  }
2639
- this.pendingConfirmations.set(listing_id, { manifest: manifestPayload, tool_manual: toolManualPayload });
2569
+ this.pendingConfirmations.set(listing_id, {
2570
+ manifest: manifestPayload,
2571
+ tool_manual: toRecord(payload.tool_manual),
2572
+ input_form_spec: toRecord(payload.input_form_spec)
2573
+ });
2640
2574
  return {
2641
2575
  listing_id,
2642
2576
  status: String(data.status ?? "draft"),
@@ -2784,11 +2718,6 @@ var init_client = __esm({
2784
2718
  // ----- end bundles -------------------------------------------------------
2785
2719
  // ----- Connected accounts (v0.7 track 3) ---------------------------------
2786
2720
  // `resolve()` is intentionally NOT wrapped: runtime-only, never over the wire.
2787
- async list_connected_account_providers() {
2788
- const [data] = await this.request("GET", "/me/connected-accounts/providers");
2789
- const items = Array.isArray(data.items) ? data.items : [];
2790
- return items.filter((item) => isRecord(item)).map(parseConnectedAccountProvider);
2791
- }
2792
2721
  async start_connected_account_oauth(input) {
2793
2722
  const body = {
2794
2723
  listing_id: input.listing_id,
@@ -2825,8 +2754,17 @@ var init_client = __esm({
2825
2754
  const body = {
2826
2755
  provider_key: input.provider_key,
2827
2756
  client_id: input.client_id,
2828
- client_secret: input.client_secret
2757
+ client_secret: input.client_secret,
2758
+ authorize_url: input.authorize_url,
2759
+ token_url: input.token_url
2829
2760
  };
2761
+ if (input.revoke_url !== void 0) body.revoke_url = input.revoke_url;
2762
+ if (input.display_name !== void 0) body.display_name = input.display_name;
2763
+ if (input.scope_separator !== void 0) body.scope_separator = input.scope_separator;
2764
+ if (input.token_endpoint_auth !== void 0) body.token_endpoint_auth = input.token_endpoint_auth;
2765
+ if (input.pkce_required !== void 0) body.pkce_required = input.pkce_required;
2766
+ if (input.refresh_supported !== void 0) body.refresh_supported = input.refresh_supported;
2767
+ if (input.available_scopes !== void 0) body.available_scopes = input.available_scopes;
2830
2768
  if (input.required_scopes !== void 0) body.required_scopes = input.required_scopes;
2831
2769
  const [data] = await this.request("PUT", `/market/capabilities/${listing_id}/oauth-credentials`, {
2832
2770
  json_body: body
@@ -4231,105 +4169,6 @@ ${details}` : summary;
4231
4169
  fetchNext: next_cursor ? (cursor) => this.list_support_cases({ ...options, cursor }) : void 0
4232
4170
  });
4233
4171
  }
4234
- async issue_partial_refund(options) {
4235
- const receipt_id = String(options.receipt_id ?? "").trim();
4236
- const idempotency_key = String(options.idempotency_key ?? "").trim();
4237
- if (!receipt_id) {
4238
- throw new SiglumeClientError("receipt_id is required.");
4239
- }
4240
- if (!idempotency_key) {
4241
- throw new SiglumeClientError("idempotency_key is required.");
4242
- }
4243
- if (!Number.isFinite(options.amount_minor)) {
4244
- throw new SiglumeClientError("amount_minor must be a finite number.");
4245
- }
4246
- const amount_minor = Math.trunc(options.amount_minor);
4247
- if (amount_minor <= 0) {
4248
- throw new SiglumeClientError("amount_minor must be positive.");
4249
- }
4250
- if (typeof options.original_amount_minor === "number" && amount_minor > Math.trunc(options.original_amount_minor)) {
4251
- throw new SiglumeClientError("amount_minor cannot exceed the original receipt amount.");
4252
- }
4253
- const [data] = await this.request("POST", "/market/refunds", {
4254
- json_body: {
4255
- receipt_id,
4256
- amount_minor,
4257
- reason_code: options.reason ?? "customer-request",
4258
- note: options.note,
4259
- idempotency_key
4260
- }
4261
- });
4262
- return parseRefund(data);
4263
- }
4264
- async issue_full_refund(options) {
4265
- const receipt_id = String(options.receipt_id ?? "").trim();
4266
- if (!receipt_id) {
4267
- throw new SiglumeClientError("receipt_id is required.");
4268
- }
4269
- const provided_key = String(options.idempotency_key ?? "").trim();
4270
- const idempotency_key = provided_key || `full-refund:${receipt_id}`;
4271
- const [data] = await this.request("POST", "/market/refunds", {
4272
- json_body: {
4273
- receipt_id,
4274
- reason_code: options.reason ?? "customer-request",
4275
- note: options.note,
4276
- idempotency_key
4277
- }
4278
- });
4279
- return parseRefund(data);
4280
- }
4281
- async list_refunds(options = {}) {
4282
- const [data] = await this.requestAny("GET", "/market/refunds", {
4283
- params: {
4284
- receipt_id: options.receipt_id,
4285
- limit: Math.max(1, Math.min(Math.trunc(options.limit ?? 50), 100))
4286
- }
4287
- });
4288
- if (!Array.isArray(data)) {
4289
- throw new SiglumeClientError("Expected refunds to be returned as an array.");
4290
- }
4291
- return data.filter((item) => isRecord(item)).map(parseRefund);
4292
- }
4293
- async get_refund(refund_id) {
4294
- const [data] = await this.request("GET", `/market/refunds/${refund_id}`);
4295
- return parseRefund(data);
4296
- }
4297
- async get_refunds_for_receipt(receipt_id, options = {}) {
4298
- return this.list_refunds({ receipt_id, limit: options.limit });
4299
- }
4300
- async list_disputes(options = {}) {
4301
- const [data] = await this.requestAny("GET", "/market/disputes", {
4302
- params: {
4303
- receipt_id: options.receipt_id,
4304
- limit: Math.max(1, Math.min(Math.trunc(options.limit ?? 50), 100))
4305
- }
4306
- });
4307
- if (!Array.isArray(data)) {
4308
- throw new SiglumeClientError("Expected disputes to be returned as an array.");
4309
- }
4310
- return data.filter((item) => isRecord(item)).map(parseDispute);
4311
- }
4312
- async get_dispute(dispute_id) {
4313
- const [data] = await this.request("GET", `/market/disputes/${dispute_id}`);
4314
- return parseDispute(data);
4315
- }
4316
- async respond_to_dispute(options) {
4317
- const dispute_id = String(options.dispute_id ?? "").trim();
4318
- if (!dispute_id) {
4319
- throw new SiglumeClientError("dispute_id is required.");
4320
- }
4321
- if (!isRecord(options.evidence)) {
4322
- throw new SiglumeClientError("evidence must be an object.");
4323
- }
4324
- const [data] = await this.request("POST", `/market/disputes/${dispute_id}/respond`, {
4325
- json_body: {
4326
- response: options.response,
4327
- evidence: toRecord(options.evidence),
4328
- note: options.note
4329
- }
4330
- });
4331
- return parseDispute(data);
4332
- }
4333
4172
  async create_webhook_subscription(options) {
4334
4173
  const normalizedEventTypes = options.event_types.map((item) => String(item).trim()).filter((item) => item.length > 0);
4335
4174
  if (normalizedEventTypes.length === 0) {
@@ -5843,16 +5682,24 @@ function coerceToolManual(manual) {
5843
5682
  }
5844
5683
  function checkSchemaForbiddenRecursive(schema, rootField, pushIssue, path = "") {
5845
5684
  for (const keyword of COMPOSITION_KEYWORDS) {
5846
- if (keyword in schema) {
5847
- const location = path ? `${rootField}.${path}.${keyword}` : `${rootField}.${keyword}`;
5848
- pushIssue(
5849
- issue(
5850
- "INPUT_SCHEMA",
5851
- `Composition keyword '${keyword}' is not allowed in beta${path ? ` at ${path}` : ""}`,
5852
- location
5853
- )
5854
- );
5685
+ if (!(keyword in schema)) {
5686
+ continue;
5687
+ }
5688
+ const branches = schema[keyword];
5689
+ const location = path ? `${rootField}.${path}.${keyword}` : `${rootField}.${keyword}`;
5690
+ if (!Array.isArray(branches) || branches.length === 0) {
5691
+ pushIssue(issue("INPUT_SCHEMA", `${keyword} must be a non-empty array`, location));
5692
+ continue;
5855
5693
  }
5694
+ branches.forEach((branch, index) => {
5695
+ const branchPath = path ? `${path}.${keyword}[${index}]` : `${keyword}[${index}]`;
5696
+ const branchLocation = `${rootField}.${branchPath}`;
5697
+ if (!isRecord(branch)) {
5698
+ pushIssue(issue("INPUT_SCHEMA", `${keyword}[${index}] must be an object`, branchLocation));
5699
+ return;
5700
+ }
5701
+ checkSchemaForbiddenRecursive(branch, rootField, pushIssue, branchPath);
5702
+ });
5856
5703
  }
5857
5704
  for (const forbidden of INPUT_SCHEMA_FORBIDDEN_KEYS) {
5858
5705
  if (forbidden in schema) {
@@ -7219,43 +7066,51 @@ async function loadProject(path = ".") {
7219
7066
  oauth_credentials
7220
7067
  };
7221
7068
  }
7222
- var OAUTH_PROVIDER_ALIASES = {
7223
- x: "twitter",
7224
- "x-twitter": "twitter",
7225
- twitter: "twitter",
7226
- slack: "slack",
7227
- google: "google",
7228
- gmail: "google",
7229
- "google-drive": "google",
7230
- "google-calendar": "google",
7231
- github: "github",
7232
- linear: "linear",
7233
- notion: "notion"
7234
- };
7069
+ function isPlatformManagedRequirement(value) {
7070
+ if (!isRecord(value)) return false;
7071
+ if (value.platform_managed === true) return true;
7072
+ const owner = String(
7073
+ value.managed_by ?? value.auth_managed_by ?? value.connection_owner ?? ""
7074
+ ).trim().toLowerCase().replaceAll("_", "-");
7075
+ return owner === "platform" || owner === "siglume" || owner === "siglume-platform";
7076
+ }
7235
7077
  function oauthProviderKeyFromRequirement(value) {
7236
- const raw = String(value ?? "").trim().toLowerCase().replaceAll("_", "-");
7237
- if (!raw) return null;
7238
- if (OAUTH_PROVIDER_ALIASES[raw]) {
7239
- return OAUTH_PROVIDER_ALIASES[raw];
7240
- }
7241
- for (const token of raw.replaceAll("/", "-").replaceAll(":", "-").split("-")) {
7242
- const next = token.trim();
7243
- if (OAUTH_PROVIDER_ALIASES[next]) {
7244
- return OAUTH_PROVIDER_ALIASES[next];
7078
+ if (isRecord(value)) {
7079
+ for (const key of ["provider_key", "provider", "account_type", "name"]) {
7080
+ const providerKey = oauthProviderKeyFromRequirement(value[key]);
7081
+ if (providerKey) return providerKey;
7245
7082
  }
7083
+ return null;
7246
7084
  }
7247
- return null;
7085
+ const raw = String(value ?? "").trim();
7086
+ return raw || null;
7248
7087
  }
7249
7088
  function requiredOauthProviders(requirements) {
7250
7089
  const providers = [];
7251
7090
  for (const item of requirements ?? []) {
7091
+ if (!isPlatformManagedRequirement(item)) continue;
7252
7092
  const providerKey = oauthProviderKeyFromRequirement(item);
7093
+ if (!providerKey) {
7094
+ throw new SiglumeProjectError(
7095
+ "required_connected_accounts platform-managed entries must include a provider_key"
7096
+ );
7097
+ }
7253
7098
  if (providerKey && !providers.includes(providerKey)) {
7254
7099
  providers.push(providerKey);
7255
7100
  }
7256
7101
  }
7257
7102
  return providers;
7258
7103
  }
7104
+ function connectedAccountRequirementLabel(value) {
7105
+ if (isRecord(value)) {
7106
+ for (const key of ["provider_key", "provider", "account_type", "name"]) {
7107
+ const label = String(value[key] ?? "").trim();
7108
+ if (label) return label;
7109
+ }
7110
+ return "";
7111
+ }
7112
+ return String(value ?? "").trim();
7113
+ }
7259
7114
  function oauthProviderRecordsMap(payload) {
7260
7115
  if (!payload) {
7261
7116
  return {};
@@ -7268,7 +7123,23 @@ function oauthProviderRecordsMap(payload) {
7268
7123
  }
7269
7124
  const providerKey = oauthProviderKeyFromRequirement(item.provider_key ?? item.provider);
7270
7125
  if (!providerKey) {
7271
- throw new SiglumeProjectError(`oauth_credentials[${index}].provider_key is unsupported.`);
7126
+ throw new SiglumeProjectError(`oauth_credentials[${index}].provider_key is required.`);
7127
+ }
7128
+ const authorizeUrl = String(item.authorize_url ?? item.authorization_url ?? item.auth_url ?? "").trim();
7129
+ const tokenUrl = String(item.token_url ?? "").trim();
7130
+ if (!authorizeUrl || !tokenUrl) {
7131
+ throw new SiglumeProjectError(
7132
+ `oauth_credentials[${index}] must include authorize_url and token_url.`
7133
+ );
7134
+ }
7135
+ for (const [urlKey, urlValue] of Object.entries({
7136
+ authorize_url: authorizeUrl,
7137
+ token_url: tokenUrl,
7138
+ revoke_url: String(item.revoke_url ?? "").trim()
7139
+ })) {
7140
+ if (urlValue && !urlValue.startsWith("https://")) {
7141
+ throw new SiglumeProjectError(`oauth_credentials[${index}].${urlKey} must be an https URL.`);
7142
+ }
7272
7143
  }
7273
7144
  const clientId = String(item.client_id ?? "").trim();
7274
7145
  const clientSecret = String(item.client_secret ?? "").trim();
@@ -7284,12 +7155,30 @@ function oauthProviderRecordsMap(payload) {
7284
7155
  } else {
7285
7156
  scopes = rawScopes.map((scope) => String(scope ?? "").trim()).filter(Boolean);
7286
7157
  }
7287
- resolved[providerKey] = {
7158
+ const record = {
7288
7159
  provider_key: providerKey,
7289
7160
  client_id: clientId,
7290
7161
  client_secret: clientSecret,
7291
7162
  required_scopes: scopes
7292
7163
  };
7164
+ for (const [key, value] of Object.entries({
7165
+ authorize_url: authorizeUrl,
7166
+ token_url: tokenUrl,
7167
+ revoke_url: String(item.revoke_url ?? "").trim(),
7168
+ display_name: String(item.display_name ?? "").trim(),
7169
+ scope_separator: String(item.scope_separator ?? "").trim(),
7170
+ token_endpoint_auth: String(item.token_endpoint_auth ?? "").trim()
7171
+ })) {
7172
+ if (value) record[key] = value;
7173
+ }
7174
+ for (const key of ["pkce_required", "refresh_supported"]) {
7175
+ if (typeof item[key] === "boolean") record[key] = item[key];
7176
+ }
7177
+ if (Array.isArray(item.available_scopes)) {
7178
+ const availableScopes = item.available_scopes.map((scope) => String(scope ?? "").trim()).filter(Boolean);
7179
+ if (availableScopes.length > 0) record.available_scopes = availableScopes;
7180
+ }
7181
+ resolved[providerKey] = record;
7293
7182
  }
7294
7183
  return resolved;
7295
7184
  }
@@ -7315,7 +7204,7 @@ function ensureRequiredOauthCredentials(project) {
7315
7204
  }
7316
7205
  const path = project.oauth_credentials_path ?? (0, import_node_path.join)(project.root_dir, "oauth_credentials.json");
7317
7206
  throw new SiglumeProjectError(
7318
- `${path} is required for OAuth-backed APIs. Missing provider seeds: ${missing.join(", ")}`
7207
+ `${path} is required for platform-managed OAuth APIs. Missing provider seeds: ${missing.join(", ")}`
7319
7208
  );
7320
7209
  }
7321
7210
  async function validateProject(path = ".", deps = {}) {
@@ -7483,7 +7372,7 @@ async function registrationPreflight(project, client) {
7483
7372
  errors.push(`remote Tool Manual quality is not publishable: ${remoteQuality.grade} (${remoteQuality.overall_score}/100)`);
7484
7373
  }
7485
7374
  if (missingOauthProviders.length > 0) {
7486
- errors.push(`oauth_credentials.json is required for OAuth-backed APIs: ${missingOauthProviders.join(", ")}`);
7375
+ errors.push(`oauth_credentials.json is required for platform-managed OAuth APIs: ${missingOauthProviders.join(", ")}`);
7487
7376
  }
7488
7377
  const preflight = {
7489
7378
  manifest_issues: manifestIssues,
@@ -7509,6 +7398,7 @@ async function runRegistration(path = ".", options = {}, deps = {}) {
7509
7398
  ensureManifestPublisherIdentity(project);
7510
7399
  ensureRuntimeValidationReady(project);
7511
7400
  ensureRequiredOauthCredentials(project);
7401
+ const canonicalOauthCredentials = canonicalOauthCredentialsPayload(project.oauth_credentials);
7512
7402
  const client = await createClient(deps);
7513
7403
  const preflight = await registrationPreflight(project, client);
7514
7404
  let developerPortalPreflight = null;
@@ -7524,7 +7414,7 @@ async function runRegistration(path = ".", options = {}, deps = {}) {
7524
7414
  }
7525
7415
  const receipt = await client.auto_register(project.manifest, project.tool_manual, {
7526
7416
  runtime_validation: project.runtime_validation,
7527
- oauth_credentials: canonicalOauthCredentialsPayload(project.oauth_credentials)
7417
+ oauth_credentials: canonicalOauthCredentials
7528
7418
  });
7529
7419
  const result = {
7530
7420
  receipt: toJsonable(receipt),
@@ -7535,7 +7425,8 @@ async function runRegistration(path = ".", options = {}, deps = {}) {
7535
7425
  if (developerPortalPreflight) {
7536
7426
  result.developer_portal_preflight = developerPortalPreflight;
7537
7427
  }
7538
- if (options.confirm) {
7428
+ const shouldConfirm = Boolean(options.confirm) || options.confirm === void 0 && !options.draft_only && !options.submit_review;
7429
+ if (shouldConfirm) {
7539
7430
  result.confirmation = toJsonable(await client.confirm_registration(receipt.listing_id));
7540
7431
  if (options.submit_review) {
7541
7432
  result.submit_review_skipped = true;
@@ -8066,8 +7957,8 @@ function operationReadmeTemplate(operation, manifest, warning) {
8066
7957
  "siglume score . --remote",
8067
7958
  "siglume preflight .",
8068
7959
  "siglume register .",
8069
- "# inspect the draft, then explicitly approve publish:",
8070
- "siglume register . --confirm",
7960
+ "# review-only staging path:",
7961
+ "siglume register . --draft-only",
8071
7962
  "```",
8072
7963
  ""
8073
7964
  ].join("\n");
@@ -8078,7 +7969,7 @@ function apiUsageDocsTemplate(manifest) {
8078
7969
  const jobToBeDone = String(manifest.job_to_be_done ?? "Describe what this API lets an agent do.");
8079
7970
  const permissionClass = String(manifest.permission_class ?? "read-only");
8080
7971
  const priceModel = String(manifest.price_model ?? "free");
8081
- const requiredAccounts = (manifest.required_connected_accounts ?? []).join(", ") || "none";
7972
+ const requiredAccounts = (manifest.required_connected_accounts ?? []).map((item) => connectedAccountRequirementLabel(item)).filter(Boolean).join(", ") || "none";
8082
7973
  const supportContact = String(manifest.support_contact ?? "replace-with-support-contact");
8083
7974
  return [
8084
7975
  `# ${name} API Usage Guide`,
@@ -8639,8 +8530,8 @@ function readmeTemplate(template) {
8639
8530
  "siglume score . --remote",
8640
8531
  "siglume preflight .",
8641
8532
  "siglume register .",
8642
- "# inspect the draft, then explicitly approve publish:",
8643
- "siglume register . --confirm",
8533
+ "# review-only staging path:",
8534
+ "siglume register . --draft-only",
8644
8535
  "```",
8645
8536
  ""
8646
8537
  ].join("\n");
@@ -8822,16 +8713,25 @@ async function runCli(argv, deps = {}) {
8822
8713
  if (report.runtime_validation_path) emit(stdout, `runtime_validation_path: ${String(report.runtime_validation_path)}`);
8823
8714
  if (report.oauth_credentials_path) emit(stdout, `oauth_credentials_path: ${String(report.oauth_credentials_path)}`);
8824
8715
  });
8825
- 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) => {
8826
- const report = await runRegistration(path, { confirm: options.confirm, submit_review: options.submitReview }, deps);
8716
+ 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) => {
8717
+ const draftOnly = Boolean(options.draftOnly);
8718
+ if (draftOnly && options.confirm) {
8719
+ throw new SiglumeProjectError("--draft-only cannot be combined with --confirm.");
8720
+ }
8721
+ if (draftOnly && options.submitReview) {
8722
+ throw new SiglumeProjectError("--draft-only cannot be combined with --submit-review.");
8723
+ }
8724
+ const shouldConfirm = Boolean(options.confirm) || !draftOnly && !options.submitReview;
8725
+ const report = await runRegistration(path, { confirm: shouldConfirm, draft_only: draftOnly, submit_review: options.submitReview }, deps);
8827
8726
  if (options.json) {
8828
8727
  emit(stdout, renderJson(report));
8829
8728
  } else {
8830
8729
  const receipt = report.receipt;
8831
- if (report.confirmation) {
8832
- emit(stdout, "Listing published.");
8833
- } else if (report.review) {
8834
- emit(stdout, "Listing published via legacy submit-review alias.");
8730
+ const published = Boolean(report.confirmation || report.review);
8731
+ if (published && receipt.registration_mode === "upgrade") {
8732
+ emit(stdout, "Upgrade registered.");
8733
+ } else if (published) {
8734
+ emit(stdout, "Registration accepted.");
8835
8735
  } else if (receipt.registration_mode === "upgrade") {
8836
8736
  emit(stdout, "Upgrade staged.");
8837
8737
  } else if (receipt.registration_mode === "refresh") {
@@ -8848,10 +8748,12 @@ async function runCli(argv, deps = {}) {
8848
8748
  if (receipt.request_id) emit(stdout, `request_id: ${receipt.request_id}`);
8849
8749
  if (report.confirmation) {
8850
8750
  const confirmation = report.confirmation;
8751
+ emit(stdout, "Listing published.");
8851
8752
  if (confirmation.status) emit(stdout, `confirmation_status: ${confirmation.status}`);
8852
8753
  if (confirmation.release?.release_status) emit(stdout, `release_status: ${confirmation.release.release_status}`);
8853
8754
  } else if (report.review) {
8854
8755
  const review = report.review;
8756
+ emit(stdout, "Listing published via legacy submit-review alias.");
8855
8757
  if (review.status) emit(stdout, `publish_status: ${review.status}`);
8856
8758
  }
8857
8759
  const preflight = report.registration_preflight;