@oxygen-agent/cli 1.1011.326 → 1.1011.440

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 (98) hide show
  1. package/README.md +1 -1
  2. package/dist/command-manifest.js +15 -4
  3. package/dist/connectors-commands.d.ts +4 -1
  4. package/dist/connectors-commands.js +84 -10
  5. package/dist/contract-flags.d.ts +2 -0
  6. package/dist/contract-flags.js +26 -11
  7. package/dist/crm-support-flags.d.ts +11 -0
  8. package/dist/crm-support-flags.js +60 -0
  9. package/dist/customer-operation-commands.d.ts +5 -0
  10. package/dist/customer-operation-commands.js +101 -0
  11. package/dist/database-query-flags.d.ts +2 -0
  12. package/dist/database-query-flags.js +6 -0
  13. package/dist/help.d.ts +3 -1
  14. package/dist/help.js +43 -0
  15. package/dist/http-client.d.ts +2 -0
  16. package/dist/http-client.js +41 -1
  17. package/dist/index.js +640 -234
  18. package/dist/knowledge-repository-commands.js +12 -14
  19. package/dist/mailbox-ramp-notice.d.ts +11 -0
  20. package/dist/mailbox-ramp-notice.js +53 -0
  21. package/dist/settings-commands.d.ts +11 -0
  22. package/dist/settings-commands.js +73 -0
  23. package/dist/skills.d.ts +5 -4
  24. package/dist/skills.js +106 -79
  25. package/dist/tool-catalog-detail-command.d.ts +7 -0
  26. package/dist/tool-catalog-detail-command.js +19 -0
  27. package/dist/tool-catalog-search-window.d.ts +6 -0
  28. package/dist/tool-catalog-search-window.js +12 -0
  29. package/dist/transcript.js +1 -0
  30. package/node_modules/@oxygen/shared/dist/bounded-read-result.d.ts +4 -0
  31. package/node_modules/@oxygen/shared/dist/bounded-read-result.js +25 -0
  32. package/node_modules/@oxygen/shared/dist/capability-discovery.d.ts +47 -1
  33. package/node_modules/@oxygen/shared/dist/capability-discovery.js +625 -39
  34. package/node_modules/@oxygen/shared/dist/connection-approval.d.ts +2 -0
  35. package/node_modules/@oxygen/shared/dist/connection-approval.js +2 -0
  36. package/node_modules/@oxygen/shared/dist/contracts/browser-operations.d.ts +2 -0
  37. package/node_modules/@oxygen/shared/dist/contracts/browser-operations.js +110 -0
  38. package/node_modules/@oxygen/shared/dist/contracts/connectors.d.ts +32 -6
  39. package/node_modules/@oxygen/shared/dist/contracts/connectors.js +56 -4
  40. package/node_modules/@oxygen/shared/dist/contracts/crm-attributes.d.ts +4 -0
  41. package/node_modules/@oxygen/shared/dist/contracts/crm-attributes.js +39 -0
  42. package/node_modules/@oxygen/shared/dist/contracts/crm-enrichment-read.d.ts +21 -0
  43. package/node_modules/@oxygen/shared/dist/contracts/crm-enrichment-read.js +15 -0
  44. package/node_modules/@oxygen/shared/dist/contracts/crm-support.d.ts +117 -0
  45. package/node_modules/@oxygen/shared/dist/contracts/crm-support.js +43 -0
  46. package/node_modules/@oxygen/shared/dist/contracts/customer-operations.d.ts +2 -0
  47. package/node_modules/@oxygen/shared/dist/contracts/customer-operations.js +131 -0
  48. package/node_modules/@oxygen/shared/dist/contracts/dashboard-tabs.d.ts +3 -0
  49. package/node_modules/@oxygen/shared/dist/contracts/dashboard-tabs.js +2 -0
  50. package/node_modules/@oxygen/shared/dist/contracts/database.d.ts +30 -0
  51. package/node_modules/@oxygen/shared/dist/contracts/database.js +29 -0
  52. package/node_modules/@oxygen/shared/dist/contracts/integration-connect.d.ts +4 -0
  53. package/node_modules/@oxygen/shared/dist/contracts/integration-connect.js +7 -0
  54. package/node_modules/@oxygen/shared/dist/contracts/knowledge-content-reads.d.ts +43 -0
  55. package/node_modules/@oxygen/shared/dist/contracts/knowledge-content-reads.js +20 -0
  56. package/node_modules/@oxygen/shared/dist/contracts/linkedin-invites-list.d.ts +12 -0
  57. package/node_modules/@oxygen/shared/dist/contracts/linkedin-invites-list.js +8 -0
  58. package/node_modules/@oxygen/shared/dist/contracts/operations.d.ts +48 -2
  59. package/node_modules/@oxygen/shared/dist/contracts/operations.js +68 -2
  60. package/node_modules/@oxygen/shared/dist/contracts/table-grid-query.d.ts +4 -0
  61. package/node_modules/@oxygen/shared/dist/contracts/table-grid-query.js +6 -0
  62. package/node_modules/@oxygen/shared/dist/contracts/table-query-grid.d.ts +21 -0
  63. package/node_modules/@oxygen/shared/dist/contracts/table-query-grid.js +27 -0
  64. package/node_modules/@oxygen/shared/dist/contracts/tool-catalog-detail.d.ts +19 -0
  65. package/node_modules/@oxygen/shared/dist/contracts/tool-catalog-detail.js +10 -0
  66. package/node_modules/@oxygen/shared/dist/contracts/tool-catalog-search-window.d.ts +12 -0
  67. package/node_modules/@oxygen/shared/dist/contracts/tool-catalog-search-window.js +7 -0
  68. package/node_modules/@oxygen/shared/dist/contracts/workspace-pages.d.ts +17 -0
  69. package/node_modules/@oxygen/shared/dist/contracts/workspace-pages.js +49 -0
  70. package/node_modules/@oxygen/shared/dist/decision-ledger-parser.d.ts +32 -0
  71. package/node_modules/@oxygen/shared/dist/decision-ledger-parser.js +303 -0
  72. package/node_modules/@oxygen/shared/dist/decision-ledger.d.ts +10 -0
  73. package/node_modules/@oxygen/shared/dist/decision-ledger.generated.d.ts +2 -0
  74. package/node_modules/@oxygen/shared/dist/decision-ledger.generated.js +717 -0
  75. package/node_modules/@oxygen/shared/dist/decision-ledger.js +20 -0
  76. package/node_modules/@oxygen/shared/dist/email-campaign-ramp.d.ts +104 -0
  77. package/node_modules/@oxygen/shared/dist/email-campaign-ramp.js +250 -0
  78. package/node_modules/@oxygen/shared/dist/mcp-event-contract.d.ts +10 -7
  79. package/node_modules/@oxygen/shared/dist/mcp-event-contract.js +11 -7
  80. package/node_modules/@oxygen/shared/dist/mcp-table-widget.d.ts +50 -0
  81. package/node_modules/@oxygen/shared/dist/mcp-table-widget.js +24 -0
  82. package/node_modules/@oxygen/shared/dist/plan-band.d.ts +8 -0
  83. package/node_modules/@oxygen/shared/dist/plan-band.js +12 -0
  84. package/node_modules/@oxygen/shared/dist/plan-limits.d.ts +20 -0
  85. package/node_modules/@oxygen/shared/dist/plan-limits.js +41 -0
  86. package/node_modules/@oxygen/shared/dist/provider-input-value.d.ts +5 -0
  87. package/node_modules/@oxygen/shared/dist/provider-input-value.js +10 -0
  88. package/node_modules/@oxygen/shared/dist/sequences.d.ts +33 -4
  89. package/node_modules/@oxygen/shared/dist/sequences.js +48 -13
  90. package/node_modules/@oxygen/shared/dist/user-capability-routing.js +17 -0
  91. package/node_modules/@oxygen/shared/dist/version.generated.d.ts +1 -1
  92. package/node_modules/@oxygen/shared/dist/version.generated.js +1 -1
  93. package/node_modules/@oxygen/shared/package.json +8 -6
  94. package/package.json +1 -1
  95. package/node_modules/@oxygen/shared/dist/copilot-skills.d.ts +0 -15
  96. package/node_modules/@oxygen/shared/dist/copilot-skills.generated.d.ts +0 -31
  97. package/node_modules/@oxygen/shared/dist/copilot-skills.generated.js +0 -41
  98. package/node_modules/@oxygen/shared/dist/copilot-skills.js +0 -6
@@ -0,0 +1,2 @@
1
+ /** Shared refusal discriminator; safe to import without the plan/pricing catalog. */
2
+ export declare const CONNECTION_CEILING_ABOVE_DEFAULT_APPROVAL_KIND = "connection_ceiling_above_default";
@@ -0,0 +1,2 @@
1
+ /** Shared refusal discriminator; safe to import without the plan/pricing catalog. */
2
+ export const CONNECTION_CEILING_ABOVE_DEFAULT_APPROVAL_KIND = "connection_ceiling_above_default";
@@ -0,0 +1,2 @@
1
+ import type { OperationSpec } from "./operations.js";
2
+ export declare const BROWSER_OPERATIONS: readonly OperationSpec[];
@@ -0,0 +1,110 @@
1
+ /** Browser resource operations, using the same scoped handlers on every surface. */
2
+ import { arr, bool, enumOf, int, nullable, num, obj, str } from "./schema.js";
3
+ const text = (description) => str(description ? { description } : {});
4
+ const json = { type: "object", additionalProperties: true };
5
+ const strings = () => arr(str());
6
+ const objects = () => arr(json);
7
+ const dataType = () => enumOf(["text", "numeric", "boolean", "jsonb", "timestamptz"]);
8
+ const selection = obj({
9
+ mode: enumOf(["all", "limit", "row_ids", "filter", "all_matching"]),
10
+ limit: int({ minimum: 1 }), row_ids: strings(), filters: objects(),
11
+ filter: text("Serialized browser filter tree."), search: text(), sort: text(), crm_object: text(),
12
+ range: obj({ offset: int({ minimum: 0 }), limit: int({ minimum: 1 }) }, { required: ["offset", "limit"] }),
13
+ }, { required: ["mode"] });
14
+ const actions = arr(obj({ type: enumOf(["tool_column"]), column: text(), definition: json }, { required: ["column"] }));
15
+ const viewFields = { name: text(), view_type: text(), config: json, group_by: text(), is_default: bool(), position: int({ minimum: 0 }) };
16
+ const crmLinks = arr(obj({ object: text(), row_id: text(), role: text() }, { required: ["object", "row_id"] }));
17
+ function operation(id, route, method, cli, mcp, pack, summary, fields = {}, required = [], options = {}) {
18
+ return {
19
+ id, route, method, parameters: [...route.matchAll(/\{(\w+)\}/g)].map((match) => match[1]),
20
+ contract: obj(fields, { required }),
21
+ cli: { path: cli.split(" "), summary },
22
+ mcp: { name: mcp, title: `Oxygen: ${cli}`, description: summary, pack },
23
+ mutates: method !== "GET", spends: false, ...options,
24
+ };
25
+ }
26
+ const table = "/api/cli/tables/{table}";
27
+ const column = `${table}/columns/{column}`;
28
+ const run = `${table}/runs/{run}`;
29
+ const upload = { content_base64: text(), file_name: text(), content_type: text(), intent: enumOf(["preview", "import"]), format: enumOf(["csv", "json", "xlsx"]), sheet: text(), table: text(), create_name: text(), project: text(), upsert_key: text(), source_key_map: json };
30
+ const multipart = { contentField: "content_base64", nameField: "file_name", typeField: "content_type", fileField: "file" };
31
+ // Both surfaces already register these exact canonical actions under their established names.
32
+ const nativeCli = { generated: { cli: false, mcp: false } };
33
+ export const BROWSER_OPERATIONS = [
34
+ 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" } }),
35
+ 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."),
36
+ 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."),
37
+ 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."),
38
+ 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."),
39
+ 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() }),
40
+ 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"]),
41
+ 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."),
42
+ 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."),
43
+ 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."),
44
+ 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() }),
45
+ 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() }),
46
+ operation("unibox.metadata", "/api/cli/unibox/metadata", "GET", "unibox metadata", "oxygen_unibox_metadata", "inbox", "Read the complete authenticated inbox account, filter and tag metadata."),
47
+ 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() }),
48
+ 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 }) }),
49
+ 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."),
50
+ operation("workflows.tool_output_paths", "/api/cli/workflows/tool-output-paths", "GET", "workflows tool-output-paths", "oxygen_workflow_tool_output_paths", "workflows", "Discover bounded workspace-observed tool output paths and run/revision provenance, without exposing provider values.", { tool_id: strings() }, ["tool_id"], { repeatedQueryFields: ["tool_id"] }),
51
+ 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() }),
52
+ 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),
53
+ 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),
54
+ 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 }) }),
55
+ 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."),
56
+ 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."),
57
+ 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."),
58
+ operation("tables.resource.columns.create", `${table}/columns`, "POST", "columns create", "oxygen_table_column_create", "tables", "Create a Table column at an optional zero-based position.", { column: obj({ label: text(), key: text(), kind: text(), data_type: dataType(), semantic_type: text(), definition: json }, { required: ["label"] }), position: int({ minimum: 0 }) }, ["column"]),
59
+ operation("tables.resource.columns.edit", column, "PATCH", "columns edit", "oxygen_table_column_edit", "tables", "Save a column's label, type, order or definition. Returns downstream reference warnings rather than silently discarding them.", { label: text(), semantic_type: nullable(text()), definition: json, definition_unset: strings(), data_type: dataType(), position: int({ minimum: 0 }) }),
60
+ operation("tables.resource.columns.archive", `${column}/archive`, "POST", "columns archive", "oxygen_columns_archive", "tables", "Archive a Table column indefinitely while preserving its stored values.", {}, [], nativeCli),
61
+ operation("tables.resource.columns.duplicate", `${column}/duplicate`, "POST", "columns duplicate", "oxygen_table_column_duplicate", "tables", "Duplicate a Table column and its definition with an optional new label.", { label: text() }),
62
+ operation("tables.resource.columns.materialize", `${column}/materialize`, "POST", "columns materialize", "oxygen_columns_materialize", "tables", "Materialize JSON paths into existing or newly created companion columns.", { preset: enumOf(["work_email"]), mappings: arr(obj({ source_path: text(), target_column: text(), label: text(), data_type: dataType(), semantic_type: text() }, { required: ["source_path", "target_column"] })), create_if_missing: bool(), overwrite_existing: bool() }, [], nativeCli),
63
+ operation("tables.resource.columns.retype", `${column}/retype`, "POST", "columns retype", "oxygen_columns_retype", "tables", "Preview or apply a manual column's stored-value type conversion.", { data_type: dataType(), dry_run: bool() }, ["data_type"], nativeCli),
64
+ operation("tables.resource.columns.run", `${column}/run`, "POST", "columns execute", "oxygen_table_column_execute", "runs", "Run one column over an exact row or bounded selection. Paid execution requires approval and a max_credits ceiling; uncertain prior effects need explicit resolution approval.", { row_id: text(), force: bool(), limit: int({ minimum: 1 }), full_table_mode: enumOf(["missing", "force"]), max_credits: num({ minimum: 0 }), max_concurrency: int({ minimum: 1 }), connection_id: text(), approved: bool(), approved_effect_unknown: bool() }, [], { spends: true }),
65
+ operation("tables.resource.columns.web_search_mode", `${table}/columns/{column_ref}/web-search-mode`, "POST", "columns web-search-mode", "oxygen_table_column_web_search_mode", "tables", "Convert a web-search column between agent, AI or keyword modes. Conversion requires confirm=true; mode plus column seeds an AI or keyword replacement.", { to: enumOf(["agent", "ai", "keyword"]), confirm: bool(), mode: enumOf(["ai", "keyword"]), column: json, prompt: text() }),
66
+ operation("tables.resource.action_columns", `${table}/action-columns`, "POST", "columns provider-action", "oxygen_table_provider_action_column", "tables", "Preview or create a provider action column; creating it does not execute provider actions.", { provider: text(), label: text(), key: text(), operations: strings(), dry_run: bool() }, ["provider"]),
67
+ operation("tables.resource.rows.page", `${table}/rows`, "GET", "tables rows page", "oxygen_table_rows_page", "tables", "Read a Table row page with the same filter, sort, counts and CRM relationship projection as the grid.", { limit: int({ minimum: 1 }), cursor: text(), offset: int({ minimum: 0 }), f: text("Serialized filter tree."), s: text("Serialized sort state."), q: text(), count: enumOf(["exact", "estimate", "registry", "skip"]), crm_object: text() }),
68
+ operation("tables.resource.rows.insert", `${table}/rows`, "POST", "tables rows insert", "oxygen_table_rows_insert", "tables", "Insert Table row values and return the committed rows plus any existing automatic run or dedupe grant.", { rows: objects(), values: json }),
69
+ operation("tables.resource.rows.get", `${table}/rows/{row}`, "GET", "tables rows inspect", "oxygen_table_row_inspect", "tables", "Read one Table row; hydrate_relations=1 includes CRM relationship display values. The optional field list narrows cell hydration to exact column keys.", { hydrate_relations: enumOf(["1"]), field: strings() }, [], { repeatedQueryFields: ["field"] }),
70
+ 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"]),
71
+ operation("tables.resource.rows.delete", `${table}/rows/{row}`, "DELETE", "tables rows remove", "oxygen_table_row_remove", "tables", "Remove one row from a workspace Table."),
72
+ 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 }),
73
+ 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"]),
74
+ 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."),
75
+ 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"]),
76
+ operation("tables.resource.views.list", `${table}/views`, "GET", "tables views list", "oxygen_tables_views_list", "tables", "List saved Table views and their complete display configuration.", {}, [], nativeCli),
77
+ operation("tables.resource.views.create", `${table}/views`, "POST", "tables views create", "oxygen_tables_views_create", "tables", "Create a saved Table view; group_by configures the same kanban grouping as the browser.", viewFields, ["name"], nativeCli),
78
+ operation("tables.resource.views.edit", `${table}/views/{view}`, "PATCH", "tables views update", "oxygen_tables_views_update", "tables", "Edit a saved view's name, type, configuration, grouping, order or default status.", viewFields, [], nativeCli),
79
+ operation("tables.resource.views.delete", `${table}/views/{view}`, "DELETE", "tables views delete", "oxygen_tables_views_delete", "tables", "Delete one saved Table view.", {}, [], nativeCli),
80
+ operation("tables.resource.runs.list", `${table}/runs`, "GET", "tables runs history", "oxygen_table_runs_history", "runs", "Read this Table's durable run history and progress.", { status: enumOf(["all", "active", "queued", "running", "paused", "completed", "completed_with_errors", "failed", "canceling", "canceled"]), limit: int({ minimum: 1 }) }),
81
+ operation("tables.resource.runs.start", `${table}/runs`, "POST", "tables runs start", "oxygen_table_resource_run_start", "runs", "Start selected Table actions using the browser's exact row-selection contract. Paid runs require an approved max_credits ceiling.", { actions, selection, max_credits: num({ minimum: 0 }), max_concurrency: int({ minimum: 1 }), force: bool(), approved: bool() }, ["actions"], { spends: true }),
82
+ operation("tables.resource.runs.estimate", `${table}/runs/estimate`, "POST", "tables runs preview", "oxygen_table_resource_run_preview", "runs", "Preview selected Table action costs and provider availability, including draft column definitions; starts no run.", { actions, selection }, ["actions"], { mutates: false }),
83
+ 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."),
84
+ 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."),
85
+ 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."),
86
+ operation("tables.resource.runs.retry", `${run}/retry-failed`, "POST", "tables runs retry", "oxygen_table_resource_run_retry", "runs", "Retry failed cells within a Table run's approved scope. Uncertain external effects require approved_effect_unknown=true.", { approved_effect_unknown: bool() }, [], { spends: true }),
87
+ 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."),
88
+ 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."),
89
+ 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."),
90
+ 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 }),
91
+ 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 }),
92
+ operation("billing.checkout", "/api/cli/billing/checkout", "POST", "billing checkout", "oxygen_billing_checkout", "billing", "Open the same hosted plan checkout as the browser; the returned URL carries the payment approval step.", { plan: text(), interval: enumOf(["month", "year"]), currency: text(), trial: bool(), return_to: text(), source: text(), blocked: text() }, ["plan"]),
93
+ operation("billing.portal", "/api/cli/billing/portal", "POST", "billing portal", "oxygen_billing_portal", "billing", "Create the workspace's authenticated Stripe billing-portal URL; requires workspace administrator authorization.", { returnUrl: text() }),
94
+ 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."),
95
+ 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"]),
96
+ 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."),
97
+ operation("integrations.default", "/api/cli/integrations/default", "POST", "integrations default", "oxygen_integration_default_set", "integrations", "Set the default active integration connection within this workspace.", { integration_id: text(), connection_id: text() }, ["integration_id", "connection_id"]),
98
+ operation("integrations.cloudflare", "/api/cli/integrations/cloudflare/connect", "POST", "integrations cloudflare-connect", "oxygen_cloudflare_connect", "integrations", "Verify a Cloudflare token, choose an account when required, and save the encrypted connection. account_id is optional for initial account discovery; no credential is returned.", { api_key: text(), account_id: text() }, ["api_key"]),
99
+ operation("integrations.github.start", "/api/cli/integrations/github/start", "POST", "integrations github-start", "oxygen_github_connection_start", "integrations", "Create the authenticated GitHub authorization URL for this workspace.", { return_to: text() }),
100
+ operation("integrations.hubspot.start", "/api/cli/integrations/hubspot/start", "POST", "integrations hubspot-start", "oxygen_hubspot_connection_start", "integrations", "Create the authenticated HubSpot authorization URL for this workspace.", { return_to: text() }),
101
+ operation("integrations.connection.test", "/api/cli/integrations/{integration}/test", "POST", "integrations connection-test", "oxygen_integration_connection_test", "integrations", "Test one workspace integration connection and save its health without changing its default or returning credentials.", { connection_id: text() }),
102
+ operation("workflows.resource.status", "/api/cli/workflows/{workflow}/status", "POST", "workflows status-set", "oxygen_workflow_resource_status_set", "workflows", "Enable or disable a Workflow and record an optional reason. Enabling paid recurring execution requires standing approval and max_credits; CRM-sync workflows use their paired lifecycle instead.", { status: enumOf(["active", "disabled"]), approved: bool(), max_credits: num({ minimum: 0 }), reason: str({ maxLength: 500 }) }, ["status"], { spends: true }),
103
+ operation("notetaker.desktop_upload", "/api/cli/notetaker/desktop-upload", "POST", "notetaker desktop-upload", "oxygen_notetaker_desktop_upload_prepare", "crm", "Prepare an approved desktop meeting recording and its scoped upload URL. Upload and completion remain separate steps.", { approved: bool(), title: text(), max_minutes: int({ minimum: 1 }), crm_links: crmLinks }, ["approved"]),
104
+ operation("notetaker.calendar.connect", "/api/cli/notetaker/calendar", "POST", "notetaker calendar connect", "oxygen_notetaker_calendar_connect", "crm", "Create the OAuth authorization URL for a Google Calendar or Outlook notetaker connection.", { integration_id: enumOf(["google_calendar", "outlook"]) }, ["integration_id"], { defaults: { action: "connect" } }),
105
+ operation("notetaker.calendar.sync", "/api/cli/notetaker/calendar", "POST", "notetaker calendar sync", "oxygen_notetaker_calendar_sync", "crm", "Synchronize upcoming Google Calendar or Outlook meeting events into this workspace's notetaker calendar.", { integration_id: enumOf(["google_calendar", "outlook"]), connection_id: text(), days_ahead: int({ minimum: 1 }) }, ["integration_id"], { defaults: { action: "sync" } }),
106
+ operation("notetaker.calendar.schedule", "/api/cli/notetaker/calendar", "POST", "notetaker calendar schedule", "oxygen_notetaker_calendar_schedule", "crm", "Schedule recording for an existing calendar event after approval; an external CLI or MCP caller must supply an explicit max_credits ceiling.", { event_id: text(), approved: bool(), max_credits: num({ minimum: 0 }) }, ["event_id", "approved"], { defaults: { action: "schedule" }, spends: true }),
107
+ operation("notetaker.note.edit", "/api/cli/notetaker/sessions/{session}/note", "PATCH", "notetaker notes edit", "oxygen_notetaker_note_edit", "crm", "Save the markdown note for one meeting session and return the committed note.", { markdown: text() }, ["markdown"]),
108
+ operation("orgs.create", "/api/cli/orgs/create", "POST", "orgs create", "oxygen_workspace_create", "workspace", "Create a workspace for the authenticated person's account and begin native company setup. Workspace API keys cannot create personal workspaces.", { name: text(), company_domain: text("Company website or domain, or its LinkedIn company page URL when it has no website."), linkedin_profile_url: text("Creator's LinkedIn profile URL, separate from the company's page.") }, ["name", "company_domain"]),
109
+ operation("onboarding.complete", "/api/cli/onboarding/complete", "POST", "onboarding complete", "oxygen_onboarding_complete", "workspace", "Complete the active workspace's onboarding step and record its discovery-source choices. The other choice requires source_other.", { sources: arr(enumOf(["linkedin_content", "linkedin_dm", "linkedin_ads", "youtube", "google", "email", "word_of_mouth", "referral", "event", "other"])), source_other: text(), redirect_url: text() }, ["sources"]),
110
+ ];
@@ -2,12 +2,14 @@
2
2
  * `PATCH /api/cli/connectors/{connection}`: the settings one connected app
3
3
  * (an MCP OAuth client such as ChatGPT, Claude or Codex) keeps for itself.
4
4
  *
5
- * Today that is its default workspace: the workspace the app works in without
6
- * asking. It is the same per-connection choice `oxygen_orgs_select` makes from
7
- * inside the app, so either surface changes one setting and the latest choice
8
- * wins. The contract is the extension point for later per-connection settings
9
- * (a per-connection credit ceiling is planned, OXP-11.5.23): add the field here
10
- * and the route, the CLI flags and the MCP tool follow.
5
+ * Its default workspace: the workspace the app works in without asking. It is
6
+ * the same per-connection choice `oxygen_orgs_select` makes from inside the
7
+ * app, so either surface changes one setting and the latest choice wins.
8
+ *
9
+ * Its credit ceiling (ADR 0030 §11, OXP-11.5.23): the most credits the app may
10
+ * spend in any rolling 24 hours while it holds MCP event subscriptions. null
11
+ * restores the plan default; a value above that default needs
12
+ * approve_above_default, the posture Agent run and trigger ceilings use.
11
13
  */
12
14
  import type { OperationSpec } from "./operations.js";
13
15
  import { type Infer } from "./schema.js";
@@ -16,8 +18,32 @@ export declare const CONNECTOR_UPDATE_CONTRACT: import("./schema.js").ContractOb
16
18
  oneOf: [import("./schema.js").StringProperty, import("./schema.js").NullProperty];
17
19
  description?: string;
18
20
  };
21
+ readonly credit_ceiling: {
22
+ oneOf: [{
23
+ type: "integer";
24
+ description?: string;
25
+ minimum?: number;
26
+ maximum?: number;
27
+ "x-clamp"?: true;
28
+ }, import("./schema.js").NullProperty];
29
+ description?: string;
30
+ };
31
+ readonly approve_above_default: import("./schema.js").BooleanProperty;
19
32
  }, never>;
20
33
  export type ConnectorUpdate = Infer<typeof CONNECTOR_UPDATE_CONTRACT>;
21
34
  /** The route's path value for "the app making this request". */
22
35
  export declare const CURRENT_CONNECTOR_REF = "current";
23
36
  export declare const CONNECTOR_UPDATE_OPERATION: OperationSpec<typeof CONNECTOR_UPDATE_CONTRACT>;
37
+ /**
38
+ * `POST /api/cli/connectors/{connection}/events/revoke`: stop one connected
39
+ * app's MCP event subscription, or every live one it holds (ADR 0030 §10;
40
+ * OXP-11.5.22). Destructive and lasting: the app cannot renew a subscription
41
+ * revoked here. The events/* protocol methods the app itself calls stay outside
42
+ * this contract; they are host-driven.
43
+ */
44
+ export declare const CONNECTOR_EVENTS_REVOKE_CONTRACT: import("./schema.js").ContractObject<{
45
+ readonly subscription: import("./schema.js").StringProperty;
46
+ readonly workspace: import("./schema.js").StringProperty;
47
+ }, "subscription">;
48
+ export type ConnectorEventsRevoke = Infer<typeof CONNECTOR_EVENTS_REVOKE_CONTRACT>;
49
+ export declare const CONNECTOR_EVENTS_REVOKE_OPERATION: OperationSpec<typeof CONNECTOR_EVENTS_REVOKE_CONTRACT>;
@@ -1,10 +1,19 @@
1
- import { nullable, obj, str } from "./schema.js";
1
+ import { AGENT_RUN_APPROVED_CEILING_MAX_CREDITS } from "../plan-limits.js";
2
+ import { bool, int, nullable, obj, str } from "./schema.js";
2
3
  export const CONNECTOR_UPDATE_CONTRACT = obj({
3
4
  default_workspace: nullable(str({
4
5
  minLength: 1,
5
6
  maxLength: 200,
6
7
  description: "Workspace id, slug or exact name (you must be a member). null = ask each time.",
7
8
  })),
9
+ credit_ceiling: nullable(int({
10
+ minimum: 0,
11
+ maximum: AGENT_RUN_APPROVED_CEILING_MAX_CREDITS,
12
+ description: "Most credits the app may spend in any 24 hours while it holds event subscriptions. null = the plan default.",
13
+ })),
14
+ approve_above_default: bool({
15
+ description: "Approve a credit_ceiling above the plan default.",
16
+ }),
8
17
  });
9
18
  const inferMatchesRoute = true;
10
19
  void inferMatchesRoute;
@@ -17,7 +26,7 @@ export const CONNECTOR_UPDATE_OPERATION = {
17
26
  contract: CONNECTOR_UPDATE_CONTRACT,
18
27
  cli: {
19
28
  path: ["connectors", "set"],
20
- summary: "Set the default workspace of one connected app (ChatGPT, Claude, Codex or another app connected to OXYGEN with OAuth), so that app works there without asking. Only that app changes; your other apps and this CLI keep their own workspace. It is the same setting the app changes when you pick a workspace inside it, so the latest choice wins. --clear-default-workspace makes the app ask again. Free; `connectors list` shows your apps and each one's current default.",
29
+ summary: "Change one connected app's settings (ChatGPT, Claude, Codex or another app connected to OXYGEN with OAuth); only that app changes. --default-workspace: where it works without asking (the same setting the app changes when you pick a workspace inside it; latest wins; --clear-default-workspace makes it ask again). --credit-ceiling: the most credits it may spend in any 24 hours while it holds event subscriptions (--clear-credit-ceiling restores the plan default; above the default also needs --approve-above-default). Free; `connectors list` shows each app's current settings.",
21
30
  argument: {
22
31
  name: "connection",
23
32
  description: "The app's id from `connectors list`, or its name (e.g. ChatGPT) when you have one app of that name.",
@@ -25,8 +34,51 @@ export const CONNECTOR_UPDATE_OPERATION = {
25
34
  },
26
35
  mcp: {
27
36
  name: "oxygen_connector_update",
28
- title: "Oxygen: Set Connected App Workspace",
29
- description: "Sets the default workspace of one connected app (ChatGPT, Claude, Codex…), leaving your other apps unchanged. Same setting as picking a workspace inside that app; latest wins. connection: id or name from oxygen_connector_list, or \"current\" for this app. Free.",
37
+ title: "Oxygen: Change Connected App Settings",
38
+ description: "Changes one connected app's settings (ChatGPT, Claude, Codex…), leaving your other apps unchanged: default_workspace (same setting as picking a workspace inside that app; latest wins) and credit_ceiling (most credits it may spend in 24 hours while it holds event subscriptions; above the plan default also needs approve_above_default). connection: id or name from oxygen_connector_list, or \"current\" for this app. Free.",
39
+ pack: "workspace",
40
+ },
41
+ mutates: true,
42
+ spends: false,
43
+ };
44
+ /**
45
+ * `POST /api/cli/connectors/{connection}/events/revoke`: stop one connected
46
+ * app's MCP event subscription, or every live one it holds (ADR 0030 §10;
47
+ * OXP-11.5.22). Destructive and lasting: the app cannot renew a subscription
48
+ * revoked here. The events/* protocol methods the app itself calls stay outside
49
+ * this contract; they are host-driven.
50
+ */
51
+ export const CONNECTOR_EVENTS_REVOKE_CONTRACT = obj({
52
+ subscription: str({
53
+ minLength: 1,
54
+ maxLength: 200,
55
+ description: "The subscription id from the app's event subscriptions, or \"all\" for every live one.",
56
+ }),
57
+ workspace: str({
58
+ minLength: 1,
59
+ maxLength: 200,
60
+ description: "Only in this workspace (id, slug or exact name). Omit for all your workspaces.",
61
+ }),
62
+ }, { required: ["subscription"] });
63
+ const revokeInferMatchesRoute = true;
64
+ void revokeInferMatchesRoute;
65
+ export const CONNECTOR_EVENTS_REVOKE_OPERATION = {
66
+ id: "connectors.events.revoke",
67
+ route: "/api/cli/connectors/{connection}/events/revoke",
68
+ method: "POST",
69
+ contract: CONNECTOR_EVENTS_REVOKE_CONTRACT,
70
+ cli: {
71
+ path: ["connectors", "events", "revoke"],
72
+ summary: "Stop OXYGEN sending events to one connected app: revoke one of its event subscriptions (--subscription <id>) or every live one (--subscription all), optionally only in one --workspace. Lasting: the app cannot renew a subscription revoked here, and nothing else about the app changes. Free; `connectors events get <app>` shows what it is subscribed to first.",
73
+ argument: {
74
+ name: "connection",
75
+ description: "The app's id from `connectors list`, or its name (e.g. ChatGPT) when you have one app of that name.",
76
+ },
77
+ },
78
+ mcp: {
79
+ name: "oxygen_connector_events_revoke",
80
+ title: "Oxygen: Revoke Connected App Event Subscriptions",
81
+ description: "Destructive: stops OXYGEN sending events to one connected app (ChatGPT…) by revoking one event subscription, or \"all\" of its live ones, optionally in one workspace. The app cannot renew a revoked subscription; nothing else about it changes. Read first with oxygen_connector_events_get. Free.",
30
82
  pack: "workspace",
31
83
  },
32
84
  mutates: true,
@@ -0,0 +1,4 @@
1
+ import type { ObjectProperty } from "./schema.js";
2
+ /** Custom CRM column writes accept both canonical snake_case and legacy aliases. */
3
+ export declare const CRM_CUSTOM_COLUMN_SCHEMA: ObjectProperty;
4
+ export declare const CRM_CUSTOM_IDENTITY_SCHEMA: ObjectProperty;
@@ -0,0 +1,39 @@
1
+ /** Custom CRM column writes accept both canonical snake_case and legacy aliases. */
2
+ export const CRM_CUSTOM_COLUMN_SCHEMA = {
3
+ type: "object",
4
+ properties: {
5
+ key: { type: "string" }, label: { type: "string" },
6
+ data_type: { type: "string", enum: ["text", "numeric", "boolean", "jsonb", "timestamptz"] },
7
+ dataType: { type: "string", enum: ["text", "numeric", "boolean", "jsonb", "timestamptz"] },
8
+ semantic_type: { type: "string" }, semanticType: { type: "string" },
9
+ kind: { type: "string" }, attribute_kind: { type: "string" }, attributeKind: { type: "string" },
10
+ option_model_type: { type: "string" }, optionModelType: { type: "string" },
11
+ is_required: { type: "boolean" }, isRequired: { type: "boolean" },
12
+ is_unique: { type: "boolean" }, isUnique: { type: "boolean" },
13
+ is_multivalue: { type: "boolean" }, isMultivalue: { type: "boolean" },
14
+ is_record_label: { type: "boolean" }, isRecordLabel: { type: "boolean" },
15
+ is_record_image: { type: "boolean" }, isRecordImage: { type: "boolean" },
16
+ kanban_candidate: { type: "boolean" }, kanbanCandidate: { type: "boolean" },
17
+ display_order: { type: "number" }, displayOrder: { type: "number" },
18
+ options: { type: "array", items: { type: "object", additionalProperties: true } },
19
+ definition: { type: "object", additionalProperties: true },
20
+ attribute_metadata: { type: "object", additionalProperties: true },
21
+ attributeMetadata: { type: "object", additionalProperties: true },
22
+ },
23
+ required: ["key", "label"],
24
+ additionalProperties: false,
25
+ };
26
+ export const CRM_CUSTOM_IDENTITY_SCHEMA = {
27
+ type: "object",
28
+ properties: {
29
+ column_key: { type: "string" }, columnKey: { type: "string" },
30
+ normalization: { type: "string", enum: ["email_v1", "domain_v1", "linkedin_url_v1", "exact_text_v1", "uuid_v1"] },
31
+ slug: { type: "string" }, display_name: { type: "string" }, displayName: { type: "string" },
32
+ identity_type: { type: "string" }, identityType: { type: "string" },
33
+ is_primary: { type: "boolean" }, isPrimary: { type: "boolean" },
34
+ is_required_for_assert: { type: "boolean" }, isRequiredForAssert: { type: "boolean" },
35
+ priority: { type: "number" },
36
+ },
37
+ required: ["normalization"],
38
+ additionalProperties: false,
39
+ };
@@ -0,0 +1,21 @@
1
+ /** Read selectors only; action=backfill is a separate governed operation. */
2
+ export declare const CRM_ENRICHMENT_READ_CONTRACT: import("./schema.js").ContractObject<{
3
+ readonly object: import("./schema.js").StringProperty;
4
+ readonly backfill: import("./schema.js").BooleanProperty;
5
+ readonly projection: {
6
+ type: "string";
7
+ enum: readonly ("full" | "summary" | "value")[];
8
+ description?: string;
9
+ };
10
+ readonly path: import("./schema.js").StringProperty;
11
+ readonly cursor: import("./schema.js").StringProperty;
12
+ readonly max_chars: {
13
+ type: "integer";
14
+ description?: string;
15
+ minimum?: number;
16
+ maximum?: number;
17
+ "x-clamp"?: true;
18
+ };
19
+ }, never>;
20
+ /** Preserve the shipped HTTP literals, including whitespace/case and 0. */
21
+ export declare function includeCrmEnrichmentBackfillCounts(value: string | null): boolean;
@@ -0,0 +1,15 @@
1
+ import { bool, enumOf, int, obj, str } from "./schema.js";
2
+ /** Read selectors only; action=backfill is a separate governed operation. */
3
+ export const CRM_ENRICHMENT_READ_CONTRACT = obj({
4
+ object: str({ minLength: 1, maxLength: 120, description: "CRM object slug (companies, people, deals)." }),
5
+ backfill: bool({ description: "list without object: include stored historical backlog counts (default true). false skips the scans; object reads ignore it. Never runs enrichment." }),
6
+ projection: enumOf(["summary", "full", "value"], { description: "summary: standing configuration without long arrays. full: legacy data. value: lossless JSON of path, continued with next_cursor. Omit for legacy output." }),
7
+ path: str({ maxLength: 1024, description: "value: JSON Pointer into the selected native result; empty selects everything. Examples /objects/0/auto_run or /presets." }),
8
+ cursor: str({ minLength: 1, maxLength: 2000, description: "value: previous next_cursor with unchanged object, backfill, path and projection. Refuses changed source." }),
9
+ max_chars: int({ minimum: 1000, maximum: 40000, description: "Opt-in complete receipt window. MCP caps external at 10000 and built-in at 4000. Use value to recover oversized fields." }),
10
+ });
11
+ /** Preserve the shipped HTTP literals, including whitespace/case and 0. */
12
+ export function includeCrmEnrichmentBackfillCounts(value) {
13
+ const normalized = value?.trim().toLowerCase();
14
+ return normalized !== "0" && normalized !== "false";
15
+ }
@@ -0,0 +1,117 @@
1
+ export declare const CRM_NOTE_BODY_MAX_CHARS = 20000;
2
+ export declare const CRM_NOTE_TITLE_MAX_CHARS = 300;
3
+ export declare const CRM_FILE_LABEL_MAX_CHARS = 300;
4
+ export declare const CRM_NOTE_EDIT_CONTRACT: import("./schema.js").ContractObject<{
5
+ readonly body: import("./schema.js").StringProperty;
6
+ readonly title: {
7
+ oneOf: [import("./schema.js").StringProperty, import("./schema.js").NullProperty];
8
+ description?: string;
9
+ };
10
+ readonly pinned: import("./schema.js").BooleanProperty;
11
+ }, never>;
12
+ export declare const CRM_FILE_ATTACH_CONTRACT: import("./schema.js").ContractObject<{
13
+ readonly name: import("./schema.js").StringProperty;
14
+ readonly content_base64: import("./schema.js").StringProperty;
15
+ readonly label: {
16
+ oneOf: [import("./schema.js").StringProperty, import("./schema.js").NullProperty];
17
+ description?: string;
18
+ };
19
+ }, "content_base64" | "name">;
20
+ export declare const CRM_FILE_PREPARE_CONTRACT: import("./schema.js").ContractObject<{
21
+ readonly name: import("./schema.js").StringProperty;
22
+ readonly byte_length: {
23
+ type: "integer";
24
+ description?: string;
25
+ minimum?: number;
26
+ maximum?: number;
27
+ "x-clamp"?: true;
28
+ };
29
+ readonly sha256: import("./schema.js").StringProperty;
30
+ }, "byte_length" | "name" | "sha256">;
31
+ export declare const CRM_FILE_COMPLETE_CONTRACT: import("./schema.js").ContractObject<{
32
+ readonly label: {
33
+ oneOf: [import("./schema.js").StringProperty, import("./schema.js").NullProperty];
34
+ description?: string;
35
+ };
36
+ }, never>;
37
+ export declare const CRM_PHOTOS_CONTRACT: import("./schema.js").ContractObject<{
38
+ readonly mode: {
39
+ type: "string";
40
+ enum: readonly ("dry_run" | "live")[];
41
+ description?: string;
42
+ };
43
+ readonly live: import("./schema.js").BooleanProperty;
44
+ readonly limit: {
45
+ type: "integer";
46
+ description?: string;
47
+ minimum?: number;
48
+ maximum?: number;
49
+ "x-clamp"?: true;
50
+ };
51
+ }, never>;
52
+ export declare const CRM_OBJECTS_QUERY_CONTRACT: import("./schema.js").ContractObject<{
53
+ readonly projection: {
54
+ type: "string";
55
+ enum: readonly ("compact" | "full")[];
56
+ description?: string;
57
+ };
58
+ readonly cursor: import("./schema.js").StringProperty;
59
+ readonly limit: {
60
+ type: "integer";
61
+ description?: string;
62
+ minimum?: number;
63
+ maximum?: number;
64
+ "x-clamp"?: true;
65
+ };
66
+ readonly max_chars: {
67
+ type: "integer";
68
+ description?: string;
69
+ minimum?: number;
70
+ maximum?: number;
71
+ "x-clamp"?: true;
72
+ };
73
+ }, never>;
74
+ export declare const CRM_CONNECTIONS_QUERY_CONTRACT: import("./schema.js").ContractObject<{
75
+ readonly projection: {
76
+ type: "string";
77
+ enum: readonly ("compact" | "full")[];
78
+ description?: string;
79
+ };
80
+ readonly max_chars: {
81
+ type: "integer";
82
+ description?: string;
83
+ minimum?: number;
84
+ maximum?: number;
85
+ "x-clamp"?: true;
86
+ };
87
+ readonly conversation_limit: {
88
+ type: "integer";
89
+ description?: string;
90
+ minimum?: number;
91
+ maximum?: number;
92
+ "x-clamp"?: true;
93
+ };
94
+ readonly sequence_limit: {
95
+ type: "integer";
96
+ description?: string;
97
+ minimum?: number;
98
+ maximum?: number;
99
+ "x-clamp"?: true;
100
+ };
101
+ }, never>;
102
+ export declare const CRM_TASKS_QUERY_CONTRACT: import("./schema.js").ContractObject<{
103
+ readonly status: {
104
+ type: "string";
105
+ enum: readonly ("all" | "cancelled" | "completed" | "open")[];
106
+ description?: string;
107
+ };
108
+ readonly assignee: import("./schema.js").StringProperty;
109
+ readonly limit: {
110
+ type: "integer";
111
+ description?: string;
112
+ minimum?: number;
113
+ maximum?: number;
114
+ "x-clamp"?: true;
115
+ };
116
+ readonly cursor: import("./schema.js").StringProperty;
117
+ }, never>;
@@ -0,0 +1,43 @@
1
+ import { bool, enumOf, int, nullable, obj, str } from "./schema.js";
2
+ export const CRM_NOTE_BODY_MAX_CHARS = 20_000;
3
+ export const CRM_NOTE_TITLE_MAX_CHARS = 300;
4
+ export const CRM_FILE_LABEL_MAX_CHARS = 300;
5
+ export const CRM_NOTE_EDIT_CONTRACT = obj({
6
+ body: str({ minLength: 1, maxLength: CRM_NOTE_BODY_MAX_CHARS, description: "Replacement Markdown text." }),
7
+ title: nullable(str({ maxLength: CRM_NOTE_TITLE_MAX_CHARS, description: "Replacement title; null or empty clears." })),
8
+ pinned: bool({ description: "Whether the note is pinned; false unpins." }),
9
+ });
10
+ export const CRM_FILE_ATTACH_CONTRACT = obj({
11
+ name: str({ minLength: 1, description: "Original filename." }),
12
+ content_base64: str({ minLength: 1, description: "Inline bytes; entire JSON request must fit 2 MB. Larger files use upload prepare/complete." }),
13
+ label: nullable(str({ maxLength: CRM_FILE_LABEL_MAX_CHARS, description: "Optional record-local label." })),
14
+ }, { required: ["name", "content_base64"] });
15
+ export const CRM_FILE_PREPARE_CONTRACT = obj({
16
+ name: str({ minLength: 1, description: "Original filename." }),
17
+ byte_length: int({ minimum: 0, maximum: 100 * 1024 * 1024, description: "Exact byte length; maximum 100 MiB." }),
18
+ sha256: str({ minLength: 64, maxLength: 64, description: "Hex SHA-256 of the exact bytes to PUT." }),
19
+ }, { required: ["name", "byte_length", "sha256"] });
20
+ export const CRM_FILE_COMPLETE_CONTRACT = obj({ label: nullable(str({ maxLength: CRM_FILE_LABEL_MAX_CHARS, description: "Optional record-local label." })) });
21
+ export const CRM_PHOTOS_CONTRACT = obj({
22
+ mode: enumOf(["dry_run", "live"], { description: "Default dry_run. Inspect preview before live." }),
23
+ live: bool({ description: "Shortcut for mode=live; conflicts with mode=dry_run." }),
24
+ limit: int({ minimum: 1, maximum: 10_000, description: "Rows scanned; default 2000." }),
25
+ });
26
+ export const CRM_OBJECTS_QUERY_CONTRACT = obj({
27
+ projection: enumOf(["compact", "full"], { description: "compact lists names and table/identity bindings; full includes all field configuration. HTTP default full." }),
28
+ cursor: str({ maxLength: 2000, description: "Previous next_cursor; bound to projection." }),
29
+ limit: int({ minimum: 1, maximum: 100, description: "Objects in one batch; default 20 for bounded reads." }),
30
+ max_chars: int({ minimum: 2000, maximum: 40_000, description: "Complete response window; oversized objects refuse without advancing." }),
31
+ });
32
+ export const CRM_CONNECTIONS_QUERY_CONTRACT = obj({
33
+ projection: enumOf(["compact", "full"], { description: "Compact returns identifiers and short communication previews. HTTP default full." }),
34
+ max_chars: int({ minimum: 2000, maximum: 40_000, description: "Complete recent-window response; hasMore includes omitted links." }),
35
+ conversation_limit: int({ minimum: 1, maximum: 100, description: "Most recent conversation links; server maximum 100." }),
36
+ sequence_limit: int({ minimum: 1, maximum: 100, description: "Most recent sequence links; server maximum 100." }),
37
+ });
38
+ export const CRM_TASKS_QUERY_CONTRACT = obj({
39
+ status: enumOf(["open", "completed", "cancelled", "all"], { description: "Workspace default open; record default all. all omits the API filter." }),
40
+ assignee: str({ description: "Workspace scope only: member email, user id, or me." }),
41
+ limit: int({ minimum: 1, maximum: 200, description: "Maximum tasks; default 50." }),
42
+ cursor: str({ minLength: 1, maxLength: 500, description: "Previous nextCursor." }),
43
+ });
@@ -0,0 +1,2 @@
1
+ import type { OperationSpec } from "./operations.js";
2
+ export declare const CUSTOMER_OPERATIONS: readonly OperationSpec[];