@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.
- package/README.md +1 -1
- package/dist/command-manifest.js +15 -4
- package/dist/connectors-commands.d.ts +4 -1
- package/dist/connectors-commands.js +84 -10
- package/dist/contract-flags.d.ts +2 -0
- package/dist/contract-flags.js +26 -11
- package/dist/crm-support-flags.d.ts +11 -0
- package/dist/crm-support-flags.js +60 -0
- package/dist/customer-operation-commands.d.ts +5 -0
- package/dist/customer-operation-commands.js +101 -0
- package/dist/database-query-flags.d.ts +2 -0
- package/dist/database-query-flags.js +6 -0
- package/dist/help.d.ts +3 -1
- package/dist/help.js +43 -0
- package/dist/http-client.d.ts +2 -0
- package/dist/http-client.js +41 -1
- package/dist/index.js +640 -234
- package/dist/knowledge-repository-commands.js +12 -14
- package/dist/mailbox-ramp-notice.d.ts +11 -0
- package/dist/mailbox-ramp-notice.js +53 -0
- package/dist/settings-commands.d.ts +11 -0
- package/dist/settings-commands.js +73 -0
- package/dist/skills.d.ts +5 -4
- package/dist/skills.js +106 -79
- package/dist/tool-catalog-detail-command.d.ts +7 -0
- package/dist/tool-catalog-detail-command.js +19 -0
- package/dist/tool-catalog-search-window.d.ts +6 -0
- package/dist/tool-catalog-search-window.js +12 -0
- package/dist/transcript.js +1 -0
- package/node_modules/@oxygen/shared/dist/bounded-read-result.d.ts +4 -0
- package/node_modules/@oxygen/shared/dist/bounded-read-result.js +25 -0
- package/node_modules/@oxygen/shared/dist/capability-discovery.d.ts +47 -1
- package/node_modules/@oxygen/shared/dist/capability-discovery.js +625 -39
- package/node_modules/@oxygen/shared/dist/connection-approval.d.ts +2 -0
- package/node_modules/@oxygen/shared/dist/connection-approval.js +2 -0
- package/node_modules/@oxygen/shared/dist/contracts/browser-operations.d.ts +2 -0
- package/node_modules/@oxygen/shared/dist/contracts/browser-operations.js +110 -0
- package/node_modules/@oxygen/shared/dist/contracts/connectors.d.ts +32 -6
- package/node_modules/@oxygen/shared/dist/contracts/connectors.js +56 -4
- package/node_modules/@oxygen/shared/dist/contracts/crm-attributes.d.ts +4 -0
- package/node_modules/@oxygen/shared/dist/contracts/crm-attributes.js +39 -0
- package/node_modules/@oxygen/shared/dist/contracts/crm-enrichment-read.d.ts +21 -0
- package/node_modules/@oxygen/shared/dist/contracts/crm-enrichment-read.js +15 -0
- package/node_modules/@oxygen/shared/dist/contracts/crm-support.d.ts +117 -0
- package/node_modules/@oxygen/shared/dist/contracts/crm-support.js +43 -0
- package/node_modules/@oxygen/shared/dist/contracts/customer-operations.d.ts +2 -0
- package/node_modules/@oxygen/shared/dist/contracts/customer-operations.js +131 -0
- package/node_modules/@oxygen/shared/dist/contracts/dashboard-tabs.d.ts +3 -0
- package/node_modules/@oxygen/shared/dist/contracts/dashboard-tabs.js +2 -0
- package/node_modules/@oxygen/shared/dist/contracts/database.d.ts +30 -0
- package/node_modules/@oxygen/shared/dist/contracts/database.js +29 -0
- package/node_modules/@oxygen/shared/dist/contracts/integration-connect.d.ts +4 -0
- package/node_modules/@oxygen/shared/dist/contracts/integration-connect.js +7 -0
- package/node_modules/@oxygen/shared/dist/contracts/knowledge-content-reads.d.ts +43 -0
- package/node_modules/@oxygen/shared/dist/contracts/knowledge-content-reads.js +20 -0
- package/node_modules/@oxygen/shared/dist/contracts/linkedin-invites-list.d.ts +12 -0
- package/node_modules/@oxygen/shared/dist/contracts/linkedin-invites-list.js +8 -0
- package/node_modules/@oxygen/shared/dist/contracts/operations.d.ts +48 -2
- package/node_modules/@oxygen/shared/dist/contracts/operations.js +68 -2
- package/node_modules/@oxygen/shared/dist/contracts/table-grid-query.d.ts +4 -0
- package/node_modules/@oxygen/shared/dist/contracts/table-grid-query.js +6 -0
- package/node_modules/@oxygen/shared/dist/contracts/table-query-grid.d.ts +21 -0
- package/node_modules/@oxygen/shared/dist/contracts/table-query-grid.js +27 -0
- package/node_modules/@oxygen/shared/dist/contracts/tool-catalog-detail.d.ts +19 -0
- package/node_modules/@oxygen/shared/dist/contracts/tool-catalog-detail.js +10 -0
- package/node_modules/@oxygen/shared/dist/contracts/tool-catalog-search-window.d.ts +12 -0
- package/node_modules/@oxygen/shared/dist/contracts/tool-catalog-search-window.js +7 -0
- package/node_modules/@oxygen/shared/dist/contracts/workspace-pages.d.ts +17 -0
- package/node_modules/@oxygen/shared/dist/contracts/workspace-pages.js +49 -0
- package/node_modules/@oxygen/shared/dist/decision-ledger-parser.d.ts +32 -0
- package/node_modules/@oxygen/shared/dist/decision-ledger-parser.js +303 -0
- package/node_modules/@oxygen/shared/dist/decision-ledger.d.ts +10 -0
- package/node_modules/@oxygen/shared/dist/decision-ledger.generated.d.ts +2 -0
- package/node_modules/@oxygen/shared/dist/decision-ledger.generated.js +717 -0
- package/node_modules/@oxygen/shared/dist/decision-ledger.js +20 -0
- package/node_modules/@oxygen/shared/dist/email-campaign-ramp.d.ts +104 -0
- package/node_modules/@oxygen/shared/dist/email-campaign-ramp.js +250 -0
- package/node_modules/@oxygen/shared/dist/mcp-event-contract.d.ts +10 -7
- package/node_modules/@oxygen/shared/dist/mcp-event-contract.js +11 -7
- package/node_modules/@oxygen/shared/dist/mcp-table-widget.d.ts +50 -0
- package/node_modules/@oxygen/shared/dist/mcp-table-widget.js +24 -0
- package/node_modules/@oxygen/shared/dist/plan-band.d.ts +8 -0
- package/node_modules/@oxygen/shared/dist/plan-band.js +12 -0
- package/node_modules/@oxygen/shared/dist/plan-limits.d.ts +20 -0
- package/node_modules/@oxygen/shared/dist/plan-limits.js +41 -0
- package/node_modules/@oxygen/shared/dist/provider-input-value.d.ts +5 -0
- package/node_modules/@oxygen/shared/dist/provider-input-value.js +10 -0
- package/node_modules/@oxygen/shared/dist/sequences.d.ts +33 -4
- package/node_modules/@oxygen/shared/dist/sequences.js +48 -13
- package/node_modules/@oxygen/shared/dist/user-capability-routing.js +17 -0
- package/node_modules/@oxygen/shared/dist/version.generated.d.ts +1 -1
- package/node_modules/@oxygen/shared/dist/version.generated.js +1 -1
- package/node_modules/@oxygen/shared/package.json +8 -6
- package/package.json +1 -1
- package/node_modules/@oxygen/shared/dist/copilot-skills.d.ts +0 -15
- package/node_modules/@oxygen/shared/dist/copilot-skills.generated.d.ts +0 -31
- package/node_modules/@oxygen/shared/dist/copilot-skills.generated.js +0 -41
- package/node_modules/@oxygen/shared/dist/copilot-skills.js +0 -6
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/** Customer operations missing from one execution surface, with one field contract. */
|
|
2
|
+
import { arr, bool, enumOf, int, nullable, num, obj, str } from "./schema.js";
|
|
3
|
+
import { DATABASE_ATTACH_CONTRACT, DATABASE_MIGRATE_CONTRACT, DATABASE_QUERY_CONTRACT } from "./database.js";
|
|
4
|
+
const text = (description) => str(description === undefined ? {} : { description });
|
|
5
|
+
const list = () => arr(str());
|
|
6
|
+
const json = { type: "object", additionalProperties: true };
|
|
7
|
+
const rows = () => arr(json);
|
|
8
|
+
function operation(id, route, method, cli, mcp, pack, summary, fields = {}, required = [], options = {}) {
|
|
9
|
+
const { annotations, ...behavior } = options;
|
|
10
|
+
const parameters = [...route.matchAll(/\{(\w+)\}/g)].map((match) => match[1]);
|
|
11
|
+
return {
|
|
12
|
+
id, route, method, parameters,
|
|
13
|
+
contract: obj(fields, { required }),
|
|
14
|
+
cli: { path: cli.split(" "), summary },
|
|
15
|
+
mcp: { name: mcp, title: `Oxygen: ${cli}`, description: summary, pack, ...(annotations ? { annotations } : {}) },
|
|
16
|
+
mutates: method !== "GET", spends: false, ...behavior,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
const mcpOnly = { generated: { cli: false, mcp: true } };
|
|
20
|
+
const cliOnly = { generated: { cli: true, mcp: false } };
|
|
21
|
+
export const CUSTOMER_OPERATIONS = [
|
|
22
|
+
operation("activation.state", "/api/cli/activation/state", "GET", "activation state", "oxygen_activation_state", "workspace", "Read this workspace's onboarding activation state and next available actions.", {}, [], mcpOnly),
|
|
23
|
+
operation("api_keys.list", "/api/cli/api-keys", "GET", "api-keys list", "oxygen_api_keys_list", "workspace", "List workspace API keys without revealing their tokens.", {}, [], mcpOnly),
|
|
24
|
+
operation("api_keys.create", "/api/cli/api-keys", "POST", "api-keys create", "oxygen_api_keys_create", "workspace", "Create a workspace API key; requires the caller's personal user session. The token is returned once.", { name: text(), expires_at: text("ISO timestamp; omit for no expiry.") }, [], mcpOnly),
|
|
25
|
+
operation("api_keys.revoke", "/api/cli/api-keys/{key_id}", "DELETE", "api-keys revoke", "oxygen_api_keys_revoke", "workspace", "Revoke a workspace API key; requires the caller's personal user session.", {}, [], mcpOnly),
|
|
26
|
+
operation("comments.edit", "/api/cli/collab/comments/{comment_id}", "PATCH", "comments edit", "oxygen_comments_edit", "collaboration", "Edit your own internal workspace comment; records the edit time.", { body: text() }, ["body"], mcpOnly),
|
|
27
|
+
operation("comments.delete", "/api/cli/collab/comments/{comment_id}", "DELETE", "comments delete", "oxygen_comments_delete", "collaboration", "Retract your own internal workspace comment while retaining its audit trail.", {}, [], mcpOnly),
|
|
28
|
+
operation("approvals.cancel", "/api/cli/collab/requests/{request_id}/cancel", "POST", "approvals cancel", "oxygen_approvals_cancel", "collaboration", "Withdraw an approval request you created; grants no approval.", { note: text() }, [], mcpOnly),
|
|
29
|
+
operation("members.client_role", "/api/cli/collab/members/role", "POST", "approvals client grant", "oxygen_members_client_role_set", "collaboration", "Set or clear a member's restricted client role; workspace admin only.", { email: text(), role: nullable(enumOf(["client"])) }, ["email", "role"], mcpOnly),
|
|
30
|
+
operation("members.workspace_role", "/api/cli/collab/members/workspace-role", "POST", "orgs member-role", "oxygen_members_workspace_role_set", "collaboration", "Change a member's workspace role; admin only and the last administrator is protected.", { email: text(), role: enumOf(["admin", "member"]) }, ["email", "role"], mcpOnly),
|
|
31
|
+
operation("copilot.sessions.list", "/api/cli/copilot/sessions", "GET", "copilot list", "oxygen_copilot_sessions_list", "agents", "List attended Copilot sessions in this workspace.", { status: text(), limit: int({ minimum: 1 }) }, [], mcpOnly),
|
|
32
|
+
operation("copilot.sessions.update", "/api/cli/copilot/sessions/{session_id}", "PATCH", "copilot policy set", "oxygen_copilot_session_update", "agents", "Set an attended Copilot session's approval and screen-follow policies. Paid auto-approval is explicit standing authorization.", { auto_approve_policy: enumOf(["off", "paid"]), surface_policy: enumOf(["off", "follow"]) }, [], { spends: true }),
|
|
33
|
+
operation("copilot.attachments.list", "/api/cli/copilot/sessions/{session_id}/attachments", "GET", "copilot attachments list", "oxygen_copilot_attachments_list", "agents", "List sent and unsent attachments in one Copilot session.", {}, []),
|
|
34
|
+
operation("copilot.attachments.prepare", "/api/cli/copilot/sessions/{session_id}/attachments", "POST", "copilot attachments prepare", "oxygen_copilot_attachment_prepare", "agents", "Reserve a Copilot attachment and return its scoped upload URL; complete only after uploading the exact bytes.", { file_name: text(), content_type: text(), content_length: int({ minimum: 1 }) }, ["file_name", "content_length"]),
|
|
35
|
+
operation("copilot.attachments.complete", "/api/cli/copilot/sessions/{session_id}/attachments/{attachment_id}/complete", "POST", "copilot attachments complete", "oxygen_copilot_attachment_complete", "agents", "Verify and describe an uploaded Copilot attachment in its session.", {}, []),
|
|
36
|
+
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."),
|
|
37
|
+
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"]),
|
|
38
|
+
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),
|
|
39
|
+
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 }),
|
|
40
|
+
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),
|
|
41
|
+
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),
|
|
42
|
+
operation("crm.files.attach_inline", "/api/cli/crm/objects/{object}/records/{row_id}/files", "POST", "crm files attach-inline", "oxygen_crm_file_attach", "crm", "Attach base64 file bytes to one CRM record. For larger files use prepare-upload and complete-upload.", { name: text(), content_base64: text(), label: text() }, ["name", "content_base64"]),
|
|
43
|
+
operation("crm.files.prepare", "/api/cli/crm/objects/{object}/records/{row_id}/files/upload-url", "POST", "crm files prepare-upload", "oxygen_crm_file_prepare_upload", "crm", "Reserve a CRM file upload by exact name, length and SHA-256; returns a scoped upload URL.", { name: text(), byte_length: int({ minimum: 0 }), sha256: text() }, ["name", "byte_length", "sha256"]),
|
|
44
|
+
operation("crm.files.complete", "/api/cli/crm/objects/{object}/records/{row_id}/files/{file_id}/uploaded", "POST", "crm files complete-upload", "oxygen_crm_file_complete_upload", "crm", "Verify a reserved CRM upload and attach it to its record; mismatched bytes remain pending.", { label: text() }),
|
|
45
|
+
operation("crm.files.delete", "/api/cli/crm/files/{attachment_id}", "DELETE", "crm files detach", "oxygen_crm_file_delete", "crm", "Detach a CRM attachment by attachment_id, preserving the stored file.", {}, [], mcpOnly),
|
|
46
|
+
operation("crm.photos", "/api/cli/crm/photos", "POST", "crm photos", "oxygen_crm_photos_backfill", "crm", "Preview or fill people photos from data this workspace already holds. Free; mode defaults to dry_run.", { mode: enumOf(["dry_run", "live"]), limit: int({ minimum: 1, maximum: 10000 }) }, [], mcpOnly),
|
|
47
|
+
operation("dashboards.tabs.create", "/api/cli/dashboards/{dashboard_id}/tabs", "POST", "dashboards tabs add", "oxygen_dashboard_tab_create", "signals", "Create a named tab in a workspace dashboard.", { title: text() }, ["title"], mcpOnly),
|
|
48
|
+
operation("dashboards.tabs.delete", "/api/cli/dashboards/{dashboard_id}/tabs", "DELETE", "dashboards tabs remove", "oxygen_dashboard_tab_delete", "signals", "Remove one dashboard tab by its id.", { tab: text() }, ["tab"], { ...mcpOnly, queryFields: ["tab"] }),
|
|
49
|
+
operation("integrations.custom.connect", "/api/cli/custom-integrations/connect", "POST", "custom-integrations connect", "oxygen_custom_integration_connect", "integrations", "Store an encrypted API key for an applied custom HTTP integration; the secret is never returned.", { slug: text(), api_key: text() }, ["slug", "api_key"], mcpOnly),
|
|
50
|
+
operation("integrations.connections", "/api/cli/integrations/connections", "GET", "integrations connections", "oxygen_integrations_connections", "integrations", "List this workspace's stored integration connections and health without credentials.", { integration_id: text() }),
|
|
51
|
+
operation("db.attach", "/api/cli/db/attach", "POST", "db attach", "oxygen_database_attach", "workspace", "Attach an owned PostgreSQL database and initialize this workspace's schema/roles immediately. Changes the workspace database; no preview or confirmation field. Native workspace write access applies. Use Supabase import tools for external Tables. 0 credits.", {}, [], { ...mcpOnly, contract: DATABASE_ATTACH_CONTRACT, annotations: { destructiveHint: true, openWorldHint: true } }),
|
|
52
|
+
operation("db.migrate", "/api/cli/db/migrate", "POST", "db migrate", "oxygen_database_migrate", "workspace", "Apply pending workspace database migrations immediately; optionally repair runtime/read passwords. Read oxygen_workspace_database_status first. No preview or confirmation field; native workspace write access applies. Fleet repair remains separate. 0 credits.", {}, [], { ...mcpOnly, contract: DATABASE_MIGRATE_CONTRACT, annotations: { destructiveHint: true } }),
|
|
53
|
+
operation("db.query", "/api/cli/db/query", "POST", "db query", "oxygen_database_query", "workspace", "Read this workspace's database with one bounded SQL statement. Complete rows, default 20, maximum 1000; writes refused. On truncation, narrow SELECT/WHERE or use your own stable ORDER BY/keyset predicate; no server cursor. 0 credits.", {}, [], { contract: DATABASE_QUERY_CONTRACT, generated: { cli: false, mcp: false }, mutates: false }),
|
|
54
|
+
operation("db.cost_policy.reconcile", "/api/cli/db/reconcile-cost-policy", "POST", "db reconcile-cost-policy", "oxygen_database_cost_policy_reconcile", "workspace", "Retired Neon compatibility action: reports applied=false with no operations; does not suspend PostgreSQL. Native workspace write access applies; no preview or confirmation field. 0 credits.", { suspend_idle: bool() }, [], mcpOnly),
|
|
55
|
+
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),
|
|
56
|
+
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" } }),
|
|
57
|
+
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),
|
|
58
|
+
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),
|
|
59
|
+
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 }),
|
|
60
|
+
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 }),
|
|
61
|
+
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),
|
|
62
|
+
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),
|
|
63
|
+
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"] }),
|
|
64
|
+
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),
|
|
65
|
+
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 }),
|
|
66
|
+
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),
|
|
67
|
+
operation("mailboxes.warmup_profiles.set", "/api/cli/mailboxes/warmup-profile", "POST", "mailboxes warmup profile", "oxygen_mailboxes_warmup_profile_set", "deliverability", "Preview or apply an OXYGEN Warm-up profile to exact mailboxes or domains; approved=true applies the reviewed scope.", { profile: { oneOf: [text(), json, { type: "null" }] }, budget: nullable(json), domains: list(), mailboxes: list(), all: bool(), approved: bool() }, [], mcpOnly),
|
|
68
|
+
operation("managed_inboxes.avatars.prepare", "/api/cli/managed-inboxes/avatars", "POST", "managed-inboxes avatars prepare", "oxygen_managed_inbox_avatar_prepare", "deliverability", "Prepare a scoped mailbox profile-picture upload; confirm the stored bytes before using its URL.", { content_type: enumOf(["image/png", "image/jpeg", "image/webp"]), content_length: int({ minimum: 1 }) }, ["content_length"]),
|
|
69
|
+
operation("managed_inboxes.avatars.confirm", "/api/cli/managed-inboxes/avatars", "PATCH", "managed-inboxes avatars confirm", "oxygen_managed_inbox_avatar_confirm", "deliverability", "Verify and normalize a mailbox profile picture owned by this workspace.", { storage_key: text() }, ["storage_key"]),
|
|
70
|
+
operation("managed_inboxes.domains.search", "/api/cli/managed-inboxes/domains/search", "POST", "managed-inboxes search-domains", "oxygen_managed_inbox_domains_search", "deliverability", "Search available domains for managed mailboxes; buys nothing.", { keyword: text(), tlds: list(), limit: int({ minimum: 1 }) }, ["keyword"], { mutates: false }),
|
|
71
|
+
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),
|
|
72
|
+
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 }),
|
|
73
|
+
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."),
|
|
74
|
+
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"]),
|
|
75
|
+
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 }),
|
|
76
|
+
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 verified uncertain Table action outcome; never repeats the external action.", { outcome: enumOf(["applied", "not_applied"]), note: text(), value: { oneOf: [text(), num(), bool(), json, rows(), { type: "null" }] } }, ["outcome"]),
|
|
77
|
+
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),
|
|
78
|
+
operation("tables.favorites.get", "/api/cli/tables/favorite", "GET", "tables favorites", "oxygen_tables_favorites", "tables", "Read this member's table and folder favorites in the active workspace. A per-member preference; free (0 credits)."),
|
|
79
|
+
operation("tables.favorite.set", "/api/cli/tables/favorite", "POST", "tables favorite", "oxygen_tables_favorite", "tables", "Star or unstar exactly one table or folder in the active workspace. Free (0 credits); reads back the saved per-member preference.", { table: text("Table id or slug. Pass exactly one of table or folder."), folder: text("Folder id or slug. Pass exactly one of table or folder."), favorite: bool({ description: "true stars; false unstars. Free (0 credits); changes only this member's preference." }) }, ["favorite"]),
|
|
80
|
+
operation("tables.import.csv", "/api/cli/tables/import-csv", "POST", "tables import-csv", "oxygen_tables_import_csv", "tables", "Import inline CSV into a hosted Table through its durable ingestion run. Use staged upload for large files.", { csv_text: text(), csv_base64: text(), table: text(), table_name: text(), project: text(), filename: text(), upsert_key: text(), batch_size: int({ minimum: 1, maximum: 5000 }) }, [], cliOnly),
|
|
81
|
+
operation("tables.import.prepare", "/api/cli/tables/import-url", "POST", "tables import-upload", "oxygen_tables_import_upload", "tables", "Prepare a scoped storage upload for a hosted Table import; uploads and imports are separate, inspectable steps.", { file_name: text(), content_type: text(), byte_length: int({ minimum: 1 }), trace_id: text(), format: enumOf(["csv", "json", "xlsx"]) }, ["file_name", "byte_length"]),
|
|
82
|
+
operation("tables.import.preview", "/api/cli/tables/import-preview", "POST", "tables import-preview", "oxygen_tables_import_preview", "tables", "Preview a staged file's headers, rows and existing-table mapping; writes no imported rows.", { storage_key: text(), file_name: text(), format: enumOf(["csv", "json", "xlsx"]), byte_length: int({ minimum: 1 }), table: text(), upsert_key: text() }, ["storage_key", "byte_length"], { mutates: false }),
|
|
83
|
+
operation("tables.import.staged", "/api/cli/tables/import-staged", "POST", "tables import-staged", "oxygen_tables_import_staged", "tables", "Start a durable hosted import from this workspace's staged file; choose an existing table or create_name.", { table: text(), create_name: text(), project: text(), storage_key: text(), storage_bucket: text(), storage_provider: enumOf(["s3"]), file_name: text(), format: enumOf(["csv", "json", "xlsx"]), sha256: text(), upsert_key: text(), source_key_map: json, byte_length: int({ minimum: 1 }), row_count: int({ minimum: 1 }), max_concurrency: int({ minimum: 1, maximum: 1000 }), source: enumOf(["cli", "mcp", "web"]), batch_size: int({ minimum: 1, maximum: 5000 }) }, ["storage_key", "byte_length"]),
|
|
84
|
+
operation("tables.import.file", "/api/cli/tables/import-file", "POST", "tables import-file", "oxygen_tables_import_file", "tables", "Import small base64 file bytes through the shared multipart import API; use staged upload for large files.", { content_base64: text(), file_name: text(), content_type: text(), table: text(), table_name: text(), project: text(), format: enumOf(["csv", "json", "xlsx"]), sheet: text(), upsert_key: text(), source_key_map: json, source_hash: text(), batch_size: int({ minimum: 1, maximum: 5000 }), max_concurrency: int({ minimum: 1 }) }, ["content_base64", "file_name"], { multipart: { contentField: "content_base64", nameField: "file_name", typeField: "content_type", fileField: "file" } }),
|
|
85
|
+
operation("tables.link.suggest", "/api/cli/tables/link/suggest", "POST", "tables link-suggest", "oxygen_tables_link_suggest", "tables", "Preview which columns can link two Tables and how many rows match; creates no relation.", { table: text(), to: text(), on: text(), scan_limit: int({ minimum: 1 }) }, ["table", "to"], { mutates: false }),
|
|
86
|
+
operation("tables.recover_pending", "/api/cli/tables/recover-pending", "POST", "tables recover-pending", "oxygen_tables_recover_pending", "tables", "Recover bounded pending cells in one Table through the platform's native recovery path.", { table: text(), max_items: int({ minimum: 1 }) }, ["table"], mcpOnly),
|
|
87
|
+
operation("tables.webhooks.create", "/api/cli/tables/webhooks", "POST", "tables webhook create", "oxygen_table_webhook_create", "tables", "Create an inbound Table webhook or platform LinkedIn feed. Optional auto_run is standing permission with explicit or plan-default delivery ceilings.", { table: text(), name: text(), mode: enumOf(["insert", "upsert"]), upsert_key: text(), items_path: text(), event_id_path: text(), event_type_path: text(), occurred_at_path: text(), auth_mode: enumOf(["none", "secret"]), feed_kind: enumOf(["generic", "unipile"]), unipile_account_id: text(), event_types: list(), mapping: text(), auto_run: json }, ["table"], mcpOnly),
|
|
88
|
+
operation("tables.webhooks.update", "/api/cli/tables/webhooks", "PATCH", "tables webhook update", "oxygen_table_webhook_update", "tables", "Edit a Table webhook's name, state or standing auto_run; auth_mode=secret rotates its secret and returns it once.", { endpoint_id: text(), name: text(), status: enumOf(["active", "disabled"]), auth_mode: enumOf(["none", "secret"]), auto_run: json, clear_auto_run: bool() }, ["endpoint_id"], mcpOnly),
|
|
89
|
+
operation("whatsapp.draft", "/api/cli/whatsapp/draft", "POST", "whatsapp draft", "oxygen_whatsapp_draft", "inbox", "Generate a WhatsApp reply draft in the workspace voice, or approve a reviewed draft for an existing chat. Draft generation uses managed AI credits.", { conversation_id: text(), goal: text(), row_id: text(), object: text(), approved: bool(), draft_id: text(), text: text() }, ["conversation_id"], { ...cliOnly, spends: true }),
|
|
90
|
+
operation("whatsapp.drafts.list", "/api/cli/whatsapp/drafts", "GET", "whatsapp drafts list", "oxygen_whatsapp_drafts_list", "inbox", "Read the WhatsApp draft review queue.", { status: text(), limit: int({ minimum: 1 }) }, [], cliOnly),
|
|
91
|
+
operation("whatsapp.drafts.update", "/api/cli/whatsapp/drafts/update", "POST", "whatsapp drafts update", "oxygen_whatsapp_draft_update", "inbox", "Edit an open WhatsApp draft before approving or sending it.", { draft_id: text(), text: text() }, ["draft_id", "text"], cliOnly),
|
|
92
|
+
operation("whatsapp.drafts.reject", "/api/cli/whatsapp/drafts/reject", "POST", "whatsapp drafts reject", "oxygen_whatsapp_draft_reject", "inbox", "Reject an open WhatsApp draft without sending it.", { draft_id: text(), reason: text() }, ["draft_id"], cliOnly),
|
|
93
|
+
operation("worker.repair", "/api/cli/worker/repair", "POST", "worker repair", "oxygen_workspace_queue_repair", "workspace", "Repair this workspace's stalled execution queues through the native bounded recovery path.", {}, [], mcpOnly),
|
|
94
|
+
operation("db.status", "/api/cli/db/status", "GET", "db status", "oxygen_workspace_database_status", "workspace", "Read this workspace's database status and latest completed provisioning/migration receipt; not a list of current pending migrations. Historical Neon fields are lineage. Hosting is plan-included; 0 credits.", {}, [], mcpOnly),
|
|
95
|
+
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),
|
|
96
|
+
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."),
|
|
97
|
+
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."),
|
|
98
|
+
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),
|
|
99
|
+
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),
|
|
100
|
+
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),
|
|
101
|
+
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),
|
|
102
|
+
operation("collaboration.members.list", "/api/cli/collab/members", "GET", "approvals client list", "oxygen_workspace_members_list", "collaboration", "Read workspace members and their collaboration roles.", {}, [], mcpOnly),
|
|
103
|
+
operation("crm.connections", "/api/cli/crm/objects/{object}/records/{row_id}/connections", "GET", "crm connections", "oxygen_crm_connections", "crm", "Read a CRM record's connected conversations, sequence enrollments and related activity.", { conversation_limit: int({ minimum: 1 }), sequence_limit: int({ minimum: 1 }) }, [], mcpOnly),
|
|
104
|
+
operation("crm.tasks.list", "/api/cli/crm/tasks", "GET", "crm tasks list", "oxygen_crm_tasks_queue", "crm", "Read the workspace task queue by status, assignee and cursor.", { status: text(), assignee: text(), cursor: text(), limit: int({ minimum: 1 }) }, [], mcpOnly),
|
|
105
|
+
operation("crm.files.download", "/api/cli/crm/files/{attachment_id}/download", "GET", "crm files download", "oxygen_crm_file_download", "crm", "Download a tenant-owned record attachment by attachment_id. The native authenticated response contains its exact bytes.", {}, [], { binary: { maxBytes: 50 * 1024 * 1024 } }),
|
|
106
|
+
operation("db.cost_policy.get", "/api/cli/db/cost-policy", "GET", "db cost-policy", "oxygen_database_cost_policy", "workspace", "Read this workspace's retired Neon cost-policy status. PostgreSQL has no per-workspace sleep control; stored Neon policy is historical. 0 credits.", {}, [], mcpOnly),
|
|
107
|
+
operation("egress.dedicated.get", "/api/cli/egress/dedicated", "GET", "egress dedicated status", "oxygen_dedicated_egress_status", "deliverability", "Read dedicated outbound egress status and its current monthly commitment without activating it.", {}, [], mcpOnly),
|
|
108
|
+
operation("knowledge.files.list", "/api/cli/knowledge/files/list", "GET", "knowledge files list", "oxygen_knowledge_files_list", "knowledge", "List files in one entitled Knowledge repository mount; returns metadata and a bounded cursor.", { mountId: text(), cursor: text(), limit: int({ minimum: 1 }) }, ["mountId"], mcpOnly),
|
|
109
|
+
operation("knowledge.files.get", "/api/cli/knowledge/files/get", "GET", "knowledge files get", "oxygen_knowledge_file_get", "knowledge", "Read one entitled Knowledge file's metadata and bounded text when supported; revision pins historical content.", { id: text(), revision: int({ minimum: 1 }) }, ["id"], mcpOnly),
|
|
110
|
+
operation("knowledge.files.download", "/api/cli/knowledge/files/download", "GET", "knowledge files download", "oxygen_knowledge_file_download", "knowledge", "Download exact bytes for one entitled Knowledge file or pinned revision.", { id: text(), revision: int({ minimum: 1 }) }, ["id"], { ...mcpOnly, binary: { maxBytes: 50 * 1024 * 1024 } }),
|
|
111
|
+
operation("mailboxes.sequences", "/api/cli/mailboxes/{mailbox_id}/sequences", "GET", "mailboxes sequences", "oxygen_mailbox_sequences", "deliverability", "Read the sequences using one sending mailbox by id or email address."),
|
|
112
|
+
operation("managed_inboxes.registrant", "/api/cli/managed-inboxes/registrant", "GET", "managed-inboxes registrant", "oxygen_managed_inbox_registrant", "deliverability", "Read this workspace's domain-registration contact.", {}, [], mcpOnly),
|
|
113
|
+
operation("orgs.billing_owners", "/api/cli/orgs/billing-owners", "GET", "orgs billing-owners", "oxygen_workspace_billing_owners", "workspace", "Read eligible billing-owner workspaces from the caller's memberships.", {}, [], mcpOnly),
|
|
114
|
+
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),
|
|
115
|
+
operation("senders.checkpoints", "/api/cli/senders/checkpoints", "GET", "senders checkpoints", "oxygen_sender_checkpoints", "sequences", "Read connected sender authentication checkpoints that need human completion.", {}, [], mcpOnly),
|
|
116
|
+
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),
|
|
117
|
+
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),
|
|
118
|
+
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),
|
|
119
|
+
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),
|
|
120
|
+
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),
|
|
121
|
+
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),
|
|
122
|
+
operation("tools.check_access", "/api/cli/tools/check-access", "POST", "tools check-access", "oxygen_tools_check_access", "enrichment", "Read tool access for this workspace; verify_credential explicitly opts into a provider credential probe.", { tool_id: text(), connection_id: text(), credential_mode: enumOf(["managed", "user_api_key"]), input: json, verify_credential: bool() }, ["tool_id"], { ...cliOnly, mutates: false }),
|
|
123
|
+
operation("linkedin.connections.import_status", "/api/cli/linkedin/connections/import", "GET", "linkedin connections import-status", "oxygen_linkedin_connections_import_status", "sequences", "Read the durable LinkedIn connections import status and target Table.", { account: text() }),
|
|
124
|
+
operation("linkedin.followers.import_status", "/api/cli/linkedin/followers/import", "GET", "linkedin followers import-status", "oxygen_linkedin_followers_import_status", "sequences", "Read the durable LinkedIn followers import status and target Table.", { account: text() }),
|
|
125
|
+
operation("linkedin.inbox.backfill_status", "/api/cli/linkedin/inbox/backfill", "GET", "linkedin inbox backfill-status", "oxygen_linkedin_inbox_backfill_status", "inbox", "Read the durable LinkedIn inbox backfill status.", { account: text() }),
|
|
126
|
+
operation("linkedin.viewers.list", "/api/cli/linkedin/viewers", "GET", "linkedin viewers list", "oxygen_profile_viewers", "publishing", "Read named LinkedIn profile viewers, respecting the connected account's privacy ceiling.", { account: text(), start: int({ minimum: 0 }), include_raw: bool() }, [], cliOnly),
|
|
127
|
+
operation("signals.search.filters", "/api/cli/signals/search/preview", "GET", "signals search filters", "oxygen_signals_search_preview", "signals", "Read the LinkedIn post-search filter catalog and credential status; runs no search.", { source: enumOf(["linkedin_posts"]) }, [], cliOnly),
|
|
128
|
+
operation("visuals.download", "/api/cli/visuals/files/{file_id}/download", "GET", "visuals download", "oxygen_visual_file_download", "publishing", "Download a tenant-owned visual source or rendered file as exact bytes.", {}, [], { ...mcpOnly, binary: { maxBytes: 50 * 1024 * 1024 } }),
|
|
129
|
+
operation("workflows.mcp_callable", "/api/cli/workflows/mcp-callable", "GET", "workflows mcp list", "oxygen_workflows_mcp_callable", "workflows", "List this workspace's published MCP-callable Workflow definitions and interfaces.", {}, [], mcpOnly),
|
|
130
|
+
operation("skills.get", "/api/cli/skills/get", "GET", "skills get", "oxygen_skills_get", "workspace", "Read one authenticated, entitled product-skill entrypoint or manifest-listed supporting file.", { name: text(), file: text("Relative supporting-file path from the manifest; omit for SKILL.md.") }, ["name"], mcpOnly),
|
|
131
|
+
];
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type ContractObject } from "./schema.js";
|
|
2
|
+
export declare const DATABASE_DEFAULT_MAX_ROWS = 100;
|
|
3
|
+
export declare const DATABASE_HARD_MAX_ROWS = 1000;
|
|
4
|
+
export declare const DATABASE_HARD_MAX_CHARS = 48000;
|
|
5
|
+
export declare function normalizeDatabaseMaxRows(value?: number): number;
|
|
6
|
+
export declare const DATABASE_ATTACH_CONTRACT: ContractObject<{
|
|
7
|
+
readonly database_url: import("./schema.js").StringProperty;
|
|
8
|
+
}, "database_url">;
|
|
9
|
+
export declare const DATABASE_MIGRATE_CONTRACT: ContractObject<{
|
|
10
|
+
readonly rotate_credentials: import("./schema.js").BooleanProperty;
|
|
11
|
+
}, never>;
|
|
12
|
+
export declare const DATABASE_QUERY_CONTRACT: ContractObject<{
|
|
13
|
+
readonly sql: import("./schema.js").StringProperty;
|
|
14
|
+
readonly max_rows: {
|
|
15
|
+
type: "integer";
|
|
16
|
+
description?: string;
|
|
17
|
+
minimum?: number;
|
|
18
|
+
maximum?: number;
|
|
19
|
+
"x-clamp"?: true;
|
|
20
|
+
};
|
|
21
|
+
readonly max_chars: {
|
|
22
|
+
type: "integer";
|
|
23
|
+
description?: string;
|
|
24
|
+
minimum?: number;
|
|
25
|
+
maximum?: number;
|
|
26
|
+
"x-clamp"?: true;
|
|
27
|
+
};
|
|
28
|
+
}, "sql">;
|
|
29
|
+
/** Normalize existing route aliases/coercions first; ignored fields stay compatible. */
|
|
30
|
+
export declare function validateDatabaseInput(contract: ContractObject, input: Record<string, unknown>): Record<string, unknown>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/** Customer database fields; fleet repair stays on its existing staff routes. */
|
|
2
|
+
import { OxygenError } from "../cli-result.js";
|
|
3
|
+
import { bool, int, obj, str, validateContract } from "./schema.js";
|
|
4
|
+
export const DATABASE_DEFAULT_MAX_ROWS = 100;
|
|
5
|
+
export const DATABASE_HARD_MAX_ROWS = 1_000;
|
|
6
|
+
export const DATABASE_HARD_MAX_CHARS = 48_000;
|
|
7
|
+
export function normalizeDatabaseMaxRows(value) {
|
|
8
|
+
return value === undefined || !Number.isFinite(value)
|
|
9
|
+
? DATABASE_DEFAULT_MAX_ROWS
|
|
10
|
+
: Math.max(1, Math.min(Math.trunc(value), DATABASE_HARD_MAX_ROWS));
|
|
11
|
+
}
|
|
12
|
+
export const DATABASE_ATTACH_CONTRACT = obj({
|
|
13
|
+
database_url: str({ minLength: 1, description: "Owner PostgreSQL URL for a database you own; attaches and initializes it immediately." }),
|
|
14
|
+
}, { required: ["database_url"] });
|
|
15
|
+
export const DATABASE_MIGRATE_CONTRACT = obj({
|
|
16
|
+
rotate_credentials: bool({ description: "Repair runtime/read passwords and stored credentials. Omitted/false keeps them; routine migrations do not need rotation." }),
|
|
17
|
+
});
|
|
18
|
+
export const DATABASE_QUERY_CONTRACT = obj({
|
|
19
|
+
sql: str({ minLength: 1, description: "One SELECT, WITH or EXPLAIN statement; read-only transaction, dedicated customer login, default 5-second timeout." }),
|
|
20
|
+
max_rows: int({ minimum: 1, maximum: DATABASE_HARD_MAX_ROWS, clamp: true, description: "CLI/API default 100; MCP default 20; hard cap 1000." }),
|
|
21
|
+
max_chars: int({ minimum: 1_000, maximum: DATABASE_HARD_MAX_CHARS, description: "Optional complete-row response window including metadata. MCP caps at 10000 chars, built-in agents 4000. Narrow SELECT if one row cannot fit." }),
|
|
22
|
+
}, { required: ["sql"] });
|
|
23
|
+
/** Normalize existing route aliases/coercions first; ignored fields stay compatible. */
|
|
24
|
+
export function validateDatabaseInput(contract, input) {
|
|
25
|
+
const result = validateContract(contract, input, { unknown: "warn", overMax: "reject" });
|
|
26
|
+
if (!result.ok)
|
|
27
|
+
throw new OxygenError("invalid_request", "Invalid workspace database request.", { details: { issues: result.issues }, exitCode: 1 });
|
|
28
|
+
return result.value;
|
|
29
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** Account selection is shared; the remaining provider-specific connect fields have separate owners. */
|
|
2
|
+
export declare const INTEGRATION_CONNECT_ACCOUNT_CONTRACT: import("./schema.js").ContractObject<{
|
|
3
|
+
readonly account_id: import("./schema.js").StringProperty;
|
|
4
|
+
}, never>;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { obj, str } from "./schema.js";
|
|
2
|
+
/** Account selection is shared; the remaining provider-specific connect fields have separate owners. */
|
|
3
|
+
export const INTEGRATION_CONNECT_ACCOUNT_CONTRACT = obj({
|
|
4
|
+
account_id: str({
|
|
5
|
+
description: "Cloudflare account id from needs_account_selection. Omit for a single-account token.",
|
|
6
|
+
}),
|
|
7
|
+
});
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export declare const knowledgeIndexReadContract: import("./schema.js").ContractObject<{
|
|
2
|
+
readonly cursor: import("./schema.js").StringProperty;
|
|
3
|
+
readonly max_chars: {
|
|
4
|
+
type: "integer";
|
|
5
|
+
description?: string;
|
|
6
|
+
minimum?: number;
|
|
7
|
+
maximum?: number;
|
|
8
|
+
"x-clamp"?: true;
|
|
9
|
+
};
|
|
10
|
+
readonly limit: {
|
|
11
|
+
type: "integer";
|
|
12
|
+
description?: string;
|
|
13
|
+
minimum?: number;
|
|
14
|
+
maximum?: number;
|
|
15
|
+
"x-clamp"?: true;
|
|
16
|
+
};
|
|
17
|
+
}, never>;
|
|
18
|
+
export declare const knowledgePageReadContract: import("./schema.js").ContractObject<{
|
|
19
|
+
readonly cursor: import("./schema.js").StringProperty;
|
|
20
|
+
readonly max_chars: {
|
|
21
|
+
type: "integer";
|
|
22
|
+
description?: string;
|
|
23
|
+
minimum?: number;
|
|
24
|
+
maximum?: number;
|
|
25
|
+
"x-clamp"?: true;
|
|
26
|
+
};
|
|
27
|
+
readonly slug: import("./schema.js").StringProperty;
|
|
28
|
+
readonly id: import("./schema.js").StringProperty;
|
|
29
|
+
readonly view: {
|
|
30
|
+
type: "string";
|
|
31
|
+
enum: readonly ("body" | "data" | "data_keys" | "full" | "links" | "metadata" | "sources")[];
|
|
32
|
+
description?: string;
|
|
33
|
+
};
|
|
34
|
+
readonly revision: {
|
|
35
|
+
type: "integer";
|
|
36
|
+
description?: string;
|
|
37
|
+
minimum?: number;
|
|
38
|
+
maximum?: number;
|
|
39
|
+
"x-clamp"?: true;
|
|
40
|
+
};
|
|
41
|
+
readonly include_links: import("./schema.js").BooleanProperty;
|
|
42
|
+
readonly path: import("./schema.js").StringProperty;
|
|
43
|
+
}, never>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { KNOWLEDGE_SLUG_MAX_LENGTH } from "../knowledge-constants.js";
|
|
2
|
+
import { bool, enumOf, int, obj, str } from "./schema.js";
|
|
3
|
+
// Optional native windows: unqualified HTTP/CLI reads retain their legacy shape.
|
|
4
|
+
const window = {
|
|
5
|
+
cursor: str({ minLength: 1, maxLength: 4096 }),
|
|
6
|
+
max_chars: int({ minimum: 2000, maximum: 48000, description: "Complete receipt window; surface cap applies." }),
|
|
7
|
+
};
|
|
8
|
+
export const knowledgeIndexReadContract = obj({
|
|
9
|
+
limit: int({ minimum: 1, maximum: 1000 }),
|
|
10
|
+
...window,
|
|
11
|
+
});
|
|
12
|
+
export const knowledgePageReadContract = obj({
|
|
13
|
+
slug: str({ minLength: 1, maxLength: KNOWLEDGE_SLUG_MAX_LENGTH }),
|
|
14
|
+
id: str({ minLength: 1 }),
|
|
15
|
+
view: enumOf(["metadata", "body", "data", "data_keys", "links", "sources", "full"]),
|
|
16
|
+
revision: int({ minimum: 1 }),
|
|
17
|
+
include_links: bool({ description: "Full only; default true." }),
|
|
18
|
+
path: str({ maxLength: 1024, description: "JSON pointer; data/data_keys/sources." }),
|
|
19
|
+
...window,
|
|
20
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare const LINKEDIN_SENT_INVITES_MAX_LIMIT = 200;
|
|
2
|
+
export declare const LINKEDIN_SENT_INVITES_QUERY_CONTRACT: import("./schema.js").ContractObject<{
|
|
3
|
+
readonly account: import("./schema.js").StringProperty;
|
|
4
|
+
readonly limit: {
|
|
5
|
+
type: "integer";
|
|
6
|
+
description?: string;
|
|
7
|
+
minimum?: number;
|
|
8
|
+
maximum?: number;
|
|
9
|
+
"x-clamp"?: true;
|
|
10
|
+
};
|
|
11
|
+
readonly cursor: import("./schema.js").StringProperty;
|
|
12
|
+
}, never>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Exact selectors for one native/provider sent-invitation page. */
|
|
2
|
+
import { int, obj, str } from "./schema.js";
|
|
3
|
+
export const LINKEDIN_SENT_INVITES_MAX_LIMIT = 200;
|
|
4
|
+
export const LINKEDIN_SENT_INVITES_QUERY_CONTRACT = obj({
|
|
5
|
+
account: str({ description: "Sender id, connection id, or Unipile account id." }),
|
|
6
|
+
limit: int({ minimum: 1, description: "Maximum invitations to return." }),
|
|
7
|
+
cursor: str({ description: "Pagination cursor from a previous response." }),
|
|
8
|
+
});
|
|
@@ -1,13 +1,41 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type ContractObject } from "./schema.js";
|
|
2
2
|
export type OperationSpec<C extends ContractObject = ContractObject> = {
|
|
3
3
|
/** Stable id, `<resource>.<verb>`. */
|
|
4
4
|
id: string;
|
|
5
5
|
/** Route template; `{name}` segments are path parameters. */
|
|
6
6
|
route: string;
|
|
7
|
-
method: "POST" | "PATCH";
|
|
7
|
+
method: "GET" | "POST" | "PATCH" | "DELETE";
|
|
8
8
|
/** When set, the contract describes `body[bodyKey]` rather than the whole body. */
|
|
9
9
|
bodyKey?: string;
|
|
10
10
|
contract: C;
|
|
11
|
+
/** Named route parameters, exposed as exact flags/properties by generated surfaces. */
|
|
12
|
+
parameters?: readonly string[];
|
|
13
|
+
/** Fields sent in the query rather than the JSON body (all fields for GET). */
|
|
14
|
+
queryFields?: readonly string[];
|
|
15
|
+
/** Array fields encoded as repeated query keys rather than a JSON string. */
|
|
16
|
+
repeatedQueryFields?: readonly string[];
|
|
17
|
+
/** Fixed discriminator fields owned by this operation, never supplied by a caller. */
|
|
18
|
+
defaults?: Readonly<Record<string, unknown>>;
|
|
19
|
+
/** A side already has a manual, domain-native implementation. */
|
|
20
|
+
generated?: {
|
|
21
|
+
cli: boolean;
|
|
22
|
+
mcp: boolean;
|
|
23
|
+
};
|
|
24
|
+
/** Multipart transport for an operation whose API takes one uploaded file. */
|
|
25
|
+
multipart?: {
|
|
26
|
+
contentField: string;
|
|
27
|
+
nameField: string;
|
|
28
|
+
typeField: string;
|
|
29
|
+
fileField: string;
|
|
30
|
+
};
|
|
31
|
+
/** Download bytes through the same authenticated route; never follow redirects. */
|
|
32
|
+
binary?: {
|
|
33
|
+
maxBytes: number;
|
|
34
|
+
stream?: never;
|
|
35
|
+
} | {
|
|
36
|
+
stream: true;
|
|
37
|
+
resourceParameter: string;
|
|
38
|
+
};
|
|
11
39
|
cli: {
|
|
12
40
|
/** Command words after `oxygen`, e.g. `["senders", "limits", "set"]`. */
|
|
13
41
|
path: readonly string[];
|
|
@@ -24,10 +52,28 @@ export type OperationSpec<C extends ContractObject = ContractObject> = {
|
|
|
24
52
|
description: string;
|
|
25
53
|
/** The MCP toolset domain (pack) the tool registers under. */
|
|
26
54
|
pack: string;
|
|
55
|
+
/** Source-reviewed effect hints; never an authorization bypass. */
|
|
56
|
+
annotations?: {
|
|
57
|
+
destructiveHint?: boolean;
|
|
58
|
+
openWorldHint?: boolean;
|
|
59
|
+
idempotentHint?: boolean;
|
|
60
|
+
};
|
|
27
61
|
};
|
|
28
62
|
mutates: boolean;
|
|
29
63
|
spends: boolean;
|
|
30
64
|
};
|
|
31
65
|
/** The route with its `{param}` segments filled in, each URL-encoded. */
|
|
32
66
|
export declare function operationPath(spec: Pick<OperationSpec, "route">, params: Readonly<Record<string, string>>): string;
|
|
67
|
+
/** The exact public grammar, including the operation's scoped route parameters. */
|
|
68
|
+
export declare function operationInputContract(spec: OperationSpec): ContractObject;
|
|
69
|
+
/** Preserve absent, false, null and empty values while assigning each field to its transport. */
|
|
70
|
+
export declare function operationRequest(spec: OperationSpec, args: Record<string, unknown>): {
|
|
71
|
+
path: string;
|
|
72
|
+
method: OperationSpec["method"];
|
|
73
|
+
body?: Record<string, unknown>;
|
|
74
|
+
};
|
|
75
|
+
/** Decode the explicit file property and keep the native multipart API contract. */
|
|
76
|
+
export declare function operationFormData(spec: OperationSpec, body: Record<string, unknown>): FormData;
|
|
33
77
|
export declare const OPERATION_SPECS: readonly OperationSpec[];
|
|
78
|
+
export declare const CLI_OPERATIONS: OperationSpec[];
|
|
79
|
+
export declare const MCP_OPERATIONS: OperationSpec[];
|
|
@@ -4,8 +4,12 @@
|
|
|
4
4
|
* The CLI command, the MCP tool and the route read the same spec, so the three
|
|
5
5
|
* cannot disagree on which fields exist. Leaf and browser-safe.
|
|
6
6
|
*/
|
|
7
|
-
import { CONNECTOR_UPDATE_OPERATION } from "./connectors.js";
|
|
7
|
+
import { CONNECTOR_EVENTS_REVOKE_OPERATION, CONNECTOR_UPDATE_OPERATION } from "./connectors.js";
|
|
8
|
+
import { str } from "./schema.js";
|
|
8
9
|
import { SENDER_LIMITS_SET_OPERATION } from "./sender-limits.js";
|
|
10
|
+
import { WORKSPACE_PAGES_GET_OPERATION, WORKSPACE_PAGES_UPDATE_OPERATION } from "./workspace-pages.js";
|
|
11
|
+
import { BROWSER_OPERATIONS } from "./browser-operations.js";
|
|
12
|
+
import { CUSTOMER_OPERATIONS } from "./customer-operations.js";
|
|
9
13
|
/** The route with its `{param}` segments filled in, each URL-encoded. */
|
|
10
14
|
export function operationPath(spec, params) {
|
|
11
15
|
return spec.route.replace(/\{(\w+)\}/g, (_match, name) => {
|
|
@@ -15,4 +19,66 @@ export function operationPath(spec, params) {
|
|
|
15
19
|
return encodeURIComponent(value);
|
|
16
20
|
});
|
|
17
21
|
}
|
|
18
|
-
|
|
22
|
+
/** The exact public grammar, including the operation's scoped route parameters. */
|
|
23
|
+
export function operationInputContract(spec) {
|
|
24
|
+
const parameters = spec.parameters ?? [];
|
|
25
|
+
for (const name of parameters) {
|
|
26
|
+
if (Object.hasOwn(spec.contract.properties, name))
|
|
27
|
+
throw new Error(`Operation ${spec.id} uses ${name} for both a route parameter and a body field.`);
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
...spec.contract,
|
|
31
|
+
properties: {
|
|
32
|
+
...Object.fromEntries(parameters.map((name) => [name, str({ minLength: 1 })])),
|
|
33
|
+
...spec.contract.properties,
|
|
34
|
+
},
|
|
35
|
+
required: [...parameters, ...(spec.contract.required ?? [])],
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/** Preserve absent, false, null and empty values while assigning each field to its transport. */
|
|
39
|
+
export function operationRequest(spec, args) {
|
|
40
|
+
const params = Object.fromEntries((spec.parameters ?? []).map((name) => [name, String(args[name] ?? "")]));
|
|
41
|
+
let path = operationPath(spec, params);
|
|
42
|
+
const body = { ...spec.defaults };
|
|
43
|
+
const query = new URLSearchParams();
|
|
44
|
+
for (const name of Object.keys(spec.contract.properties)) {
|
|
45
|
+
const value = args[name];
|
|
46
|
+
if (value === undefined)
|
|
47
|
+
continue;
|
|
48
|
+
if (spec.method === "GET" || spec.queryFields?.includes(name)) {
|
|
49
|
+
if (spec.repeatedQueryFields?.includes(name) && Array.isArray(value)) {
|
|
50
|
+
for (const entry of value)
|
|
51
|
+
query.append(name, String(entry));
|
|
52
|
+
}
|
|
53
|
+
else if (value !== null)
|
|
54
|
+
query.set(name, typeof value === "object" ? JSON.stringify(value) : String(value));
|
|
55
|
+
}
|
|
56
|
+
else
|
|
57
|
+
body[name] = value;
|
|
58
|
+
}
|
|
59
|
+
if (query.size)
|
|
60
|
+
path += `?${query}`;
|
|
61
|
+
return { path, method: spec.method, ...(spec.method !== "GET" && Object.keys(body).length > 0 ? { body: spec.bodyKey ? { [spec.bodyKey]: body } : body } : {}) };
|
|
62
|
+
}
|
|
63
|
+
/** Decode the explicit file property and keep the native multipart API contract. */
|
|
64
|
+
export function operationFormData(spec, body) {
|
|
65
|
+
const fields = spec.multipart;
|
|
66
|
+
if (!fields)
|
|
67
|
+
throw new Error("This operation does not accept a file.");
|
|
68
|
+
const encoded = body[fields.contentField];
|
|
69
|
+
if (typeof encoded !== "string" || !/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(encoded) || !encoded) {
|
|
70
|
+
throw new Error(`${fields.contentField} must contain valid non-empty base64 file bytes.`);
|
|
71
|
+
}
|
|
72
|
+
const bytes = Uint8Array.from(atob(encoded), (character) => character.charCodeAt(0));
|
|
73
|
+
const form = new FormData();
|
|
74
|
+
form.set(fields.fileField, new Blob([bytes], { type: String(body[fields.typeField] ?? "application/octet-stream") }), String(body[fields.nameField] ?? "upload"));
|
|
75
|
+
for (const [key, value] of Object.entries(body)) {
|
|
76
|
+
if ([fields.contentField, fields.nameField, fields.typeField].includes(key) || value === undefined)
|
|
77
|
+
continue;
|
|
78
|
+
form.set(key, typeof value === "object" ? JSON.stringify(value) : String(value));
|
|
79
|
+
}
|
|
80
|
+
return form;
|
|
81
|
+
}
|
|
82
|
+
export const OPERATION_SPECS = [SENDER_LIMITS_SET_OPERATION, CONNECTOR_UPDATE_OPERATION, CONNECTOR_EVENTS_REVOKE_OPERATION, WORKSPACE_PAGES_GET_OPERATION, WORKSPACE_PAGES_UPDATE_OPERATION, ...CUSTOMER_OPERATIONS, ...BROWSER_OPERATIONS];
|
|
83
|
+
export const CLI_OPERATIONS = [...CUSTOMER_OPERATIONS, ...BROWSER_OPERATIONS].filter((spec) => spec.generated?.cli !== false);
|
|
84
|
+
export const MCP_OPERATIONS = [...CUSTOMER_OPERATIONS, ...BROWSER_OPERATIONS].filter((spec) => spec.generated?.mcp !== false);
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Optional first-page metadata on the shared Table grid query. */
|
|
2
|
+
import { bool, obj } from "./schema.js";
|
|
3
|
+
export const TABLE_GRID_QUERY_OPTIONS_CONTRACT = obj({
|
|
4
|
+
include_stats: bool({ description: "With --format grid, include column fill statistics and their table row count when available; 0 credits." }),
|
|
5
|
+
include_fill: bool({ description: "With --format grid, include fill progress on an empty first page when available; ignored on cursor pages. 0 credits." }),
|
|
6
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** Optional representation of Query; canonical raw rows remain the default. */
|
|
2
|
+
export declare const TABLE_QUERY_GRID_CONTRACT: import("./schema.js").ContractObject<{
|
|
3
|
+
readonly format: {
|
|
4
|
+
type: "string";
|
|
5
|
+
enum: readonly "grid"[];
|
|
6
|
+
description?: string;
|
|
7
|
+
};
|
|
8
|
+
readonly include_stats: import("./schema.js").BooleanProperty;
|
|
9
|
+
readonly include_fill: import("./schema.js").BooleanProperty;
|
|
10
|
+
readonly max_chars: {
|
|
11
|
+
type: "integer";
|
|
12
|
+
description?: string;
|
|
13
|
+
minimum?: number;
|
|
14
|
+
maximum?: number;
|
|
15
|
+
"x-clamp"?: true;
|
|
16
|
+
};
|
|
17
|
+
}, never>;
|
|
18
|
+
export declare const TABLE_QUERY_GRID_NATIVE_WINDOW = 10000;
|
|
19
|
+
export declare const TABLE_QUERY_GRID_BUILTIN_WINDOW = 4000;
|
|
20
|
+
/** Measure the complete native receipt and the escaped built-in host receipt. */
|
|
21
|
+
export declare function tableQueryGridResultFits(data: Record<string, unknown>, maxChars: number | undefined, surface: string | null): boolean;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { success } from "../cli-result.js";
|
|
2
|
+
import { OXYGEN_VERSION } from "../version.js";
|
|
3
|
+
import { bool, enumOf, int, obj } from "./schema.js";
|
|
4
|
+
/** Optional representation of Query; canonical raw rows remain the default. */
|
|
5
|
+
export const TABLE_QUERY_GRID_CONTRACT = obj({
|
|
6
|
+
format: enumOf(["grid"], { description: "Grid cell previews." }),
|
|
7
|
+
include_stats: bool({ description: "Optional column stats." }),
|
|
8
|
+
include_fill: bool({ description: "Empty first-page fill state." }),
|
|
9
|
+
max_chars: int({ minimum: 1_000, maximum: 100_000, description: "Complete grid envelope chars." }),
|
|
10
|
+
});
|
|
11
|
+
export const TABLE_QUERY_GRID_NATIVE_WINDOW = 10_000;
|
|
12
|
+
// Deliberately below Strands' shipped 6000 default; counts the complete host
|
|
13
|
+
// object rather than only its text. This changes no adapter's outer ceiling.
|
|
14
|
+
export const TABLE_QUERY_GRID_BUILTIN_WINDOW = 4_000;
|
|
15
|
+
/** Measure the complete native receipt and the escaped built-in host receipt. */
|
|
16
|
+
export function tableQueryGridResultFits(data, maxChars, surface) {
|
|
17
|
+
if (maxChars === undefined)
|
|
18
|
+
return true;
|
|
19
|
+
if (JSON.stringify(success("tables query", data)).length > maxChars)
|
|
20
|
+
return false;
|
|
21
|
+
if (surface === "agent" || surface === "copilot") {
|
|
22
|
+
return JSON.stringify({
|
|
23
|
+
ok: true, text: JSON.stringify(data), structured: { ...data, oxygen_version: OXYGEN_VERSION },
|
|
24
|
+
}).length <= TABLE_QUERY_GRID_BUILTIN_WINDOW;
|
|
25
|
+
}
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type Infer } from "./schema.js";
|
|
2
|
+
/** Explicit metadata projections; omitted native HTTP/CLI options retain full detail. */
|
|
3
|
+
export declare const toolCatalogDetailQueryContract: import("./schema.js").ContractObject<{
|
|
4
|
+
readonly view: {
|
|
5
|
+
type: "string";
|
|
6
|
+
enum: readonly ("access" | "examples" | "field_names" | "full" | "guidance" | "input_schema" | "native_fields" | "output_schema" | "pricing" | "summary")[];
|
|
7
|
+
description?: string;
|
|
8
|
+
};
|
|
9
|
+
readonly field_keys: import("./schema.js").ArrayProperty<import("./schema.js").StringProperty>;
|
|
10
|
+
readonly field_query: import("./schema.js").StringProperty;
|
|
11
|
+
readonly max_chars: {
|
|
12
|
+
type: "integer";
|
|
13
|
+
description?: string;
|
|
14
|
+
minimum?: number;
|
|
15
|
+
maximum?: number;
|
|
16
|
+
"x-clamp"?: true;
|
|
17
|
+
};
|
|
18
|
+
}, never>;
|
|
19
|
+
export type ToolCatalogDetailQuery = Infer<typeof toolCatalogDetailQueryContract>;
|