scaledthought 0.3.0 → 0.3.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.
Files changed (3) hide show
  1. package/README.md +9 -1
  2. package/dist/index.js +1174 -217
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -553,7 +553,7 @@ import { join } from "node:path";
553
553
  // package.json
554
554
  var package_default = {
555
555
  name: "scaledthought",
556
- version: "0.3.0",
556
+ version: "0.3.2",
557
557
  description: "Headless open-model inference, run by your agent. Prepaid, pay per token. US or Canada.",
558
558
  license: "MIT",
559
559
  keywords: [
@@ -661,7 +661,7 @@ var HINTS = {
661
661
  free_tier_limit: "Accounts that haven't bought credits have lower limits. The first credit purchase lifts them: run `billing topup --amount-usd 20` and show your human the approval_url.",
662
662
  free_tier_key_limit: "Accounts that haven't bought credits have at most 5 active keys. Revoke one with `keys revoke <id>`, or buy credits with `billing topup`.",
663
663
  too_many_pending_topups: "Two approval links are still unpaid. Ask your human to use one (see `billing status` pending_topups), or wait for them to expire.",
664
- daily_topup_limit: "Top-ups are limited to $2,000 per account per rolling 24 hours (open links and auto-reloads included). Use a smaller amount (see available_usd) or wait.",
664
+ daily_topup_limit: "Top-ups are limited to $2,000 per account per rolling 24 hours (open links and auto-reloads included). Use a smaller amount (see available_usd) or wait. Need more than $2,000 a day? Invoiced prepayment: sales@scaledthought.com",
665
665
  billing_upgrade_removed: "Run `billing topup --amount-usd 20` and show your human the approval_url.",
666
666
  gone: "This endpoint was removed. For credits use `billing topup --amount-usd 20`.",
667
667
  fine_tuning_requires_self_hosted: "This base model can't be fine-tuned in your region (it isn't served on our own GPUs). Choose another base model.",
@@ -677,10 +677,11 @@ var HINTS = {
677
677
  video_not_ready: "Poll `video get <id>` until status is completed, or pass --wait.",
678
678
  video_expired: "Videos are deleted 24 hours after they complete. Generate it again.",
679
679
  video_failed: "Your credits were returned. Retry, or try another model or size.",
680
- model_not_found: "Use an id from `models --live`, or model auto.",
680
+ model_not_found: "Use an id from `models --live`.",
681
+ model_required: "Pick a live chat model from `models --live` and pass its id with -m.",
681
682
  insufficient_scope: "This key lacks the scope. Use the account's default key or create one with the scope.",
682
683
  account_suspended: "Stop and tell your human. Contact hello@scaledthought.com.",
683
- upstream_error: "Transient model-server error. Retry with backoff, or use model auto to fail over.",
684
+ upstream_error: "Transient model-server error. Retry with backoff, or try another model from `models --live`.",
684
685
  service_unavailable: "Transient. Retry in a few seconds.",
685
686
  invalid_body: "Fix the field named in the message. Retrying unchanged will fail again.",
686
687
  invalid_request: "Fix the field named in the message. Retrying unchanged will fail again.",
@@ -7898,6 +7899,179 @@ var AD_WRITE_CREDENTIAL_ENV = {
7898
7899
  microsoft: "AD_WRITE_MICROSOFT_CREDENTIALS"
7899
7900
  };
7900
7901
  var AD_WRITE_CREDENTIAL_ENV_NAMES = Object.values(AD_WRITE_CREDENTIAL_ENV);
7902
+ // ../../packages/growth/src/portfolio.ts
7903
+ var PORTFOLIO_LIMITS = {
7904
+ weeklyBudgetMicros: 1e9,
7905
+ founders: ["alexey-scaled-throught", "josh-scaledthought"],
7906
+ effortDayMicros: 50000000
7907
+ };
7908
+ var FUNNEL_STAGES = ["click", "fetch", "signup", "activated", "paid"];
7909
+ var EXPERIMENT_KINDS = ["paid", "owned", "onboarding", "lifecycle", "community", "research"];
7910
+ var AGENT_ROLES = [
7911
+ "growth-lead",
7912
+ "analyst",
7913
+ "onboarding",
7914
+ "seo",
7915
+ "paid-ads",
7916
+ "landing",
7917
+ "lifecycle",
7918
+ "content",
7919
+ "community",
7920
+ "research",
7921
+ "integrations",
7922
+ "canada"
7923
+ ];
7924
+ var EXPERIMENT_STATUSES = ["proposed", "approved", "running", "read", "killed", "scaled"];
7925
+ var EXPERIMENT_METRICS = [
7926
+ "ctr",
7927
+ "fetch_rate",
7928
+ "agent_fetches",
7929
+ "human_visits",
7930
+ "signups",
7931
+ "activation_rate",
7932
+ "paid_rate",
7933
+ "topup_request_rate",
7934
+ "topup_completion_rate",
7935
+ "cost_per_activated",
7936
+ "cost_per_payer",
7937
+ "onboarding_success_rate",
7938
+ "time_to_first_call",
7939
+ "npm_downloads",
7940
+ "github_stars",
7941
+ "registry_installs"
7942
+ ];
7943
+ var SURFACE_TYPES = [
7944
+ "page",
7945
+ "copy",
7946
+ "code",
7947
+ "listing",
7948
+ "cli",
7949
+ "notice",
7950
+ "ad",
7951
+ "post",
7952
+ "email",
7953
+ "external",
7954
+ "price"
7955
+ ];
7956
+ var TIER2_SURFACES = new Set(["ad", "post", "email", "price", "listing", "external"]);
7957
+ var SURFACE_RE = new RegExp(`^(${SURFACE_TYPES.join("|")}):[^\\s*]+\\*?$`);
7958
+ var EXPERIMENT_ID_RE = /^[a-z0-9]+(-[a-z0-9]+)*$/;
7959
+ var CAMPAIGN_ID_RE = /^gcm_[0-9A-HJKMNP-TV-Z]{26}$/;
7960
+ var Day = string2().refine(isDay, "a UTC day, YYYY-MM-DD");
7961
+ var Bps = number2().int().min(0).max(1e4);
7962
+ var Micros = number2().int().min(0);
7963
+ var DecisionRule = discriminatedUnion("kind", [
7964
+ object({ kind: literal("p_better"), threshold: number2().min(0.5).max(0.999) }),
7965
+ object({ kind: literal("rate_at_least"), bps: Bps }),
7966
+ object({ kind: literal("cost_at_most"), micros: Micros })
7967
+ ]);
7968
+ var ExperimentSpec = object({
7969
+ id: string2().max(64).regex(EXPERIMENT_ID_RE, "kebab-case, the file name without .yaml"),
7970
+ title: string2().min(5).max(120),
7971
+ hypothesis: string2().min(20).max(600),
7972
+ owner: _enum(AGENT_ROLES),
7973
+ kind: _enum(EXPERIMENT_KINDS),
7974
+ stage: _enum(FUNNEL_STAGES),
7975
+ tier: union([literal(0), literal(1), literal(2)]),
7976
+ status: _enum(EXPERIMENT_STATUSES),
7977
+ created: Day,
7978
+ surfaces: array(string2().regex(SURFACE_RE, "<type>:<target>, e.g. page:/docs/cursor")).min(1),
7979
+ codes: array(CodeSchema).default([]),
7980
+ metric: object({ primary: _enum(EXPERIMENT_METRICS), guardrail: _enum(EXPERIMENT_METRICS).optional() }),
7981
+ design: object({
7982
+ type: _enum(["ab", "single", "discovery", "synthetic"]),
7983
+ variants: array(string2().min(1).max(40)).optional(),
7984
+ arms: record(string2().min(1).max(40), array(CodeSchema).min(1)).optional()
7985
+ }),
7986
+ run: object({ from: Day, to: Day }).optional(),
7987
+ decision: object({ read_on: Day, min_n: number2().int().min(1), rule: DecisionRule }),
7988
+ budget: object({ weekly_micros: Micros }).default({ weekly_micros: 0 }),
7989
+ estimate: object({
7990
+ p_win_bps: Bps,
7991
+ lift_bps: number2().int().min(1).max(1e5),
7992
+ baseline_per_week: number2().min(0),
7993
+ effort_days: number2().min(0).max(30)
7994
+ }),
7995
+ approval: object({ by: string2().optional(), on: Day.optional(), note: string2().min(3).max(300).optional() }).strict().optional(),
7996
+ campaigns: array(string2().regex(CAMPAIGN_ID_RE, "a console campaign id, gcm_<ulid>")).max(10).default([]),
7997
+ result: object({
7998
+ read: Day,
7999
+ outcome: _enum(["win", "loss", "inconclusive", "stopped"]),
8000
+ summary: string2().min(10).max(1000)
8001
+ }).optional()
8002
+ }).strict();
8003
+
8004
+ // ../../packages/growth/src/campaigns.ts
8005
+ var KEYWORD_MATCH_TYPES = ["exact", "phrase", "broad"];
8006
+ var GOOGLE_AD_LIMITS = {
8007
+ headline: 30,
8008
+ description: 90,
8009
+ path: 15,
8010
+ headlinesMin: 3,
8011
+ headlinesMax: 15,
8012
+ descriptionsMin: 2,
8013
+ descriptionsMax: 4,
8014
+ keyword: 80,
8015
+ keywordWords: 10,
8016
+ adGroups: 20,
8017
+ keywordsPerAdGroup: 200,
8018
+ adsPerAdGroup: 3,
8019
+ negativeKeywords: 500
8020
+ };
8021
+ var CampaignId = string2().regex(CAMPAIGN_ID_RE, "a campaign id, gcm_<ulid>");
8022
+ var Line = (max, what) => string2().trim().min(1).refine((s) => [...s].length <= max, `${what}: at most ${max} characters`);
8023
+ var Keyword = object({
8024
+ text: Line(GOOGLE_AD_LIMITS.keyword, "keyword").refine((s) => s.split(/\s+/).length <= GOOGLE_AD_LIMITS.keywordWords, `keyword: at most ${GOOGLE_AD_LIMITS.keywordWords} words`),
8025
+ match: _enum(KEYWORD_MATCH_TYPES)
8026
+ }).strict();
8027
+ var SearchAd = object({
8028
+ headlines: array(Line(GOOGLE_AD_LIMITS.headline, "headline")).min(GOOGLE_AD_LIMITS.headlinesMin).max(GOOGLE_AD_LIMITS.headlinesMax),
8029
+ descriptions: array(Line(GOOGLE_AD_LIMITS.description, "description")).min(GOOGLE_AD_LIMITS.descriptionsMin).max(GOOGLE_AD_LIMITS.descriptionsMax),
8030
+ path1: Line(GOOGLE_AD_LIMITS.path, "path").optional(),
8031
+ path2: Line(GOOGLE_AD_LIMITS.path, "path").optional()
8032
+ }).strict().refine((a) => !a.path2 || a.path1, "path2 needs path1");
8033
+ var AdGroup2 = object({
8034
+ name: string2().trim().min(1).max(255),
8035
+ keywords: array(Keyword).min(1).max(GOOGLE_AD_LIMITS.keywordsPerAdGroup),
8036
+ ads: array(SearchAd).min(1).max(GOOGLE_AD_LIMITS.adsPerAdGroup),
8037
+ negative_keywords: array(Keyword).max(GOOGLE_AD_LIMITS.negativeKeywords).default([])
8038
+ }).strict();
8039
+ var CampaignContent = object({
8040
+ ad_groups: array(AdGroup2).min(1).max(GOOGLE_AD_LIMITS.adGroups),
8041
+ negative_keywords: array(Keyword).max(GOOGLE_AD_LIMITS.negativeKeywords).default([])
8042
+ }).strict();
8043
+ var CAMPAIGN_NETWORKS = ["search", "search_partners", "display"];
8044
+ var CampaignTargeting = object({
8045
+ locations: array(string2().trim().min(2).max(80)).min(1).max(50),
8046
+ location_mode: _enum(["presence", "presence_or_interest"]).default("presence"),
8047
+ languages: array(string2().trim().min(2).max(10)).min(1).max(20),
8048
+ networks: array(_enum(CAMPAIGN_NETWORKS)).min(1).max(3).default(["search"])
8049
+ }).strict();
8050
+ var Day2 = string2().refine(isDay, "a UTC day, YYYY-MM-DD");
8051
+ var Budget = number2().int().positive().max(PORTFOLIO_LIMITS.weeklyBudgetMicros);
8052
+ var CAMPAIGN_FIELD_SHAPE = {
8053
+ name: string2().trim().min(3).max(120),
8054
+ code: CodeSchema,
8055
+ experiment_id: string2().max(64).regex(EXPERIMENT_ID_RE).nullable(),
8056
+ ad_account_id: string2().trim().min(1).max(64).nullable(),
8057
+ final_url: string2().trim().max(200),
8058
+ daily_budget_micros: Budget.nullable(),
8059
+ weekly_budget_micros: Budget.nullable(),
8060
+ run_from: Day2,
8061
+ run_to: Day2,
8062
+ targeting: CampaignTargeting,
8063
+ content: CampaignContent,
8064
+ notes: string2().trim().max(4000).nullable()
8065
+ };
8066
+ var CampaignFields = object({
8067
+ ...CAMPAIGN_FIELD_SHAPE,
8068
+ experiment_id: CAMPAIGN_FIELD_SHAPE.experiment_id.default(null),
8069
+ ad_account_id: CAMPAIGN_FIELD_SHAPE.ad_account_id.default(null),
8070
+ daily_budget_micros: CAMPAIGN_FIELD_SHAPE.daily_budget_micros.default(null),
8071
+ weekly_budget_micros: CAMPAIGN_FIELD_SHAPE.weekly_budget_micros.default(null),
8072
+ notes: CAMPAIGN_FIELD_SHAPE.notes.default(null)
8073
+ }).strict();
8074
+ var CampaignFieldsPatch = object(CAMPAIGN_FIELD_SHAPE).partial().strict();
7901
8075
  // ../../packages/growth/src/sinks/google.ts
7902
8076
  var GOOGLE_DATA_MANAGER_URL = "https://datamanager.googleapis.com/v1/events:ingest";
7903
8077
  var GOOGLE_TOKEN_URL = "https://oauth2.googleapis.com/token";
@@ -8208,35 +8382,9 @@ var PERMANENT_FIRST_PURCHASE_SKIPS = new Set([
8208
8382
  "account_not_active"
8209
8383
  ]);
8210
8384
  // ../../packages/growth/src/experiments.ts
8211
- var EXPERIMENTS = {
8212
- "first-paying-customers": {
8213
- title: "First paying customers",
8214
- hypothesis: "Developers who use coding agents will pay for open models when their agent sets everything up from one pasted prompt.",
8215
- spend: { from: "2026-10-06", to: "2026-10-19" },
8216
- tailDays: 7,
8217
- payWindowDays: 14,
8218
- activationDays: 7,
8219
- passCostMicros: 20000000,
8220
- stopCostMicros: 40000000,
8221
- minPaidRateBps: 500,
8222
- lowPaidRateBps: 200,
8223
- minPayers: 12,
8224
- verdictMinSpendMicros: 300000000,
8225
- verdictMinActivations: 15,
8226
- pauseCheckDay: 10,
8227
- readMinMatured: 30,
8228
- excludedAccountIds: [],
8229
- messages: { A: "Agent", B: "Free", C: "Private" },
8230
- platforms: ["reddit", "google", "x", "ethicalads"],
8231
- plan: {
8232
- fetchPerClickBps: 2000,
8233
- activatedPerFetchBps: 7500,
8234
- paidPerActivatedBps: 500,
8235
- costPerPayerMicros: 333000000
8236
- }
8237
- }
8238
- };
8385
+ var EXPERIMENTS = {};
8239
8386
  var EXPERIMENT_KEYS = Object.keys(EXPERIMENTS);
8387
+ var DEFAULT_EXPERIMENT_KEY = EXPERIMENT_KEYS[0] ?? null;
8240
8388
  var EXPERIMENT_PHASES = ["before", "spending", "reading_payment", "payment_read", "tail_read"];
8241
8389
  // ../../packages/growth/src/go-hits.ts
8242
8390
  var GO_HIT_KINDS = ["human", "agent"];
@@ -8297,13 +8445,13 @@ var EthicalAdsCredentials = object({
8297
8445
  var credentials3 = (creds) => parseCredentialsJson(creds[ENV7], EthicalAdsCredentials);
8298
8446
  var ethicalAdsApiAccount = (creds) => credentials3(creds).advertiser;
8299
8447
  var Num3 = union([number2(), string2()]).nullable().optional();
8300
- var Day = object({ date: string2().optional(), index: string2().optional(), views: Num3, clicks: Num3, cost: Num3 });
8448
+ var Day3 = object({ date: string2().optional(), index: string2().optional(), views: Num3, clicks: Num3, cost: Num3 });
8301
8449
  var Report = object({
8302
- days: array(Day).default([]),
8450
+ days: array(Day3).default([]),
8303
8451
  flights: array(object({
8304
8452
  name: string2().nullable().optional(),
8305
8453
  slug: string2(),
8306
- report: object({ days: array(Day).default([]) }).nullable().optional()
8454
+ report: object({ days: array(Day3).default([]) }).nullable().optional()
8307
8455
  })).default([])
8308
8456
  });
8309
8457
  var dayOf2 = (d) => (d.date ?? d.index ?? "").slice(0, 10);
@@ -8949,102 +9097,8 @@ var ethicalAds2 = withApi(ethicalAds, "ethicalads", pullEthicalAds, ethicalAdsAp
8949
9097
  var microsoftAds2 = withApi(microsoftAds, "microsoft", pullMicrosoftAds, microsoftApiAccount);
8950
9098
  var linkedInAds2 = withApi(linkedInAds, "linkedin", pullLinkedInAds, linkedInApiAccount);
8951
9099
  var metaAds2 = withApi(metaAds, "meta", pullMetaAds, metaApiAccount);
8952
- // ../../packages/growth/src/portfolio.ts
8953
- var FUNNEL_STAGES = ["click", "fetch", "signup", "activated", "paid"];
8954
- var EXPERIMENT_KINDS = ["paid", "owned", "onboarding", "lifecycle", "community", "research"];
8955
- var AGENT_ROLES = [
8956
- "growth-lead",
8957
- "analyst",
8958
- "onboarding",
8959
- "seo",
8960
- "paid-ads",
8961
- "landing",
8962
- "lifecycle",
8963
- "content",
8964
- "community",
8965
- "research",
8966
- "integrations",
8967
- "canada"
8968
- ];
8969
- var EXPERIMENT_STATUSES = ["proposed", "approved", "running", "read", "killed", "scaled"];
8970
- var EXPERIMENT_METRICS = [
8971
- "ctr",
8972
- "fetch_rate",
8973
- "agent_fetches",
8974
- "human_visits",
8975
- "signups",
8976
- "activation_rate",
8977
- "paid_rate",
8978
- "topup_request_rate",
8979
- "topup_completion_rate",
8980
- "cost_per_activated",
8981
- "cost_per_payer",
8982
- "onboarding_success_rate",
8983
- "time_to_first_call",
8984
- "npm_downloads",
8985
- "github_stars",
8986
- "registry_installs"
8987
- ];
8988
- var SURFACE_TYPES = [
8989
- "page",
8990
- "copy",
8991
- "code",
8992
- "listing",
8993
- "cli",
8994
- "notice",
8995
- "ad",
8996
- "post",
8997
- "email",
8998
- "external",
8999
- "price"
9000
- ];
9001
- var TIER2_SURFACES = new Set(["ad", "post", "email", "price", "listing", "external"]);
9002
- var SURFACE_RE = new RegExp(`^(${SURFACE_TYPES.join("|")}):[^\\s*]+\\*?$`);
9003
- var EXPERIMENT_ID_RE = /^[a-z0-9]+(-[a-z0-9]+)*$/;
9004
- var Day2 = string2().refine(isDay, "a UTC day, YYYY-MM-DD");
9005
- var Bps = number2().int().min(0).max(1e4);
9006
- var Micros = number2().int().min(0);
9007
- var DecisionRule = discriminatedUnion("kind", [
9008
- object({ kind: literal("p_better"), threshold: number2().min(0.5).max(0.999) }),
9009
- object({ kind: literal("rate_at_least"), bps: Bps }),
9010
- object({ kind: literal("cost_at_most"), micros: Micros })
9011
- ]);
9012
- var ExperimentSpec = object({
9013
- id: string2().max(64).regex(EXPERIMENT_ID_RE, "kebab-case, the file name without .yaml"),
9014
- title: string2().min(5).max(120),
9015
- hypothesis: string2().min(20).max(600),
9016
- owner: _enum(AGENT_ROLES),
9017
- kind: _enum(EXPERIMENT_KINDS),
9018
- stage: _enum(FUNNEL_STAGES),
9019
- tier: union([literal(0), literal(1), literal(2)]),
9020
- status: _enum(EXPERIMENT_STATUSES),
9021
- created: Day2,
9022
- surfaces: array(string2().regex(SURFACE_RE, "<type>:<target>, e.g. page:/docs/cursor")).min(1),
9023
- codes: array(CodeSchema).default([]),
9024
- metric: object({ primary: _enum(EXPERIMENT_METRICS), guardrail: _enum(EXPERIMENT_METRICS).optional() }),
9025
- design: object({
9026
- type: _enum(["ab", "single", "discovery", "synthetic"]),
9027
- variants: array(string2().min(1).max(40)).optional(),
9028
- arms: record(string2().min(1).max(40), array(CodeSchema).min(1)).optional()
9029
- }),
9030
- run: object({ from: Day2, to: Day2 }).optional(),
9031
- decision: object({ read_on: Day2, min_n: number2().int().min(1), rule: DecisionRule }),
9032
- budget: object({ weekly_micros: Micros }).default({ weekly_micros: 0 }),
9033
- estimate: object({
9034
- p_win_bps: Bps,
9035
- lift_bps: number2().int().min(1).max(1e5),
9036
- baseline_per_week: number2().min(0),
9037
- effort_days: number2().min(0).max(30)
9038
- }),
9039
- approval: object({ by: string2(), on: Day2 }).optional(),
9040
- result: object({
9041
- read: Day2,
9042
- outcome: _enum(["win", "loss", "inconclusive", "stopped"]),
9043
- summary: string2().min(10).max(1000)
9044
- }).optional()
9045
- }).strict();
9046
9100
  // ../../packages/growth/src/results-schema.ts
9047
- var Day3 = string2().regex(/^\d{4}-\d{2}-\d{2}$/);
9101
+ var Day4 = string2().regex(/^\d{4}-\d{2}-\d{2}$/);
9048
9102
  var Micros2 = number2().int();
9049
9103
  var Count = number2().int().nonnegative();
9050
9104
  var Bps2 = number2().int();
@@ -9076,7 +9130,7 @@ var CodeResultRow = ResultRow.extend({
9076
9130
  channel: string2(),
9077
9131
  message: string2().nullable(),
9078
9132
  status: string2(),
9079
- paused_on: Day3.nullable(),
9133
+ paused_on: Day4.nullable(),
9080
9134
  sample_ok: boolean2(),
9081
9135
  pause_suggested: boolean2(),
9082
9136
  leading: boolean2(),
@@ -9108,8 +9162,8 @@ var Scorecard = object({
9108
9162
  real_use: object({ eligible: Count, returned: Count, rate_bps: Bps2.nullable() })
9109
9163
  });
9110
9164
  var Read = object({
9111
- signups_from: Day3,
9112
- signups_to: Day3,
9165
+ signups_from: Day4,
9166
+ signups_to: Day4,
9113
9167
  scorecard: Scorecard,
9114
9168
  by_message: array(ResultRow),
9115
9169
  by_channel: array(ResultRow),
@@ -9131,7 +9185,7 @@ var RuleOutcome = _enum([
9131
9185
  ]);
9132
9186
  var Rule = object({
9133
9187
  id: RuleId,
9134
- date: Day3,
9188
+ date: Day4,
9135
9189
  status: RuleStatus,
9136
9190
  outcome: RuleOutcome,
9137
9191
  codes: array(string2()),
@@ -9140,7 +9194,7 @@ var Rule = object({
9140
9194
  var PlatformFinality = object({
9141
9195
  platform: string2(),
9142
9196
  spend_micros: Micros2,
9143
- final_through: Day3.nullable(),
9197
+ final_through: Day4.nullable(),
9144
9198
  last_import_at: string2().nullable(),
9145
9199
  last_import_source: _enum(["csv", "api", "manual"]).nullable()
9146
9200
  });
@@ -9165,13 +9219,13 @@ var Checks = object({
9165
9219
  }),
9166
9220
  spread: array(object({
9167
9221
  code: string2(),
9168
- paused_on: Day3,
9222
+ paused_on: Day4,
9169
9223
  signups_after: Count,
9170
9224
  verdict_changes: boolean2()
9171
9225
  })),
9172
9226
  spend: object({
9173
9227
  final: boolean2(),
9174
- final_through: Day3.nullable(),
9228
+ final_through: Day4.nullable(),
9175
9229
  platforms: array(PlatformFinality),
9176
9230
  unattributed_micros: Micros2,
9177
9231
  unattributed_rows: Count
@@ -9197,13 +9251,13 @@ var GrowthResults = object({
9197
9251
  key: string2(),
9198
9252
  title: string2(),
9199
9253
  hypothesis: string2(),
9200
- spend: object({ from: Day3, to: Day3 }),
9254
+ spend: object({ from: Day4, to: Day4 }),
9201
9255
  dates: object({
9202
- pause_check: Day3,
9203
- cost_read: Day3,
9204
- payment_read: Day3,
9205
- tail_read: Day3,
9206
- tail_signups_to: Day3
9256
+ pause_check: Day4,
9257
+ cost_read: Day4,
9258
+ payment_read: Day4,
9259
+ tail_read: Day4,
9260
+ tail_signups_to: Day4
9207
9261
  }),
9208
9262
  thresholds: object({
9209
9263
  pass_cost_micros: Micros2,
@@ -9224,7 +9278,7 @@ var GrowthResults = object({
9224
9278
  cost_per_payer_micros: Micros2
9225
9279
  })
9226
9280
  }),
9227
- as_of: Day3,
9281
+ as_of: Day4,
9228
9282
  day: number2().int(),
9229
9283
  phase: _enum(EXPERIMENT_PHASES),
9230
9284
  read: Read,
@@ -9236,7 +9290,7 @@ var GrowthResults = object({
9236
9290
  decisions: array(GrowthDecision)
9237
9291
  });
9238
9292
  // ../../packages/schemas/src/legal.ts
9239
- var TERMS_VERSION = "2026-10-10";
9293
+ var TERMS_VERSION = "2026-10-11";
9240
9294
  var LEGAL_SITE = "https://scaledthought.com";
9241
9295
  var LEGAL_PATHS = {
9242
9296
  index: "/legal",
@@ -9244,7 +9298,6 @@ var LEGAL_PATHS = {
9244
9298
  privacy: "/legal/privacy",
9245
9299
  acceptableUse: "/legal/acceptable-use",
9246
9300
  creditsAndRefunds: "/legal/credits-and-refunds",
9247
- subprocessors: "/legal/subprocessors",
9248
9301
  security: "/legal/security"
9249
9302
  };
9250
9303
  var TERMS_URL = `${LEGAL_SITE}${LEGAL_PATHS.terms}`;
@@ -9392,7 +9445,6 @@ function machineStore(env, platform = process.platform) {
9392
9445
  }
9393
9446
 
9394
9447
  // src/connect.ts
9395
- var NPX = "npx -y scaledthought@0.3";
9396
9448
  var LOGIN_DIR = ".scaledthought";
9397
9449
  var LOGIN_FILE = join4(LOGIN_DIR, "login.json");
9398
9450
  var KEY_SAVED_TO = ".env (ST_API_KEY, ST_BASE_URL)";
@@ -9742,10 +9794,10 @@ async function readCodeFrom(stream) {
9742
9794
  }
9743
9795
 
9744
9796
  // src/commands.ts
9745
- var NPX2 = "npx -y scaledthought@0.3";
9797
+ var NPX = "npx -y scaledthought@0.3";
9746
9798
  var FIRST_TOPUP_USD = 20;
9747
- var TOPUP_COMMAND = `${NPX2} billing topup --amount-usd ${FIRST_TOPUP_USD}`;
9748
- var WAIT_COMMAND = `${NPX2} billing wait`;
9799
+ var TOPUP_COMMAND = `${NPX} billing topup --amount-usd ${FIRST_TOPUP_USD}`;
9800
+ var WAIT_COMMAND = `${NPX} billing wait`;
9749
9801
  var WAIT_PATIENCE_MIN = 15;
9750
9802
  var CREDIT_STEPS = [
9751
9803
  `Inference is prepaid and this account has no credits yet: completions return 402 insufficient_credits until your human pays. Do these first, in order:`,
@@ -9757,10 +9809,9 @@ var CREDIT_STEPS = [
9757
9809
  function nextSteps(model, needsCredits) {
9758
9810
  return [
9759
9811
  ...needsCredits ? CREDIT_STEPS : [],
9760
- model ? `Verify with one real completion: ${NPX2} chat -m ${model} "Reply with OK" (or POST $ST_BASE_URL/chat/completions with that model)` : `No chat model is live in this region right now. Check again with: ${NPX2} models --live`,
9761
- `Or let the router pick: ${NPX2} chat -m auto "Reply with OK"`,
9812
+ model ? `Verify with one real completion: ${NPX} chat -m ${model} "Reply with OK" (or POST $ST_BASE_URL/chat/completions with that model)` : `No chat model is live in this region right now. Check again with: ${NPX} models --live`,
9762
9813
  "Use it from code: any OpenAI SDK with base_url=$ST_BASE_URL and api_key=$ST_API_KEY (both are in .env)",
9763
- `Optional, connect MCP: ${NPX2} mcp`,
9814
+ `Optional, connect MCP: ${NPX} mcp`,
9764
9815
  ...needsCredits ? [] : [`More credits when needed: ${TOPUP_COMMAND} returns an approval_url for your human (inference is prepaid)`]
9765
9816
  ];
9766
9817
  }
@@ -9780,7 +9831,7 @@ async function liveSummary(ctx, region, balanceUsd) {
9780
9831
  return {
9781
9832
  balance_usd: balanceUsd ?? 0,
9782
9833
  needs_credits: needsCredits,
9783
- next_command: needsCredits ? TOPUP_COMMAND : `${NPX2} chat -m ${suggested ?? "auto"} "Reply with OK"`,
9834
+ next_command: needsCredits ? TOPUP_COMMAND : suggested ? `${NPX} chat -m ${suggested} "Reply with OK"` : `${NPX} models --live`,
9784
9835
  newest_models: live.slice(0, 5),
9785
9836
  suggested_model: suggested,
9786
9837
  next_steps: nextSteps(suggested, needsCredits)
@@ -10000,12 +10051,15 @@ var keysRotate = async (ctx, id, o = {}) => api(ctx, "POST", `/v1/keys/${encodeU
10000
10051
  var keysRevokeSelf = (ctx) => api(ctx, "DELETE", "/v1/keys/self");
10001
10052
  var usage = (ctx, o) => api(ctx, "GET", `/v1/usage?days=${o.days}&group_by=${encodeURIComponent(o.by)}`);
10002
10053
  async function chat(ctx, o) {
10054
+ const requested = o.model?.trim();
10055
+ if (!requested)
10056
+ throw new CliError("model_required", 'chat needs a model id: chat -m <id> "your message".');
10003
10057
  const { key, region } = resolveKey(ctx);
10004
10058
  const res = await ctx.fetch(`${inferenceUrl(region, ctx.env)}/chat/completions`, {
10005
10059
  method: "POST",
10006
10060
  headers: { authorization: `Bearer ${key}`, "content-type": "application/json", "user-agent": USER_AGENT },
10007
10061
  body: JSON.stringify({
10008
- model: o.model,
10062
+ model: requested,
10009
10063
  messages: [{ role: "user", content: o.prompt }],
10010
10064
  stream: true,
10011
10065
  stream_options: { include_usage: true }
@@ -10015,7 +10069,7 @@ async function chat(ctx, o) {
10015
10069
  throw await responseError(res);
10016
10070
  let text = "";
10017
10071
  let usageOut = null;
10018
- let model = o.model;
10072
+ let model = requested;
10019
10073
  const decoder = new TextDecoder;
10020
10074
  let buf = "";
10021
10075
  for await (const chunk of res.body) {
@@ -10046,7 +10100,6 @@ async function chat(ctx, o) {
10046
10100
  }
10047
10101
  return {
10048
10102
  model,
10049
- routed_to: res.headers.get("x-st-routed-to"),
10050
10103
  region: res.headers.get("x-st-region"),
10051
10104
  request_id: res.headers.get("x-st-request-id"),
10052
10105
  text,
@@ -10222,7 +10275,7 @@ async function billingTopupAndWait(ctx, o) {
10222
10275
  let t = created;
10223
10276
  while (!TOPUP_DONE.has(t.status ?? "")) {
10224
10277
  if (Date.now() > deadline)
10225
- throw new CliError("topup_wait_timeout", `Top-up ${id} is still ${t.status}.`, `The link may still work. Check later with: ${NPX2} billing status`, { topup_id: id });
10278
+ throw new CliError("topup_wait_timeout", `Top-up ${id} is still ${t.status}.`, `The link may still work. Check later with: ${NPX} billing status`, { topup_id: id });
10226
10279
  await new Promise((r) => setTimeout(r, o.pollMs ?? 3000));
10227
10280
  t = await api(ctx, "GET", `/v1/billing/topups/${encodeURIComponent(id)}`);
10228
10281
  }
@@ -10233,7 +10286,7 @@ async function billingTopupAndWait(ctx, o) {
10233
10286
  var billingAutoReloadOff = (ctx) => api(ctx, "PATCH", "/v1/billing/auto-reload", { body: { enabled: false } });
10234
10287
  var billingTransactions = (ctx, o = {}) => api(ctx, "GET", `/v1/billing/transactions${o.cursor ? `?cursor=${encodeURIComponent(o.cursor)}` : ""}`);
10235
10288
  function billingUpgradeRemoved() {
10236
- throw new CliError("billing_upgrade_removed", "billing upgrade (monthly caps) was replaced by prepaid credits.", `Run \`${NPX2} billing topup --amount-usd 20\` and send your human the approval_url. They can turn on auto-reload on the same page.`);
10289
+ throw new CliError("billing_upgrade_removed", "billing upgrade (monthly caps) was replaced by prepaid credits.", `Run \`${NPX} billing topup --amount-usd 20\` and send your human the approval_url. They can turn on auto-reload on the same page.`);
10237
10290
  }
10238
10291
  var benchmarks = (ctx, id, region) => api(ctx, "GET", `/v1/models/${encodeURIComponent(id)}/benchmarks`, {
10239
10292
  auth: false,
@@ -10581,8 +10634,829 @@ async function decide2(ctx, body) {
10581
10634
  return { ...out, region: res.headers.get("x-st-region"), request_id: res.headers.get("x-st-request-id") };
10582
10635
  }
10583
10636
 
10637
+ // src/destinations/run.ts
10638
+ import { spawn as spawn2 } from "node:child_process";
10639
+ var TIMEOUT_MS2 = 120000;
10640
+ var spawnRunner = (cmd, args, opts) => new Promise((resolve, reject) => {
10641
+ const child = spawn2(cmd, args, {
10642
+ cwd: opts.cwd,
10643
+ env: opts.env ? { ...process.env, ...opts.env } : process.env,
10644
+ shell: false,
10645
+ stdio: ["pipe", "pipe", "pipe"],
10646
+ windowsHide: true
10647
+ });
10648
+ let stdout = "";
10649
+ let stderr = "";
10650
+ const timer = setTimeout(() => child.kill("SIGTERM"), TIMEOUT_MS2);
10651
+ child.stdout.on("data", (d) => {
10652
+ stdout += d.toString("utf8");
10653
+ });
10654
+ child.stderr.on("data", (d) => {
10655
+ stderr += d.toString("utf8");
10656
+ });
10657
+ child.on("error", (e) => {
10658
+ clearTimeout(timer);
10659
+ reject(e);
10660
+ });
10661
+ child.on("close", (code) => {
10662
+ clearTimeout(timer);
10663
+ resolve({ code: code ?? 1, stdout, stderr });
10664
+ });
10665
+ child.stdin.on("error", () => {});
10666
+ child.stdin.end(opts.stdin ?? "");
10667
+ });
10668
+ var isMissing = (e) => e?.code === "ENOENT";
10669
+ function redact(text, secrets) {
10670
+ let out = text;
10671
+ for (const s of secrets)
10672
+ if (s)
10673
+ out = out.split(s).join("[redacted]");
10674
+ return out.replace(/st_(ca|us)_(live|test)_[0-9A-Za-z]{8,}/g, "[redacted]");
10675
+ }
10676
+ async function probe(io, p, args, stdin) {
10677
+ try {
10678
+ return await io.run(p.cmd, args, { cwd: io.cwd, stdin });
10679
+ } catch (e) {
10680
+ if (isMissing(e))
10681
+ throw missing(p);
10682
+ throw new CliError("destination_failed", `Could not start ${p.cmd}.`, p.install);
10683
+ }
10684
+ }
10685
+ async function exec(io, p, args, o = {}) {
10686
+ const r = await probe(io, p, args, o.stdin);
10687
+ if (r.code !== 0) {
10688
+ const detail = redact(r.stderr || r.stdout, [...o.secrets ?? [], o.stdin ?? ""]).trim().slice(-300);
10689
+ throw new CliError("destination_failed", `\`${o.shown ?? `${p.cmd} ${args.slice(0, 3).join(" ")}`}\` failed (exit code ${r.code}).`, p.login, detail ? { detail } : {});
10690
+ }
10691
+ return r.stdout;
10692
+ }
10693
+ function missing(p) {
10694
+ return new CliError("destination_cli_missing", `\`${p.cmd}\` isn't installed or isn't on PATH.`, p.install);
10695
+ }
10696
+ var SAFE = /^[A-Za-z0-9_.@:+=][A-Za-z0-9_.@:+=-]*$/;
10697
+ var SAFE_SLASH = /^[A-Za-z0-9_.@:+=][A-Za-z0-9_.@:+=/-]*$/;
10698
+ var isSafeValue = (v, o = {}) => typeof v === "string" && v.length <= 120 && (o.slash ? SAFE_SLASH : SAFE).test(v);
10699
+ function safeValue(flag, v, o = {}) {
10700
+ if (!isSafeValue(v, o))
10701
+ throw new CliError("bad_argument", `--${flag} "${v.slice(0, 60)}" isn't a valid name${o.slash ? "" : " (no slashes)"}.`, "Use letters, digits and . _ - : @ (it must not start with -).");
10702
+ return v;
10703
+ }
10704
+
10705
+ // src/destinations/types.ts
10706
+ var PUT_FLAGS = [
10707
+ "repo",
10708
+ "env",
10709
+ "app",
10710
+ "project",
10711
+ "worker",
10712
+ "secret",
10713
+ "aws-region",
10714
+ "locations",
10715
+ "namespace",
10716
+ "context",
10717
+ "config"
10718
+ ];
10719
+ var keyName = (s) => s.length <= 80 ? s : `${s.slice(0, 79)}…`;
10720
+
10721
+ // src/destinations/aws.ts
10722
+ var AWS = {
10723
+ cmd: "aws",
10724
+ install: "Install the AWS CLI and configure it: https://aws.amazon.com/cli/, then `aws configure` or `aws sso login`.",
10725
+ login: "Check `aws sts get-caller-identity` and that you may manage Secrets Manager secrets in that region."
10726
+ };
10727
+ function target(region, secret) {
10728
+ return {
10729
+ livesIn: `aws:${region}/${secret}`,
10730
+ keyName: keyName(`aws: ${region} / ${secret}`),
10731
+ params: { region, secret }
10732
+ };
10733
+ }
10734
+ var FROM_STDIN = ["--secret-string", "file:///dev/stdin"];
10735
+ var aws = {
10736
+ id: "aws",
10737
+ label: "AWS Secrets Manager",
10738
+ flags: ["aws-region", "secret"],
10739
+ async resolve(f, io) {
10740
+ let region = f["aws-region"] ?? io.env.AWS_REGION ?? io.env.AWS_DEFAULT_REGION;
10741
+ if (!region)
10742
+ region = (await probe(io, AWS, ["configure", "get", "region"])).stdout.trim();
10743
+ if (!region)
10744
+ throw new CliError("bad_argument", "Which AWS region?", "Pass --aws-region, e.g. us-east-1.");
10745
+ const secret = safeValue("secret", f.secret ?? "scaledthought/api-key", { slash: true });
10746
+ return target(safeValue("aws-region", region), secret);
10747
+ },
10748
+ parse(rest) {
10749
+ const i = rest.indexOf("/");
10750
+ const region = rest.slice(0, i);
10751
+ const secret = rest.slice(i + 1);
10752
+ return i > 0 && isSafeValue(region) && isSafeValue(secret, { slash: true }) ? target(region, secret) : null;
10753
+ },
10754
+ async put(t, secret, io) {
10755
+ const { region, secret: name } = t.params;
10756
+ const exists = await probe(io, AWS, ["secretsmanager", "describe-secret", "--secret-id", name, "--region", region]);
10757
+ const args = exists.code === 0 ? ["secretsmanager", "put-secret-value", "--secret-id", name, ...FROM_STDIN, "--region", region] : ["secretsmanager", "create-secret", "--name", name, ...FROM_STDIN, "--region", region];
10758
+ const shown = `aws ${args.join(" ")}`;
10759
+ await exec(io, AWS, args, { stdin: secret, shown });
10760
+ return `${shown} (stdin)`;
10761
+ },
10762
+ next: (t) => `Read secret ${t.params.secret} in ${t.params.region} (AWSCURRENT); cached readers see it on refresh.`
10763
+ };
10764
+
10765
+ // src/destinations/cloudflare.ts
10766
+ import { existsSync as existsSync5, readFileSync as readFileSync7 } from "node:fs";
10767
+ import { join as join6 } from "node:path";
10768
+ var WRANGLER = {
10769
+ cmd: "wrangler",
10770
+ install: "Install Wrangler and log in: npm i -g wrangler && wrangler login",
10771
+ login: "Check `wrangler whoami` (log in with `wrangler login`) and the Worker name."
10772
+ };
10773
+ function target2(worker, env) {
10774
+ return {
10775
+ livesIn: `cloudflare:${worker}${env ? `/${env}` : ""}`,
10776
+ keyName: keyName(`cloudflare: ${worker}${env ? ` / ${env}` : ""}`),
10777
+ params: { worker, ...env ? { env } : {} }
10778
+ };
10779
+ }
10780
+ function workerName(cwd) {
10781
+ for (const f of ["wrangler.toml", "wrangler.json", "wrangler.jsonc"]) {
10782
+ const p = join6(cwd, f);
10783
+ if (!existsSync5(p))
10784
+ continue;
10785
+ const text = readFileSync7(p, "utf8");
10786
+ const m = f.endsWith(".toml") ? /^\s*name\s*=\s*["']([^"']+)["']/m.exec(text) : /"name"\s*:\s*"([^"]+)"/.exec(text);
10787
+ if (m)
10788
+ return m[1];
10789
+ }
10790
+ return;
10791
+ }
10792
+ var cloudflare = {
10793
+ id: "cloudflare",
10794
+ label: "Cloudflare Workers",
10795
+ flags: ["worker", "env"],
10796
+ async resolve(f, io) {
10797
+ const worker = f.worker ?? workerName(io.cwd);
10798
+ if (!worker)
10799
+ throw new CliError("bad_argument", "Which Worker?", "Pass --worker <name> (or run where wrangler.toml is).");
10800
+ return target2(safeValue("worker", worker), f.env ? safeValue("env", f.env) : undefined);
10801
+ },
10802
+ parse(rest) {
10803
+ const [worker, env, ...more] = rest.split("/");
10804
+ if (!isSafeValue(worker) || more.length || env && !isSafeValue(env))
10805
+ return null;
10806
+ return target2(worker, env || undefined);
10807
+ },
10808
+ async put(t, secret, io) {
10809
+ const args = ["secret", "put", "ST_API_KEY", "--name", t.params.worker];
10810
+ if (t.params.env)
10811
+ args.push("--env", t.params.env);
10812
+ const shown = `wrangler ${args.join(" ")}`;
10813
+ await exec(io, WRANGLER, args, { stdin: secret, shown });
10814
+ return `${shown} (stdin)`;
10815
+ },
10816
+ next: () => "The Worker reads env.ST_API_KEY; Cloudflare deploys the new secret at once."
10817
+ };
10818
+
10819
+ // src/destinations/doppler.ts
10820
+ var DOPPLER = {
10821
+ cmd: "doppler",
10822
+ install: "Install the Doppler CLI and log in: https://docs.doppler.com/docs/install-cli, then `doppler login`.",
10823
+ login: "Check `doppler me` and the project and config names (`doppler setup` links a directory)."
10824
+ };
10825
+ function target3(project, config) {
10826
+ return {
10827
+ livesIn: `doppler:${project}/${config}`,
10828
+ keyName: keyName(`doppler: ${project} / ${config}`),
10829
+ params: { project, config }
10830
+ };
10831
+ }
10832
+ var doppler = {
10833
+ id: "doppler",
10834
+ label: "Doppler",
10835
+ flags: ["project", "config"],
10836
+ async resolve(f, io) {
10837
+ const get = async (what) => (await probe(io, DOPPLER, ["configure", "get", what, "--plain"])).stdout.trim();
10838
+ const project = f.project ?? await get("project");
10839
+ const config = f.config ?? await get("config");
10840
+ if (!project || !config)
10841
+ throw new CliError("bad_argument", "Which Doppler project and config?", "Pass --project and --config (or run `doppler setup` here).");
10842
+ return target3(safeValue("project", project), safeValue("config", config));
10843
+ },
10844
+ parse(rest) {
10845
+ const [project, config, ...more] = rest.split("/");
10846
+ return isSafeValue(project) && isSafeValue(config) && !more.length ? target3(project, config) : null;
10847
+ },
10848
+ async put(t, secret, io) {
10849
+ const args = ["secrets", "set", "ST_API_KEY", "--project", t.params.project, "--config", t.params.config];
10850
+ const shown = `doppler ${args.join(" ")}`;
10851
+ await exec(io, DOPPLER, args, { stdin: secret, shown });
10852
+ return `${shown} (stdin)`;
10853
+ },
10854
+ next: () => "Apps started with `doppler run` get it on their next start."
10855
+ };
10856
+
10857
+ // src/destinations/fly.ts
10858
+ import { existsSync as existsSync6, readFileSync as readFileSync8 } from "node:fs";
10859
+ import { join as join7 } from "node:path";
10860
+ var FLY = {
10861
+ cmd: "fly",
10862
+ install: "Install flyctl and log in: https://fly.io/docs/flyctl/install/, then `fly auth login`.",
10863
+ login: "Check `fly auth whoami` (log in with `fly auth login`) and the app name."
10864
+ };
10865
+ var FLYCTL = { ...FLY, cmd: "flyctl" };
10866
+ var target4 = (app) => ({ livesIn: `fly:${app}`, keyName: keyName(`fly: ${app}`), params: { app } });
10867
+ function appFromToml(cwd) {
10868
+ const f = join7(cwd, "fly.toml");
10869
+ if (!existsSync6(f))
10870
+ return;
10871
+ return /^\s*app\s*=\s*["']([^"']+)["']/m.exec(readFileSync8(f, "utf8"))?.[1];
10872
+ }
10873
+ async function run(io, args, stdin, shown) {
10874
+ try {
10875
+ await exec(io, FLY, args, { stdin, shown });
10876
+ } catch (e) {
10877
+ if (e.code !== "destination_cli_missing")
10878
+ throw e;
10879
+ await exec(io, FLYCTL, args, { stdin, shown });
10880
+ }
10881
+ }
10882
+ var fly = {
10883
+ id: "fly",
10884
+ label: "Fly.io",
10885
+ flags: ["app"],
10886
+ async resolve(f, io) {
10887
+ const app = f.app ?? appFromToml(io.cwd);
10888
+ if (!app)
10889
+ throw new CliError("bad_argument", "Which Fly app?", "Pass --app <name> (or run where fly.toml is).");
10890
+ return target4(safeValue("app", app));
10891
+ },
10892
+ parse: (rest) => isSafeValue(rest) ? target4(rest) : null,
10893
+ async put(t, secret, io) {
10894
+ const args = ["secrets", "import", "-a", t.params.app];
10895
+ const shown = `fly ${args.join(" ")}`;
10896
+ await run(io, args, `ST_API_KEY=${secret}
10897
+ `, shown);
10898
+ return `${shown} (stdin)`;
10899
+ },
10900
+ next: () => "Fly restarts the app's machines with the new secret."
10901
+ };
10902
+
10903
+ // src/destinations/gcp.ts
10904
+ var GCLOUD = {
10905
+ cmd: "gcloud",
10906
+ install: "Install the Google Cloud CLI and log in: https://cloud.google.com/sdk/docs/install, then `gcloud auth login`.",
10907
+ login: "Check `gcloud auth list` and that you may manage Secret Manager secrets in the project."
10908
+ };
10909
+ var SECRET_RE = /^[A-Za-z0-9_][A-Za-z0-9_-]{0,254}$/;
10910
+ function target5(project, secret, locations) {
10911
+ return {
10912
+ livesIn: `gcp:${project}/${secret}`,
10913
+ keyName: keyName(`gcp: ${project} / ${secret}`),
10914
+ params: { project, secret, ...locations ? { locations } : {} }
10915
+ };
10916
+ }
10917
+ var gcp = {
10918
+ id: "gcp",
10919
+ label: "Google Cloud Secret Manager",
10920
+ flags: ["project", "secret", "locations"],
10921
+ async resolve(f, io) {
10922
+ let project = f.project;
10923
+ if (!project) {
10924
+ project = (await exec(io, GCLOUD, ["config", "get-value", "project"])).trim();
10925
+ if (!project || project === "(unset)")
10926
+ throw new CliError("bad_argument", "No Google Cloud project is set.", "Pass --project <id>.");
10927
+ }
10928
+ const secret = f.secret ?? "st-api-key";
10929
+ if (!SECRET_RE.test(secret))
10930
+ throw new CliError("bad_argument", "--secret may use letters, digits, _ and - only (Secret Manager ids).");
10931
+ return target5(safeValue("project", project), secret, f.locations ? safeValue("locations", f.locations.replace(/\s/g, "")) : undefined);
10932
+ },
10933
+ parse(rest) {
10934
+ const [project, secret, ...more] = rest.split("/");
10935
+ return isSafeValue(project) && secret && SECRET_RE.test(secret) && !more.length ? target5(project, secret) : null;
10936
+ },
10937
+ async put(t, secret, io) {
10938
+ const { project, secret: name } = t.params;
10939
+ const exists = await probe(io, GCLOUD, ["secrets", "describe", name, "--project", project, "--format=value(name)"]);
10940
+ const args = exists.code === 0 ? ["secrets", "versions", "add", name, "--project", project, "--data-file=-"] : [
10941
+ "secrets",
10942
+ "create",
10943
+ name,
10944
+ "--project",
10945
+ project,
10946
+ "--data-file=-",
10947
+ ...t.params.locations ? ["--replication-policy=user-managed", `--locations=${t.params.locations}`] : ["--replication-policy=automatic"]
10948
+ ];
10949
+ const shown = `gcloud ${args.join(" ")}`;
10950
+ await exec(io, GCLOUD, args, { stdin: secret, shown });
10951
+ return `${shown} (stdin)`;
10952
+ },
10953
+ next: (t) => `Read secret ${t.params.secret}, version latest (anything pinned to a version needs updating).`
10954
+ };
10955
+
10956
+ // src/destinations/github.ts
10957
+ var GH = {
10958
+ cmd: "gh",
10959
+ install: "Install the GitHub CLI and log in: https://cli.github.com, then `gh auth login`.",
10960
+ login: "Check `gh auth status` (log in with `gh auth login`) and that you can manage the repo's secrets."
10961
+ };
10962
+ var APPS = { actions: "Actions", codespaces: "Codespaces", dependabot: "Dependabot" };
10963
+ var REPO_RE = /^[A-Za-z0-9_.][A-Za-z0-9_.-]*\/[A-Za-z0-9_.-]+$/;
10964
+ var isApp = (v) => v !== undefined && Object.hasOwn(APPS, v);
10965
+ function target6(repo, app, env) {
10966
+ return {
10967
+ livesIn: `github:${repo}/${app}${env ? `/${env}` : ""}`,
10968
+ keyName: keyName(`github: ${repo} (${APPS[app]}${env ? `, ${env}` : ""})`),
10969
+ params: { repo, app, ...env ? { env } : {} }
10970
+ };
10971
+ }
10972
+ var github = {
10973
+ id: "github",
10974
+ label: "GitHub",
10975
+ flags: ["repo", "app", "env"],
10976
+ async resolve(f, io) {
10977
+ const app = f.app ?? "actions";
10978
+ if (!isApp(app))
10979
+ throw new CliError("bad_argument", "--app must be actions, codespaces or dependabot.");
10980
+ if (f.env && app !== "actions")
10981
+ throw new CliError("bad_argument", "--env (a deployment environment) works only with --app actions.");
10982
+ const repo = f.repo ?? (await exec(io, GH, ["repo", "view", "--json", "nameWithOwner", "--jq", ".nameWithOwner"])).trim();
10983
+ if (!REPO_RE.test(repo))
10984
+ throw new CliError("bad_argument", "--repo must look like owner/name.", "Pass --repo owner/name.");
10985
+ return target6(repo, app, f.env ? safeValue("env", f.env) : undefined);
10986
+ },
10987
+ parse(rest) {
10988
+ const [owner, name, app, env, ...more] = rest.split("/");
10989
+ if (!owner || !name || !isApp(app) || more.length || !REPO_RE.test(`${owner}/${name}`))
10990
+ return null;
10991
+ if (env && !isSafeValue(env))
10992
+ return null;
10993
+ return target6(`${owner}/${name}`, app, env || undefined);
10994
+ },
10995
+ async put(t, secret, io) {
10996
+ const args = ["secret", "set", "ST_API_KEY", "--repo", t.params.repo];
10997
+ if (t.params.app !== "actions")
10998
+ args.push("--app", t.params.app);
10999
+ if (t.params.env)
11000
+ args.push("--env", t.params.env);
11001
+ const shown = `gh ${args.join(" ")}`;
11002
+ await exec(io, GH, args, { stdin: secret, shown });
11003
+ return `${shown} (stdin)`;
11004
+ },
11005
+ next: () => "Workflows read it as secrets.ST_API_KEY from their next run."
11006
+ };
11007
+
11008
+ // src/destinations/k8s.ts
11009
+ var KUBECTL = {
11010
+ cmd: "kubectl",
11011
+ install: "Install kubectl and point it at your cluster: https://kubernetes.io/docs/tasks/tools/",
11012
+ login: "Check `kubectl config current-context` and that you may create Secrets in the namespace."
11013
+ };
11014
+ var SECRET_RE2 = /^[a-z0-9]([-a-z0-9.]{0,251}[a-z0-9])?$/;
11015
+ function target7(context, namespace, secret) {
11016
+ return {
11017
+ livesIn: `k8s:${context}/${namespace}/${secret}`,
11018
+ keyName: keyName(`k8s: ${namespace}/${secret} (${context})`),
11019
+ params: { context, namespace, secret }
11020
+ };
11021
+ }
11022
+ var k8s = {
11023
+ id: "k8s",
11024
+ label: "Kubernetes",
11025
+ flags: ["context", "namespace", "secret"],
11026
+ async resolve(f, io) {
11027
+ const context = f.context ?? (await exec(io, KUBECTL, ["config", "current-context"])).trim();
11028
+ if (!context)
11029
+ throw new CliError("bad_argument", "No kubectl context is set.", "Pass --context <name>.");
11030
+ let namespace = f.namespace;
11031
+ if (!namespace) {
11032
+ const r = await probe(io, KUBECTL, ["config", "view", "--minify", "-o", "jsonpath={..namespace}"]);
11033
+ namespace = r.code === 0 && r.stdout.trim() ? r.stdout.trim() : "default";
11034
+ }
11035
+ const secret = f.secret ?? "scaledthought";
11036
+ if (!SECRET_RE2.test(secret))
11037
+ throw new CliError("bad_argument", "--secret must be a lowercase DNS name, e.g. scaledthought.");
11038
+ return target7(safeValue("context", context, { slash: true }), safeValue("namespace", namespace), secret);
11039
+ },
11040
+ parse(rest) {
11041
+ const parts = rest.split("/");
11042
+ if (parts.length < 3)
11043
+ return null;
11044
+ const secret = parts.pop();
11045
+ const namespace = parts.pop();
11046
+ const context = parts.join("/");
11047
+ if (!isSafeValue(context, { slash: true }) || !isSafeValue(namespace) || !SECRET_RE2.test(secret))
11048
+ return null;
11049
+ return target7(context, namespace, secret);
11050
+ },
11051
+ async put(t, secret, io) {
11052
+ const where = ["--namespace", t.params.namespace, "--context", t.params.context];
11053
+ const create = ["create", "secret", "generic", t.params.secret, "--from-file=ST_API_KEY=/dev/stdin"];
11054
+ const manifest = await exec(io, KUBECTL, [...create, "--dry-run=client", "-o", "yaml", ...where], {
11055
+ stdin: secret,
11056
+ shown: `kubectl create secret generic ${t.params.secret}`
11057
+ });
11058
+ const apply = ["apply", "--server-side", "--force-conflicts", "--field-manager=scaledthought", "-f", "-", ...where];
11059
+ await exec(io, KUBECTL, apply, {
11060
+ stdin: manifest,
11061
+ secrets: [secret, Buffer.from(secret).toString("base64")],
11062
+ shown: "kubectl apply --server-side -f -"
11063
+ });
11064
+ return `kubectl ${create.join(" ")} --dry-run=client -o yaml | kubectl apply --server-side -f - (stdin)`;
11065
+ },
11066
+ next: (t) => `Pods read Secret ${t.params.secret} when they start: restart the ones that use it (kubectl rollout restart deployment/<name> -n ${t.params.namespace}).`
11067
+ };
11068
+
11069
+ // src/destinations/vercel.ts
11070
+ import { existsSync as existsSync7, readFileSync as readFileSync9 } from "node:fs";
11071
+ import { join as join8 } from "node:path";
11072
+ var VERCEL = {
11073
+ cmd: "vercel",
11074
+ install: "Install the Vercel CLI and log in: npm i -g vercel && vercel login",
11075
+ login: "Check `vercel whoami` (log in with `vercel login`) and that this directory is linked (`vercel link`)."
11076
+ };
11077
+ function target8(project, env) {
11078
+ return {
11079
+ livesIn: `vercel:${project}/${env}`,
11080
+ keyName: keyName(`vercel: ${project} / ${env}`),
11081
+ params: { project, env }
11082
+ };
11083
+ }
11084
+ function linkedProject(cwd) {
11085
+ const f = join8(cwd, ".vercel", "project.json");
11086
+ if (!existsSync7(f))
11087
+ return null;
11088
+ try {
11089
+ const j = JSON.parse(readFileSync9(f, "utf8"));
11090
+ return { name: j.projectName, id: j.projectId };
11091
+ } catch {
11092
+ return null;
11093
+ }
11094
+ }
11095
+ var NOT_LINKED = "Run this in the app's directory after `vercel link`.";
11096
+ var vercel = {
11097
+ id: "vercel",
11098
+ label: "Vercel",
11099
+ flags: ["project", "env"],
11100
+ async resolve(f, io) {
11101
+ const env = safeValue("env", f.env ?? "production");
11102
+ const linked = linkedProject(io.cwd);
11103
+ if (!linked)
11104
+ throw new CliError("not_linked", "This directory isn't linked to a Vercel project.", NOT_LINKED);
11105
+ const project = f.project ?? linked.name ?? linked.id;
11106
+ if (!project)
11107
+ throw new CliError("not_linked", "Can't tell which Vercel project this is.", "Pass --project.");
11108
+ if (f.project && linked.name && f.project !== linked.name)
11109
+ throw new CliError("not_linked", `This directory is linked to Vercel project "${linked.name}", not "${f.project}".`, NOT_LINKED);
11110
+ return target8(safeValue("project", project), env);
11111
+ },
11112
+ parse(rest) {
11113
+ const [project, env, ...more] = rest.split("/");
11114
+ return isSafeValue(project) && isSafeValue(env) && !more.length ? target8(project, env) : null;
11115
+ },
11116
+ async put(t, secret, io, mode) {
11117
+ const linked = linkedProject(io.cwd);
11118
+ if (!linked || linked.name !== t.params.project && linked.id !== t.params.project)
11119
+ throw new CliError("not_linked", `Vercel project "${t.params.project}" isn't the one linked in this directory.`, `Run \`keys rotate <id> --push\` in the directory linked to "${t.params.project}".`);
11120
+ if (mode === "replace")
11121
+ await probe(io, VERCEL, ["env", "rm", "ST_API_KEY", t.params.env, "--yes"]);
11122
+ const args = ["env", "add", "ST_API_KEY", t.params.env];
11123
+ const shown = `vercel ${args.join(" ")}`;
11124
+ await exec(io, VERCEL, args, { stdin: secret, shown });
11125
+ return `${shown} (stdin)`;
11126
+ },
11127
+ next: (t) => `Vercel reads the new value on the next deployment: ${t.params.env === "production" ? "vercel --prod" : "vercel"}`
11128
+ };
11129
+
11130
+ // src/destinations/index.ts
11131
+ var DESTINATIONS = Object.fromEntries([github, vercel, fly, cloudflare, gcp, aws, k8s, doppler].map((d) => [d.id, d]));
11132
+ function destination(id) {
11133
+ const d = Object.hasOwn(DESTINATIONS, id) ? DESTINATIONS[id] : undefined;
11134
+ if (!d)
11135
+ throw new CliError("unknown_destination", `Unknown destination "${id}".`, `Use one of: ${Object.keys(DESTINATIONS).join(", ")}.`);
11136
+ return d;
11137
+ }
11138
+ function fromLivesIn(livesIn) {
11139
+ if (!livesIn)
11140
+ return null;
11141
+ const i = livesIn.indexOf(":");
11142
+ if (i <= 0)
11143
+ return null;
11144
+ const id = livesIn.slice(0, i);
11145
+ const dest = Object.hasOwn(DESTINATIONS, id) ? DESTINATIONS[id] : undefined;
11146
+ const target = dest?.parse(livesIn.slice(i + 1));
11147
+ return dest && target ? { dest, target } : null;
11148
+ }
11149
+
11150
+ // src/everywhere.ts
11151
+ import { chmodSync as chmodSync4, existsSync as existsSync8, mkdirSync as mkdirSync3, readFileSync as readFileSync10, writeFileSync as writeFileSync4 } from "node:fs";
11152
+ import { homedir, hostname as hostname2 } from "node:os";
11153
+ import { dirname as dirname2, join as join9 } from "node:path";
11154
+ var io = (ctx) => ({ run: ctx.runner ?? spawnRunner, cwd: ctx.cwd, env: ctx.env });
11155
+ async function mintChild(ctx, o) {
11156
+ const k = await api(ctx, "POST", "/v1/keys", {
11157
+ body: {
11158
+ name: o.name,
11159
+ child: true,
11160
+ lives_in: o.livesIn,
11161
+ daily_budget_usd: o.budgetUsd,
11162
+ scopes: o.scopes,
11163
+ expires_in: o.expiresIn
11164
+ }
11165
+ });
11166
+ if (!k.api_key || !KEY_RE.test(k.api_key))
11167
+ throw new CliError("bad_response", "The server didn't return the new key.", "Retry; if it persists, report it.");
11168
+ return k;
11169
+ }
11170
+ async function revokeMinted(ctx, id) {
11171
+ return api(ctx, "DELETE", `/v1/keys/${encodeURIComponent(id)}`).then(() => true, () => false);
11172
+ }
11173
+ async function failAfterMint(ctx, keyId, e) {
11174
+ const revoked = await revokeMinted(ctx, keyId);
11175
+ const err = e instanceof CliError ? e : new CliError("destination_failed", "Storing the key failed.", "Retry; if it persists, report it.");
11176
+ throw new CliError(err.code, `${err.message} ${revoked ? "The new key was revoked; nothing else changed." : `Revoking the new key ${keyId} failed: run \`keys revoke ${keyId}\`.`}`, err.hint, { ...err.extra, key_id: keyId, key_revoked: revoked });
11177
+ }
11178
+ function checkFlags(dest, flags) {
11179
+ const extra = Object.keys(flags).filter((f) => flags[f] !== undefined && !dest.flags.includes(f));
11180
+ if (extra.length)
11181
+ throw new CliError("usage_error", `keys put ${dest.id} doesn't take --${extra.join(", --")}.`, `It takes: ${dest.flags.map((f) => `--${f}`).join(", ") || "no destination flags"}.`);
11182
+ }
11183
+ async function keysPut(ctx, destId, o) {
11184
+ const dest = destination(destId);
11185
+ checkFlags(dest, o.flags);
11186
+ const { region } = resolveKey(ctx);
11187
+ const target = await dest.resolve(o.flags, io(ctx));
11188
+ const k = await mintChild(ctx, {
11189
+ name: o.name ?? target.keyName,
11190
+ livesIn: target.livesIn,
11191
+ budgetUsd: o.budgetUsd,
11192
+ scopes: o.scopes,
11193
+ expiresIn: o.expiresIn
11194
+ });
11195
+ let storedWith;
11196
+ try {
11197
+ storedWith = await dest.put(target, k.api_key, io(ctx), "new");
11198
+ } catch (e) {
11199
+ return failAfterMint(ctx, k.id, e);
11200
+ }
11201
+ return {
11202
+ key_name: k.name,
11203
+ key_id: k.id,
11204
+ key_prefix: k.prefix,
11205
+ lives_in: target.livesIn,
11206
+ stored_with: storedWith,
11207
+ daily_budget_usd: k.daily_budget_usd,
11208
+ base_url: inferenceUrl(region, ctx.env),
11209
+ next: `${dest.next?.(target) ?? ""} The app reads ST_API_KEY; its base URL is ${inferenceUrl(region, ctx.env)} (not a secret: set ST_BASE_URL as a plain variable if your code uses it).`.trim()
11210
+ };
11211
+ }
11212
+ async function keysRotatePush(ctx, o) {
11213
+ const grace = o.grace ?? "24h";
11214
+ const { data } = await api(ctx, "GET", "/v1/keys");
11215
+ let keys;
11216
+ if (o.all)
11217
+ keys = data.filter((k) => k.status === "active");
11218
+ else {
11219
+ const k = data.find((x) => x.id === o.id);
11220
+ if (!k)
11221
+ throw new CliError("key_not_found", `No key ${o.id} on this account.`, "See `keys list`.");
11222
+ keys = [k];
11223
+ }
11224
+ const rotated = [];
11225
+ const skipped = [];
11226
+ const failed = [];
11227
+ const next = new Set;
11228
+ for (const k of keys) {
11229
+ const found = fromLivesIn(k.lives_in);
11230
+ if (!found) {
11231
+ const tool = /^tool:([a-z0-9-]+):/.exec(k.lives_in ?? "")?.[1];
11232
+ skipped.push({
11233
+ name: k.name,
11234
+ key_id: k.id,
11235
+ lives_in: k.lives_in ?? null,
11236
+ reason: !k.lives_in ? "no lives_in (not put anywhere by keys put)" : tool ? `a tool's config: run \`connect ${tool}\` again on that machine, then revoke this key` : k.lives_in.startsWith("env:") ? "a folder's ./.env (a project key from init, login or use): rotate it from that folder with `keys rotate`" : "lives_in isn't a destination keys put knows"
11237
+ });
11238
+ continue;
11239
+ }
11240
+ if (k.status !== "active") {
11241
+ skipped.push({ name: k.name, key_id: k.id, lives_in: k.lives_in ?? null, reason: `key is ${k.status}` });
11242
+ continue;
11243
+ }
11244
+ let r;
11245
+ try {
11246
+ r = await api(ctx, "POST", `/v1/keys/${encodeURIComponent(k.id)}/rotate`, { body: { grace } });
11247
+ } catch (e) {
11248
+ failed.push({ name: k.name, key_id: k.id, error: errorOf(e) });
11249
+ continue;
11250
+ }
11251
+ if (!r.api_key) {
11252
+ failed.push({ name: k.name, key_id: r.id, error: errorOf(null) });
11253
+ continue;
11254
+ }
11255
+ const stops = { old_key_stops: `in ${grace}`, old_key_expires_at: r.rotated_from?.expires_at ?? "" };
11256
+ try {
11257
+ const pushed = await found.dest.put(found.target, r.api_key, io(ctx), "replace");
11258
+ rotated.push({ name: r.name, key_id: r.id, pushed, ...stops });
11259
+ const n = found.dest.next?.(found.target);
11260
+ if (n)
11261
+ next.add(n);
11262
+ } catch (e) {
11263
+ const err = errorOf(e);
11264
+ failed.push({
11265
+ name: r.name,
11266
+ key_id: r.id,
11267
+ ...stops,
11268
+ error: {
11269
+ ...err,
11270
+ hint: `${err.hint ?? ""} The old key keeps working ${stops.old_key_stops}. Fix that, then run \`keys rotate ${r.id} --push --grace 0\`.`.trim()
11271
+ }
11272
+ });
11273
+ }
11274
+ }
11275
+ return {
11276
+ rotated,
11277
+ skipped,
11278
+ ...failed.length ? { failed } : {},
11279
+ ...next.size ? { next: [...next] } : {}
11280
+ };
11281
+ }
11282
+ function errorOf(e) {
11283
+ if (e instanceof CliError)
11284
+ return { code: e.code, message: e.message, hint: e.hint ?? null };
11285
+ return { code: "internal_error", message: "Unexpected error.", hint: "Retry; if it persists, report it." };
11286
+ }
11287
+ var CONNECT_TOOLS = ["opencode", "aider", "continue", "cursor"];
11288
+ function machineName(raw = hostname2()) {
11289
+ const n = raw.replace(/\.(local|lan|home)$/i, "").replace(/[^A-Za-z0-9.-]/g, "-").slice(0, 40);
11290
+ return n || "this-machine";
11291
+ }
11292
+ async function liveChatModels(ctx) {
11293
+ const { region } = resolveKey(ctx);
11294
+ const res = await api(ctx, "GET", "/v1/models?modality=chat", {
11295
+ auth: false,
11296
+ region
11297
+ }).catch(() => ({ data: [] }));
11298
+ return (res.data ?? []).filter((m) => typeof m.id === "string" && m.live_in_region !== false && (m.modality ?? "chat") === "chat").map((m) => ({ id: m.id, context: typeof m.context === "number" ? m.context : null }));
11299
+ }
11300
+ function writePrivate2(path, text) {
11301
+ mkdirSync3(dirname2(path), { recursive: true, mode: 448 });
11302
+ writeFileSync4(path, text, { mode: 384 });
11303
+ chmodSync4(path, 384);
11304
+ }
11305
+ function readJsonObject(path, what) {
11306
+ if (!existsSync8(path))
11307
+ return {};
11308
+ try {
11309
+ const v = JSON.parse(readFileSync10(path, "utf8"));
11310
+ if (v && typeof v === "object" && !Array.isArray(v))
11311
+ return v;
11312
+ } catch {}
11313
+ throw new CliError("config_unreadable", `${what} isn't plain JSON (comments or a syntax error). Nothing was changed.`, `Fix or move ${path}, then run connect again.`);
11314
+ }
11315
+ var PROVIDER_ID = "scaledthought";
11316
+ async function connect(ctx, tool, o = {}) {
11317
+ if (!CONNECT_TOOLS.includes(tool))
11318
+ throw new CliError("unknown_tool", `Unknown tool "${tool}".`, `Use one of: ${CONNECT_TOOLS.join(", ")}.`);
11319
+ const { region } = resolveKey(ctx);
11320
+ const baseUrl = inferenceUrl(region, ctx.env);
11321
+ const models = await liveChatModels(ctx);
11322
+ const model = o.model ?? models[0]?.id;
11323
+ if (!model)
11324
+ throw new CliError("no_live_model", "No chat model is live in this region right now, so there is nothing to configure. Nothing was changed.", "Check `models --live` again later, or pass --model <id>.");
11325
+ if (!/^[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}$/.test(model))
11326
+ throw new CliError("bad_argument", "--model isn't a model id.", "Pick one from `models --live`.");
11327
+ const host = machineName();
11328
+ const keyName = `${tool}: ${host}`;
11329
+ const livesIn = `tool:${tool}:${host}`;
11330
+ const t = tool;
11331
+ if (t === "cursor" || t === "continue")
11332
+ return instructions(t, baseUrl, model, models, keyName);
11333
+ if (t === "aider") {
11334
+ const existing = readDotEnv(ctx.cwd);
11335
+ if (existing.OPENAI_API_KEY && !KEY_RE.test(existing.OPENAI_API_KEY))
11336
+ throw new CliError("env_conflict", "./.env already has an OPENAI_API_KEY that isn't a ScaledThought key. Nothing was changed.", "Aider reads OPENAI_API_KEY from .env, so this would replace it. Run connect aider in another directory, or remove that line first.");
11337
+ const k = await mintChild(ctx, { name: keyName, livesIn, budgetUsd: o.budgetUsd });
11338
+ try {
11339
+ writeEnv(ctx.cwd, { OPENAI_API_BASE: baseUrl, OPENAI_API_KEY: k.api_key, AIDER_MODEL: `openai/${model}` });
11340
+ ensureGitignored(ctx.cwd);
11341
+ } catch (e) {
11342
+ return failAfterMint(ctx, k.id, e);
11343
+ }
11344
+ return {
11345
+ tool,
11346
+ key_name: k.name,
11347
+ key_prefix: k.prefix,
11348
+ lives_in: livesIn,
11349
+ daily_budget_usd: k.daily_budget_usd,
11350
+ configured: ".env (OPENAI_API_BASE, OPENAI_API_KEY, AIDER_MODEL), mode 0600, git-ignored",
11351
+ model: `openai/${model}`,
11352
+ models: models.map((m) => m.id),
11353
+ next: "Run `aider` in this directory. Aider may warn that it doesn't know the model's context window; that's harmless."
11354
+ };
11355
+ }
11356
+ const dataHome = ctx.env.XDG_DATA_HOME || join9(ctx.env.HOME || homedir(), ".local", "share");
11357
+ const authPath = join9(dataHome, "opencode", "auth.json");
11358
+ const configPath = join9(ctx.cwd, "opencode.json");
11359
+ const config = readJsonObject(configPath, "opencode.json");
11360
+ const auth = readJsonObject(authPath, authPath);
11361
+ const providers = config.provider && typeof config.provider === "object" ? config.provider : {};
11362
+ const modelEntries = {};
11363
+ for (const m of models)
11364
+ modelEntries[m.id] = {
11365
+ name: m.id,
11366
+ ...m.context ? { limit: { context: m.context, output: Math.min(32768, Math.floor(m.context / 2)) } } : {}
11367
+ };
11368
+ if (!modelEntries[model])
11369
+ modelEntries[model] = { name: model };
11370
+ const k = await mintChild(ctx, { name: keyName, livesIn, budgetUsd: o.budgetUsd });
11371
+ try {
11372
+ const next = {
11373
+ ...existsSync8(configPath) ? {} : { $schema: "https://opencode.ai/config.json" },
11374
+ ...config,
11375
+ provider: {
11376
+ ...providers,
11377
+ [PROVIDER_ID]: {
11378
+ npm: "@ai-sdk/openai-compatible",
11379
+ name: "ScaledThought",
11380
+ options: { baseURL: baseUrl },
11381
+ models: modelEntries
11382
+ }
11383
+ },
11384
+ ...config.model ? {} : { model: `${PROVIDER_ID}/${model}` }
11385
+ };
11386
+ writePrivate2(configPath, `${JSON.stringify(next, null, 2)}
11387
+ `);
11388
+ writePrivate2(authPath, `${JSON.stringify({ ...auth, [PROVIDER_ID]: { type: "api", key: k.api_key } }, null, 2)}
11389
+ `);
11390
+ } catch (e) {
11391
+ return failAfterMint(ctx, k.id, e);
11392
+ }
11393
+ return {
11394
+ tool,
11395
+ key_name: k.name,
11396
+ key_prefix: k.prefix,
11397
+ lives_in: livesIn,
11398
+ daily_budget_usd: k.daily_budget_usd,
11399
+ configured: `opencode.json (provider ${PROVIDER_ID}, base URL ${baseUrl}) + ${authPath} (key, mode 0600)`,
11400
+ model: `${PROVIDER_ID}/${model}`,
11401
+ models: Object.keys(modelEntries),
11402
+ restart_needed: true,
11403
+ next: `Restart OpenCode in this directory and pick a ${PROVIDER_ID}/… model.`
11404
+ };
11405
+ }
11406
+ function instructions(tool, baseUrl, model, models, name) {
11407
+ const ids = models.some((m) => m.id === model) ? models.map((m) => m.id) : [model, ...models.map((m) => m.id)];
11408
+ if (tool === "cursor")
11409
+ return {
11410
+ tool,
11411
+ configured: false,
11412
+ key_minted: false,
11413
+ why: "Cursor keeps its OpenAI key in its own settings store, which other programs can't write safely. A human sets it once.",
11414
+ steps_for_human: [
11415
+ `Cursor Settings → Models → API Keys: turn on "Override OpenAI Base URL" and enter ${baseUrl}`,
11416
+ `In your own terminal (not through the agent) run: ${NPX} keys create --child --name "${name}" and paste the key it prints into "OpenAI API Key", then Verify.`,
11417
+ `Add model names under Models: ${ids.join(", ")}`
11418
+ ],
11419
+ base_url: baseUrl,
11420
+ models: ids,
11421
+ restart_needed: false
11422
+ };
11423
+ const block = [
11424
+ "models:",
11425
+ ` - name: ScaledThought ${model}`,
11426
+ " provider: openai",
11427
+ ` model: ${model}`,
11428
+ ` apiBase: ${baseUrl}`,
11429
+ ` apiKey: \${{ secrets.ST_API_KEY }}`,
11430
+ " defaultCompletionOptions:",
11431
+ " maxTokens: 32768",
11432
+ " roles: [chat, edit, apply]"
11433
+ ].join(`
11434
+ `);
11435
+ return {
11436
+ tool,
11437
+ configured: false,
11438
+ key_minted: false,
11439
+ why: "Continue's config.yaml is hand-edited YAML; this CLI won't rewrite it. The block below holds no secret: Continue reads ST_API_KEY from this workspace's .env.",
11440
+ steps_for_human: [
11441
+ "Open ~/.continue/config.yaml (Continue: Open configuration) and add this entry under models:",
11442
+ "Reload Continue and pick the ScaledThought model."
11443
+ ],
11444
+ config_yaml: block,
11445
+ base_url: baseUrl,
11446
+ models: ids,
11447
+ restart_needed: false
11448
+ };
11449
+ }
11450
+ function putFlagsFrom(args) {
11451
+ const out = {};
11452
+ for (const f of PUT_FLAGS)
11453
+ if (typeof args[f] === "string")
11454
+ out[f] = args[f];
11455
+ return out;
11456
+ }
11457
+
10584
11458
  // src/realtime.ts
10585
- import { readFileSync as readFileSync7, writeFileSync as writeFileSync4 } from "node:fs";
11459
+ import { readFileSync as readFileSync11, writeFileSync as writeFileSync5 } from "node:fs";
10586
11460
  import { resolve as resolve4 } from "node:path";
10587
11461
  var SAMPLE_RATE = 24000;
10588
11462
  var MAX_INPUT_SECONDS = 300;
@@ -10647,7 +11521,7 @@ async function realtime(ctx, o) {
10647
11521
  throw new CliError("unsupported_runtime", "This command needs a WebSocket client (Node.js 22 or newer).", "Upgrade Node.js to 22+.");
10648
11522
  let pcm;
10649
11523
  try {
10650
- pcm = readWav(readFileSync7(resolve4(ctx.cwd, o.input)));
11524
+ pcm = readWav(readFileSync11(resolve4(ctx.cwd, o.input)));
10651
11525
  } catch (e) {
10652
11526
  if (e instanceof CliError)
10653
11527
  throw e;
@@ -10739,7 +11613,7 @@ async function realtime(ctx, o) {
10739
11613
  });
10740
11614
  const audio = Buffer.concat(out);
10741
11615
  const path = resolve4(ctx.cwd, o.output);
10742
- writeFileSync4(path, wavOf(audio));
11616
+ writeFileSync5(path, wavOf(audio));
10743
11617
  return {
10744
11618
  model: o.model,
10745
11619
  region,
@@ -10770,7 +11644,7 @@ function out(data, args) {
10770
11644
  process.stdout.write(`${JSON.stringify(data, null, wantsJson(args) ? 0 : 2)}
10771
11645
  `);
10772
11646
  }
10773
- var run = async (fn, args) => out(await fn(), args);
11647
+ var run2 = async (fn, args) => out(await fn(), args);
10774
11648
  function region(v) {
10775
11649
  if (v === undefined)
10776
11650
  return;
@@ -10818,7 +11692,7 @@ var init2 = defineCommand({
10818
11692
  description: "Save the account's key in this machine's credential store so other folders reuse it (--no-save to opt out)"
10819
11693
  }
10820
11694
  },
10821
- run: ({ args }) => run(() => init(makeCtx(), {
11695
+ run: ({ args }) => run2(() => init(makeCtx(), {
10822
11696
  region: region(args.region),
10823
11697
  name: args.name,
10824
11698
  email: args.email,
@@ -10861,7 +11735,7 @@ var login2 = defineCommand({
10861
11735
  const t = args["timeout-s"] === undefined ? undefined : num("timeout-s", args["timeout-s"]);
10862
11736
  if (t !== undefined && t > 600)
10863
11737
  throw new CliError("bad_argument", `--timeout-s must be at most 600, got ${t}.`, "Run login --wait again.");
10864
- await run(async () => args.code ? loginWithCode(ctx, {
11738
+ await run2(async () => args.code ? loginWithCode(ctx, {
10865
11739
  code: args.code === "-" ? await readCodeFrom(process.stdin) : args.code,
10866
11740
  region: region(args.region),
10867
11741
  label: args.label,
@@ -10885,7 +11759,7 @@ var use = defineCommand({
10885
11759
  ...jsonFlag,
10886
11760
  account: { type: "positional", required: true, description: "The account's name or id" }
10887
11761
  },
10888
- run: ({ args }) => run(() => useAccount(makeCtx(), { target: args.account }), args)
11762
+ run: ({ args }) => run2(() => useAccount(makeCtx(), { target: args.account }), args)
10889
11763
  });
10890
11764
  var models = defineCommand({
10891
11765
  meta: { name: "models", description: "List models with prices and benchmarks, newest first; or show one" },
@@ -10905,7 +11779,7 @@ var models = defineCommand({
10905
11779
  },
10906
11780
  search: { type: "string", description: "Match id, name or lab" }
10907
11781
  },
10908
- run: ({ args }) => run(() => {
11782
+ run: ({ args }) => run2(() => {
10909
11783
  const r = region(args.region);
10910
11784
  return args.id ? showModel(makeCtx(), args.id, r) : listModels(makeCtx(), {
10911
11785
  live: args.live,
@@ -10923,7 +11797,7 @@ var account2 = defineCommand({
10923
11797
  run: ({ args, rawArgs }) => {
10924
11798
  if (rawArgs.some((a) => ACCOUNT_SUBCOMMANDS.has(a)))
10925
11799
  return;
10926
- return run(() => account(makeCtx()), args);
11800
+ return run2(() => account(makeCtx()), args);
10927
11801
  },
10928
11802
  subCommands: {
10929
11803
  delete: defineCommand({
@@ -10935,7 +11809,7 @@ var account2 = defineCommand({
10935
11809
  ...jsonFlag,
10936
11810
  confirm: { type: "string", required: true, description: "The account id (acct_...), to confirm" }
10937
11811
  },
10938
- run: ({ args }) => run(() => accountDelete(makeCtx(), { confirm: args.confirm }), args)
11812
+ run: ({ args }) => run2(() => accountDelete(makeCtx(), { confirm: args.confirm }), args)
10939
11813
  }),
10940
11814
  "ad-measurement": defineCommand({
10941
11815
  meta: {
@@ -10946,7 +11820,7 @@ var account2 = defineCommand({
10946
11820
  ...jsonFlag,
10947
11821
  state: { type: "positional", required: true, description: "off or on" }
10948
11822
  },
10949
- run: ({ args }) => run(() => accountAdMeasurement(makeCtx(), args.state), args)
11823
+ run: ({ args }) => run2(() => accountAdMeasurement(makeCtx(), args.state), args)
10950
11824
  })
10951
11825
  }
10952
11826
  });
@@ -10956,7 +11830,7 @@ var keys = defineCommand({
10956
11830
  list: defineCommand({
10957
11831
  meta: { name: "list", description: "Keys on this account (prefixes only)" },
10958
11832
  args: jsonFlag,
10959
- run: ({ args }) => run(() => keysList(makeCtx()), args)
11833
+ run: ({ args }) => run2(() => keysList(makeCtx()), args)
10960
11834
  }),
10961
11835
  create: defineCommand({
10962
11836
  meta: { name: "create", description: "Create a key; the full key is printed once" },
@@ -10974,7 +11848,7 @@ var keys = defineCommand({
10974
11848
  description: "Sub-agent key: budget, scopes and expiry within your key's; revoked when your key is"
10975
11849
  }
10976
11850
  },
10977
- run: ({ args }) => run(() => keysCreate(makeCtx(), {
11851
+ run: ({ args }) => run2(() => keysCreate(makeCtx(), {
10978
11852
  name: args.name,
10979
11853
  budgetUsd: num("budget-usd", args["budget-usd"]),
10980
11854
  expiresIn: args["expires-in"],
@@ -10982,23 +11856,89 @@ var keys = defineCommand({
10982
11856
  child: args.child
10983
11857
  }), args)
10984
11858
  }),
11859
+ put: defineCommand({
11860
+ meta: {
11861
+ name: "put",
11862
+ description: "Put a new child key straight into a platform's secret store as ST_API_KEY, through its own CLI on stdin (never printed). Records where it lives"
11863
+ },
11864
+ args: {
11865
+ ...jsonFlag,
11866
+ destination: {
11867
+ type: "positional",
11868
+ required: true,
11869
+ description: `Where: ${Object.keys(DESTINATIONS).join(", ")}`
11870
+ },
11871
+ name: { type: "string", description: "Key name (default: named after the destination)" },
11872
+ "budget-usd": { type: "string", description: "Hard daily budget in USD (default: none beyond your key's)" },
11873
+ "expires-in": { type: "string", description: "Key lifetime, e.g. 30d (max 365d)" },
11874
+ scopes: {
11875
+ type: "string",
11876
+ description: "Comma-separated scopes, a subset of your key's. Default inference,read"
11877
+ },
11878
+ repo: { type: "string", description: "github: owner/name (default: this directory's repo)" },
11879
+ app: { type: "string", description: "github: actions|codespaces|dependabot (default actions); fly: app name" },
11880
+ env: {
11881
+ type: "string",
11882
+ description: "github: deployment environment; vercel: production|preview|development (default production); cloudflare: Wrangler env"
11883
+ },
11884
+ project: { type: "string", description: "vercel (must match the linked project), gcp, doppler: project" },
11885
+ worker: { type: "string", description: "cloudflare: Worker name (default: wrangler.toml's name)" },
11886
+ secret: {
11887
+ type: "string",
11888
+ description: "gcp (default st-api-key), aws (default scaledthought/api-key), k8s (default scaledthought): secret name"
11889
+ },
11890
+ "aws-region": { type: "string", description: "aws: region (default: AWS_REGION or the CLI's)" },
11891
+ locations: {
11892
+ type: "string",
11893
+ description: "gcp: user-managed replication locations, e.g. northamerica-northeast1"
11894
+ },
11895
+ namespace: { type: "string", description: "k8s: namespace (default: the context's)" },
11896
+ context: { type: "string", description: "k8s: kubectl context (default: current)" },
11897
+ config: { type: "string", description: "doppler: config, e.g. prd (default: this directory's)" }
11898
+ },
11899
+ run: ({ args }) => run2(() => keysPut(makeCtx(), args.destination, {
11900
+ name: args.name,
11901
+ budgetUsd: num("budget-usd", args["budget-usd"]),
11902
+ expiresIn: args["expires-in"],
11903
+ scopes: args.scopes?.split(",").map((x) => x.trim()).filter(Boolean),
11904
+ flags: putFlagsFrom(args)
11905
+ }), args)
11906
+ }),
10985
11907
  rotate: defineCommand({
10986
11908
  meta: {
10987
11909
  name: "rotate",
10988
- description: "Replace a key: prints the new key once; the old key keeps working for --grace (default 24h, 0 to 7d)"
11910
+ description: "Replace a key: prints the new key once; the old key keeps working for --grace (default 24h, 0 to 7d). With --push, puts the new key where the old one lives instead of printing it"
10989
11911
  },
10990
11912
  args: {
10991
11913
  ...jsonFlag,
10992
- id: { type: "positional", required: true, description: "Key id (key_…)" },
11914
+ id: { type: "positional", required: false, description: "Key id (key_…); or --all with --push" },
10993
11915
  grace: { type: "string", description: "How long the old key keeps working: 0 to 7d (default 24h)" },
10994
- "expires-in": { type: "string", description: "New key's lifetime (default: the old key's)" }
11916
+ "expires-in": { type: "string", description: "New key's lifetime (default: the old key's)" },
11917
+ push: {
11918
+ type: "boolean",
11919
+ description: "Put each new key where the old one lives (its lives_in, from keys put); prints no keys"
11920
+ },
11921
+ all: { type: "boolean", description: "With --push: every active key that has a lives_in keys put can reach" }
10995
11922
  },
10996
- run: ({ args }) => run(() => keysRotate(makeCtx(), args.id, { grace: args.grace, expiresIn: args["expires-in"] }), args)
11923
+ run: ({ args }) => run2(() => {
11924
+ if (args.all && !args.push)
11925
+ throw new CliError("usage_error", "--all needs --push (rotating every key never prints them).");
11926
+ if (args.all && args.id)
11927
+ throw new CliError("usage_error", "Pass a key id or --all, not both.");
11928
+ if (!args.all && !args.id)
11929
+ throw new CliError("usage_error", "Pass a key id (or --all --push).");
11930
+ if (args.push) {
11931
+ if (args["expires-in"])
11932
+ throw new CliError("usage_error", "--expires-in can't be combined with --push.");
11933
+ return keysRotatePush(makeCtx(), { id: args.id, all: args.all, grace: args.grace });
11934
+ }
11935
+ return keysRotate(makeCtx(), args.id, { grace: args.grace, expiresIn: args["expires-in"] });
11936
+ }, args)
10997
11937
  }),
10998
11938
  revoke: defineCommand({
10999
11939
  meta: { name: "revoke", description: "Revoke a key by id (and its sub-agent keys)" },
11000
11940
  args: { ...jsonFlag, id: { type: "positional", required: true, description: "Key id (key_…)" } },
11001
- run: ({ args }) => run(() => keysRevoke(makeCtx(), args.id), args)
11941
+ run: ({ args }) => run2(() => keysRevoke(makeCtx(), args.id), args)
11002
11942
  }),
11003
11943
  "revoke-self": defineCommand({
11004
11944
  meta: {
@@ -11006,7 +11946,7 @@ var keys = defineCommand({
11006
11946
  description: "Revoke the key you are using now (e.g. if it may have leaked). Irreversible"
11007
11947
  },
11008
11948
  args: jsonFlag,
11009
- run: ({ args }) => run(() => keysRevokeSelf(makeCtx()), args)
11949
+ run: ({ args }) => run2(() => keysRevokeSelf(makeCtx()), args)
11010
11950
  })
11011
11951
  }
11012
11952
  });
@@ -11017,18 +11957,18 @@ var usage3 = defineCommand({
11017
11957
  days: { type: "string", default: "7", description: "Look-back window, 1-90" },
11018
11958
  by: { type: "string", default: "model", description: "model|day|key|modality" }
11019
11959
  },
11020
- run: ({ args }) => run(() => usage(makeCtx(), { days: num("days", args.days) ?? 7, by: args.by }), args)
11960
+ run: ({ args }) => run2(() => usage(makeCtx(), { days: num("days", args.days) ?? 7, by: args.by }), args)
11021
11961
  });
11022
11962
  var chat2 = defineCommand({
11023
- meta: { name: "chat", description: "Send one message. Use -m auto to let the router pick" },
11963
+ meta: { name: "chat", description: 'Send one message to a model: chat -m <id> "…" (ids from `models --live`)' },
11024
11964
  args: {
11025
11965
  ...jsonFlag,
11026
- model: { type: "string", alias: "m", default: "auto", description: "Model id or auto" },
11966
+ model: { type: "string", alias: "m", description: "Model id, required (from `models --live`)" },
11027
11967
  prompt: { type: "positional", required: true, description: "The message" }
11028
11968
  },
11029
11969
  run: async ({ args }) => {
11030
11970
  const human = !wantsJson(args);
11031
- await run(async () => {
11971
+ await run2(async () => {
11032
11972
  const r = await chat(makeCtx(), {
11033
11973
  model: args.model,
11034
11974
  prompt: args.prompt,
@@ -11091,7 +12031,7 @@ var speak2 = defineCommand({
11091
12031
  speed: { type: "string", description: "0.25 to 4 (default 1)" },
11092
12032
  instructions: { type: "string", description: "Delivery instructions for models that take them, optional" }
11093
12033
  },
11094
- run: ({ args }) => run(() => speak(makeCtx(), {
12034
+ run: ({ args }) => run2(() => speak(makeCtx(), {
11095
12035
  text: args.text,
11096
12036
  output: args.output,
11097
12037
  model: args.model,
@@ -11114,7 +12054,7 @@ var decideCmd = defineCommand({
11114
12054
  question: { type: "string", alias: "q", description: "id:type:instructions[:criteria], repeatable" },
11115
12055
  file: { type: "string", description: "A JSON request: {state, questions, model?}" }
11116
12056
  },
11117
- run: ({ args }) => run(() => {
12057
+ run: ({ args }) => run2(() => {
11118
12058
  const ctx = makeCtx();
11119
12059
  const raw = currentArgv;
11120
12060
  const questions = [];
@@ -11147,7 +12087,7 @@ var realtime2 = defineCommand({
11147
12087
  instructions: { type: "string", description: "System instructions for the session (optional)" },
11148
12088
  timeout: { type: "string", description: "Seconds to wait for the reply (default 120)" }
11149
12089
  },
11150
- run: ({ args }) => run(async () => {
12090
+ run: ({ args }) => run2(async () => {
11151
12091
  const t = num("timeout", args.timeout);
11152
12092
  return realtime(makeCtx(), {
11153
12093
  model: args.model,
@@ -11165,7 +12105,7 @@ function autoReloadArgs(args) {
11165
12105
  if (below === undefined && amount === undefined && max === undefined)
11166
12106
  return;
11167
12107
  if (below === undefined || amount === undefined)
11168
- throw new CliError("bad_argument", "Auto-reload needs both --auto-reload-below and --auto-reload-amount.", "e.g. --auto-reload-below 5 --auto-reload-amount 10");
12108
+ throw new CliError("bad_argument", "Auto-reload needs both --auto-reload-below and --auto-reload-amount.", "e.g. --auto-reload-below 5 --auto-reload-amount 20");
11169
12109
  return { threshold_usd: below, amount_usd: amount, ...max !== undefined ? { monthly_limit_usd: max } : {} };
11170
12110
  }
11171
12111
  var billing = defineCommand({
@@ -11177,7 +12117,7 @@ var billing = defineCommand({
11177
12117
  description: "Credit balance, auto-reload, pending top-ups (with their approval links), recent transactions"
11178
12118
  },
11179
12119
  args: jsonFlag,
11180
- run: ({ args }) => run(() => billingStatus(makeCtx()), args)
12120
+ run: ({ args }) => run2(() => billingStatus(makeCtx()), args)
11181
12121
  }),
11182
12122
  topup: defineCommand({
11183
12123
  meta: {
@@ -11214,7 +12154,7 @@ var billing = defineCommand({
11214
12154
  const autoReload = autoReloadArgs(args);
11215
12155
  checkTopupLimits(amountUsd, autoReload);
11216
12156
  const noOpen = args.open === false;
11217
- await run(() => args.wait ? billingTopupAndWait(makeCtx(), { amountUsd, autoReload, noOpen, onPending: (t) => out(t, args) }) : billingTopup(makeCtx(), { amountUsd, autoReload, noOpen }), args);
12157
+ await run2(() => args.wait ? billingTopupAndWait(makeCtx(), { amountUsd, autoReload, noOpen, onPending: (t) => out(t, args) }) : billingTopup(makeCtx(), { amountUsd, autoReload, noOpen }), args);
11218
12158
  }
11219
12159
  }),
11220
12160
  wait: defineCommand({
@@ -11234,7 +12174,7 @@ var billing = defineCommand({
11234
12174
  const t = args["timeout-s"] === undefined ? undefined : num("timeout-s", args["timeout-s"]);
11235
12175
  if (t !== undefined && t > 600)
11236
12176
  throw new CliError("bad_argument", `--timeout-s must be at most 600, got ${t}.`, "Run wait again instead.");
11237
- await run(() => billingWait(makeCtx(), { topupId: args.topup_id || undefined, timeoutS: t }), args);
12177
+ await run2(() => billingWait(makeCtx(), { topupId: args.topup_id || undefined, timeoutS: t }), args);
11238
12178
  }
11239
12179
  }),
11240
12180
  "auto-reload": defineCommand({
@@ -11261,7 +12201,7 @@ var billing = defineCommand({
11261
12201
  description: "Open the page in the browser (--no-open only prints approval_url)"
11262
12202
  }
11263
12203
  },
11264
- run: ({ args }) => run(() => billingAutoReloadSetup(makeCtx(), {
12204
+ run: ({ args }) => run2(() => billingAutoReloadSetup(makeCtx(), {
11265
12205
  thresholdUsd: num("below", args.below),
11266
12206
  amountUsd: num("amount", args.amount),
11267
12207
  noOpen: args.open === false
@@ -11270,14 +12210,14 @@ var billing = defineCommand({
11270
12210
  off: defineCommand({
11271
12211
  meta: { name: "off", description: "Disable auto-reload. No approval needed" },
11272
12212
  args: jsonFlag,
11273
- run: ({ args }) => run(() => billingAutoReloadOff(makeCtx()), args)
12213
+ run: ({ args }) => run2(() => billingAutoReloadOff(makeCtx()), args)
11274
12214
  })
11275
12215
  }
11276
12216
  }),
11277
12217
  transactions: defineCommand({
11278
12218
  meta: { name: "transactions", description: "Credit ledger: purchases, auto-reloads, usage, batches, refunds" },
11279
12219
  args: { ...jsonFlag, cursor: { type: "string", description: "next_cursor from the previous page" } },
11280
- run: ({ args }) => run(() => billingTransactions(makeCtx(), { cursor: args.cursor }), args)
12220
+ run: ({ args }) => run2(() => billingTransactions(makeCtx(), { cursor: args.cursor }), args)
11281
12221
  }),
11282
12222
  upgrade: defineCommand({
11283
12223
  meta: { name: "upgrade", description: "Removed: monthly caps became prepaid credits. Use billing topup" },
@@ -11296,34 +12236,34 @@ var batches = defineCommand({
11296
12236
  file: { type: "positional", required: true, description: "Path to requests.jsonl" },
11297
12237
  endpoint: { type: "string", default: "/v1/chat/completions", description: "Endpoint every line calls" }
11298
12238
  },
11299
- run: ({ args }) => run(() => batchCreate(makeCtx(), { path: args.file, endpoint: args.endpoint }), args)
12239
+ run: ({ args }) => run2(() => batchCreate(makeCtx(), { path: args.file, endpoint: args.endpoint }), args)
11300
12240
  }),
11301
12241
  list: defineCommand({
11302
12242
  meta: { name: "list", description: "Your batches" },
11303
12243
  args: jsonFlag,
11304
- run: ({ args }) => run(() => batchList(makeCtx()), args)
12244
+ run: ({ args }) => run2(() => batchList(makeCtx()), args)
11305
12245
  }),
11306
12246
  get: defineCommand({
11307
12247
  meta: { name: "get", description: "One batch" },
11308
12248
  args: { ...jsonFlag, id: { type: "positional", required: true, description: "Batch id" } },
11309
- run: ({ args }) => run(() => batchGet(makeCtx(), args.id), args)
12249
+ run: ({ args }) => run2(() => batchGet(makeCtx(), args.id), args)
11310
12250
  }),
11311
12251
  results: defineCommand({
11312
12252
  meta: { name: "results", description: "Print the output lines of a finished batch" },
11313
12253
  args: { ...jsonFlag, id: { type: "positional", required: true, description: "Batch id" } },
11314
- run: ({ args }) => run(() => batchResults(makeCtx(), args.id), args)
12254
+ run: ({ args }) => run2(() => batchResults(makeCtx(), args.id), args)
11315
12255
  }),
11316
12256
  cancel: defineCommand({
11317
12257
  meta: { name: "cancel", description: "Cancel a batch" },
11318
12258
  args: { ...jsonFlag, id: { type: "positional", required: true, description: "Batch id" } },
11319
- run: ({ args }) => run(() => batchCancel(makeCtx(), args.id), args)
12259
+ run: ({ args }) => run2(() => batchCancel(makeCtx(), args.id), args)
11320
12260
  })
11321
12261
  }
11322
12262
  });
11323
12263
  var benchmarks2 = defineCommand({
11324
12264
  meta: { name: "benchmarks", description: "Our own benchmark results for a model" },
11325
12265
  args: { ...jsonFlag, ...regionFlag, id: { type: "positional", required: true, description: "Model id" } },
11326
- run: ({ args }) => run(() => benchmarks(makeCtx(), args.id, region(args.region)), args)
12266
+ run: ({ args }) => run2(() => benchmarks(makeCtx(), args.id, region(args.region)), args)
11327
12267
  });
11328
12268
  var fineTune = defineCommand({
11329
12269
  meta: {
@@ -11340,7 +12280,7 @@ var fineTune = defineCommand({
11340
12280
  suffix: { type: "string", description: "Suffix for the fine-tuned model id" },
11341
12281
  epochs: { type: "string", description: "1-10, default 3" }
11342
12282
  },
11343
- run: ({ args }) => run(() => fineTuneCreate(makeCtx(), {
12283
+ run: ({ args }) => run2(() => fineTuneCreate(makeCtx(), {
11344
12284
  path: args.file,
11345
12285
  model: args.model,
11346
12286
  suffix: args.suffix,
@@ -11350,27 +12290,27 @@ var fineTune = defineCommand({
11350
12290
  list: defineCommand({
11351
12291
  meta: { name: "list", description: "Your jobs" },
11352
12292
  args: jsonFlag,
11353
- run: ({ args }) => run(() => fineTuneList(makeCtx()), args)
12293
+ run: ({ args }) => run2(() => fineTuneList(makeCtx()), args)
11354
12294
  }),
11355
12295
  get: defineCommand({
11356
12296
  meta: { name: "get", description: "One job" },
11357
12297
  args: { ...jsonFlag, id: { type: "positional", required: true, description: "Job id" } },
11358
- run: ({ args }) => run(() => fineTuneGet(makeCtx(), args.id), args)
12298
+ run: ({ args }) => run2(() => fineTuneGet(makeCtx(), args.id), args)
11359
12299
  }),
11360
12300
  events: defineCommand({
11361
12301
  meta: { name: "events", description: "A job's progress events" },
11362
12302
  args: { ...jsonFlag, id: { type: "positional", required: true, description: "Job id" } },
11363
- run: ({ args }) => run(() => fineTuneEvents(makeCtx(), args.id), args)
12303
+ run: ({ args }) => run2(() => fineTuneEvents(makeCtx(), args.id), args)
11364
12304
  }),
11365
12305
  cancel: defineCommand({
11366
12306
  meta: { name: "cancel", description: "Cancel a job" },
11367
12307
  args: { ...jsonFlag, id: { type: "positional", required: true, description: "Job id" } },
11368
- run: ({ args }) => run(() => fineTuneCancel(makeCtx(), args.id), args)
12308
+ run: ({ args }) => run2(() => fineTuneCancel(makeCtx(), args.id), args)
11369
12309
  }),
11370
12310
  models: defineCommand({
11371
12311
  meta: { name: "models", description: "Your fine-tuned models" },
11372
12312
  args: jsonFlag,
11373
- run: ({ args }) => run(() => fineTuneModels(makeCtx()), args)
12313
+ run: ({ args }) => run2(() => fineTuneModels(makeCtx()), args)
11374
12314
  })
11375
12315
  }
11376
12316
  });
@@ -11396,7 +12336,7 @@ var video = defineCommand({
11396
12336
  wait: { type: "boolean", description: "Wait until the video is ready" },
11397
12337
  output: { type: "string", alias: "o", description: "Save the MP4 here (waits for it)" }
11398
12338
  },
11399
- run: ({ args }) => run(() => videoCreate(makeCtx(), {
12339
+ run: ({ args }) => run2(() => videoCreate(makeCtx(), {
11400
12340
  prompt: args.prompt,
11401
12341
  model: args.model,
11402
12342
  seconds: num("seconds", args.seconds),
@@ -11410,7 +12350,7 @@ var video = defineCommand({
11410
12350
  get: defineCommand({
11411
12351
  meta: { name: "get", description: "One video job: status, progress, cost" },
11412
12352
  args: { ...jsonFlag, id: { type: "positional", required: true, description: "Video id" } },
11413
- run: ({ args }) => run(() => videoGet(makeCtx(), args.id), args)
12353
+ run: ({ args }) => run2(() => videoGet(makeCtx(), args.id), args)
11414
12354
  }),
11415
12355
  list: defineCommand({
11416
12356
  meta: { name: "list", description: "Your video jobs, newest first" },
@@ -11419,7 +12359,7 @@ var video = defineCommand({
11419
12359
  limit: { type: "string", description: "Page size, 1-100 (default 20)" },
11420
12360
  after: { type: "string", description: "Continue after this video id" }
11421
12361
  },
11422
- run: ({ args }) => run(() => videoList(makeCtx(), { limit: num("limit", args.limit), after: args.after }), args)
12362
+ run: ({ args }) => run2(() => videoList(makeCtx(), { limit: num("limit", args.limit), after: args.after }), args)
11423
12363
  }),
11424
12364
  download: defineCommand({
11425
12365
  meta: { name: "download", description: "Save a finished video (or --thumbnail) to a file" },
@@ -11429,12 +12369,12 @@ var video = defineCommand({
11429
12369
  output: { type: "string", alias: "o", required: true, description: "File to write" },
11430
12370
  thumbnail: { type: "boolean", description: "Download the JPEG thumbnail instead" }
11431
12371
  },
11432
- run: ({ args }) => run(() => videoDownload(makeCtx(), args.id, args.output, args.thumbnail ? "thumbnail" : "video"), args)
12372
+ run: ({ args }) => run2(() => videoDownload(makeCtx(), args.id, args.output, args.thumbnail ? "thumbnail" : "video"), args)
11433
12373
  }),
11434
12374
  delete: defineCommand({
11435
12375
  meta: { name: "delete", description: "Cancel (credits returned) or delete a video and its files" },
11436
12376
  args: { ...jsonFlag, id: { type: "positional", required: true, description: "Video id" } },
11437
- run: ({ args }) => run(() => videoDelete(makeCtx(), args.id), args)
12377
+ run: ({ args }) => run2(() => videoDelete(makeCtx(), args.id), args)
11438
12378
  })
11439
12379
  }
11440
12380
  });
@@ -11444,7 +12384,7 @@ var status2 = defineCommand({
11444
12384
  description: "Per-model health in the region (last hour), plus your account's notices when a key is set"
11445
12385
  },
11446
12386
  args: { ...jsonFlag, ...regionFlag },
11447
- run: ({ args }) => run(() => status(makeCtx(), region(args.region)), args)
12387
+ run: ({ args }) => run2(() => status(makeCtx(), region(args.region)), args)
11448
12388
  });
11449
12389
  var doctor2 = defineCommand({
11450
12390
  meta: {
@@ -11452,7 +12392,7 @@ var doctor2 = defineCommand({
11452
12392
  description: "Check this project's setup: key and region, account, credit, and notices to tell your human"
11453
12393
  },
11454
12394
  args: jsonFlag,
11455
- run: ({ args }) => run(() => doctor(makeCtx()), args)
12395
+ run: ({ args }) => run2(() => doctor(makeCtx()), args)
11456
12396
  });
11457
12397
  var webhooks = defineCommand({
11458
12398
  meta: {
@@ -11470,27 +12410,43 @@ var webhooks = defineCommand({
11470
12410
  description: "Comma-separated events (default: all four)"
11471
12411
  }
11472
12412
  },
11473
- run: ({ args }) => run(() => webhooksAdd(makeCtx(), { url: args.url, events: args.events }), args)
12413
+ run: ({ args }) => run2(() => webhooksAdd(makeCtx(), { url: args.url, events: args.events }), args)
11474
12414
  }),
11475
12415
  list: defineCommand({
11476
12416
  meta: { name: "list", description: "This account's webhook endpoints" },
11477
12417
  args: jsonFlag,
11478
- run: ({ args }) => run(() => webhooksList(makeCtx()), args)
12418
+ run: ({ args }) => run2(() => webhooksList(makeCtx()), args)
11479
12419
  }),
11480
12420
  remove: defineCommand({
11481
12421
  meta: { name: "remove", description: "Delete an endpoint by id (whk_…)" },
11482
12422
  args: { ...jsonFlag, id: { type: "positional", required: true, description: "Webhook id" } },
11483
- run: ({ args }) => run(() => webhooksRemove(makeCtx(), args.id), args)
12423
+ run: ({ args }) => run2(() => webhooksRemove(makeCtx(), args.id), args)
11484
12424
  })
11485
12425
  }
11486
12426
  });
12427
+ var connectTool = defineCommand({
12428
+ meta: {
12429
+ name: "connect",
12430
+ description: "Point an OpenAI-compatible tool at ScaledThought: writes its config with the base URL and a new child key (never printed), or prints the steps when the tool's key store can't be written safely"
12431
+ },
12432
+ args: {
12433
+ ...jsonFlag,
12434
+ tool: { type: "positional", required: true, description: CONNECT_TOOLS.join(", ") },
12435
+ model: { type: "string", description: "Default model (default: the newest live chat model)" },
12436
+ "budget-usd": { type: "string", description: "Hard daily budget for the tool's key, in USD" }
12437
+ },
12438
+ run: ({ args }) => run2(() => connect(makeCtx(), args.tool, {
12439
+ model: args.model,
12440
+ budgetUsd: num("budget-usd", args["budget-usd"])
12441
+ }), args)
12442
+ });
11487
12443
  var mcp = defineCommand({
11488
12444
  meta: {
11489
12445
  name: "mcp",
11490
12446
  description: "Print the `claude mcp add` command and JSON config for this account's MCP server"
11491
12447
  },
11492
12448
  args: jsonFlag,
11493
- run: ({ args }) => run(() => mcpSetup(makeCtx()), args)
12449
+ run: ({ args }) => run2(() => mcpSetup(makeCtx()), args)
11494
12450
  });
11495
12451
  var dashboard = defineCommand({
11496
12452
  meta: {
@@ -11506,7 +12462,7 @@ var dashboard = defineCommand({
11506
12462
  },
11507
12463
  open: { type: "boolean", default: true, description: "Open it in the browser (--no-open only prints the URL)" }
11508
12464
  },
11509
- run: ({ args }) => run(() => dashboardOpen(makeCtx(), {
12465
+ run: ({ args }) => run2(() => dashboardOpen(makeCtx(), {
11510
12466
  page: args.page,
11511
12467
  email: args.email,
11512
12468
  noOpen: args.open === false
@@ -11515,7 +12471,7 @@ var dashboard = defineCommand({
11515
12471
  var members2 = defineCommand({
11516
12472
  meta: { name: "members", description: "Who can sign in to this account's dashboard (email, role, status)" },
11517
12473
  args: jsonFlag,
11518
- run: ({ args }) => run(() => membersList(makeCtx()), args)
12474
+ run: ({ args }) => run2(() => membersList(makeCtx()), args)
11519
12475
  });
11520
12476
  var root = defineCommand({
11521
12477
  meta: {
@@ -11544,6 +12500,7 @@ var root = defineCommand({
11544
12500
  video,
11545
12501
  webhooks,
11546
12502
  doctor: doctor2,
12503
+ connect: connectTool,
11547
12504
  mcp,
11548
12505
  dashboard,
11549
12506
  members: members2