@oxygen-agent/cli 1.1011.855 → 1.1011.1091

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/README.md +1 -1
  2. package/dist/admin-lead-magnet-commands.d.ts +7 -0
  3. package/dist/admin-lead-magnet-commands.js +128 -0
  4. package/dist/command-manifest.js +29 -0
  5. package/dist/crm-support-flags.d.ts +1 -0
  6. package/dist/crm-support-flags.js +5 -1
  7. package/dist/customer-operation-commands.js +30 -1
  8. package/dist/functions-commands.js +1 -1
  9. package/dist/help.js +10 -2
  10. package/dist/http-client.d.ts +4 -0
  11. package/dist/http-client.js +21 -10
  12. package/dist/index.js +444 -208
  13. package/dist/sender-limits-flags.d.ts +7 -0
  14. package/dist/sender-limits-flags.js +13 -0
  15. package/dist/workspace-utility-flags.d.ts +7 -0
  16. package/dist/workspace-utility-flags.js +45 -0
  17. package/node_modules/@oxygen/shared/dist/attempt-provenance.d.ts +22 -0
  18. package/node_modules/@oxygen/shared/dist/attempt-provenance.js +83 -0
  19. package/node_modules/@oxygen/shared/dist/billing-anchors.d.ts +6 -0
  20. package/node_modules/@oxygen/shared/dist/billing-anchors.js +7 -1
  21. package/node_modules/@oxygen/shared/dist/capability-discovery.d.ts +6 -0
  22. package/node_modules/@oxygen/shared/dist/capability-discovery.js +279 -13
  23. package/node_modules/@oxygen/shared/dist/cli-result.js +6 -0
  24. package/node_modules/@oxygen/shared/dist/contracts/browser-operations.js +21 -9
  25. package/node_modules/@oxygen/shared/dist/contracts/crm-attributes.d.ts +7 -1
  26. package/node_modules/@oxygen/shared/dist/contracts/crm-attributes.js +5 -1
  27. package/node_modules/@oxygen/shared/dist/contracts/crm-support.d.ts +14 -0
  28. package/node_modules/@oxygen/shared/dist/contracts/crm-support.js +4 -0
  29. package/node_modules/@oxygen/shared/dist/contracts/customer-operations.js +13 -11
  30. package/node_modules/@oxygen/shared/dist/contracts/limits-read.js +11 -1
  31. package/node_modules/@oxygen/shared/dist/contracts/operations.d.ts +6 -0
  32. package/node_modules/@oxygen/shared/dist/contracts/publishing-reads.js +1 -0
  33. package/node_modules/@oxygen/shared/dist/contracts/schema.js +10 -6
  34. package/node_modules/@oxygen/shared/dist/contracts/spintax.d.ts +18 -0
  35. package/node_modules/@oxygen/shared/dist/contracts/spintax.js +11 -0
  36. package/node_modules/@oxygen/shared/dist/contracts/table-row-removal.d.ts +8 -0
  37. package/node_modules/@oxygen/shared/dist/contracts/table-row-removal.js +21 -0
  38. package/node_modules/@oxygen/shared/dist/contracts/workspace-utilities.d.ts +162 -0
  39. package/node_modules/@oxygen/shared/dist/contracts/workspace-utilities.js +46 -0
  40. package/node_modules/@oxygen/shared/dist/credit-topup-review.d.ts +11 -0
  41. package/node_modules/@oxygen/shared/dist/credit-topup-review.js +3 -0
  42. package/node_modules/@oxygen/shared/dist/emailguard-placement-probe.d.ts +70 -0
  43. package/node_modules/@oxygen/shared/dist/emailguard-placement-probe.js +161 -0
  44. package/node_modules/@oxygen/shared/dist/future-signup-events.d.ts +1 -1
  45. package/node_modules/@oxygen/shared/dist/future-signup-events.js +4 -0
  46. package/node_modules/@oxygen/shared/dist/knowledge-seed-content.js +2 -2
  47. package/node_modules/@oxygen/shared/dist/linkedin-quota-denial.d.ts +48 -0
  48. package/node_modules/@oxygen/shared/dist/linkedin-quota-denial.js +94 -0
  49. package/node_modules/@oxygen/shared/dist/partner-coupon-bonus.d.ts +45 -0
  50. package/node_modules/@oxygen/shared/dist/partner-coupon-bonus.js +57 -0
  51. package/node_modules/@oxygen/shared/dist/provider-balance-signal.js +3 -2
  52. package/node_modules/@oxygen/shared/dist/table-filter-operators.d.ts +6 -0
  53. package/node_modules/@oxygen/shared/dist/table-filter-operators.js +50 -0
  54. package/node_modules/@oxygen/shared/dist/telemetry.js +4 -0
  55. package/node_modules/@oxygen/shared/dist/version.d.ts +1 -1
  56. package/node_modules/@oxygen/shared/dist/version.generated.d.ts +1 -1
  57. package/node_modules/@oxygen/shared/dist/version.generated.js +1 -1
  58. package/node_modules/@oxygen/shared/dist/version.js +1 -1
  59. package/node_modules/@oxygen/shared/dist/whatsapp-sender-limits.d.ts +42 -0
  60. package/node_modules/@oxygen/shared/dist/whatsapp-sender-limits.js +68 -0
  61. package/node_modules/@oxygen/shared/dist/workflow-trigger-metadata.d.ts +15 -0
  62. package/node_modules/@oxygen/shared/dist/workflow-trigger-metadata.js +33 -0
  63. package/node_modules/@oxygen/shared/package.json +5 -5
  64. package/node_modules/@oxygen/workflows/dist/index.d.ts +1 -0
  65. package/node_modules/@oxygen/workflows/dist/index.js +1 -0
  66. package/node_modules/@oxygen/workflows/dist/recipe-timestamp.d.ts +22 -0
  67. package/node_modules/@oxygen/workflows/dist/recipe-timestamp.js +72 -0
  68. package/node_modules/@oxygen/workflows/dist/usage-estimate.js +9 -5
  69. package/package.json +1 -1
  70. package/node_modules/@oxygen/shared/dist/vercel-sandbox-fetch.d.ts +0 -9
  71. package/node_modules/@oxygen/shared/dist/vercel-sandbox-fetch.js +0 -33
@@ -1,7 +1,19 @@
1
1
  /** Browser resource operations, using the same scoped handlers on every surface. */
2
2
  import { arr, bool, enumOf, int, nullable, num, obj, str } from "./schema.js";
3
3
  import { TABLE_ROW_READ_WINDOW_FIELDS } from "./table-row-read.js";
4
+ import { TABLE_ROW_REMOVAL_FIELDS } from "./table-row-removal.js";
4
5
  const text = (description) => str(description ? { description } : {});
6
+ // The grid's own URL state (Sequence lead/contact grids reuse the Table grid): copying f / s from a
7
+ // filtered, sorted browser view is the supported way to build them.
8
+ const FILTER_PARAM = "Filter tree as the grid URL's f parameter (base64url JSON); copy it from a filtered browser view.";
9
+ const SORT_PARAM = "Sort list as the grid URL's s parameter (base64url JSON); copy it from a sorted browser view.";
10
+ // Sequence lead/contact rows: one row can carry ~100 KB of research and
11
+ // enrichment values, so these reads select columns and compact values (OXP-1.11.67).
12
+ const sequenceRowsProjection = {
13
+ fields: text("Comma-separated column keys to return, e.g. full_name,company,__seq_status; omit for every column."),
14
+ projection: enumOf(["grid", "values"], { description: "values: compact {id, values} rows, long values capped; grid (default): the full grid payload." }),
15
+ };
16
+ const SEQUENCE_ROWS_TRUNCATION_HINT = "Result trimmed for context size. Pass projection=values (values over 2,000 characters are capped) and fields=<column keys>; a smaller limit cannot shrink one row.";
5
17
  const json = { type: "object", additionalProperties: true };
6
18
  const strings = () => arr(str());
7
19
  const objects = () => arr(json);
@@ -15,12 +27,12 @@ const selection = obj({
15
27
  const actions = arr(obj({ type: enumOf(["tool_column"]), column: text(), definition: json }, { required: ["column"] }));
16
28
  const viewFields = { name: text(), view_type: text(), config: json, group_by: text(), is_default: bool(), position: int({ minimum: 0 }) };
17
29
  const crmLinks = arr(obj({ object: text(), row_id: text(), role: text() }, { required: ["object", "row_id"] }));
18
- function operation(id, route, method, cli, mcp, pack, summary, fields = {}, required = [], options = {}) {
30
+ function operation(id, route, method, cli, mcp, pack, summary, fields = {}, required = [], options = {}, annotations) {
19
31
  return {
20
32
  id, route, method, parameters: [...route.matchAll(/\{(\w+)\}/g)].map((match) => match[1]),
21
33
  contract: obj(fields, { required }),
22
34
  cli: { path: cli.split(" "), summary },
23
- mcp: { name: mcp, title: `Oxygen: ${cli}`, description: summary, pack },
35
+ mcp: { name: mcp, title: `Oxygen: ${cli}`, description: summary, pack, ...(annotations ? { annotations } : {}) },
24
36
  mutates: method !== "GET", spends: false, ...options,
25
37
  };
26
38
  }
@@ -33,18 +45,18 @@ const multipart = { contentField: "content_base64", nameField: "file_name", type
33
45
  const nativeCli = { generated: { cli: false, mcp: false } };
34
46
  export const BROWSER_OPERATIONS = [
35
47
  operation("tables.resource.export_csv", `${table}/export/csv`, "GET", "tables export-csv", "oxygen_table_export_csv", "tables", "Download every row in the exact filtered Table view as streamed CSV. CLI writes --output; MCP returns an authenticated download resource link. Unsupported live lookup filters fail before download; rows and bytes are not capped or truncated.", { f: text("Serialized filter tree."), s: text("Serialized sort state."), q: text(), fields: text("Comma-separated exact column keys.") }, [], { binary: { stream: true, resourceParameter: "table" } }),
36
- operation("billing.allowance.view", "/api/cli/billing/allowance/view", "GET", "billing allowance view", "oxygen_billing_allowance_view", "billing", "Read the complete current-cycle allowance view, including billing-owner display and partner-bonus eligibility."),
48
+ operation("billing.allowance.view", "/api/cli/billing/allowance/view", "GET", "billing allowance view", "oxygen_billing_allowance_view", "billing", "Inspect the current-cycle allowance, billing owner and partner-bonus eligibility. 0 credits; reserves nothing. Due plan grants or credit expiry may apply."),
37
49
  operation("billing.commitments.view", "/api/cli/billing/commitments/view", "GET", "billing commitments view", "oxygen_billing_commitments_view", "billing", "Read the complete fixed-credit commitment view and linked billing-owner display, without enumerating a child's sibling resources."),
38
50
  operation("billing.invoices.view", "/api/cli/billing/invoices/view", "GET", "billing invoices view", "oxygen_billing_invoices_view", "billing", "Read the browser invoice-history projection, including exact native timestamps, amounts and signed Stripe invoice links."),
39
51
  operation("billing.summary", "/api/cli/billing/summary", "GET", "billing summary", "oxygen_billing_summary", "billing", "Read the complete non-writing wallet, plan, seat-capacity and billing-owner summary."),
40
- operation("billing.usage.view", "/api/cli/billing/usage/view", "GET", "billing usage view", "oxygen_billing_usage_view", "billing", "Read the full selected-window credit-spend view, including permitted linked workspace rollups.", { days: enumOf(["7", "30", "90"]), workspace: text() }),
52
+ operation("billing.usage.view", "/api/cli/billing/usage/view", "GET", "billing usage view", "oxygen_billing_usage_view", "billing", "Credit spend over 7, 30 or 90 days by category and provider, each with its share, plus permitted linked-workspace rollups. totalSpent is reserved minus released; billing usage managed_credits_used counts captured credits only. Other windows or groupings: billing audit.", { days: enumOf(["7", "30", "90"]), workspace: text() }),
41
53
  operation("integrations.managed_endpoints", "/api/cli/integrations/composio/endpoints", "GET", "integrations managed-endpoints", "oxygen_integration_managed_endpoints", "integrations", "Read a managed integration's full action catalog and parameter schemas.", { integration_id: text() }, ["integration_id"]),
42
54
  operation("integrations.openrouter_models", "/api/cli/integrations/openrouter/models", "GET", "integrations openrouter-models", "oxygen_openrouter_models", "integrations", "Read model and pricing metadata using this workspace's connected OpenRouter account; credentials are never returned."),
43
55
  operation("integrations.status", "/api/cli/integrations/status", "GET", "integrations status", "oxygen_integration_status", "integrations", "Read active connection counts, sender connection state and the workspace's usable BYOK plan entitlement."),
44
56
  operation("pricing.customer_credit_prices", "/api/cli/pricing/customer-credit-prices", "GET", "pricing customer-credit-prices", "oxygen_customer_credit_prices", "workspace", "Read the customer credit-price catalog, quantity decisions and price provenance used by the Table picker."),
45
- operation("sequences.contacts.rows", "/api/cli/sequences/{sequence}/contacts/rows", "GET", "sequences contacts rows", "oxygen_sequence_contacts_rows", "sequences", "Read the full contact grid projection with exact contact-state filter and native synthetic status columns.", { contact_state: enumOf(["all", "not_contacted", "contacted", "connected", "replied", "positive_reply"]), limit: int({ minimum: 1, maximum: 2000 }), cursor: text(), offset: int({ minimum: 0 }), f: text(), s: text() }),
46
- operation("sequences.leads.rows", "/api/cli/sequences/{sequence}/leads/rows", "GET", "sequences leads rows", "oxygen_sequence_leads_rows", "sequences", "Read the complete enrolled-lead grid projection, including sequence status, step, action and failure columns.", { limit: int({ minimum: 1, maximum: 2000 }), cursor: text(), offset: int({ minimum: 0 }), f: text(), s: text() }),
47
- operation("unibox.metadata", "/api/cli/unibox/metadata", "GET", "unibox metadata", "oxygen_unibox_metadata", "inbox", "Read the complete authenticated inbox account, filter and tag metadata."),
57
+ operation("sequences.contacts.rows", "/api/cli/sequences/{sequence}/contacts/rows", "GET", "sequences contacts rows", "oxygen_sequence_contacts_rows", "sequences", "Read the full contact grid projection with exact contact-state filter and native synthetic status columns.", { contact_state: enumOf(["all", "not_contacted", "contacted", "connected", "replied", "positive_reply"]), limit: int({ minimum: 1, maximum: 2000 }), cursor: text(), offset: int({ minimum: 0 }), f: text(FILTER_PARAM), s: text(SORT_PARAM), ...sequenceRowsProjection }, [], { truncationHint: SEQUENCE_ROWS_TRUNCATION_HINT }),
58
+ operation("sequences.leads.rows", "/api/cli/sequences/{sequence}/leads/rows", "GET", "sequences leads rows", "oxygen_sequence_leads_rows", "sequences", "Read the complete enrolled-lead grid projection, including sequence status, step, action and failure columns.", { limit: int({ minimum: 1, maximum: 2000 }), cursor: text(), offset: int({ minimum: 0 }), f: text(FILTER_PARAM), s: text(SORT_PARAM), ...sequenceRowsProjection }, [], { truncationHint: SEQUENCE_ROWS_TRUNCATION_HINT }),
59
+ operation("unibox.metadata", "/api/cli/unibox/metadata", "GET", "unibox metadata", "oxygen_unibox_metadata", "inbox", "Read the complete authenticated inbox account, filter and tag metadata, including each sender profile (person) and its id."),
48
60
  operation("workflows.observed_output", "/api/cli/workflows/{workflow}/observed-output", "GET", "workflows observed-output", "oxygen_workflow_observed_output", "workflows", "Inspect observed output paths and bounded samples from an exact run or recent matching workflow revision.", { run_id: text(), source_hash: text() }),
49
61
  operation("workflows.run.events", "/api/cli/workflows/{workflow}/runs/{run}/events", "GET", "workflows runs events", "oxygen_workflow_run_events", "workflows", "Read the exact Workflow run's bounded event history and whether it is still active.", { limit: int({ minimum: 1, maximum: 1000 }) }),
50
62
  operation("workflows.run.step_statuses", "/api/cli/workflows/{workflow}/runs/{run}/step-statuses", "GET", "workflows runs step-statuses", "oxygen_workflow_run_step_statuses", "workflows", "Read the current Workflow run status and every step status for immediate execution readback."),
@@ -52,7 +64,7 @@ export const BROWSER_OPERATIONS = [
52
64
  operation("tables.resource.edit", table, "PATCH", "tables edit", "oxygen_table_resource_edit", "tables", "Rename a Table or move it to a workspace project; returns the saved Table.", { name: text(), project_id: text() }),
53
65
  operation("tables.resource.archive", table, "DELETE", "tables archive", "oxygen_tables_archive", "tables", "Archive a Table indefinitely without dropping its physical data or scheduling a purge.", {}, [], nativeCli),
54
66
  operation("tables.resource.duplicate", `${table}/duplicate`, "POST", "tables duplicate", "oxygen_tables_duplicate", "tables", "Duplicate a Table with its columns and optionally its row values.", { name: text(), include_rows: bool() }, [], nativeCli),
55
- operation("tables.resource.activity", `${table}/activity`, "GET", "tables changes", "oxygen_table_resource_activity", "tables", "Read a Table's bounded activity history.", { limit: int({ minimum: 1 }) }),
67
+ operation("tables.resource.activity", `${table}/activity`, "GET", "tables changes", "oxygen_table_resource_activity", "tables", "Read a Table's live runs and queue health.", { limit: int({ minimum: 1 }) }),
56
68
  operation("tables.resource.column_stats", `${table}/column-stats`, "GET", "tables column-stats", "oxygen_table_column_stats", "tables", "Read per-column completion and provider statistics; large Tables use labeled samples."),
57
69
  operation("tables.resource.fill_progress", `${table}/fill-progress`, "GET", "tables fill-progress", "oxygen_table_fill_progress", "tables", "Read hosted Table fill progress and any actionable ingestion failure."),
58
70
  operation("tables.resource.kind_estimates", "/api/cli/tables/column-kind-estimates", "GET", "columns kind-estimates", "oxygen_column_kind_estimates", "tables", "Read managed credit estimates for available Table column kinds."),
@@ -70,7 +82,7 @@ export const BROWSER_OPERATIONS = [
70
82
  operation("tables.resource.rows.get", `${table}/rows/{row}`, "GET", "tables rows inspect", "oxygen_table_row_inspect", "tables", "Read one row; field selects column keys and hydrate_relations=1 includes relations. projection=value returns lossless JSON fragments; resume value_cursor with identical table/row/field/path.", { hydrate_relations: enumOf(["1"]), field: strings(), ...TABLE_ROW_READ_WINDOW_FIELDS }, [], { repeatedQueryFields: ["field"] }),
71
83
  operation("tables.resource.rows.edit", `${table}/rows/{row}`, "PATCH", "tables rows edit", "oxygen_table_row_edit", "tables", "Patch one row's values and return the committed row.", { values: json }, ["values"]),
72
84
  operation("tables.resource.rows.delete", `${table}/rows/{row}`, "DELETE", "tables rows remove", "oxygen_table_row_remove", "tables", "Remove one row from a workspace Table."),
73
- operation("tables.resource.rows.bulk_delete", `${table}/rows/delete`, "POST", "tables rows remove-selection", "oxygen_table_rows_remove_selection", "tables", "Remove exact row ids or the same all-matching filtered selection used by the browser.", { row_ids: strings(), selection }),
85
+ operation("tables.resource.rows.bulk_delete", `${table}/rows/delete`, "POST", "tables rows remove-selection", "oxygen_table_rows_remove_selection", "tables", "Permanently delete Table rows by exact ids or a matching filtered selection. Unsupported scope fields are refused.", TABLE_ROW_REMOVAL_FIELDS, [], {}, { destructiveHint: true }),
74
86
  operation("tables.resource.rows.ids", `${table}/rows/ids`, "GET", "tables rows range-ids", "oxygen_table_rows_range_ids", "tables", "Resolve a bounded row range into exact ids, preserving the current filter, search, sort and CRM scope.", { offset: int({ minimum: 0 }), limit: int({ minimum: 1 }), filter: text(), search: text(), sort: text(), crm_object: text() }, ["offset", "limit"]),
75
87
  operation("tables.resource.relationships.get", `${table}/records/{row}/relationships`, "GET", "tables rows relationships", "oxygen_table_row_relationships", "crm", "Read a CRM-backed Table row's relationship links and available targets."),
76
88
  operation("tables.resource.relationships.set", `${table}/records/{row}/relationships`, "POST", "tables rows relationship-set", "oxygen_table_row_relationship_set", "crm", "Set one CRM-backed Table row's relationship and return the saved links.", { relationship: text(), target_row_id: text() }, ["relationship", "target_row_id"]),
@@ -1,4 +1,10 @@
1
1
  import type { ObjectProperty } from "./schema.js";
2
2
  /** Custom CRM column writes accept both canonical snake_case and legacy aliases. */
3
- export declare const CRM_CUSTOM_COLUMN_SCHEMA: ObjectProperty;
3
+ export declare const CRM_CUSTOM_COLUMN_SCHEMA: ObjectProperty & {
4
+ allOf: Array<{
5
+ anyOf: Array<{
6
+ required: string[];
7
+ }>;
8
+ }>;
9
+ };
4
10
  export declare const CRM_CUSTOM_IDENTITY_SCHEMA: ObjectProperty;
@@ -5,7 +5,7 @@ export const CRM_CUSTOM_COLUMN_SCHEMA = {
5
5
  key: { type: "string" }, label: { type: "string" },
6
6
  data_type: { type: "string", enum: ["text", "numeric", "boolean", "jsonb", "timestamptz"] },
7
7
  dataType: { type: "string", enum: ["text", "numeric", "boolean", "jsonb", "timestamptz"] },
8
- semantic_type: { type: "string" }, semanticType: { type: "string" },
8
+ semantic_type: { type: "string", minLength: 1, description: "Required with data_type; text for a generic field, or a semantic such as company.name, company.domain or email." }, semanticType: { type: "string", minLength: 1, description: "Alias of semantic_type." },
9
9
  kind: { type: "string" }, attribute_kind: { type: "string" }, attributeKind: { type: "string" },
10
10
  option_model_type: { type: "string" }, optionModelType: { type: "string" },
11
11
  is_required: { type: "boolean" }, isRequired: { type: "boolean" },
@@ -21,6 +21,10 @@ export const CRM_CUSTOM_COLUMN_SCHEMA = {
21
21
  attributeMetadata: { type: "object", additionalProperties: true },
22
22
  },
23
23
  required: ["key", "label"],
24
+ allOf: [
25
+ { anyOf: [{ required: ["data_type"] }, { required: ["dataType"] }] },
26
+ { anyOf: [{ required: ["semantic_type"] }, { required: ["semanticType"] }] },
27
+ ],
24
28
  additionalProperties: false,
25
29
  };
26
30
  export const CRM_CUSTOM_IDENTITY_SCHEMA = {
@@ -72,6 +72,20 @@ export declare const CRM_OBJECTS_QUERY_CONTRACT: import("./schema.js").ContractO
72
72
  "x-clamp"?: true;
73
73
  };
74
74
  }, never>;
75
+ export declare const CRM_RECORD_QUERY_CONTRACT: import("./schema.js").ContractObject<{
76
+ readonly projection: {
77
+ type: "string";
78
+ enum: readonly ("compact" | "full")[];
79
+ description?: string;
80
+ };
81
+ readonly max_chars: {
82
+ type: "integer";
83
+ description?: string;
84
+ minimum?: number;
85
+ maximum?: number;
86
+ "x-clamp"?: true;
87
+ };
88
+ }, never>;
75
89
  export declare const CRM_CONNECTIONS_QUERY_CONTRACT: import("./schema.js").ContractObject<{
76
90
  readonly projection: {
77
91
  type: "string";
@@ -30,6 +30,10 @@ export const CRM_OBJECTS_QUERY_CONTRACT = obj({
30
30
  limit: int({ minimum: 1, maximum: 100, description: "Objects in one batch; default 20 for bounded reads." }),
31
31
  max_chars: int({ minimum: 2000, maximum: 40_000, description: "Complete response window; oversized objects refuse without advancing." }),
32
32
  });
33
+ export const CRM_RECORD_QUERY_CONTRACT = obj({
34
+ projection: enumOf(["compact", "full"], { description: "compact omits object configuration and oversized row fields, naming omissions. HTTP/CLI default full; MCP default compact." }),
35
+ max_chars: int({ minimum: 2000, maximum: 40_000, description: "Complete receipt window. Omitted cells remain available through the Table row inspector." }),
36
+ });
33
37
  export const CRM_CONNECTIONS_QUERY_CONTRACT = obj({
34
38
  projection: enumOf(["compact", "full"], { description: "Compact returns identifiers and short communication previews. HTTP default full." }),
35
39
  max_chars: int({ minimum: 2000, maximum: 40_000, description: "Complete recent-window response; hasMore includes omitted links." }),
@@ -6,6 +6,8 @@ import { TABLE_FAVORITE_CONTRACT, TABLE_FAVORITES_LIST_CONTRACT, TABLE_ITEM_RESO
6
6
  import { BILLING_OWNER_READ_CONTRACT } from "./billing-owner-read.js";
7
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
+ import { spintaxContract } from "./spintax.js";
10
+ import { betaFeaturesUpdateContract, emailDomainSuppressionListContract, emailDomainSuppressionRemoveContract, emailSuppressionRemoveContract, providerLimitListContract, providerLimitSelectorContract, providerLimitUpdateContract } from "./workspace-utilities.js";
9
11
  const text = (description) => str(description === undefined ? {} : { description });
10
12
  const list = () => arr(str());
11
13
  const json = { type: "object", additionalProperties: true };
@@ -41,7 +43,7 @@ export const CUSTOMER_OPERATIONS = [
41
43
  operation("copilot.attachments.delete", "/api/cli/copilot/sessions/{session_id}/attachments/{attachment_id}", "DELETE", "copilot attachments delete", "oxygen_copilot_attachment_delete", "agents", "Detach an unsent Copilot attachment; attachments already quoted by a turn cannot be removed."),
42
44
  operation("copilot.feedback", "/api/cli/copilot/sessions/{session_id}/turns/{turn_id}/feedback", "POST", "copilot feedback", "oxygen_copilot_feedback", "agents", "Rate one attended Copilot turn and optionally explain the rating.", { rating: enumOf(["up", "down"]), comment: text() }, ["rating"]),
43
45
  operation("copilot.interrupt", "/api/cli/copilot/sessions/{session_id}/turns/{turn_id}/interrupt", "POST", "copilot interrupt", "oxygen_copilot_interrupt", "agents", "Request cancellation of one Copilot turn. Read the session again to confirm it stopped.", {}, [], mcpOnly),
44
- operation("context.canonical.get", "/api/cli/context/canonical/get", "POST", "context canonical get", "oxygen_context_canonical_get", "knowledge", "Read the pinned active context asset for a type; present=false means none is set.", { type: text() }, ["type"], { mutates: false }),
46
+ operation("context.canonical.get", "/api/cli/context/canonical/get", "POST", "context canonical get", "oxygen_context_canonical_get", "knowledge", "Read the current canonical (pinned) voice, brand or positioning that AI copy uses, or any type's pinned asset. present=false means none is pinned; grounding_when_absent says what AI copy uses instead.", { type: text("Type to read: voice, brand or positioning (the canonical copy AI uses), or another context type such as playbook or persona.") }, ["type"], { mutates: false }),
45
47
  operation("crm.notes.update", "/api/cli/crm/notes/{note_id}", "PATCH", "crm notes update", "oxygen_crm_note_update", "crm", "Edit a CRM note's body, title or pinned state; an empty title clears it.", { body: text(), title: nullable(text()), pinned: bool() }, [], mcpOnly),
46
48
  operation("crm.notes.delete", "/api/cli/crm/notes/{note_id}", "DELETE", "crm notes delete", "oxygen_crm_note_delete", "crm", "Delete one CRM note in this workspace.", {}, [], mcpOnly),
47
49
  operation("crm.files.attach_inline", "/api/cli/crm/objects/{object}/records/{row_id}/files", "POST", "crm files attach-inline", "oxygen_crm_file_attach", "crm", CRM_FILE_ATTACH_DESCRIPTION, CRM_FILE_ATTACH_CONTRACT.properties, [...(CRM_FILE_ATTACH_CONTRACT.required ?? [])]),
@@ -60,12 +62,12 @@ export const CUSTOMER_OPERATIONS = [
60
62
  operation("directory.apply", "/api/cli/directory/apply", "POST", "directory apply", "oxygen_directory_apply", "crm", "Apply for an agency-directory listing for this workspace; reuses an existing open application.", { message: text(), website: text() }, [], mcpOnly),
61
63
  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" } }),
62
64
  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),
63
- operation("knowledge.pages.archive", "/api/cli/knowledge/pages/archive", "POST", "knowledge page archive", "oxygen_knowledge_page_archive", "knowledge", "Archive a knowledge page while preserving its history.", { slug: text(), id: text(), expected_revision: int({ minimum: 1 }) }, [], mcpOnly),
65
+ 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),
64
66
  operation("knowledge.sync.manifest", "/api/cli/knowledge/sync/manifest", "POST", "knowledge sync-manifest", "oxygen_knowledge_sync_manifest", "knowledge", "Read the wiki revision and content-hash inventory without downloading instruction bodies.", {}, [], { mutates: false }),
65
67
  operation("knowledge.sync.delta", "/api/cli/knowledge/sync/delta", "POST", "knowledge sync", "oxygen_knowledge_sync_delta", "knowledge", "Read one resumable batch of wiki pages and tombstones, bounded by the server's byte budget.", { cursor: text(), limit: int({ minimum: 1, maximum: 200 }) }, [], { ...mcpOnly, mutates: false }),
66
- operation("limits.provider.get", "/api/cli/limits/provider", "GET", "limits provider list", "oxygen_provider_limits_list", "billing", "Read effective workspace provider rate limits.", { provider: text() }, [], mcpOnly),
67
- operation("limits.provider.set", "/api/cli/limits/provider", "POST", "limits provider set", "oxygen_provider_limits_set", "billing", "Set a workspace provider rate limit; admin or owner only.", { provider: text(), operation: text(), limit: int({ minimum: 1 }), window_seconds: int({ minimum: 1 }) }, ["provider", "limit", "window_seconds"], mcpOnly),
68
- operation("limits.provider.delete", "/api/cli/limits/provider", "DELETE", "limits provider delete", "oxygen_provider_limits_delete", "billing", "Clear a workspace provider rate-limit override; admin or owner only.", { provider: text(), operation: text() }, ["provider"], { ...mcpOnly, queryFields: ["provider", "operation"] }),
68
+ 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 } }),
69
+ 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 }),
70
+ 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"] }),
69
71
  operation("mailboxes.emailguard.auto_enroll.get", "/api/cli/mailboxes/emailguard/auto-enroll", "GET", "mailboxes emailguard auto-enroll", "oxygen_mailboxes_emailguard_auto_enroll_get", "deliverability", "Read the workspace's automatic monitoring enrollment grant and last sweep.", {}, [], mcpOnly),
70
72
  operation("mailboxes.emailguard.auto_enroll.set", "/api/cli/mailboxes/emailguard/auto-enroll", "POST", "mailboxes emailguard auto-enroll", "oxygen_mailboxes_emailguard_auto_enroll_set", "deliverability", "Preview, arm or disarm automatic mailbox monitoring. Arming recurring spend requires approved=true and max_credits_per_cycle.", { enabled: bool(), approved: bool(), max_credits_per_cycle: num({ minimum: 0 }), run: bool(), dry_run: bool() }, [], { ...mcpOnly, spends: true }),
71
73
  operation("mailboxes.warmup_profiles.get", "/api/cli/mailboxes/warmup-profile", "GET", "mailboxes warmup profile", "oxygen_mailboxes_warmup_profiles", "deliverability", "Read available OXYGEN Warm-up profiles and current bindings.", {}, [], mcpOnly),
@@ -76,8 +78,8 @@ export const CUSTOMER_OPERATIONS = [
76
78
  operation("publishing.drafts.update", "/api/cli/publishing/drafts/{draft_id}", "PATCH", "publishing drafts edit", "oxygen_publishing_draft_update", "publishing", "Edit a queued publishing draft's text without publishing it.", { text: text(), variant_index: int({ minimum: 0 }) }, ["text"], mcpOnly),
77
79
  operation("publishing.mentions.search", "/api/cli/publishing/mentions/search", "POST", "publishing mentions search", "oxygen_publishing_mentions_search", "publishing", "Find LinkedIn company or person identities for a mention; free, subject to the connected account's read quota.", { query: text(), kind: enumOf(["company", "person"]), connection_id: text() }, ["query"], { mutates: false }),
78
80
  operation("settings.beta.get", "/api/cli/settings/beta-features", "GET", "settings beta-features get", "oxygen_settings_beta_features_get", "workspace", "Read this workspace's beta-navigation opt-in."),
79
- operation("settings.beta.set", "/api/cli/settings/beta-features", "POST", "settings beta-features set", "oxygen_settings_beta_features_set", "workspace", "Enable or disable beta navigation for this workspace; admin or owner only.", { enabled: bool() }, ["enabled"]),
80
- operation("spintax.generate", "/api/cli/spintax", "POST", "spintax generate", "oxygen_spintax_generate", "sequences", "Generate spintax for outreach text. Costs exactly 3 credits; failed generation refunds the reservation.", { text: str({ minLength: 1, maxLength: 4000 }), section: str({ maxLength: 80 }) }, ["text"], { spends: true }),
81
+ operation("settings.beta.set", "/api/cli/settings/beta-features", "POST", "settings beta-features set", "oxygen_settings_beta_features_set", "workspace", "Enable or disable beta navigation for every workspace member; admin or owner only. Approve the preference change. This does not disable routes. 0 credits.", {}, [], { contract: betaFeaturesUpdateContract }),
82
+ operation("spintax.generate", "/api/cli/spintax", "POST", "spintax generate", "oxygen_spintax_generate", "sequences", "Generate wording or copy variations as spintax: live (default) costs 3 credits and requires approval and a credit ceiling; explicit dry_run is a free preview. Preserve merge variables; send nothing. Live requires approved:true and max_credits>=3 after preview; failed generation refunds the reservation.", {}, [], { contract: spintaxContract, defaults: { mode: "live" }, spends: true }),
81
83
  operation("table_action_items.resolve", "/api/cli/table-action-items/{item_id}/resolve", "POST", "table-actions resolve", "oxygen_table_action_item_resolve", "tables", "Record a human-verified uncertain Table action outcome without repeating it. Use cells resolve for row/column coordinates.", TABLE_ITEM_RESOLVE_CONTRACT.properties, ["outcome"]),
82
84
  operation("table_ingestions.append", "/api/cli/table-ingestion-runs/{ingestion_run_id}/items", "POST", "table-ingestions append", "oxygen_table_ingestions_append_items", "runs", "Append bounded ingestion items to an existing run; preserves the run's approved scope.", { items: rows(), max_attempts: int({ minimum: 1 }) }, ["items"], cliOnly),
83
85
  operation("tables.favorites.get", "/api/cli/tables/favorite", "GET", "tables favorites", "oxygen_tables_favorites", "tables", "Read starred Tables/folders (per-member preference; free (0 credits)); next_cursor. Catalog stars differ.", TABLE_FAVORITES_LIST_CONTRACT.properties, [], { generated: { cli: true, mcp: false } }),
@@ -100,7 +102,7 @@ export const CUSTOMER_OPERATIONS = [
100
102
  operation("db.provision", "/api/cli/db/provision", "POST", "db provision", "oxygen_workspace_database_provision", "workspace", "Provision or retry this workspace database immediately; already-ready workspaces retain it. No preview or confirmation field; native workspace write access applies. May outlast the connector deadline: read oxygen_workspace_database_status before retrying. Hosting is plan-included; 0 credits.", {}, [], mcpOnly),
101
103
  operation("sessions.list", "/api/cli/sessions", "GET", "sessions list", "oxygen_sessions_list", "workspace", "List your personal CLI sessions across workspaces; OAuth or personal user session required, organization API keys are refused."),
102
104
  operation("sessions.revoke", "/api/cli/sessions/{session_id}", "DELETE", "sessions revoke", "oxygen_sessions_revoke", "workspace", "Revoke one of your personal CLI sessions; OAuth or personal user session required, organization API keys are refused."),
103
- operation("billing.allowance", "/api/cli/billing/allowance", "GET", "billing allowance", "oxygen_billing_allowance", "billing", "Read this workspace's current recurring credit allowance and period.", {}, [], mcpOnly),
105
+ operation("billing.allowance", "/api/cli/billing/allowance", "GET", "billing allowance", "oxygen_billing_allowance", "billing", "Inspect this workspace's recurring credit allowance and period. 0 credits; reserves nothing. Due plan grants or credit expiry may apply.", {}, [], mcpOnly),
104
106
  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),
105
107
  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),
106
108
  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),
@@ -118,9 +120,9 @@ export const CUSTOMER_OPERATIONS = [
118
120
  operation("orgs.billing_owners", "/api/cli/orgs/billing-owners", "GET", "orgs billing-owners", "oxygen_workspace_billing_owners", "workspace", "Read the current workspace's billing owner, entitlement and payer candidates, including ineligibility reasons. Optional organization asserts the current workspace. Free.", BILLING_OWNER_READ_CONTRACT.properties, [], mcpOnly),
119
121
  operation("search.runs.items", "/api/cli/search/runs/{search_run_id}/items", "GET", "search runs items", "oxygen_search_run_items", "enrichment", "Read durable search ingestion items by run id and optional status.", { status: text(), limit: int({ minimum: 1 }) }, [], mcpOnly),
120
122
  operation("senders.checkpoints", "/api/cli/senders/checkpoints", "GET", "senders checkpoints", "oxygen_sender_checkpoints", "sequences", "Read connected sender authentication checkpoints that need human completion.", {}, [], mcpOnly),
121
- operation("suppressions.domains.list", "/api/cli/suppressions/domains", "GET", "suppressions domains", "oxygen_suppressed_domains_list", "sequences", "Read domain-wide email suppressions with reason, search and pagination.", { reason: text(), search: text(), limit: int({ minimum: 1 }), offset: int({ minimum: 0 }) }, [], mcpOnly),
122
- operation("suppressions.domains.remove", "/api/cli/suppressions/domains", "DELETE", "suppressions remove-domain", "oxygen_suppressed_domains_remove", "sequences", "Remove one domain-wide email suppression, or exact domains in bulk. This does not resume enrollments automatically.", { domain: text(), domains: list() }, [], mcpOnly),
123
- operation("suppressions.addresses.remove", "/api/cli/suppressions/addresses", "DELETE", "suppressions remove-address", "oxygen_suppressed_addresses_remove", "sequences", "Remove one email-address suppression, or exact emails in bulk. This does not resume enrollments automatically.", { email: text(), emails: list() }, [], mcpOnly),
123
+ operation("suppressions.domains.list", "/api/cli/suppressions/domains", "GET", "suppressions domains", "oxygen_suppressed_domains_list", "sequences", "Read domain-wide sending blocks, newest first. Domain reasons differ from address reasons. MCP defaults to bounded summary pages; follow paging.next_offset with the same filters. 0 credits.", {}, [], { contract: emailDomainSuppressionListContract, generated: { cli: false, mcp: false } }),
124
+ operation("suppressions.domains.remove", "/api/cli/suppressions/domains", "DELETE", "suppressions remove-domain", "oxygen_suppressed_domains_remove", "sequences", "Remove one domain-wide sending block or up to 500 exact domains after approval of the keys. Can restore future sending eligibility; other suppression ledgers still apply. This does not resume enrollments automatically. 0 credits.", {}, [], { ...mcpOnly, contract: emailDomainSuppressionRemoveContract }),
125
+ operation("suppressions.addresses.remove", "/api/cli/suppressions/addresses", "DELETE", "suppressions remove-address", "oxygen_suppressed_addresses_remove", "sequences", "Remove one email-address sending block or up to 500 exact addresses after approval of the keys. Can restore future sending eligibility; other suppression ledgers still apply. This does not resume enrollments automatically. 0 credits.", {}, [], { ...mcpOnly, contract: emailSuppressionRemoveContract }),
124
126
  operation("table_action_runs.list", "/api/cli/table-action-runs", "GET", "table-runs list", "oxygen_table_action_runs_list", "runs", "Read durable Table action runs, optionally filtered by status or trace.", { table: text(), status: text(), trace_id: text(), limit: int({ minimum: 1 }) }, ["table"], mcpOnly),
125
127
  operation("tables.columns.fields", "/api/cli/tables/columns/fields", "GET", "columns fields", "oxygen_table_column_fields", "tables", "Read the output fields available from one hosted Table column.", { table: text(), column: text() }, ["table", "column"], mcpOnly),
126
128
  operation("tools.favorites", "/api/cli/tools/favorites", "GET", "tools favorites", "oxygen_tool_favorites", "enrichment", "Read this member's favorite tool catalog entries in the active workspace.", {}, [], mcpOnly),
@@ -12,7 +12,7 @@ export function limitsReadQueryIssue(query) {
12
12
  }
13
13
  const record = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : {};
14
14
  const pick = (value, keys) => Object.fromEntries(keys.filter(key => Object.hasOwn(value, key)).map(key => [key, value[key]]));
15
- const COMMON = ["organization_id", "plan_band", "plan_band_label", "plan_tier", "limits_tier", "source", "entitled", "shared_billing", "web_url", "deepLink"];
15
+ const COMMON = ["organization_id", "plan_band", "plan_band_label", "plan_tier", "limits_tier", "source", "entitled", "plan_resolution", "shared_billing", "web_url", "deepLink"];
16
16
  const SECTION_FIELDS = { api: "api_rate_limits", webhooks: "webhook_ingress", spend: "spend_safety_defaults", sending: "sending_limits", workflow: "workflow_limits" };
17
17
  function capacityProjection(value) {
18
18
  const capacity = record(value), usage = record(capacity.usage), reconciled = usage.row_usage_reconciled === true;
@@ -119,5 +119,15 @@ export function projectLimitsRead(data, query) {
119
119
  delete bounded[key];
120
120
  markOmitted(key);
121
121
  }
122
+ // Both links open the limits page. Drop duplicate navigation last when a
123
+ // long app URL crowds out the protected workspace and plan scope.
124
+ for (const key of ["deepLink", "web_url"]) {
125
+ if (JSON.stringify(bounded).length <= maxChars)
126
+ break;
127
+ if (Object.hasOwn(bounded, key)) {
128
+ delete bounded[key];
129
+ markOmitted(key);
130
+ }
131
+ }
122
132
  return bounded;
123
133
  }
@@ -61,6 +61,12 @@ export type OperationSpec<C extends ContractObject = ContractObject> = {
61
61
  };
62
62
  mutates: boolean;
63
63
  spends: boolean;
64
+ /**
65
+ * MCP only: what a trimmed result should advise instead of the generic
66
+ * "smaller limit / a cursor", for a read whose single row can exceed the
67
+ * result ceiling (OXP-1.11.67).
68
+ */
69
+ truncationHint?: string;
64
70
  };
65
71
  /** The route with its `{param}` segments filled in, each URL-encoded. */
66
72
  export declare function operationPath(spec: Pick<OperationSpec, "route">, params: Readonly<Record<string, string>>): string;
@@ -12,6 +12,7 @@ export const PUBLISHING_AMPLIFICATION_SCOPE_KINDS = ["all", "tag", "post", "ugc_
12
12
  * closed. Coarse tool annotations remain mixed; native identity/schema checks
13
13
  * still run after this call-level classification. */
14
14
  export const PUBLISHING_STORED_READ_SELECTORS = {
15
+ oxygen_publishing_comments: { argument: "action", values: ["list", "get"] },
15
16
  oxygen_publishing_notes: { argument: "action", values: ["list"] },
16
17
  oxygen_publishing_revisions: { argument: "action", values: ["list"] },
17
18
  oxygen_publishing_analytics: { argument: "scope", values: ["summary", "timeseries", "post", "account"] },
@@ -118,18 +118,22 @@ function childPath(parent, key) {
118
118
  }
119
119
  function walkObject(schema, value, path, walk) {
120
120
  const out = {};
121
+ const set = (key, entry) => {
122
+ // JSON keys remain own data properties, including an explicit __proto__.
123
+ Object.defineProperty(out, key, { value: entry, enumerable: true, writable: true, configurable: true });
124
+ };
121
125
  const properties = schema.properties ?? {};
122
126
  for (const key of schema.required ?? []) {
123
- if (value[key] === undefined)
127
+ if (!Object.hasOwn(value, key) || value[key] === undefined)
124
128
  walk.issues.push({ path: childPath(path, key), message: `${childPath(path, key)} is required.` });
125
129
  }
126
130
  for (const [key, entry] of Object.entries(value)) {
127
131
  if (entry === undefined)
128
132
  continue;
129
133
  const at = childPath(path, key);
130
- const property = properties[key];
134
+ const property = Object.hasOwn(properties, key) ? properties[key] : undefined;
131
135
  if (property !== undefined) {
132
- out[key] = walkValue(property, entry, at, walk);
136
+ set(key, walkValue(property, entry, at, walk));
133
137
  continue;
134
138
  }
135
139
  const extra = schema.additionalProperties;
@@ -139,14 +143,14 @@ function walkObject(schema, value, path, walk) {
139
143
  }
140
144
  else {
141
145
  walk.unknownKeys.push(at);
142
- out[key] = entry;
146
+ set(key, entry);
143
147
  }
144
148
  }
145
149
  else if (extra && typeof extra === "object") {
146
- out[key] = walkValue(extra, entry, at, walk);
150
+ set(key, walkValue(extra, entry, at, walk));
147
151
  }
148
152
  else {
149
- out[key] = entry;
153
+ set(key, entry);
150
154
  }
151
155
  }
152
156
  return out;
@@ -0,0 +1,18 @@
1
+ export declare const SPINTAX_GENERATION_CREDITS = 3;
2
+ export declare const spintaxContract: import("./schema.js").ContractObject<{
3
+ readonly text: import("./schema.js").StringProperty;
4
+ readonly section: import("./schema.js").StringProperty;
5
+ readonly mode: {
6
+ type: "string";
7
+ enum: readonly ("dry_run" | "live")[];
8
+ description?: string;
9
+ };
10
+ readonly approved: import("./schema.js").BooleanProperty;
11
+ readonly max_credits: {
12
+ type: "number";
13
+ description?: string;
14
+ minimum?: number;
15
+ maximum?: number;
16
+ "x-clamp"?: true;
17
+ };
18
+ }, "text">;
@@ -0,0 +1,11 @@
1
+ import { bool, enumOf, num, obj, str } from "./schema.js";
2
+ // The native managed service charges this fixed amount for a usable spin.
3
+ // Preview, reservation, settlement and agent-visible schemas share this owner.
4
+ export const SPINTAX_GENERATION_CREDITS = 3;
5
+ export const spintaxContract = obj({
6
+ text: str({ minLength: 1, maxLength: 4000, description: "Outreach copy to vary; merge variables are preserved." }),
7
+ section: str({ maxLength: 80, description: "Optional section label, e.g. Subject." }),
8
+ mode: enumOf(["dry_run", "live"], { description: `Omitted mode is live. Explicit dry_run previews the fixed ${SPINTAX_GENERATION_CREDITS}-credit cost without generation; live requires approval and a ceiling.` }),
9
+ approved: bool({ description: `True only after approval of the exact text and ${SPINTAX_GENERATION_CREDITS}-credit cost.` }),
10
+ max_credits: num({ minimum: 0, description: `Live ceiling must cover the fixed ${SPINTAX_GENERATION_CREDITS}-credit cost.` }),
11
+ }, { required: ["text"] });
@@ -0,0 +1,8 @@
1
+ export declare const TABLE_ROW_REMOVAL_FIELDS: {
2
+ row_ids: import("./schema.js").ArrayProperty<import("./schema.js").StringProperty>;
3
+ selection: import("./schema.js").OneOfProperty;
4
+ };
5
+ export declare const TABLE_ROW_REMOVAL_CONTRACT: import("./schema.js").ContractObject<{
6
+ row_ids: import("./schema.js").ArrayProperty<import("./schema.js").StringProperty>;
7
+ selection: import("./schema.js").OneOfProperty;
8
+ }, never>;
@@ -0,0 +1,21 @@
1
+ import { arr, enumOf, int, obj, str } from "./schema.js";
2
+ const rowIds = () => arr(str({ minLength: 1 }), { minItems: 1 });
3
+ // Removal uses the grid's scope, not the broader execution selection. In
4
+ // particular, execution's `filters` array is not a serialized browser filter.
5
+ const selection = {
6
+ description: '{"mode":"row_ids","row_ids":["id"]} or {"mode":"all_matching","filter":"<grid f>"}. Optional search, sort, range {offset,limit}, excluded_row_ids, crm_object. filter is base64url grid JSON; filters/limit are refused. Unqualified all_matching removes every row. Encoding guide: oxygen_skills_get({name:"oxygen-tables"}) or oxygen skills get oxygen-tables --json.',
7
+ oneOf: [
8
+ obj({ mode: enumOf(["row_ids"]), row_ids: rowIds() }, { required: ["mode", "row_ids"] }),
9
+ obj({
10
+ mode: enumOf(["all_matching"]),
11
+ filter: str({ description: "Serialized browser filter tree." }),
12
+ search: str(),
13
+ sort: str(),
14
+ range: obj({ offset: int({ minimum: 0 }), limit: int({ minimum: 1 }) }, { required: ["offset", "limit"] }),
15
+ excluded_row_ids: arr(str({ minLength: 1 })),
16
+ crm_object: str(),
17
+ }, { required: ["mode"] }),
18
+ ],
19
+ };
20
+ export const TABLE_ROW_REMOVAL_FIELDS = { row_ids: rowIds(), selection };
21
+ export const TABLE_ROW_REMOVAL_CONTRACT = obj(TABLE_ROW_REMOVAL_FIELDS);
@@ -0,0 +1,162 @@
1
+ export declare const betaFeaturesUpdateContract: import("./schema.js").ContractObject<{
2
+ readonly enabled: import("./schema.js").BooleanProperty;
3
+ }, "enabled">;
4
+ export declare const providerLimitSelectorContract: import("./schema.js").ContractObject<{
5
+ readonly provider: import("./schema.js").StringProperty;
6
+ readonly operation: import("./schema.js").StringProperty;
7
+ }, "provider">;
8
+ export declare const providerLimitUpdateContract: import("./schema.js").ContractObject<{
9
+ readonly provider: import("./schema.js").StringProperty;
10
+ readonly operation: {
11
+ oneOf: [import("./schema.js").StringProperty, import("./schema.js").NullProperty];
12
+ description?: string;
13
+ };
14
+ readonly limit: {
15
+ type: "integer";
16
+ description?: string;
17
+ minimum?: number;
18
+ maximum?: number;
19
+ "x-clamp"?: true;
20
+ };
21
+ readonly window_seconds: {
22
+ type: "integer";
23
+ description?: string;
24
+ minimum?: number;
25
+ maximum?: number;
26
+ "x-clamp"?: true;
27
+ };
28
+ }, "limit" | "provider" | "window_seconds">;
29
+ export declare const SUPPRESSION_BULK_MAX_KEYS = 500;
30
+ export declare const utilityListWindowProperties: {
31
+ view: {
32
+ type: "string";
33
+ enum: readonly ("full" | "summary")[];
34
+ description?: string;
35
+ };
36
+ max_chars: {
37
+ type: "integer";
38
+ description?: string;
39
+ minimum?: number;
40
+ maximum?: number;
41
+ "x-clamp"?: true;
42
+ };
43
+ };
44
+ export declare const utilityListWindowContract: import("./schema.js").ContractObject<{
45
+ view: {
46
+ type: "string";
47
+ enum: readonly ("full" | "summary")[];
48
+ description?: string;
49
+ };
50
+ max_chars: {
51
+ type: "integer";
52
+ description?: string;
53
+ minimum?: number;
54
+ maximum?: number;
55
+ "x-clamp"?: true;
56
+ };
57
+ }, never>;
58
+ export declare const providerLimitListContract: import("./schema.js").ContractObject<{
59
+ readonly view: {
60
+ type: "string";
61
+ enum: readonly ("full" | "summary")[];
62
+ description?: string;
63
+ };
64
+ readonly max_chars: {
65
+ type: "integer";
66
+ description?: string;
67
+ minimum?: number;
68
+ maximum?: number;
69
+ "x-clamp"?: true;
70
+ };
71
+ readonly provider: import("./schema.js").StringProperty;
72
+ readonly limit: {
73
+ type: "integer";
74
+ description?: string;
75
+ minimum?: number;
76
+ maximum?: number;
77
+ "x-clamp"?: true;
78
+ };
79
+ readonly offset: {
80
+ type: "integer";
81
+ description?: string;
82
+ minimum?: number;
83
+ maximum?: number;
84
+ "x-clamp"?: true;
85
+ };
86
+ }, never>;
87
+ export declare const emailSuppressionListContract: import("./schema.js").ContractObject<{
88
+ readonly view: {
89
+ type: "string";
90
+ enum: readonly ("full" | "summary")[];
91
+ description?: string;
92
+ };
93
+ readonly max_chars: {
94
+ type: "integer";
95
+ description?: string;
96
+ minimum?: number;
97
+ maximum?: number;
98
+ "x-clamp"?: true;
99
+ };
100
+ readonly reason: {
101
+ type: "string";
102
+ enum: readonly ("complaint" | "hard_bounce" | "manual" | "unsubscribe")[];
103
+ description?: string;
104
+ };
105
+ readonly search: import("./schema.js").StringProperty;
106
+ readonly limit: {
107
+ type: "integer";
108
+ description?: string;
109
+ minimum?: number;
110
+ maximum?: number;
111
+ "x-clamp"?: true;
112
+ };
113
+ readonly offset: {
114
+ type: "integer";
115
+ description?: string;
116
+ minimum?: number;
117
+ maximum?: number;
118
+ "x-clamp"?: true;
119
+ };
120
+ }, never>;
121
+ export declare const emailDomainSuppressionListContract: import("./schema.js").ContractObject<{
122
+ readonly view: {
123
+ type: "string";
124
+ enum: readonly ("full" | "summary")[];
125
+ description?: string;
126
+ };
127
+ readonly max_chars: {
128
+ type: "integer";
129
+ description?: string;
130
+ minimum?: number;
131
+ maximum?: number;
132
+ "x-clamp"?: true;
133
+ };
134
+ readonly limit: {
135
+ type: "integer";
136
+ description?: string;
137
+ minimum?: number;
138
+ maximum?: number;
139
+ "x-clamp"?: true;
140
+ };
141
+ readonly offset: {
142
+ type: "integer";
143
+ description?: string;
144
+ minimum?: number;
145
+ maximum?: number;
146
+ "x-clamp"?: true;
147
+ };
148
+ readonly reason: {
149
+ type: "string";
150
+ enum: readonly ("complaint" | "manual" | "policy")[];
151
+ description?: string;
152
+ };
153
+ readonly search: import("./schema.js").StringProperty;
154
+ }, never>;
155
+ export declare const emailSuppressionRemoveContract: import("./schema.js").ContractObject<{
156
+ readonly email: import("./schema.js").StringProperty;
157
+ readonly emails: import("./schema.js").ArrayProperty<import("./schema.js").StringProperty>;
158
+ }, never>;
159
+ export declare const emailDomainSuppressionRemoveContract: import("./schema.js").ContractObject<{
160
+ readonly domain: import("./schema.js").StringProperty;
161
+ readonly domains: import("./schema.js").ArrayProperty<import("./schema.js").StringProperty>;
162
+ }, never>;