@oxygen-agent/cli 1.987.20 → 1.1010.1
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 +1 -1
- package/dist/admin-primary-providers-render.d.ts +0 -2
- package/dist/admin-primary-providers-render.js +1 -1
- package/dist/browser-login.js +1 -4
- package/dist/column-decision-options.d.ts +20 -0
- package/dist/column-decision-options.js +54 -0
- package/dist/command-manifest.d.ts +3 -2
- package/dist/command-manifest.js +25 -2
- package/dist/credentials.d.ts +1 -1
- package/dist/functions-commands.js +13 -9
- package/dist/help.d.ts +8 -0
- package/dist/help.js +46 -0
- package/dist/index.js +2751 -242
- package/dist/knowledge-mirror.d.ts +2 -2
- package/dist/runtime.d.ts +0 -15
- package/dist/runtime.js +1 -1
- package/dist/search-ai-filter-notice.d.ts +17 -0
- package/dist/search-ai-filter-notice.js +38 -0
- package/dist/session.d.ts +4 -3
- package/dist/skills.d.ts +8 -7
- package/dist/skills.js +58 -20
- package/dist/transcript.d.ts +2 -1
- package/dist/util.d.ts +10 -1
- package/dist/util.js +14 -2
- package/node_modules/@oxygen/cli-ugc/dist/commands.js +296 -140
- package/node_modules/@oxygen/cli-ugc/dist/field-parser.d.ts +9 -0
- package/node_modules/@oxygen/cli-ugc/dist/field-parser.js +34 -0
- package/node_modules/@oxygen/formula/dist/coerce.d.ts +10 -0
- package/node_modules/@oxygen/formula/dist/coerce.js +10 -0
- package/node_modules/@oxygen/formula/dist/formula-functions.js +65 -0
- package/node_modules/@oxygen/formula/dist/hash.d.ts +19 -0
- package/node_modules/@oxygen/formula/dist/hash.js +199 -0
- package/node_modules/@oxygen/formula/dist/value-cleaners.d.ts +6 -1
- package/node_modules/@oxygen/formula/dist/value-cleaners.js +10 -26
- package/node_modules/@oxygen/recipe-sdk/dist/index.d.ts +13 -0
- package/node_modules/@oxygen/shared/dist/array-utils.d.ts +5 -0
- package/node_modules/@oxygen/shared/dist/array-utils.js +11 -0
- package/node_modules/@oxygen/shared/dist/billing.d.ts +99 -22
- package/node_modules/@oxygen/shared/dist/billing.js +195 -40
- package/node_modules/@oxygen/shared/dist/byok-connect.js +5 -0
- package/node_modules/@oxygen/shared/dist/capability-discovery.d.ts +27 -0
- package/node_modules/@oxygen/shared/dist/capability-discovery.js +311 -28
- package/node_modules/@oxygen/shared/dist/cli-http-error.d.ts +8 -0
- package/node_modules/@oxygen/shared/dist/cli-http-error.js +8 -0
- package/node_modules/@oxygen/shared/dist/cli-result.js +1 -0
- package/node_modules/@oxygen/shared/dist/column-autofill.d.ts +52 -0
- package/node_modules/@oxygen/shared/dist/column-autofill.js +62 -0
- package/node_modules/@oxygen/shared/dist/column-decision.d.ts +50 -0
- package/node_modules/@oxygen/shared/dist/column-decision.js +228 -0
- package/node_modules/@oxygen/shared/dist/column-output-fields.js +2 -6
- package/node_modules/@oxygen/shared/dist/company-enrichment-fields.d.ts +113 -0
- package/node_modules/@oxygen/shared/dist/company-enrichment-fields.js +548 -0
- package/node_modules/@oxygen/shared/dist/copilot-skills.generated.d.ts +6 -6
- package/node_modules/@oxygen/shared/dist/copilot-skills.generated.js +6 -6
- package/node_modules/@oxygen/shared/dist/cutover-freeze.d.ts +26 -0
- package/node_modules/@oxygen/shared/dist/cutover-freeze.js +52 -0
- package/node_modules/@oxygen/shared/dist/data-suppliers.d.ts +57 -0
- package/node_modules/@oxygen/shared/dist/data-suppliers.js +59 -0
- package/node_modules/@oxygen/shared/dist/deploy-env.d.ts +74 -0
- package/node_modules/@oxygen/shared/dist/deploy-env.js +82 -0
- package/node_modules/@oxygen/shared/dist/dnc-rules.d.ts +130 -0
- package/node_modules/@oxygen/shared/dist/dnc-rules.js +221 -0
- package/node_modules/@oxygen/shared/dist/enrichment-intents.d.ts +107 -0
- package/node_modules/@oxygen/shared/dist/enrichment-intents.js +809 -0
- package/node_modules/@oxygen/shared/dist/error-message.d.ts +1 -0
- package/node_modules/@oxygen/shared/dist/error-message.js +3 -0
- package/node_modules/@oxygen/shared/dist/error-redaction.js +1 -3
- package/node_modules/@oxygen/shared/dist/external-write-policy.d.ts +33 -0
- package/node_modules/@oxygen/shared/dist/external-write-policy.js +68 -0
- package/node_modules/@oxygen/shared/dist/format-percent.d.ts +8 -0
- package/node_modules/@oxygen/shared/dist/format-percent.js +13 -0
- package/node_modules/@oxygen/shared/dist/freemail-domains.d.ts +81 -0
- package/node_modules/@oxygen/shared/dist/freemail-domains.js +157 -0
- package/node_modules/@oxygen/shared/dist/future-signup-lifecycle-projection.d.ts +1 -0
- package/node_modules/@oxygen/shared/dist/future-signup-lifecycle-projection.js +1 -1
- package/node_modules/@oxygen/shared/dist/hosted-ai.d.ts +60 -4
- package/node_modules/@oxygen/shared/dist/hosted-ai.js +125 -10
- package/node_modules/@oxygen/shared/dist/index.d.ts +15 -0
- package/node_modules/@oxygen/shared/dist/index.js +15 -0
- package/node_modules/@oxygen/shared/dist/json-path.js +1 -3
- package/node_modules/@oxygen/shared/dist/knowledge-bases.js +1 -3
- package/node_modules/@oxygen/shared/dist/knowledge-bootstrap.d.ts +2 -2
- package/node_modules/@oxygen/shared/dist/knowledge-bootstrap.js +2 -2
- package/node_modules/@oxygen/shared/dist/langfuse.d.ts +44 -1
- package/node_modules/@oxygen/shared/dist/langfuse.js +416 -14
- package/node_modules/@oxygen/shared/dist/linkedin-countries.d.ts +33 -0
- package/node_modules/@oxygen/shared/dist/linkedin-countries.js +361 -0
- package/node_modules/@oxygen/shared/dist/linkedin-country-timezones.d.ts +24 -0
- package/node_modules/@oxygen/shared/dist/linkedin-country-timezones.js +276 -0
- package/node_modules/@oxygen/shared/dist/linkedin-message-deletion.d.ts +2 -0
- package/node_modules/@oxygen/shared/dist/linkedin-message-deletion.js +5 -0
- package/node_modules/@oxygen/shared/dist/linkedin-post-keywords.d.ts +44 -0
- package/node_modules/@oxygen/shared/dist/linkedin-post-keywords.js +116 -0
- package/node_modules/@oxygen/shared/dist/linkedin-sequences.d.ts +96 -0
- package/node_modules/@oxygen/shared/dist/linkedin-sequences.js +123 -0
- package/node_modules/@oxygen/shared/dist/llm-durable-capture.d.ts +24 -0
- package/node_modules/@oxygen/shared/dist/llm-durable-capture.js +89 -0
- package/node_modules/@oxygen/shared/dist/llm-prompts.d.ts +75 -0
- package/node_modules/@oxygen/shared/dist/llm-prompts.js +161 -0
- package/node_modules/@oxygen/shared/dist/log-sink-selector.d.ts +39 -0
- package/node_modules/@oxygen/shared/dist/log-sink-selector.js +56 -0
- package/node_modules/@oxygen/shared/dist/log.d.ts +1 -0
- package/node_modules/@oxygen/shared/dist/log.js +6 -1
- package/node_modules/@oxygen/shared/dist/mailbox-egress-ownership.d.ts +90 -0
- package/node_modules/@oxygen/shared/dist/mailbox-egress-ownership.js +130 -0
- package/node_modules/@oxygen/shared/dist/object-storage.d.ts +17 -0
- package/node_modules/@oxygen/shared/dist/object-storage.js +21 -0
- package/node_modules/@oxygen/shared/dist/operational-telemetry.d.ts +24 -0
- package/node_modules/@oxygen/shared/dist/operational-telemetry.js +73 -0
- package/node_modules/@oxygen/shared/dist/otlp-log-sink.d.ts +79 -0
- package/node_modules/@oxygen/shared/dist/otlp-log-sink.js +366 -0
- package/node_modules/@oxygen/shared/dist/plan-capabilities.js +1 -0
- package/node_modules/@oxygen/shared/dist/plan-limits.d.ts +23 -22
- package/node_modules/@oxygen/shared/dist/plan-limits.js +45 -18
- package/node_modules/@oxygen/shared/dist/pricing-sheet.d.ts +48 -41
- package/node_modules/@oxygen/shared/dist/pricing-sheet.js +36 -25
- package/node_modules/@oxygen/shared/dist/pricing-snapshot.generated.d.ts +22 -22
- package/node_modules/@oxygen/shared/dist/pricing-snapshot.generated.js +40 -34
- package/node_modules/@oxygen/shared/dist/product-analytics-environment.js +9 -0
- package/node_modules/@oxygen/shared/dist/product-analytics-events.d.ts +36 -2
- package/node_modules/@oxygen/shared/dist/product-analytics-events.js +36 -1
- package/node_modules/@oxygen/shared/dist/rate-window.d.ts +5 -0
- package/node_modules/@oxygen/shared/dist/rate-window.js +8 -0
- package/node_modules/@oxygen/shared/dist/redaction.js +4 -1
- package/node_modules/@oxygen/shared/dist/research-output-contract.js +1 -3
- package/node_modules/@oxygen/shared/dist/scraper-lane-credential.d.ts +18 -0
- package/node_modules/@oxygen/shared/dist/scraper-lane-credential.js +23 -0
- package/node_modules/@oxygen/shared/dist/search-vocab.js +4 -5
- package/node_modules/@oxygen/shared/dist/select-options.js +6 -1
- package/node_modules/@oxygen/shared/dist/sequence-failures.js +1 -5
- package/node_modules/@oxygen/shared/dist/sequences.d.ts +23 -0
- package/node_modules/@oxygen/shared/dist/sequences.js +115 -5
- package/node_modules/@oxygen/shared/dist/signup-lead-payload.d.ts +80 -0
- package/node_modules/@oxygen/shared/dist/signup-lead-payload.js +198 -0
- package/node_modules/@oxygen/shared/dist/social-capabilities.d.ts +6 -0
- package/node_modules/@oxygen/shared/dist/social-capabilities.js +25 -16
- package/node_modules/@oxygen/shared/dist/social-post-metrics-core.d.ts +32 -0
- package/node_modules/@oxygen/shared/dist/social-post-metrics-core.js +32 -0
- package/node_modules/@oxygen/shared/dist/social-post-metrics-linkedin.d.ts +31 -0
- package/node_modules/@oxygen/shared/dist/social-post-metrics-linkedin.js +103 -0
- package/node_modules/@oxygen/shared/dist/social-post-metrics-series.d.ts +96 -0
- package/node_modules/@oxygen/shared/dist/social-post-metrics-series.js +213 -0
- package/node_modules/@oxygen/shared/dist/social-post-metrics-x.d.ts +13 -0
- package/node_modules/@oxygen/shared/dist/social-post-metrics-x.js +78 -0
- package/node_modules/@oxygen/shared/dist/social-post-metrics.d.ts +36 -0
- package/node_modules/@oxygen/shared/dist/social-post-metrics.js +51 -0
- package/node_modules/@oxygen/shared/dist/spend-safety.d.ts +22 -10
- package/node_modules/@oxygen/shared/dist/spend-safety.js +15 -21
- package/node_modules/@oxygen/shared/dist/sql-rows.d.ts +1 -0
- package/node_modules/@oxygen/shared/dist/sql-rows.js +3 -0
- package/node_modules/@oxygen/shared/dist/stripe-price-catalog.d.ts +36 -0
- package/node_modules/@oxygen/shared/dist/stripe-price-catalog.js +184 -0
- package/node_modules/@oxygen/shared/dist/stripe-subscription-kind.d.ts +41 -0
- package/node_modules/@oxygen/shared/dist/stripe-subscription-kind.js +44 -0
- package/node_modules/@oxygen/shared/dist/table-limits.d.ts +3 -0
- package/node_modules/@oxygen/shared/dist/table-limits.js +3 -0
- package/node_modules/@oxygen/shared/dist/telemetry-export-observer.d.ts +94 -0
- package/node_modules/@oxygen/shared/dist/telemetry-export-observer.js +298 -0
- package/node_modules/@oxygen/shared/dist/telemetry.d.ts +11 -0
- package/node_modules/@oxygen/shared/dist/telemetry.js +28 -2
- package/node_modules/@oxygen/shared/dist/type-guards.d.ts +22 -0
- package/node_modules/@oxygen/shared/dist/type-guards.js +35 -0
- package/node_modules/@oxygen/shared/dist/ugc.d.ts +22 -11
- package/node_modules/@oxygen/shared/dist/ugc.js +10 -0
- package/node_modules/@oxygen/shared/dist/value-readers.d.ts +21 -0
- package/node_modules/@oxygen/shared/dist/value-readers.js +59 -0
- package/node_modules/@oxygen/shared/dist/version.generated.d.ts +1 -0
- package/node_modules/@oxygen/shared/dist/version.generated.js +2 -0
- package/node_modules/@oxygen/shared/dist/version.js +8 -1
- package/node_modules/@oxygen/shared/dist/workspace-event-catalog.js +0 -23
- package/node_modules/@oxygen/shared/dist/workspace-file-storage.d.ts +29 -0
- package/node_modules/@oxygen/shared/dist/workspace-file-storage.js +31 -0
- package/node_modules/@oxygen/shared/package.json +59 -0
- package/node_modules/@oxygen/workflows/dist/graph/expression.js +2 -5
- package/node_modules/@oxygen/workflows/dist/graph/params.js +1 -1
- package/package.json +3 -2
|
@@ -1,34 +1,62 @@
|
|
|
1
|
-
import { AUTOMATION_ACTION_CREDITS as SNAPSHOT_AUTOMATION_ACTION_CREDITS, CREDITS_PER_USD as SNAPSHOT_CREDITS_PER_USD, PRICING_PLAN_SNAPSHOT,
|
|
1
|
+
import { AUTOMATION_ACTION_CREDITS as SNAPSHOT_AUTOMATION_ACTION_CREDITS, CREDITS_PER_USD as SNAPSHOT_CREDITS_PER_USD, PRICING_PLAN_SNAPSHOT, TOPUP_USD_CENTS_PER_100_CREDITS as SNAPSHOT_TOPUP_USD_CENTS_PER_100_CREDITS, } from "./pricing-snapshot.generated.js";
|
|
2
2
|
import { freeTierEntitlementEnabled } from "./plan-capabilities.js";
|
|
3
|
+
import { asRecordOrNull } from "./type-guards.js";
|
|
3
4
|
export const WEEKLY_USAGE_WINDOW_DAYS = 7;
|
|
4
5
|
export const BILLING_CURRENCIES = ["usd"];
|
|
5
6
|
export const DEFAULT_BILLING_CURRENCY = "usd";
|
|
7
|
+
/**
|
|
8
|
+
* The SIX purchasable rungs of the one "Oxygen" product (founder 2026-09-19).
|
|
9
|
+
*
|
|
10
|
+
* These are plan KEYS — what Stripe sells and what `subscriptions.tier` stores —
|
|
11
|
+
* not tiers. They all share the single `oxygen` entitlement tier, which is the
|
|
12
|
+
* coarse rung plan-limits.ts and spend-safety.ts enforce against.
|
|
13
|
+
*
|
|
14
|
+
* Why keys and not six tiers: six tiers would force six new columns into every
|
|
15
|
+
* `Record<PlanTier, …>` ladder (plan limits, trigger ceilings, BYOK caps), i.e.
|
|
16
|
+
* ~40 invented numbers on an axis nobody ratified. Why not reuse starter/pro/team
|
|
17
|
+
* instead: then `plan.tier` would be ambiguous between a grandfathered $99
|
|
18
|
+
* Starter and a $49 Oxygen, and plan-change.ts — which refuses when
|
|
19
|
+
* `currentTier === targetTier` — would call a real $49 -> $99 upgrade
|
|
20
|
+
* `plan_unchanged`.
|
|
21
|
+
*/
|
|
22
|
+
export const OXYGEN_PLAN_KEYS = [
|
|
23
|
+
"oxygen_49",
|
|
24
|
+
"oxygen_99",
|
|
25
|
+
"oxygen_199",
|
|
26
|
+
"oxygen_499",
|
|
27
|
+
"oxygen_999",
|
|
28
|
+
"oxygen_1999",
|
|
29
|
+
];
|
|
6
30
|
// Scale/Enterprise contact routes to the shared support inbox, not to a
|
|
7
31
|
// founder's calendar. priority@oxygen-agent.com is the Plain Email channel
|
|
8
32
|
// (PLAIN_SUPPORT_EMAIL_ADDRESS), so an enterprise enquiry lands in the support
|
|
9
33
|
// queue as a Thread that either founder can pick up, instead of hard-coding one
|
|
10
34
|
// person's booking page into every public pricing card.
|
|
11
35
|
export const CONTACT_SALES_URL = "mailto:priority@oxygen-agent.com";
|
|
12
|
-
// One Oxygen credit is worth $0.
|
|
36
|
+
// One Oxygen credit is worth $0.01 of managed work: $1 = 100 credits.
|
|
13
37
|
// Subscription plans convert at face value — every subscription dollar grants
|
|
14
|
-
// exactly
|
|
15
|
-
// at $1.25 per
|
|
38
|
+
// exactly 100 credits — while on-demand top-up packs price the same credit
|
|
39
|
+
// at $1.25 per 100, making subscription credits exactly 20% cheaper than
|
|
16
40
|
// credits bought on demand.
|
|
17
41
|
//
|
|
42
|
+
// Re-denominated from $1 = 1,000 credits on 2026-09-19. That was a PURE unit
|
|
43
|
+
// change: every credit-denominated price divided by 10 in the same release, so
|
|
44
|
+
// the USD cost of every action is unchanged.
|
|
45
|
+
//
|
|
18
46
|
// Sourced from the generated snapshot rather than declared here: this pair was
|
|
19
47
|
// previously written down in seven production modules, and if any two ever
|
|
20
48
|
// disagreed every markup-derived price would be silently wrong by the ratio.
|
|
21
49
|
// Change them in packages/control-db/src/pricing/seed.ts.
|
|
22
50
|
export const CREDITS_PER_USD = SNAPSHOT_CREDITS_PER_USD;
|
|
23
|
-
export const
|
|
51
|
+
export const TOPUP_USD_CENTS_PER_100_CREDITS = SNAPSHOT_TOPUP_USD_CENTS_PER_100_CREDITS;
|
|
24
52
|
// On-demand purchases start at the original fixed packs' $10 floor and run up
|
|
25
|
-
// to a $1,250 ceiling, in any
|
|
53
|
+
// to a $1,250 ceiling, in any 100-credit increment. The ceiling is a
|
|
26
54
|
// single-checkout guard rail, not a spend cap: a workspace that needs more
|
|
27
55
|
// tops up again (purchased credits never expire).
|
|
28
|
-
export const CREDIT_TOPUP_MIN_CREDITS =
|
|
29
|
-
export const CREDIT_TOPUP_MAX_CREDITS =
|
|
30
|
-
export const CREDIT_TOPUP_STEP_CREDITS =
|
|
31
|
-
export const CREDIT_TOPUP_DEFAULT_CREDITS =
|
|
56
|
+
export const CREDIT_TOPUP_MIN_CREDITS = 800;
|
|
57
|
+
export const CREDIT_TOPUP_MAX_CREDITS = 100_000;
|
|
58
|
+
export const CREDIT_TOPUP_STEP_CREDITS = 100;
|
|
59
|
+
export const CREDIT_TOPUP_DEFAULT_CREDITS = 2_000;
|
|
32
60
|
export function isValidCreditTopupCredits(credits) {
|
|
33
61
|
return Number.isInteger(credits)
|
|
34
62
|
&& credits >= CREDIT_TOPUP_MIN_CREDITS
|
|
@@ -58,7 +86,7 @@ export function creditTopupAmountForShortfall(credits) {
|
|
|
58
86
|
export function creditTopupUsdCents(credits) {
|
|
59
87
|
if (!isValidCreditTopupCredits(credits))
|
|
60
88
|
return null;
|
|
61
|
-
return (credits /
|
|
89
|
+
return (credits / 100) * TOPUP_USD_CENTS_PER_100_CREDITS;
|
|
62
90
|
}
|
|
63
91
|
// Workflow/automation actions (steps, tool calls, row writes, retries) draw
|
|
64
92
|
// from the same credit pool at a flat capacity-guard rate — the old separate
|
|
@@ -101,12 +129,12 @@ export const CREDIT_COMMITMENT_KINDS = [
|
|
|
101
129
|
* Gmail and Microsoft inboxes included — and it STACKS on Oxygen-sold mailboxes,
|
|
102
130
|
* which additionally pay their own mailbox/warmup/placement lines.
|
|
103
131
|
*/
|
|
104
|
-
export const SENDING_MAILBOX_MONTHLY_CREDITS =
|
|
132
|
+
export const SENDING_MAILBOX_MONTHLY_CREDITS = 100;
|
|
105
133
|
/**
|
|
106
134
|
* Oxygen-sold managed mailbox per month, in credits ($3.00). Flat, superseding
|
|
107
135
|
* the dynamic vendor-COGS x 1.25 quote for the recurring mailbox line.
|
|
108
136
|
*/
|
|
109
|
-
export const MANAGED_MAILBOX_MONTHLY_CREDITS =
|
|
137
|
+
export const MANAGED_MAILBOX_MONTHLY_CREDITS = 300;
|
|
110
138
|
/**
|
|
111
139
|
* Grace window after a commitment goes past_due before the owning subsystem may
|
|
112
140
|
* suspend the resource. Notify -> pause -> lapse; never auto-cancel. Aligned with
|
|
@@ -168,10 +196,10 @@ export function ratifiedCommitmentCredits(kind) {
|
|
|
168
196
|
}
|
|
169
197
|
}
|
|
170
198
|
export const CREDIT_TOPUP_PACKS = [
|
|
171
|
-
{ id: "10", usdCents: 1_000, credits:
|
|
172
|
-
{ id: "25", usdCents: 2_500, credits:
|
|
173
|
-
{ id: "100", usdCents: 10_000, credits:
|
|
174
|
-
{ id: "250", usdCents: 25_000, credits:
|
|
199
|
+
{ id: "10", usdCents: 1_000, credits: 800 },
|
|
200
|
+
{ id: "25", usdCents: 2_500, credits: 2_000 },
|
|
201
|
+
{ id: "100", usdCents: 10_000, credits: 8_000 },
|
|
202
|
+
{ id: "250", usdCents: 25_000, credits: 20_000 },
|
|
175
203
|
];
|
|
176
204
|
export function resolveCreditTopupPack(id) {
|
|
177
205
|
if (!id)
|
|
@@ -184,7 +212,7 @@ export function resolveCreditTopupPack(id) {
|
|
|
184
212
|
// to that paid plan on credit exhaustion or when the trial clock elapses,
|
|
185
213
|
// whichever comes first. Starter remains the signup default.
|
|
186
214
|
export const TRIAL_PERIOD_DAYS = 7;
|
|
187
|
-
export const TRIAL_CREDIT_GRANT =
|
|
215
|
+
export const TRIAL_CREDIT_GRANT = 2_000;
|
|
188
216
|
/**
|
|
189
217
|
* Free-tier entry (founder-ratified 2026-08-16; grant collapsed to a single
|
|
190
218
|
* 10,000-credit signup grant 2026-08-26).
|
|
@@ -210,7 +238,7 @@ export const TRIAL_CREDIT_GRANT = 20_000;
|
|
|
210
238
|
* mints it a second time. Top-ups stay purchasable on free, which is what keeps
|
|
211
239
|
* the metered surface open-ended rather than capped at the grant.
|
|
212
240
|
*/
|
|
213
|
-
export const FREE_SIGNUP_GRANT_CREDITS =
|
|
241
|
+
export const FREE_SIGNUP_GRANT_CREDITS = 1_000;
|
|
214
242
|
export const FREE_TIER_GRANTS_ENABLED_ENV_VAR = "OXYGEN_FREE_TIER_GRANTS_ENABLED";
|
|
215
243
|
/**
|
|
216
244
|
* Fail-closed rollout switch for the free-tier grants, matching the staged
|
|
@@ -236,8 +264,8 @@ export function freeTierGrantsEnabled(env = process.env) {
|
|
|
236
264
|
// "start scraping engagers" step may spend at most this many credits on the
|
|
237
265
|
// managed cookieless scraper (founder-approved budget; the rest of the kickoff
|
|
238
266
|
// is free connected-account reads).
|
|
239
|
-
export const WALKTHROUGH_COMPLETION_BONUS_CREDITS =
|
|
240
|
-
export const WALKTHROUGH_SCRAPE_MAX_CREDITS =
|
|
267
|
+
export const WALKTHROUGH_COMPLETION_BONUS_CREDITS = 100;
|
|
268
|
+
export const WALKTHROUGH_SCRAPE_MAX_CREDITS = 200;
|
|
241
269
|
/**
|
|
242
270
|
* The five NUMERIC fields of a plan, read from the generated pricing snapshot.
|
|
243
271
|
*
|
|
@@ -262,6 +290,20 @@ function planPricing(planKey) {
|
|
|
262
290
|
byokEnabled: row.byokEnabled,
|
|
263
291
|
};
|
|
264
292
|
}
|
|
293
|
+
/**
|
|
294
|
+
* The monthly-credit feature bullet, DERIVED rather than written down.
|
|
295
|
+
*
|
|
296
|
+
* These strings used to be hand-typed literals ("99,000 credits every month").
|
|
297
|
+
* A re-denomination then had to find and retype every one of them, which is
|
|
298
|
+
* exactly how a price sheet ends up quoting a number the product does not
|
|
299
|
+
* charge. Never reintroduce a literal here.
|
|
300
|
+
*/
|
|
301
|
+
function monthlyCreditsFeature(planKey) {
|
|
302
|
+
const credits = planPricing(planKey).monthlyCredits;
|
|
303
|
+
if (credits === null)
|
|
304
|
+
return "Custom monthly credits";
|
|
305
|
+
return `${credits.toLocaleString("en-US")} credits every month`;
|
|
306
|
+
}
|
|
265
307
|
export const BASE_PRICING_PLANS = {
|
|
266
308
|
// The ENTRY tier since 2026-08-16, superseding the 2026-07-22 retirement that
|
|
267
309
|
// left this as the unentitled fallback for churned / never-subscribed orgs.
|
|
@@ -294,9 +336,33 @@ export const BASE_PRICING_PLANS = {
|
|
|
294
336
|
"Credits for enrichment and AI, topped up any time",
|
|
295
337
|
],
|
|
296
338
|
},
|
|
339
|
+
// The one purchasable product since 2026-09-19. Its numbers are the ENTRY
|
|
340
|
+
// rung ($49); the other five live in OXYGEN_PLAN_OVERRIDES and share this
|
|
341
|
+
// tier. Anything that needs a rung's real allowance must resolve the plan
|
|
342
|
+
// KEY (resolveBasePricingPlan("oxygen_499")), never this representative row.
|
|
343
|
+
oxygen: {
|
|
344
|
+
tier: "oxygen",
|
|
345
|
+
name: "Oxygen",
|
|
346
|
+
...planPricing("oxygen_49"),
|
|
347
|
+
monthlyAutomationActions: null,
|
|
348
|
+
automationOverageCentsPerMillion: null,
|
|
349
|
+
automationOverageEnabledDefault: false,
|
|
350
|
+
description: "Your whole GTM stack. One plan — choose the credits you need.",
|
|
351
|
+
badge: "Your whole GTM stack",
|
|
352
|
+
highlighted: true,
|
|
353
|
+
ctaLabel: "Get started",
|
|
354
|
+
features: [
|
|
355
|
+
monthlyCreditsFeature("oxygen_49"),
|
|
356
|
+
"All integrations",
|
|
357
|
+
"Workflows",
|
|
358
|
+
"Bring your own keys",
|
|
359
|
+
"Standard support",
|
|
360
|
+
],
|
|
361
|
+
},
|
|
297
362
|
starter: {
|
|
298
363
|
tier: "starter",
|
|
299
364
|
name: "Starter",
|
|
365
|
+
isLegacy: true,
|
|
300
366
|
...planPricing("starter"),
|
|
301
367
|
monthlyAutomationActions: null,
|
|
302
368
|
automationOverageCentsPerMillion: null,
|
|
@@ -304,7 +370,7 @@ export const BASE_PRICING_PLANS = {
|
|
|
304
370
|
description: "For founders running focused managed enrichment and AI columns.",
|
|
305
371
|
ctaLabel: "Choose Starter",
|
|
306
372
|
features: [
|
|
307
|
-
"
|
|
373
|
+
monthlyCreditsFeature("starter"),
|
|
308
374
|
"All integrations",
|
|
309
375
|
"Workflows",
|
|
310
376
|
"Bring your own keys",
|
|
@@ -314,6 +380,7 @@ export const BASE_PRICING_PLANS = {
|
|
|
314
380
|
pro: {
|
|
315
381
|
tier: "pro",
|
|
316
382
|
name: "Pro",
|
|
383
|
+
isLegacy: true,
|
|
317
384
|
...planPricing("pro"),
|
|
318
385
|
monthlyAutomationActions: null,
|
|
319
386
|
automationOverageCentsPerMillion: null,
|
|
@@ -323,7 +390,7 @@ export const BASE_PRICING_PLANS = {
|
|
|
323
390
|
highlighted: true,
|
|
324
391
|
ctaLabel: "Choose Pro",
|
|
325
392
|
features: [
|
|
326
|
-
"
|
|
393
|
+
monthlyCreditsFeature("pro"),
|
|
327
394
|
"All integrations",
|
|
328
395
|
"Workflows",
|
|
329
396
|
"Bring your own keys",
|
|
@@ -333,6 +400,7 @@ export const BASE_PRICING_PLANS = {
|
|
|
333
400
|
team: {
|
|
334
401
|
tier: "team",
|
|
335
402
|
name: "Team",
|
|
403
|
+
isLegacy: true,
|
|
336
404
|
...planPricing("team"),
|
|
337
405
|
monthlyAutomationActions: null,
|
|
338
406
|
automationOverageCentsPerMillion: null,
|
|
@@ -340,7 +408,7 @@ export const BASE_PRICING_PLANS = {
|
|
|
340
408
|
description: "For small GTM teams and agencies running shared workflows with their own AI keys.",
|
|
341
409
|
ctaLabel: "Choose Team",
|
|
342
410
|
features: [
|
|
343
|
-
"
|
|
411
|
+
monthlyCreditsFeature("team"),
|
|
344
412
|
"All integrations",
|
|
345
413
|
"Workflows",
|
|
346
414
|
"Bring your own keys",
|
|
@@ -358,7 +426,7 @@ export const BASE_PRICING_PLANS = {
|
|
|
358
426
|
ctaLabel: "Contact sales",
|
|
359
427
|
contactHref: CONTACT_SALES_URL,
|
|
360
428
|
features: [
|
|
361
|
-
"
|
|
429
|
+
monthlyCreditsFeature("scale"),
|
|
362
430
|
"Workflows",
|
|
363
431
|
"Phone number enrichment on managed credits",
|
|
364
432
|
"Custom provider routing and BYOK policies",
|
|
@@ -383,16 +451,22 @@ export const BASE_PRICING_PLANS = {
|
|
|
383
451
|
],
|
|
384
452
|
},
|
|
385
453
|
};
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
454
|
+
/** One public card; the six rungs are a selector inside it. */
|
|
455
|
+
export const PUBLIC_PLAN_ORDER = ["oxygen"];
|
|
456
|
+
/**
|
|
457
|
+
* Tiers whose Stripe prices must still RESOLVE. Deliberately wider than what is
|
|
458
|
+
* purchasable: starter/pro/team are grandfathered, so a live subscription on one
|
|
459
|
+
* of their prices must keep mapping to a plan. Use PURCHASABLE_PLAN_KEYS for
|
|
460
|
+
* anything that offers a plan for sale.
|
|
461
|
+
*/
|
|
391
462
|
export const SELF_SERVE_PLAN_TIERS = [
|
|
463
|
+
"oxygen",
|
|
392
464
|
"starter",
|
|
393
465
|
"pro",
|
|
394
466
|
"team",
|
|
395
467
|
];
|
|
468
|
+
/** What a customer can actually buy or switch to, cheapest first. */
|
|
469
|
+
export const PURCHASABLE_PLAN_KEYS = OXYGEN_PLAN_KEYS;
|
|
396
470
|
export const CONTACT_SALES_PLAN_TIERS = [
|
|
397
471
|
"scale",
|
|
398
472
|
"enterprise",
|
|
@@ -465,6 +539,37 @@ export function resolveSubscriptionEntitlement(input) {
|
|
|
465
539
|
}
|
|
466
540
|
return { entitled: false, reason: "missing_subscription", graceEndsAt: null };
|
|
467
541
|
}
|
|
542
|
+
/**
|
|
543
|
+
* The six purchasable rungs, keyed by plan key.
|
|
544
|
+
*
|
|
545
|
+
* Each is the representative `oxygen` plan with that rung's real price and
|
|
546
|
+
* allowance substituted in. `tier` stays "oxygen" for all six — the rung is the
|
|
547
|
+
* key, the entitlement is the tier.
|
|
548
|
+
*/
|
|
549
|
+
const OXYGEN_PLAN_OVERRIDES = {
|
|
550
|
+
oxygen_49: oxygenRung("oxygen_49"),
|
|
551
|
+
oxygen_99: oxygenRung("oxygen_99"),
|
|
552
|
+
oxygen_199: oxygenRung("oxygen_199"),
|
|
553
|
+
oxygen_499: oxygenRung("oxygen_499"),
|
|
554
|
+
oxygen_999: oxygenRung("oxygen_999"),
|
|
555
|
+
oxygen_1999: oxygenRung("oxygen_1999"),
|
|
556
|
+
};
|
|
557
|
+
function oxygenRung(planKey) {
|
|
558
|
+
const pricing = planPricing(planKey);
|
|
559
|
+
const dollars = pricing.monthlyPriceCents === null
|
|
560
|
+
? null
|
|
561
|
+
: Math.round(pricing.monthlyPriceCents / 100);
|
|
562
|
+
return {
|
|
563
|
+
...BASE_PRICING_PLANS.oxygen,
|
|
564
|
+
...pricing,
|
|
565
|
+
name: dollars === null ? "Oxygen" : `Oxygen $${dollars.toLocaleString("en-US")}`,
|
|
566
|
+
ctaLabel: dollars === null ? "Get started" : `Choose $${dollars.toLocaleString("en-US")}`,
|
|
567
|
+
features: [
|
|
568
|
+
monthlyCreditsFeature(planKey),
|
|
569
|
+
...BASE_PRICING_PLANS.oxygen.features.slice(1),
|
|
570
|
+
],
|
|
571
|
+
};
|
|
572
|
+
}
|
|
468
573
|
const LEGACY_PRICING_PLAN_OVERRIDES = {
|
|
469
574
|
launch_50: {
|
|
470
575
|
...BASE_PRICING_PLANS.starter,
|
|
@@ -515,6 +620,12 @@ const LEGACY_PRICING_PLAN_OVERRIDES = {
|
|
|
515
620
|
export function resolveBasePricingPlan(tier) {
|
|
516
621
|
if (!tier)
|
|
517
622
|
return null;
|
|
623
|
+
// Plan KEYS before tiers: `subscriptions.tier` stores "oxygen_499", and the
|
|
624
|
+
// rung's own allowance — not the representative $49 row — is what the
|
|
625
|
+
// customer paid for.
|
|
626
|
+
const oxygen = OXYGEN_PLAN_OVERRIDES[tier];
|
|
627
|
+
if (oxygen)
|
|
628
|
+
return oxygen;
|
|
518
629
|
if (tier in BASE_PRICING_PLANS) {
|
|
519
630
|
return BASE_PRICING_PLANS[tier];
|
|
520
631
|
}
|
|
@@ -523,13 +634,13 @@ export function resolveBasePricingPlan(tier) {
|
|
|
523
634
|
}
|
|
524
635
|
export function applyPricingPlanMetadataOverrides(// skipcq: JS-R1005
|
|
525
636
|
plan, metadata) {
|
|
526
|
-
const record =
|
|
637
|
+
const record = asRecordOrNull(metadata);
|
|
527
638
|
if (!record)
|
|
528
639
|
return plan;
|
|
529
|
-
const config =
|
|
530
|
-
??
|
|
531
|
-
??
|
|
532
|
-
??
|
|
640
|
+
const config = asRecordOrNull(record.billing_plan)
|
|
641
|
+
?? asRecordOrNull(record.custom_plan)
|
|
642
|
+
?? asRecordOrNull(record.custom_limits)
|
|
643
|
+
?? asRecordOrNull(record.plan_limits)
|
|
533
644
|
?? record;
|
|
534
645
|
const name = readString(config, "name")
|
|
535
646
|
?? readString(config, "plan_name")
|
|
@@ -567,17 +678,33 @@ plan, metadata) {
|
|
|
567
678
|
export function isSelfServePlanTier(value) {
|
|
568
679
|
return SELF_SERVE_PLAN_TIERS.includes(value);
|
|
569
680
|
}
|
|
681
|
+
// Keyed by PlanTier so a new tier is a compile error here until someone decides
|
|
682
|
+
// it. The hand-typed list this replaced predated the 2026-09-19 "oxygen" tier,
|
|
683
|
+
// so every customer on the one purchasable plan was refused managed phone
|
|
684
|
+
// enrichment that Free and the grandfathered plans still had.
|
|
685
|
+
const MANAGED_PHONE_PLAN_TIER_ALLOWED = {
|
|
686
|
+
free: true,
|
|
687
|
+
oxygen: true,
|
|
688
|
+
starter: true,
|
|
689
|
+
pro: true,
|
|
690
|
+
team: true,
|
|
691
|
+
scale: true,
|
|
692
|
+
enterprise: true,
|
|
693
|
+
};
|
|
694
|
+
export const MANAGED_PHONE_PLAN_TIERS = Object.keys(MANAGED_PHONE_PLAN_TIER_ALLOWED).filter((tier) => MANAGED_PHONE_PLAN_TIER_ALLOWED[tier]);
|
|
695
|
+
export function planAllowsManagedPhoneEnrichment(tier) {
|
|
696
|
+
return MANAGED_PHONE_PLAN_TIERS.includes(tier);
|
|
697
|
+
}
|
|
698
|
+
/** True for the six rungs a customer may buy or switch to. */
|
|
699
|
+
export function isPurchasablePlanKey(value) {
|
|
700
|
+
return PURCHASABLE_PLAN_KEYS.includes(value);
|
|
701
|
+
}
|
|
570
702
|
export function isBillingCurrency(value) {
|
|
571
703
|
return BILLING_CURRENCIES.includes(value);
|
|
572
704
|
}
|
|
573
705
|
export function normalizeBillingCurrency(value) {
|
|
574
706
|
return value && isBillingCurrency(value) ? value : DEFAULT_BILLING_CURRENCY;
|
|
575
707
|
}
|
|
576
|
-
function readRecord(value) {
|
|
577
|
-
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
578
|
-
return null;
|
|
579
|
-
return value;
|
|
580
|
-
}
|
|
581
708
|
function readString(record, key) {
|
|
582
709
|
const value = record[key];
|
|
583
710
|
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
@@ -645,6 +772,34 @@ function formatUtcDay(date) {
|
|
|
645
772
|
timeZone: "UTC",
|
|
646
773
|
});
|
|
647
774
|
}
|
|
775
|
+
/**
|
|
776
|
+
* Whether a subscription row has a real Stripe object behind it that Stripe's
|
|
777
|
+
* own APIs (retrieve, update, invoice preview, portal flows) can act on.
|
|
778
|
+
*
|
|
779
|
+
* Three kinds of row say no: a staff-invoiced manual contract (`manual_contract_`
|
|
780
|
+
* id and/or `off_stripe` in either spelling the codebase has written), a
|
|
781
|
+
* control-plane-only internal grant (`internal_dogfood_…`), and a hand-inserted
|
|
782
|
+
* synthetic row that DOES carry a `sub_` prefix but marks itself
|
|
783
|
+
* `metadata.synthetic: true`. That last shape is why the id prefix alone is not
|
|
784
|
+
* the test: the dev dogfood org's `sub_synthetic_dev_dogfood_…` row passed every
|
|
785
|
+
* `startsWith("sub_")` check and reached `stripe.subscriptions.retrieve`, where
|
|
786
|
+
* Stripe answered "No such subscription" and the customer read the generic
|
|
787
|
+
* "Unable to preview the plan change." Every self-serve Stripe mutation must
|
|
788
|
+
* refuse these rows before it calls Stripe, with a message that names the fix.
|
|
789
|
+
*/
|
|
790
|
+
export function isStripeManagedSubscription(subscription) {
|
|
791
|
+
// A row with no usable id is not something Stripe manages; answer false
|
|
792
|
+
// rather than throw, because this runs inside read-only pages (the billing
|
|
793
|
+
// summary) where a throw becomes a 500 for the whole page.
|
|
794
|
+
if (typeof subscription.stripeSubscriptionId !== "string")
|
|
795
|
+
return false;
|
|
796
|
+
if (!subscription.stripeSubscriptionId.startsWith("sub_"))
|
|
797
|
+
return false;
|
|
798
|
+
const metadata = subscription.metadata ?? {};
|
|
799
|
+
return (metadata.off_stripe !== true
|
|
800
|
+
&& metadata.off_stripe !== "true"
|
|
801
|
+
&& metadata.synthetic !== true);
|
|
802
|
+
}
|
|
648
803
|
/**
|
|
649
804
|
* The window the credit-allowance bar measures: "this month's credits", resolved
|
|
650
805
|
* to the boundary at which the plan's grant actually renews.
|
|
@@ -72,13 +72,18 @@ export const NATIVE_API_KEY_CONNECT_INTEGRATION_IDS = new Set([
|
|
|
72
72
|
// Native api-key connect added in catalog.ts (2026-09-10): connect writes an
|
|
73
73
|
// integration_secrets api_key row the native parallel.* runner reads. T-104.
|
|
74
74
|
"parallel",
|
|
75
|
+
"pipedrive",
|
|
75
76
|
"predictleads",
|
|
76
77
|
"prospeo",
|
|
77
78
|
"scalelist",
|
|
79
|
+
// scrapeli / up2data (2026-09-25): the company-followers and LinkedIn post lanes
|
|
80
|
+
// offer "Bring your own API key"; both connect forms live in catalog.ts.
|
|
81
|
+
"scrapeli",
|
|
78
82
|
// scraper: dev v1.920.2 added the HarvestAPI workspace-key connect (native api-key form).
|
|
79
83
|
"scraper",
|
|
80
84
|
"serper",
|
|
81
85
|
"signalbase",
|
|
86
|
+
"up2data",
|
|
82
87
|
"zapmail",
|
|
83
88
|
"zerobounce",
|
|
84
89
|
]);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type EnrichmentIntentTaxonomyEntry } from "./enrichment-intents.js";
|
|
1
2
|
import { type RecipePrimitive } from "./recipes.js";
|
|
2
3
|
export type CapabilityLayer = "Control" | "Knowledge" | "Data" | "Action" | "External";
|
|
3
4
|
export type CapabilityPosture = "read_only" | "workspace_write" | "paid_read" | "external_write" | "mixed";
|
|
@@ -29,6 +30,22 @@ export type CapabilityRouteMatch = {
|
|
|
29
30
|
* intent is that narrow; `recommendedCommands[0]` is the same command.
|
|
30
31
|
*/
|
|
31
32
|
exactCommand?: string;
|
|
33
|
+
/**
|
|
34
|
+
* The opinionated enrichment catalogue row a data-type ask resolves to
|
|
35
|
+
* ("get the funding round" -> enrich_company:funding). Present only when
|
|
36
|
+
* the ask names a data type; the catalogue command is then the first
|
|
37
|
+
* recommendation, ahead of any raw provider tool.
|
|
38
|
+
*/
|
|
39
|
+
catalogIntent?: {
|
|
40
|
+
id: string;
|
|
41
|
+
label: string;
|
|
42
|
+
status: EnrichmentIntentTaxonomyEntry["status"];
|
|
43
|
+
group: EnrichmentIntentTaxonomyEntry["group"];
|
|
44
|
+
/** The catalogue-first path: read the row, then add/preview; `exactCommand` names the row. */
|
|
45
|
+
tools: string[];
|
|
46
|
+
commands: string[];
|
|
47
|
+
exactCommand: string;
|
|
48
|
+
};
|
|
32
49
|
};
|
|
33
50
|
export type PrimitiveRouteMatch = CapabilityRouteMatch & {
|
|
34
51
|
card: PrimitiveRouteCard;
|
|
@@ -40,5 +57,15 @@ export declare function getCapabilityRouteMatch(id: string): CapabilityRouteMatc
|
|
|
40
57
|
export declare function inferCapabilityRoute(query: string): CapabilityRouteMatch | null;
|
|
41
58
|
export declare function inferPrimitiveRoute(query: string): PrimitiveRouteMatch | null;
|
|
42
59
|
export declare function serializeCapabilityRoute(route: CapabilityRouteMatch | null): Record<string, unknown> | null;
|
|
60
|
+
export declare const COMPANY_PAGE_FOLLOWERS_COMMAND = "oxygen tables followers check --company <linkedin company page URL> --records <n> --json";
|
|
43
61
|
/** The exact `companies search plan` invocation for the url_recovery intent. */
|
|
44
62
|
export declare const COMPANY_URL_RECOVERY_COMMAND = "oxygen companies search plan --prompt \"Find the websites for these companies: <company names>\" --source-intent url_recovery";
|
|
63
|
+
/** The free native preview for Google Maps businesses; import follows its reviewed quote. */
|
|
64
|
+
export declare const LOCAL_BUSINESS_SCRAPE_COMMAND = "oxygen companies search preview --source google_maps --filters-json '{\"q\":\"<category> in <city, region>\"}'";
|
|
65
|
+
/**
|
|
66
|
+
* The free list of classification columns. Production answers it with its one
|
|
67
|
+
* classification template (B2B or B2C); a deployment that runs the native
|
|
68
|
+
* Classify column lists that entry here too. Any other scheme is an AI prompt
|
|
69
|
+
* column through `columns add`, which the route recommends next.
|
|
70
|
+
*/
|
|
71
|
+
export declare const ROW_CLASSIFICATION_COMMAND = "oxygen columns catalog --family classification";
|