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.
- package/README.md +9 -1
- package/dist/index.js +1174 -217
- 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.
|
|
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
|
|
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
|
|
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
|
|
8448
|
+
var Day3 = object({ date: string2().optional(), index: string2().optional(), views: Num3, clicks: Num3, cost: Num3 });
|
|
8301
8449
|
var Report = object({
|
|
8302
|
-
days: array(
|
|
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(
|
|
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
|
|
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:
|
|
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:
|
|
9112
|
-
signups_to:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
9254
|
+
spend: object({ from: Day4, to: Day4 }),
|
|
9201
9255
|
dates: object({
|
|
9202
|
-
pause_check:
|
|
9203
|
-
cost_read:
|
|
9204
|
-
payment_read:
|
|
9205
|
-
tail_read:
|
|
9206
|
-
tail_signups_to:
|
|
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:
|
|
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-
|
|
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
|
|
9797
|
+
var NPX = "npx -y scaledthought@0.3";
|
|
9746
9798
|
var FIRST_TOPUP_USD = 20;
|
|
9747
|
-
var TOPUP_COMMAND = `${
|
|
9748
|
-
var WAIT_COMMAND = `${
|
|
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: ${
|
|
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: ${
|
|
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 : `${
|
|
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:
|
|
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 =
|
|
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: ${
|
|
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 \`${
|
|
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
|
|
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(
|
|
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
|
-
|
|
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
|
|
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 }) =>
|
|
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
|
|
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 }) =>
|
|
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 }) =>
|
|
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
|
|
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 }) =>
|
|
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 }) =>
|
|
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 }) =>
|
|
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 }) =>
|
|
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:
|
|
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 }) =>
|
|
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 }) =>
|
|
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 }) =>
|
|
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 }) =>
|
|
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:
|
|
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",
|
|
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
|
|
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 }) =>
|
|
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 }) =>
|
|
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 }) =>
|
|
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
|
|
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 }) =>
|
|
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
|
|
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
|
|
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 }) =>
|
|
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 }) =>
|
|
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 }) =>
|
|
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 }) =>
|
|
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 }) =>
|
|
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 }) =>
|
|
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 }) =>
|
|
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 }) =>
|
|
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 }) =>
|
|
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 }) =>
|
|
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 }) =>
|
|
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 }) =>
|
|
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 }) =>
|
|
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 }) =>
|
|
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 }) =>
|
|
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 }) =>
|
|
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 }) =>
|
|
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 }) =>
|
|
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 }) =>
|
|
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 }) =>
|
|
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 }) =>
|
|
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 }) =>
|
|
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 }) =>
|
|
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 }) =>
|
|
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 }) =>
|
|
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 }) =>
|
|
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 }) =>
|
|
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 }) =>
|
|
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
|