@oxygen-agent/cli 1.1014.86 → 1.1014.119
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/command-manifest.js +4 -1
- package/dist/help.js +5 -0
- package/dist/index.js +133 -80
- package/dist/skills.js +2 -0
- package/node_modules/@oxygen/shared/dist/capability-discovery.js +122 -0
- package/node_modules/@oxygen/shared/dist/contracts/browser-operations.js +14 -4
- package/node_modules/@oxygen/shared/dist/contracts/customer-operations.js +6 -5
- package/node_modules/@oxygen/shared/dist/contracts/knowledge-sync.d.ts +19 -0
- package/node_modules/@oxygen/shared/dist/contracts/knowledge-sync.js +8 -0
- package/node_modules/@oxygen/shared/dist/contracts/publishing-reads.d.ts +7 -0
- package/node_modules/@oxygen/shared/dist/contracts/schema.d.ts +3 -0
- package/node_modules/@oxygen/shared/dist/contracts/schema.js +3 -0
- package/node_modules/@oxygen/shared/dist/contracts/table-feed-read.d.ts +1 -0
- package/node_modules/@oxygen/shared/dist/contracts/table-row-read.d.ts +2 -0
- package/node_modules/@oxygen/shared/dist/credit-gate.js +2 -1
- package/node_modules/@oxygen/shared/dist/mcp-event-contract.d.ts +12 -0
- package/node_modules/@oxygen/shared/dist/otlp-log-sink.d.ts +1 -1
- package/node_modules/@oxygen/shared/dist/otlp-log-sink.js +1 -0
- package/node_modules/@oxygen/shared/dist/plan-capabilities.d.ts +9 -2
- package/node_modules/@oxygen/shared/dist/plan-capabilities.js +14 -1
- package/node_modules/@oxygen/shared/dist/sending-schedule.d.ts +7 -0
- package/node_modules/@oxygen/shared/dist/sending-schedule.js +10 -0
- package/node_modules/@oxygen/shared/dist/user-capability-routing.d.ts +2 -0
- package/node_modules/@oxygen/shared/dist/user-capability-routing.js +8 -0
- package/node_modules/@oxygen/shared/dist/version.generated.d.ts +1 -1
- package/node_modules/@oxygen/shared/dist/version.generated.js +1 -1
- package/package.json +1 -1
|
@@ -1018,6 +1018,18 @@ const CRM_ENRICHMENT_READ_VIEW = {
|
|
|
1018
1018
|
};
|
|
1019
1019
|
/** The card a route reports: Publishing's own, or its UGC view for a creator-program ask. */
|
|
1020
1020
|
function routeCardFor(card, query) {
|
|
1021
|
+
const placementGuide = card.id === "sending-infrastructure" ? placementGuideRecommendation(query) : null;
|
|
1022
|
+
if (placementGuide)
|
|
1023
|
+
card = { ...card, posture: "read_only", execution: placementGuide.execution };
|
|
1024
|
+
const lookup = card.id === "tables" ? linkedinUrlFindingRecommendation(query) : null;
|
|
1025
|
+
if (lookup)
|
|
1026
|
+
card = { ...card, execution: lookup.execution };
|
|
1027
|
+
const pageResearch = card.id === "sourcing-and-provider-tools" ? pageScrapingRecommendation(query) : null;
|
|
1028
|
+
if (pageResearch)
|
|
1029
|
+
card = { ...card, execution: pageResearch.execution };
|
|
1030
|
+
const collaboration = card.id === "collaboration" ? collaborationRecommendation(query) : null;
|
|
1031
|
+
if (collaboration)
|
|
1032
|
+
card = { ...card, execution: collaboration.execution, posture: collaboration.posture };
|
|
1021
1033
|
if (card.id === "records" && isCrmEnrichmentConfigurationRead(query))
|
|
1022
1034
|
return { ...card, ...CRM_ENRICHMENT_READ_VIEW };
|
|
1023
1035
|
const crmMaintenance = card.id === "records" ? crmMaintenanceRecommendation(query) : null;
|
|
@@ -1115,6 +1127,8 @@ function routeCardFor(card, query) {
|
|
|
1115
1127
|
/** Search surfaces share the selected skill owner; a general router is fallback. */
|
|
1116
1128
|
function preferredSkillForIntent(card, query) {
|
|
1117
1129
|
if (card.id === "tables") {
|
|
1130
|
+
if (linkedinUrlFindingRecommendation(query))
|
|
1131
|
+
return "oxygen-enrichment";
|
|
1118
1132
|
if (/\bclay\b/.test(query) && /\b(import|export|migrat\w*|mov\w*)\b/.test(query))
|
|
1119
1133
|
return "oxygen-clay-migration";
|
|
1120
1134
|
if (isTableMaintenanceIntent(query))
|
|
@@ -1926,6 +1940,8 @@ function explicitCapabilityIntent(query) {
|
|
|
1926
1940
|
if (isWorkspacePagesIntent(query) || isWorkspaceSettingsIntent(query)) {
|
|
1927
1941
|
return ROUTE_BY_ID.get("workspace-access") ?? null;
|
|
1928
1942
|
}
|
|
1943
|
+
if (collaborationRecommendation(query))
|
|
1944
|
+
return ROUTE_BY_ID.get("collaboration") ?? null;
|
|
1929
1945
|
if (/\btables?\b/.test(query) && isSecondPartyDecisionIntent(query))
|
|
1930
1946
|
return ROUTE_BY_ID.get("collaboration") ?? null;
|
|
1931
1947
|
if (tableReadRecommendation(query) || tableMaintenanceRecommendation(query))
|
|
@@ -2009,6 +2025,8 @@ function explicitCapabilityIntent(query) {
|
|
|
2009
2025
|
}
|
|
2010
2026
|
if (isHostedWorkflowIntent(query))
|
|
2011
2027
|
return ROUTE_BY_PRIMITIVE.get("workflows") ?? null;
|
|
2028
|
+
if (placementGuideRecommendation(query))
|
|
2029
|
+
return ROUTE_BY_ID.get("sending-infrastructure") ?? null;
|
|
2012
2030
|
if (isCompanySourcingIntent(query))
|
|
2013
2031
|
return ROUTE_BY_ID.get("sourcing-and-provider-tools") ?? null;
|
|
2014
2032
|
if (isOwnedPostCommentIntent(query))
|
|
@@ -2053,6 +2071,8 @@ function explicitCapabilityIntent(query) {
|
|
|
2053
2071
|
// research input.
|
|
2054
2072
|
if (isNetNewLinkedInInitiation(query))
|
|
2055
2073
|
return ROUTE_BY_PRIMITIVE.get("sequences") ?? null;
|
|
2074
|
+
if (linkedinUrlFindingRecommendation(query))
|
|
2075
|
+
return ROUTE_BY_PRIMITIVE.get("tables") ?? null;
|
|
2056
2076
|
if (isPublicLinkedInRead(query))
|
|
2057
2077
|
return ROUTE_BY_ID.get("linkedin-public-research") ?? null;
|
|
2058
2078
|
if (/\b(my|our|own)\b.{0,40}\blinkedin\b.{0,40}\b(post )?engagers?\b/.test(query)) {
|
|
@@ -2134,6 +2154,10 @@ function explicitCapabilityIntent(query) {
|
|
|
2134
2154
|
// company_enrich preset instead.
|
|
2135
2155
|
if (isCompanyUrlRecoveryIntent(query))
|
|
2136
2156
|
return ROUTE_BY_ID.get("sourcing-and-provider-tools") ?? null;
|
|
2157
|
+
if (pageScrapingRecommendation(query))
|
|
2158
|
+
return ROUTE_BY_ID.get("sourcing-and-provider-tools") ?? null;
|
|
2159
|
+
if (/\bagency partners?\b/.test(query))
|
|
2160
|
+
return ROUTE_BY_ID.get("agency-directory") ?? null;
|
|
2137
2161
|
// A category-plus-place ask ("dental practices in Austin", "local businesses",
|
|
2138
2162
|
// "scrape Google Maps") is the companies-search `local` intent. A 2026-09-21
|
|
2139
2163
|
// blind user typing "find local businesses like dental practices in a city"
|
|
@@ -2212,6 +2236,18 @@ function isPublishingPostIntent(query) {
|
|
|
2212
2236
|
&& !(/\b(find|search|scrape|research)\b/.test(query) && /\b(about|mention|containing)\b/.test(query));
|
|
2213
2237
|
}
|
|
2214
2238
|
function recommendationsFor(card, query) {
|
|
2239
|
+
const placementGuide = card.id === "sending-infrastructure" ? placementGuideRecommendation(query) : null;
|
|
2240
|
+
if (placementGuide)
|
|
2241
|
+
return placementGuide;
|
|
2242
|
+
const lookup = card.id === "tables" ? linkedinUrlFindingRecommendation(query) : null;
|
|
2243
|
+
if (lookup)
|
|
2244
|
+
return lookup;
|
|
2245
|
+
const pageResearch = card.id === "sourcing-and-provider-tools" ? pageScrapingRecommendation(query) : null;
|
|
2246
|
+
if (pageResearch)
|
|
2247
|
+
return pageResearch;
|
|
2248
|
+
const collaboration = card.id === "collaboration" ? collaborationRecommendation(query) : null;
|
|
2249
|
+
if (collaboration)
|
|
2250
|
+
return collaboration;
|
|
2215
2251
|
if (card.id === "knowledge-graph" && isWorkspaceSkillIntent(query)) {
|
|
2216
2252
|
return { tools: ["oxygen_workspace_skills_list", "oxygen_workspace_skills_create", "oxygen_workspace_skills_import", "oxygen_workspace_skills_get", "oxygen_workspace_skills_update", "oxygen_workspace_skills_archive"],
|
|
2217
2253
|
commands: ["skills workspace list", "skills workspace create", "skills workspace import", "skills workspace get", "skills workspace update", "skills workspace archive"] };
|
|
@@ -2930,6 +2966,48 @@ function isRowClassificationIntent(query) {
|
|
|
2930
2966
|
function isCompanyResearchQuestionIntent(query) {
|
|
2931
2967
|
return /\b(founders?|founded by|parent compan(?:y|ies)|subsidiar(?:y|ies)|cloud provider|naics|column templates?|template catalog|ready[- ]made|research question|company research|offers? demos?|gives? demos?)\b/.test(query);
|
|
2932
2968
|
}
|
|
2969
|
+
/** Supporting placement instructions belong to deliverability, even when the ask names an inbox. */
|
|
2970
|
+
function placementGuideRecommendation(query) {
|
|
2971
|
+
if (!/\bplacement(?:[- ]tests?)?\b/.test(query)
|
|
2972
|
+
|| !/\b(guidance|guide|instructions|supporting|read|docs?|documentation)\b/.test(query)
|
|
2973
|
+
|| /\b(run|send|create|connect|enable)\b/.test(query))
|
|
2974
|
+
return null;
|
|
2975
|
+
return {
|
|
2976
|
+
tools: ["oxygen_skills_get"],
|
|
2977
|
+
commands: ["skills get"],
|
|
2978
|
+
exactCommand: "oxygen skills get oxygen-deliverability --file references/placement.md --json",
|
|
2979
|
+
exactMcpCall: { tool: "oxygen_skills_get", arguments: { name: "oxygen-deliverability", file: "references/placement.md" } },
|
|
2980
|
+
execution: "Read oxygen-deliverability, references/placement.md for placement-test guidance and references/emailguard.md for inbox monitoring. Instruction reads do not run a test or enroll a mailbox. Keep the live preview, sender scope, credit ceiling and separate approvals for provider provisioning and test sends.",
|
|
2981
|
+
};
|
|
2982
|
+
}
|
|
2983
|
+
/** OXP-43.72: pricing qualifies the lookup or scrape, rather than changing its owner. */
|
|
2984
|
+
function linkedinUrlFindingRecommendation(query) {
|
|
2985
|
+
if (!/\blinkedin\b/.test(query) || !/\b(urls?|links?)\b/.test(query)
|
|
2986
|
+
|| !/\b(find|finding|lookup|look up|resolve|missing)\b/.test(query)
|
|
2987
|
+
|| /\b(scrape\w*|posts?|comments?|engagers?|followers?|connect|inbox|send\w*|publish\w*)\b/.test(query)
|
|
2988
|
+
|| /\bcompany pages?\b/.test(query))
|
|
2989
|
+
return null;
|
|
2990
|
+
return {
|
|
2991
|
+
tools: ["oxygen_tools_search", "oxygen_columns_add", "oxygen_enrich_column_preview"],
|
|
2992
|
+
commands: ["tools search", "columns add", "enrich-column preview"],
|
|
2993
|
+
exactCommand: "oxygen tools search find_linkedin_url --json",
|
|
2994
|
+
exactMcpCall: { tool: "oxygen_tools_search", arguments: { query: "find_linkedin_url" } },
|
|
2995
|
+
execution: "Inspect the native LinkedIn URL waterfall and current pricing with tools search find_linkedin_url. Read oxygen-enrichment and its references/linkedin-url.md. Add the linkedin_url capability to existing rows, then preview the exact row scope for free before an approved run with a credit ceiling. Known-profile scraping is a separate operation.",
|
|
2996
|
+
};
|
|
2997
|
+
}
|
|
2998
|
+
function pageScrapingRecommendation(query) {
|
|
2999
|
+
if (!/\b(scrap(?:e|ing)|crawl\w*|fetch|extract)\b/.test(query)
|
|
3000
|
+
|| !/\b(pages?|websites?|web ?sites?|web content|urls?)\b/.test(query)
|
|
3001
|
+
|| /\b(linkedin|emails?|phones?|crm|records?)\b/.test(query))
|
|
3002
|
+
return null;
|
|
3003
|
+
return {
|
|
3004
|
+
tools: ["oxygen_tools_search", "oxygen_tools_get"],
|
|
3005
|
+
commands: ["tools search", "tools get"],
|
|
3006
|
+
exactCommand: "oxygen tools search firecrawl --json",
|
|
3007
|
+
exactMcpCall: { tool: "oxygen_tools_search", arguments: { query: "firecrawl" } },
|
|
3008
|
+
execution: "Discover public-page operations with tools search firecrawl, then hydrate one exact tool and its pricing. Read oxygen-sourcing and provider-runbooks/firecrawl.md. Preview the selected URLs and price before execution; live scraping requires approval for the exact URL scope and credit ceiling. For durable per-row research, use native Tables research columns. Discovery does not run a scrape.",
|
|
3009
|
+
};
|
|
3010
|
+
}
|
|
2933
3011
|
function isCompanyUrlRecoveryIntent(query) {
|
|
2934
3012
|
const urlNoun = /\b(websites?|web ?sites?|website urls?|domains?|urls?|homepages?)\b/;
|
|
2935
3013
|
const companyNoun = /\b(compan(?:y|ies)|accounts?|organi[sz]ations?|brands?|vendors?)\b/;
|
|
@@ -3109,6 +3187,50 @@ function isNetNewLinkedInInitiation(query) {
|
|
|
3109
3187
|
return false;
|
|
3110
3188
|
return !/\b(sequence|campaign|cadence|enroll|nurture|multi[ -]step|multi[ -]recipient|leads|contacts|recipients|audience|rotate senders?|stop on reply|day\s*\d+)\b/.test(query);
|
|
3111
3189
|
}
|
|
3190
|
+
/** Recommendations point to the mounted native owners, without conferring their write authority. */
|
|
3191
|
+
function collaborationRecommendation(query) {
|
|
3192
|
+
const memberRead = { tools: ["oxygen_workspace_members_list"], commands: ["approvals client list"],
|
|
3193
|
+
execution: "Read workspace member roles, Clerk profiles and pending invitations. This does not invite anyone or change access. Free.", posture: "read_only" };
|
|
3194
|
+
const member = /\b(members?|memberships?)\b/.test(query);
|
|
3195
|
+
const workspace = /\b(workspace|organization|org)\b/.test(query);
|
|
3196
|
+
const clientRole = /\bclient (?:role|access|login)\b/.test(query);
|
|
3197
|
+
const roleWrite = /\b(set|change|grant|clear|remove|revoke|restrict|promote|demote)\b/.test(query);
|
|
3198
|
+
if (clientRole && roleWrite && !/\b(crm|records?|contacts?|companies|api|oauth)\b/.test(query)) {
|
|
3199
|
+
const clear = /\b(clear|remove|revoke)\b/.test(query);
|
|
3200
|
+
return { tools: ["oxygen_members_client_role_set", ...memberRead.tools], commands: [clear ? "approvals client revoke" : "approvals client grant", ...memberRead.commands],
|
|
3201
|
+
execution: "An admin can set or clear the restricted client overlay; a pending invite is checked in Clerk. This sends no invitation and does not change the Clerk workspace role. Free.", posture: "workspace_write" };
|
|
3202
|
+
}
|
|
3203
|
+
if (workspace && member && roleWrite && /\b(roles?|admin|administrator)\b/.test(query))
|
|
3204
|
+
return {
|
|
3205
|
+
tools: ["oxygen_members_workspace_role_set", ...memberRead.tools], commands: ["orgs member-role", ...memberRead.commands],
|
|
3206
|
+
execution: "An admin changes a member's workspace role in Clerk before Oxygen mirrors it. Self-role changes and the last administrator are protected; the client overlay is separate. Free.", posture: "workspace_write",
|
|
3207
|
+
};
|
|
3208
|
+
if (((workspace && member) || clientRole || /\bwho is in (?:my|our|this|the) workspace\b/.test(query))
|
|
3209
|
+
&& !/\b(invite|add|delete|cancel|enable|disable|set|change|grant|clear|remove|revoke|restrict|promote|demote)\b/.test(query))
|
|
3210
|
+
return memberRead;
|
|
3211
|
+
if (/\b(?:approval|launch|sign ?off) gates?\b/.test(query)) {
|
|
3212
|
+
const write = /\b(arm|set|enable|disable|require|change|turn)\b/.test(query);
|
|
3213
|
+
return { tools: write ? ["oxygen_approvals_gate_set", "oxygen_approval_gates_list"] : ["oxygen_approval_gates_list", "oxygen_approvals_gate_set"],
|
|
3214
|
+
commands: write ? ["approvals gate set", "approvals gate list"] : ["approvals gate list", "approvals gate set"],
|
|
3215
|
+
execution: write ? "An admin configures the approval gate; this grants no approval. Launch gates a sequence; signoff gates a table. The owning primitive enforces it. Free."
|
|
3216
|
+
: "Read configured approval gates and effective state for an exact subject. Reading a gate grants no approval. Free.", posture: write ? "workspace_write" : "read_only" };
|
|
3217
|
+
}
|
|
3218
|
+
if (/\bcomments?\b/.test(query) && /\b(internal|workspace|teammate|client)\b/.test(query)
|
|
3219
|
+
&& !/\b(linkedin|public|published|posts?|publishing)\b/.test(query)) {
|
|
3220
|
+
if (/\b(edit|update|correct)\b/.test(query))
|
|
3221
|
+
return { tools: ["oxygen_comments_edit", "oxygen_comments_list"], commands: ["comments edit", "comments list"],
|
|
3222
|
+
execution: "Edit your own internal workspace comment by comment id; the author check and edit time are enforced by its native owner. Free.", posture: "workspace_write" };
|
|
3223
|
+
if (/\b(delete|retract|remove)\b/.test(query))
|
|
3224
|
+
return { tools: ["oxygen_comments_delete", "oxygen_comments_list"], commands: ["comments delete", "comments list"],
|
|
3225
|
+
execution: "Retract your own internal comment by comment id. Its audit placeholder remains; this does not delete a public post comment. Free.", posture: "workspace_write" };
|
|
3226
|
+
}
|
|
3227
|
+
if (/\b(cancel|withdraw|retract)\b/.test(query) && /\b(?:approval|sign ?off) requests?\b/.test(query))
|
|
3228
|
+
return {
|
|
3229
|
+
tools: ["oxygen_approvals_cancel", "oxygen_approvals_list"], commands: ["approvals cancel", "approvals list"],
|
|
3230
|
+
execution: "Withdraw an approval request you created, by request id; this grants no approval. The requester check remains enforced by the native owner. Free.", posture: "workspace_write",
|
|
3231
|
+
};
|
|
3232
|
+
return null;
|
|
3233
|
+
}
|
|
3112
3234
|
function isSecondPartyDecisionIntent(query) {
|
|
3113
3235
|
const decisionLanguage = /\b(sign ?off|signoff|approval request|request approval|approval gate|go no go)\b/.test(query);
|
|
3114
3236
|
const clientDecision = /\bclient\b.{0,20}\b(approv\w*|sign ?off|review|decide|decision|login|role)\b/.test(query)
|
|
@@ -97,15 +97,25 @@ export const BROWSER_OPERATIONS = [
|
|
|
97
97
|
operation("tables.resource.runs.cancel", `${run}/cancel`, "POST", "tables runs stop", "oxygen_table_resource_run_stop", "runs", "Cancel one durable Table run; never repeats external provider effects."),
|
|
98
98
|
operation("tables.resource.runs.pause", `${run}/pause`, "POST", "tables runs pause", "oxygen_table_resource_run_pause", "runs", "Pause one durable Table run without discarding its approved scope."),
|
|
99
99
|
operation("tables.resource.runs.resume", `${run}/resume`, "POST", "tables runs resume", "oxygen_table_resource_run_resume", "runs", "Resume a paused Table run within its existing approved scope and credit ceiling."),
|
|
100
|
-
operation("tables.resource.runs.retry", `${run}/retry-failed`, "POST", "tables runs retry", "oxygen_table_resource_run_retry", "runs", "Retry failed cells
|
|
100
|
+
operation("tables.resource.runs.retry", `${run}/retry-failed`, "POST", "tables runs retry", "oxygen_table_resource_run_retry", "runs", "Retry failed cells; a fresh allowance requires approved, retry_plan_hash and max_additional_credits. Uncertain effects require separate approval.", { approved_effect_unknown: bool(), approved: bool(), retry_plan_hash: text(), max_additional_credits: num({ minimum: 0 }) }, [], { spends: true }),
|
|
101
101
|
operation("tables.resource.runs.provider_summary", `${run}/provider-summary`, "GET", "tables runs provider-summary", "oxygen_table_resource_run_provider_summary", "runs", "Read a Table run's provider outcomes, fulfilled rows, costs and timing."),
|
|
102
102
|
operation("tables.resource.ingestions.cancel", `${table}/ingestions/{ingestion_run}/cancel`, "POST", "tables ingestion stop", "oxygen_table_resource_ingestion_stop", "runs", "Cancel this Table's active hosted ingestion run."),
|
|
103
103
|
operation("tables.resource.ingestions.retry", `${table}/ingestions/{ingestion_run}/retry-failed`, "POST", "tables ingestion retry", "oxygen_table_resource_ingestion_retry", "runs", "Retry failed items in this Table's hosted ingestion run."),
|
|
104
104
|
operation("tables.resource.import", "/api/cli/tables/import", "POST", "tables upload", "oxygen_table_resource_upload", "tables", "Preview or import small uploaded CSV, JSON or XLSX bytes through the exact browser import contract. Preview writes no rows.", upload, ["content_base64", "file_name"], { multipart }),
|
|
105
105
|
operation("billing.activate", "/api/cli/billing/activate", "POST", "billing activate", "oxygen_billing_activate", "billing", "Activate a trial subscription now and charge its saved payment method; administrator approval is required. An optional tier reprices the active trial in the same call.", { approved: bool(), tier: text() }, ["approved"], { spends: true }),
|
|
106
|
-
operation("billing.checkout", "/api/cli/billing/checkout", "POST", "billing checkout", "oxygen_billing_checkout", "billing", "Open
|
|
107
|
-
|
|
108
|
-
|
|
106
|
+
operation("billing.checkout", "/api/cli/billing/checkout", "POST", "billing checkout", "oxygen_billing_checkout", "billing", "Open browser Checkout; payment approves purchase. First purchase: admin/owner. New yearly plans use interval month, term year and the current terms_version.", {
|
|
107
|
+
plan: text("Plan key from billing balance available_plans, for example oxygen_49."),
|
|
108
|
+
interval: enumOf(["month", "year"], { description: "New purchases use month. year is legacy prepaid cadence, refused for new purchases." }),
|
|
109
|
+
term: enumOf(["month", "year"], { description: "year commits to twelve discounted monthly payments; month is the default." }),
|
|
110
|
+
terms_version: text("Required for term year: annual_monthly_terms.terms_version from billing balance."),
|
|
111
|
+
currency: text("Billing currency: usd (default)."),
|
|
112
|
+
trial: bool({ description: "Retired compatibility option; omit for a new paid subscription." }),
|
|
113
|
+
return_to: text("Same-origin path to return to after Checkout, for example /home."),
|
|
114
|
+
source: text("Optional upgrade-entry attribution; omit if unknown."),
|
|
115
|
+
blocked: text("Optional capability that led to the upgrade; omit if unknown."),
|
|
116
|
+
}, ["plan"]),
|
|
117
|
+
operation("billing.confirm", "/api/cli/billing/confirm", "POST", "billing confirm", "oxygen_billing_confirm", "billing", "Confirm a plan-change preview within 15 minutes; approved accepts payment, term and effective date. Unrestricted members allowed; restricted clients denied.", { token: text(), approved: bool() }, ["token", "approved"], { spends: true }),
|
|
118
|
+
operation("billing.portal", "/api/cli/billing/portal", "POST", "billing portal", "oxygen_billing_portal", "billing", "Create a Stripe billing-portal URL. Unrestricted members allowed; restricted clients denied.", { returnUrl: text() }),
|
|
109
119
|
operation("billing.ownership.get", "/api/cli/billing/ownership", "GET", "billing ownership get", "oxygen_billing_ownership_get", "billing", "Read the active workspace's shared billing owner, candidate owners and credit cap."),
|
|
110
120
|
operation("billing.ownership.set", "/api/cli/billing/ownership", "POST", "billing ownership set", "oxygen_billing_ownership_set", "billing", "Set the billing owner and optional monthly credit cap using the browser's administrator and workspace eligibility checks.", { billing_owner_organization_id: text(), monthly_credit_cap: nullable(num({ minimum: 0 })) }, ["billing_owner_organization_id"]),
|
|
111
121
|
operation("billing.ownership.clear", "/api/cli/billing/ownership", "DELETE", "billing ownership clear", "oxygen_billing_ownership_clear", "billing", "Restore this workspace's own billing ownership after the same administrator checks as the browser."),
|
|
@@ -8,6 +8,7 @@ import { COPILOT_SESSIONS_LIST_CONTRACT } from "./copilot-sessions.js";
|
|
|
8
8
|
import { CRM_FILE_ATTACH_CONTRACT, CRM_FILE_ATTACH_DESCRIPTION } from "./crm-support.js";
|
|
9
9
|
import { spintaxContract } from "./spintax.js";
|
|
10
10
|
import { betaFeaturesUpdateContract, emailDomainSuppressionListContract, emailDomainSuppressionRemoveContract, emailSuppressionRemoveContract, providerLimitListContract, providerLimitSelectorContract, providerLimitUpdateContract } from "./workspace-utilities.js";
|
|
11
|
+
import { knowledgeSyncReadContract } from "./knowledge-sync.js";
|
|
11
12
|
const text = (description) => str(description === undefined ? {} : { description });
|
|
12
13
|
const list = () => arr(str());
|
|
13
14
|
const json = { type: "object", additionalProperties: true };
|
|
@@ -34,8 +35,8 @@ export const CUSTOMER_OPERATIONS = [
|
|
|
34
35
|
operation("comments.edit", "/api/cli/collab/comments/{comment_id}", "PATCH", "comments edit", "oxygen_comments_edit", "collaboration", "Edit your own internal workspace comment; records the edit time.", { body: text() }, ["body"], mcpOnly),
|
|
35
36
|
operation("comments.delete", "/api/cli/collab/comments/{comment_id}", "DELETE", "comments delete", "oxygen_comments_delete", "collaboration", "Retract your own internal workspace comment while retaining its audit trail.", {}, [], mcpOnly),
|
|
36
37
|
operation("approvals.cancel", "/api/cli/collab/requests/{request_id}/cancel", "POST", "approvals cancel", "oxygen_approvals_cancel", "collaboration", "Withdraw an approval request you created; grants no approval.", { note: text() }, [], mcpOnly),
|
|
37
|
-
operation("members.client_role", "/api/cli/collab/members/role", "POST", "approvals client grant", "oxygen_members_client_role_set", "collaboration", "Set or clear
|
|
38
|
-
operation("members.workspace_role", "/api/cli/collab/members/workspace-role", "POST", "orgs member-role", "oxygen_members_workspace_role_set", "collaboration", "Change a member's workspace role; admin only and
|
|
38
|
+
operation("members.client_role", "/api/cli/collab/members/role", "POST", "approvals client grant", "oxygen_members_client_role_set", "collaboration", "Set or clear the restricted client overlay; admin only. May read pending Clerk invitations; sends no invitation. Free.", { email: text(), role: nullable(enumOf(["client"])) }, ["email", "role"], { ...mcpOnly, annotations: { openWorldHint: true } }),
|
|
39
|
+
operation("members.workspace_role", "/api/cli/collab/members/workspace-role", "POST", "orgs member-role", "oxygen_members_workspace_role_set", "collaboration", "Change a member's workspace role in Clerk; admin only, with self-role and last-administrator protection. Free.", { email: text(), role: enumOf(["admin", "member"]) }, ["email", "role"], { ...mcpOnly, annotations: { openWorldHint: true } }),
|
|
39
40
|
operation("copilot.sessions.list", "/api/cli/copilot/sessions", "GET", "copilot list", "oxygen_copilot_sessions_list", "agents", "List attended Copilot sessions in this workspace.", COPILOT_SESSIONS_LIST_CONTRACT.properties, [], mcpOnly),
|
|
40
41
|
operation("copilot.sessions.update", "/api/cli/copilot/sessions/{session_id}", "PATCH", "copilot policy set", "oxygen_copilot_session_update", "agents", "Set an attended Copilot session's approval and screen-follow policies. Paid auto-approval is explicit standing authorization.", { auto_approve_policy: enumOf(["off", "paid"]), surface_policy: enumOf(["off", "follow"]) }, [], { spends: true }),
|
|
41
42
|
operation("copilot.attachments.list", "/api/cli/copilot/sessions/{session_id}/attachments", "GET", "copilot attachments list", "oxygen_copilot_attachments_list", "agents", "List sent and unsent attachments in one Copilot session.", {}, []),
|
|
@@ -64,8 +65,8 @@ export const CUSTOMER_OPERATIONS = [
|
|
|
64
65
|
operation("directory.logo", "/api/cli/directory/listing/logo", "POST", "directory logo upload", "oxygen_directory_logo_upload", "crm", "Upload a public agency-directory logo and read back the updated listing; PNG, JPEG, WebP or SVG, at most 2 MB.", { content_base64: text(), file_name: text(), content_type: enumOf(["image/png", "image/jpeg", "image/webp", "image/svg+xml"]) }, ["content_base64", "file_name", "content_type"], { multipart: { contentField: "content_base64", nameField: "file_name", typeField: "content_type", fileField: "file" } }),
|
|
65
66
|
operation("domains.delete", "/api/cli/domains/delete", "POST", "domains delete", "oxygen_domains_delete", "deliverability", "Preview domain removal and renewal cancellation; execute only with the exact plan hash and confirmation.", { domains: list(), approved: bool(), plan_hash: text(), confirmation: text() }, ["domains"], mcpOnly),
|
|
66
67
|
operation("knowledge.pages.archive", "/api/cli/knowledge/pages/archive", "POST", "knowledge page archive", "oxygen_knowledge_page_archive", "knowledge", "Archive a knowledge page; content/history remain, links become unresolved. Pass expected_revision for the version you reviewed.", { slug: text(), id: text(), expected_revision: int({ minimum: 1 }) }, [], mcpOnly),
|
|
67
|
-
operation("knowledge.sync.manifest", "/api/cli/knowledge/sync/manifest", "POST", "knowledge sync-manifest", "oxygen_knowledge_sync_manifest", "knowledge", "Read
|
|
68
|
-
operation("knowledge.sync.delta", "/api/cli/knowledge/sync/delta", "POST", "knowledge sync", "oxygen_knowledge_sync_delta", "knowledge", "Read
|
|
68
|
+
operation("knowledge.sync.manifest", "/api/cli/knowledge/sync/manifest", "POST", "knowledge sync-manifest", "oxygen_knowledge_sync_manifest", "knowledge", "Read wiki revision/hash metadata. Follow next_cursor for remaining pages; scope is a live keyset, not a snapshot.", {}, [], { contract: knowledgeSyncReadContract, mutates: false }),
|
|
69
|
+
operation("knowledge.sync.delta", "/api/cli/knowledge/sync/delta", "POST", "knowledge sync-delta", "oxygen_knowledge_sync_delta", "knowledge", "Read complete wiki pages/tombstones. First call seeds missing starter pages. Follow next_cursor; an oversized page is refused without skipping. 0 credits.", {}, [], { contract: knowledgeSyncReadContract }),
|
|
69
70
|
operation("limits.provider.get", "/api/cli/limits/provider", "GET", "limits provider list", "oxygen_provider_limits_list", "billing", "Read provider request limits and BYOK warning defaults. MCP defaults to bounded summary pages; follow paging.next_offset with the same filter. HTTP/CLI omit pagination for the full legacy list. 0 credits.", {}, [], { contract: providerLimitListContract, generated: { cli: false, mcp: false } }),
|
|
70
71
|
operation("limits.provider.set", "/api/cli/limits/provider", "POST", "limits provider set", "oxygen_provider_limits_set", "billing", "Set an enforced provider request limit; admin or owner only. Approve the exact provider, operation and window: raising a cap may permit more provider use. 0 credits.", {}, [], { ...mcpOnly, contract: providerLimitUpdateContract }),
|
|
71
72
|
operation("limits.provider.delete", "/api/cli/limits/provider", "DELETE", "limits provider delete", "oxygen_provider_limits_delete", "billing", "Clear one provider request-limit override; admin or owner only. Approve the exact selector. Other operation overrides remain; the provider returns to its defaults, whose BYOK threshold may be observe-only. 0 credits.", {}, [], { ...mcpOnly, contract: providerLimitSelectorContract, queryFields: ["provider", "operation"] }),
|
|
@@ -107,7 +108,7 @@ export const CUSTOMER_OPERATIONS = [
|
|
|
107
108
|
operation("billing.invoices", "/api/cli/billing/invoices", "GET", "billing invoices", "oxygen_billing_invoices", "billing", "Read this workspace's billing invoices and their hosted payment links.", {}, [], mcpOnly),
|
|
108
109
|
operation("billing.seats.set", "/api/cli/billing/seats", "POST", "billing seats set", "oxygen_billing_seats_set", "billing", "Set purchased legacy sending-seat quantity. Retired seats cannot increase; reducing existing seats lowers the next renewal charge.", { seat_key: enumOf(["linkedin", "whatsapp", "phone_number", "email_sender"]), quantity: int({ minimum: 0 }) }, ["seat_key", "quantity"], mcpOnly),
|
|
109
110
|
operation("collaboration.gates.list", "/api/cli/collab/gates", "GET", "approvals gate list", "oxygen_approval_gates_list", "collaboration", "Read this workspace's approval gates, optionally for one exact subject.", { subject: text() }, [], mcpOnly),
|
|
110
|
-
operation("collaboration.members.list", "/api/cli/collab/members", "GET", "approvals client list", "oxygen_workspace_members_list", "collaboration", "Read workspace
|
|
111
|
+
operation("collaboration.members.list", "/api/cli/collab/members", "GET", "approvals client list", "oxygen_workspace_members_list", "collaboration", "Read workspace member roles, with Clerk profiles and pending invitations. Free.", {}, [], { ...mcpOnly, annotations: { openWorldHint: true } }),
|
|
111
112
|
operation("crm.connections", "/api/cli/crm/objects/{object}/records/{row_id}/connections", "GET", "crm connections", "oxygen_crm_connections", "crm", "Read a CRM record's connected conversations, sequence enrollments and related activity.", { conversation_limit: int({ minimum: 1 }), sequence_limit: int({ minimum: 1 }) }, [], mcpOnly),
|
|
112
113
|
operation("crm.tasks.list", "/api/cli/crm/tasks", "GET", "crm tasks list", "oxygen_crm_tasks_queue", "crm", "Read the workspace task queue by status, assignee and cursor.", { status: text(), assignee: text(), cursor: text(), limit: int({ minimum: 1 }) }, [], mcpOnly),
|
|
113
114
|
operation("crm.files.download", "/api/cli/crm/files/{attachment_id}/download", "GET", "crm files download", "oxygen_crm_file_download", "crm", "Download a tenant-owned record attachment by attachment_id. The native authenticated response contains its exact bytes.", {}, [], { binary: { maxBytes: 50 * 1024 * 1024 } }),
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** Both sync readers expose complete native pages; no formatter may trim a
|
|
2
|
+
* page after its continuation position has been issued. */
|
|
3
|
+
export declare const knowledgeSyncReadContract: import("./schema.js").ContractObject<{
|
|
4
|
+
readonly cursor: import("./schema.js").StringProperty;
|
|
5
|
+
readonly limit: {
|
|
6
|
+
type: "integer";
|
|
7
|
+
description?: string;
|
|
8
|
+
minimum?: number;
|
|
9
|
+
maximum?: number;
|
|
10
|
+
"x-clamp"?: true;
|
|
11
|
+
};
|
|
12
|
+
readonly max_chars: {
|
|
13
|
+
type: "integer";
|
|
14
|
+
description?: string;
|
|
15
|
+
minimum?: number;
|
|
16
|
+
maximum?: number;
|
|
17
|
+
"x-clamp"?: true;
|
|
18
|
+
};
|
|
19
|
+
}, never>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { int, obj, str } from "./schema.js";
|
|
2
|
+
/** Both sync readers expose complete native pages; no formatter may trim a
|
|
3
|
+
* page after its continuation position has been issued. */
|
|
4
|
+
export const knowledgeSyncReadContract = obj({
|
|
5
|
+
cursor: str({ minLength: 1, maxLength: 256 }),
|
|
6
|
+
limit: int({ minimum: 1, maximum: 200 }),
|
|
7
|
+
max_chars: int({ minimum: 1000, maximum: 48000, description: "Complete receipt window; surface cap applies." }),
|
|
8
|
+
});
|
|
@@ -20,6 +20,7 @@ export declare const publishingReadProjectionContract: ContractObject<{
|
|
|
20
20
|
readonly description?: string;
|
|
21
21
|
readonly minLength?: number;
|
|
22
22
|
readonly maxLength?: number;
|
|
23
|
+
readonly pattern?: string;
|
|
23
24
|
readonly enum: readonly ["full", "summary", "value"];
|
|
24
25
|
};
|
|
25
26
|
readonly value_path: import("./schema.js").StringProperty;
|
|
@@ -40,6 +41,7 @@ export declare const publishingAmplificationListQueryContract: ContractObject<{
|
|
|
40
41
|
readonly description?: string;
|
|
41
42
|
readonly minLength?: number;
|
|
42
43
|
readonly maxLength?: number;
|
|
44
|
+
readonly pattern?: string;
|
|
43
45
|
readonly enum: readonly ["full", "summary", "value"];
|
|
44
46
|
};
|
|
45
47
|
readonly value_path: import("./schema.js").StringProperty;
|
|
@@ -57,6 +59,7 @@ export declare const publishingAmplificationListQueryContract: ContractObject<{
|
|
|
57
59
|
readonly description?: string;
|
|
58
60
|
readonly minLength?: number;
|
|
59
61
|
readonly maxLength?: number;
|
|
62
|
+
readonly pattern?: string;
|
|
60
63
|
readonly enum: readonly ["all", "tag", "post", "ugc_program", "ugc_peer_program"];
|
|
61
64
|
};
|
|
62
65
|
readonly limit: {
|
|
@@ -73,6 +76,7 @@ export declare const publishingAmplificationActionsQueryContract: ContractObject
|
|
|
73
76
|
readonly description?: string;
|
|
74
77
|
readonly minLength?: number;
|
|
75
78
|
readonly maxLength?: number;
|
|
79
|
+
readonly pattern?: string;
|
|
76
80
|
readonly enum: readonly ["full", "summary", "value"];
|
|
77
81
|
};
|
|
78
82
|
readonly value_path: import("./schema.js").StringProperty;
|
|
@@ -99,6 +103,7 @@ export declare const publishingNotesQueryContract: ContractObject<{
|
|
|
99
103
|
readonly description?: string;
|
|
100
104
|
readonly minLength?: number;
|
|
101
105
|
readonly maxLength?: number;
|
|
106
|
+
readonly pattern?: string;
|
|
102
107
|
readonly enum: readonly ["full", "summary", "value"];
|
|
103
108
|
};
|
|
104
109
|
readonly value_path: import("./schema.js").StringProperty;
|
|
@@ -127,6 +132,7 @@ export declare const publishingRevisionsQueryContract: ContractObject<{
|
|
|
127
132
|
readonly description?: string;
|
|
128
133
|
readonly minLength?: number;
|
|
129
134
|
readonly maxLength?: number;
|
|
135
|
+
readonly pattern?: string;
|
|
130
136
|
readonly enum: readonly ["full", "summary", "value"];
|
|
131
137
|
};
|
|
132
138
|
readonly value_path: import("./schema.js").StringProperty;
|
|
@@ -166,6 +172,7 @@ export declare const publishingAnalyticsQueryContract: ContractObject<{
|
|
|
166
172
|
readonly description?: string;
|
|
167
173
|
readonly minLength?: number;
|
|
168
174
|
readonly maxLength?: number;
|
|
175
|
+
readonly pattern?: string;
|
|
169
176
|
readonly enum: readonly ["full", "summary", "value"];
|
|
170
177
|
};
|
|
171
178
|
readonly value_path: import("./schema.js").StringProperty;
|
|
@@ -15,6 +15,8 @@ export type StringProperty = {
|
|
|
15
15
|
enum?: readonly string[];
|
|
16
16
|
minLength?: number;
|
|
17
17
|
maxLength?: number;
|
|
18
|
+
/** JSON Schema regular expression, evaluated with Unicode semantics. */
|
|
19
|
+
pattern?: string;
|
|
18
20
|
};
|
|
19
21
|
export type NumberProperty = {
|
|
20
22
|
type: "number" | "integer";
|
|
@@ -99,6 +101,7 @@ export declare function jsonValue(options?: Described): {
|
|
|
99
101
|
export declare function str(options?: Described & {
|
|
100
102
|
minLength?: number;
|
|
101
103
|
maxLength?: number;
|
|
104
|
+
pattern?: string;
|
|
102
105
|
}): StringProperty;
|
|
103
106
|
export declare function enumOf<const V extends string>(values: readonly V[], options?: Described): {
|
|
104
107
|
type: "string";
|
|
@@ -210,6 +210,9 @@ function walkValue(schema, value, path, walk) {
|
|
|
210
210
|
else if (schema.maxLength !== undefined && value.length > schema.maxLength) {
|
|
211
211
|
walk.issues.push({ path, message: `${path} must be at most ${schema.maxLength} characters.` });
|
|
212
212
|
}
|
|
213
|
+
else if (schema.pattern !== undefined && !new RegExp(schema.pattern, "u").test(value)) {
|
|
214
|
+
walk.issues.push({ path, message: `${path} must match the required pattern.` });
|
|
215
|
+
}
|
|
213
216
|
return value;
|
|
214
217
|
}
|
|
215
218
|
case "integer":
|
|
@@ -11,6 +11,7 @@ export declare const TABLE_ROW_READ_WINDOW_FIELDS: {
|
|
|
11
11
|
readonly enum?: readonly string[];
|
|
12
12
|
readonly minLength?: number;
|
|
13
13
|
readonly maxLength?: number;
|
|
14
|
+
readonly pattern?: string;
|
|
14
15
|
readonly description: "JSON Pointer; empty=root.";
|
|
15
16
|
};
|
|
16
17
|
readonly value_cursor: {
|
|
@@ -18,6 +19,7 @@ export declare const TABLE_ROW_READ_WINDOW_FIELDS: {
|
|
|
18
19
|
readonly enum?: readonly string[];
|
|
19
20
|
readonly minLength?: number;
|
|
20
21
|
readonly maxLength?: number;
|
|
22
|
+
readonly pattern?: string;
|
|
21
23
|
readonly description: "Resume with identical selection/path.";
|
|
22
24
|
};
|
|
23
25
|
readonly max_chars: {
|
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
// on, a connect is admitted when the spendable balance covers the account's
|
|
8
8
|
// first monthly credit reservation, refused with `insufficient_credits` when it
|
|
9
9
|
// does not, and `billing seats` reports that seats are retired (S21). The plan
|
|
10
|
-
// wall removal (S22) sits behind the same flag
|
|
10
|
+
// wall removal (S22) sits behind the same flag; a LinkedIn account keeps its
|
|
11
|
+
// plan wall (`linkedin_connect`, founder 2026-10-12).
|
|
11
12
|
//
|
|
12
13
|
// WHY IT IS ITS OWN FLAG, AND WHY IT IS NOT ENOUGH ALONE. A balance check debits
|
|
13
14
|
// nothing: while commitments are dark, a workspace holding 3,400 credits would
|
|
@@ -94,6 +94,7 @@ declare const REPLY_CLASSIFIED_PAYLOAD: ContractObject<{
|
|
|
94
94
|
enum?: readonly string[];
|
|
95
95
|
minLength?: number;
|
|
96
96
|
maxLength?: number;
|
|
97
|
+
pattern?: string;
|
|
97
98
|
format: "date-time";
|
|
98
99
|
};
|
|
99
100
|
readonly url: {
|
|
@@ -102,6 +103,7 @@ declare const REPLY_CLASSIFIED_PAYLOAD: ContractObject<{
|
|
|
102
103
|
enum?: readonly string[];
|
|
103
104
|
minLength?: number;
|
|
104
105
|
maxLength?: number;
|
|
106
|
+
pattern?: string;
|
|
105
107
|
format: "uri";
|
|
106
108
|
};
|
|
107
109
|
}, "channel" | "classification" | "conversation_id" | "enrollment_id" | "occurred_at" | "record_id" | "sequence_id" | "url">;
|
|
@@ -143,6 +145,7 @@ declare const ENROLLMENT_ENDED_PAYLOAD: ContractObject<{
|
|
|
143
145
|
enum?: readonly string[];
|
|
144
146
|
minLength?: number;
|
|
145
147
|
maxLength?: number;
|
|
148
|
+
pattern?: string;
|
|
146
149
|
format: "date-time";
|
|
147
150
|
};
|
|
148
151
|
readonly url: {
|
|
@@ -151,6 +154,7 @@ declare const ENROLLMENT_ENDED_PAYLOAD: ContractObject<{
|
|
|
151
154
|
enum?: readonly string[];
|
|
152
155
|
minLength?: number;
|
|
153
156
|
maxLength?: number;
|
|
157
|
+
pattern?: string;
|
|
154
158
|
format: "uri";
|
|
155
159
|
};
|
|
156
160
|
}, "enrollment_id" | "occurred_at" | "outcome" | "sequence_id" | "steps_sent" | "url">;
|
|
@@ -205,6 +209,7 @@ declare const MEETING_COMPLETED_PAYLOAD: ContractObject<{
|
|
|
205
209
|
enum?: readonly string[];
|
|
206
210
|
minLength?: number;
|
|
207
211
|
maxLength?: number;
|
|
212
|
+
pattern?: string;
|
|
208
213
|
format: "date-time";
|
|
209
214
|
};
|
|
210
215
|
readonly url: {
|
|
@@ -213,6 +218,7 @@ declare const MEETING_COMPLETED_PAYLOAD: ContractObject<{
|
|
|
213
218
|
enum?: readonly string[];
|
|
214
219
|
minLength?: number;
|
|
215
220
|
maxLength?: number;
|
|
221
|
+
pattern?: string;
|
|
216
222
|
format: "uri";
|
|
217
223
|
};
|
|
218
224
|
}, "activity_id" | "duration_seconds" | "occurred_at" | "record_ids" | "session_id" | "url">;
|
|
@@ -277,6 +283,7 @@ declare const RECORD_STAGE_CHANGED_PAYLOAD: ContractObject<{
|
|
|
277
283
|
enum?: readonly string[];
|
|
278
284
|
minLength?: number;
|
|
279
285
|
maxLength?: number;
|
|
286
|
+
pattern?: string;
|
|
280
287
|
format: "date-time";
|
|
281
288
|
};
|
|
282
289
|
readonly url: {
|
|
@@ -285,6 +292,7 @@ declare const RECORD_STAGE_CHANGED_PAYLOAD: ContractObject<{
|
|
|
285
292
|
enum?: readonly string[];
|
|
286
293
|
minLength?: number;
|
|
287
294
|
maxLength?: number;
|
|
295
|
+
pattern?: string;
|
|
288
296
|
format: "uri";
|
|
289
297
|
};
|
|
290
298
|
}, "activity_id" | "from_stage_id" | "object" | "occurred_at" | "pipeline_id" | "record_id" | "to_stage_id" | "url">;
|
|
@@ -323,6 +331,7 @@ declare const RUN_SETTLED_PAYLOAD: ContractObject<{
|
|
|
323
331
|
enum?: readonly string[];
|
|
324
332
|
minLength?: number;
|
|
325
333
|
maxLength?: number;
|
|
334
|
+
pattern?: string;
|
|
326
335
|
format: "date-time";
|
|
327
336
|
};
|
|
328
337
|
readonly url: {
|
|
@@ -331,6 +340,7 @@ declare const RUN_SETTLED_PAYLOAD: ContractObject<{
|
|
|
331
340
|
enum?: readonly string[];
|
|
332
341
|
minLength?: number;
|
|
333
342
|
maxLength?: number;
|
|
343
|
+
pattern?: string;
|
|
334
344
|
format: "uri";
|
|
335
345
|
};
|
|
336
346
|
}, "credits_used" | "kind" | "occurred_at" | "run_id" | "status" | "url">;
|
|
@@ -362,6 +372,7 @@ declare const APPROVAL_REQUESTED_PAYLOAD: ContractObject<{
|
|
|
362
372
|
enum?: readonly string[];
|
|
363
373
|
minLength?: number;
|
|
364
374
|
maxLength?: number;
|
|
375
|
+
pattern?: string;
|
|
365
376
|
format: "date-time";
|
|
366
377
|
};
|
|
367
378
|
readonly url: {
|
|
@@ -370,6 +381,7 @@ declare const APPROVAL_REQUESTED_PAYLOAD: ContractObject<{
|
|
|
370
381
|
enum?: readonly string[];
|
|
371
382
|
minLength?: number;
|
|
372
383
|
maxLength?: number;
|
|
384
|
+
pattern?: string;
|
|
373
385
|
format: "uri";
|
|
374
386
|
};
|
|
375
387
|
}, "approval_id" | "kind" | "occurred_at" | "run_id" | "url">;
|
|
@@ -60,7 +60,7 @@ export type OtlpLogSinkOptions = {
|
|
|
60
60
|
* `worker.log_shipper.stats` is the Axiom shipper's once-a-minute loss accounting,
|
|
61
61
|
* which by design never reaches Axiom (OXP-1.6.126).
|
|
62
62
|
*/
|
|
63
|
-
export declare const OTLP_MONITOR_INFO_EVENTS: readonly ["diagnostics.capture_stored", "diagnostics.invocation_completed", "diagnostics.canary_completed", "diagnostics.digest_completed", "tenant.migrations.cron.done", "outbound_send.sent", "worker_workflow_cron_overlap_skipped", "worker_workflow_cron_enqueued", "copilot.turn.finished", "worker.queue.heartbeat", "worker.queue.ledger", "worker.queue.redis", "worker.queue.unregistered_kind", "automation_usage.reconcile_completed", "provider_health.cron_completed", "provider_balances.cron_completed", "cost_snapshot.cron_completed", "worker.egress_order_reconcile_sweep", "posthog_canary.round_trip_ok", "web.log_volume", "worker.log_shipper.stats"];
|
|
63
|
+
export declare const OTLP_MONITOR_INFO_EVENTS: readonly ["diagnostics.capture_stored", "diagnostics.invocation_completed", "diagnostics.canary_completed", "diagnostics.digest_completed", "tenant.migrations.cron.done", "outbound_send.sent", "worker_workflow_cron_overlap_skipped", "worker_workflow_cron_enqueued", "copilot.turn.finished", "worker.queue.heartbeat", "worker.queue.depth", "worker.queue.ledger", "worker.queue.redis", "worker.queue.unregistered_kind", "automation_usage.reconcile_completed", "provider_health.cron_completed", "provider_balances.cron_completed", "cost_snapshot.cron_completed", "worker.egress_order_reconcile_sweep", "posthog_canary.round_trip_ok", "web.log_volume", "worker.log_shipper.stats"];
|
|
64
64
|
export type OtlpLogSinkHandle = {
|
|
65
65
|
sink: LogSink;
|
|
66
66
|
flush: () => Promise<void>;
|
|
@@ -37,11 +37,16 @@
|
|
|
37
37
|
* billed that way (the credit gate, `OXYGEN_CREDIT_GATE_ENABLED`) credits are the
|
|
38
38
|
* only gate and the sending walls retire: `CREDIT_GATE_RETIRED_CAPABILITIES`.
|
|
39
39
|
* Until the gate is in force everything above still holds.
|
|
40
|
+
*
|
|
41
|
+
* EXCEPT LINKEDIN (founder, current chat, 2026-10-12: "you can only connect a
|
|
42
|
+
* linkedin account on a plan"). `linkedin_connect` is not retired by the credit
|
|
43
|
+
* gate, so a free workspace is told to subscribe before any balance check,
|
|
44
|
+
* however many credits it holds.
|
|
40
45
|
*/
|
|
41
46
|
import type { PlanTier, PricingPlanDefinition } from "./billing.js";
|
|
42
47
|
import { CREDIT_GATE_RETIRED_CAPABILITIES, isCapabilityRetiredByCreditGate } from "./credit-gate.js";
|
|
43
48
|
import { type RepricingOptions } from "./repricing.js";
|
|
44
|
-
export declare const PLAN_GATED_CAPABILITIES: readonly ["sender_connect", "sequence_dispatch", "publishing_connect", "publishing_deliver", "managed_email_infrastructure", "byok_provider_keys"];
|
|
49
|
+
export declare const PLAN_GATED_CAPABILITIES: readonly ["sender_connect", "linkedin_connect", "sequence_dispatch", "publishing_connect", "publishing_deliver", "managed_email_infrastructure", "byok_provider_keys"];
|
|
45
50
|
export type PlanGatedCapability = (typeof PLAN_GATED_CAPABILITIES)[number];
|
|
46
51
|
/**
|
|
47
52
|
* Every tier except `free` unblocks every gated capability.
|
|
@@ -75,7 +80,9 @@ export declare function isPlanGatedCapability(value: unknown): value is PlanGate
|
|
|
75
80
|
* (`assertCreditGateArmed`). Until then every one of them stays walled exactly
|
|
76
81
|
* as before.
|
|
77
82
|
*
|
|
78
|
-
*
|
|
83
|
+
* Three capabilities stay walled under the gate:
|
|
84
|
+
* - `linkedin_connect`: a LinkedIn account connects only on a plan (founder,
|
|
85
|
+
* current chat, 2026-10-12), whatever the balance.
|
|
79
86
|
* - `byok_provider_keys`: bringing your own keys needs a plan that includes it
|
|
80
87
|
* ($99 or above from the repricing's effective date).
|
|
81
88
|
* - `publishing_connect`: the only publishing connects that still reach it are
|
|
@@ -37,11 +37,17 @@
|
|
|
37
37
|
* billed that way (the credit gate, `OXYGEN_CREDIT_GATE_ENABLED`) credits are the
|
|
38
38
|
* only gate and the sending walls retire: `CREDIT_GATE_RETIRED_CAPABILITIES`.
|
|
39
39
|
* Until the gate is in force everything above still holds.
|
|
40
|
+
*
|
|
41
|
+
* EXCEPT LINKEDIN (founder, current chat, 2026-10-12: "you can only connect a
|
|
42
|
+
* linkedin account on a plan"). `linkedin_connect` is not retired by the credit
|
|
43
|
+
* gate, so a free workspace is told to subscribe before any balance check,
|
|
44
|
+
* however many credits it holds.
|
|
40
45
|
*/
|
|
41
46
|
import { CREDIT_GATE_RETIRED_CAPABILITIES, isCapabilityRetiredByCreditGate } from "./credit-gate.js";
|
|
42
47
|
import { OXYGEN_49_BYOK_REPRICING, readRepricingSwitch, repricedValue, } from "./repricing.js";
|
|
43
48
|
export const PLAN_GATED_CAPABILITIES = [
|
|
44
49
|
"sender_connect",
|
|
50
|
+
"linkedin_connect",
|
|
45
51
|
"sequence_dispatch",
|
|
46
52
|
"publishing_connect",
|
|
47
53
|
"publishing_deliver",
|
|
@@ -71,6 +77,11 @@ export const PLAN_GATED_CAPABILITY_COPY = {
|
|
|
71
77
|
freeAlternative: "You can build and preview the whole motion on Free — sequences, steps, and enrollment all work. Connecting a mailbox, LinkedIn account, or WhatsApp number is what needs a plan.",
|
|
72
78
|
deepLinkPath: "/settings/connections",
|
|
73
79
|
},
|
|
80
|
+
linkedin_connect: {
|
|
81
|
+
label: "Connecting a LinkedIn account",
|
|
82
|
+
freeAlternative: "Leads, sequences and enrollment all work on Free. To connect a LinkedIn account, subscribe to the Oxygen plan; its monthly credits pay for the account.",
|
|
83
|
+
deepLinkPath: "/settings/connections",
|
|
84
|
+
},
|
|
74
85
|
sequence_dispatch: {
|
|
75
86
|
label: "Sending a sequence",
|
|
76
87
|
freeAlternative: "Authoring, versioning, enrolling, and previewing a sequence are all free. Dispatching to real recipients is what needs a plan.",
|
|
@@ -113,7 +124,9 @@ export function isPlanGatedCapability(value) {
|
|
|
113
124
|
* (`assertCreditGateArmed`). Until then every one of them stays walled exactly
|
|
114
125
|
* as before.
|
|
115
126
|
*
|
|
116
|
-
*
|
|
127
|
+
* Three capabilities stay walled under the gate:
|
|
128
|
+
* - `linkedin_connect`: a LinkedIn account connects only on a plan (founder,
|
|
129
|
+
* current chat, 2026-10-12), whatever the balance.
|
|
117
130
|
* - `byok_provider_keys`: bringing your own keys needs a plan that includes it
|
|
118
131
|
* ($99 or above from the repricing's effective date).
|
|
119
132
|
* - `publishing_connect`: the only publishing connects that still reach it are
|