@oxygen-agent/cli 1.1011.326 → 1.1011.405
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 +7 -0
- package/dist/connectors-commands.d.ts +4 -1
- package/dist/connectors-commands.js +81 -10
- package/dist/contract-flags.d.ts +2 -0
- package/dist/contract-flags.js +4 -2
- package/dist/crm-support-flags.d.ts +11 -0
- package/dist/crm-support-flags.js +60 -0
- package/dist/help.js +10 -0
- package/dist/index.js +175 -65
- package/dist/settings-commands.d.ts +11 -0
- package/dist/settings-commands.js +72 -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 +30 -0
- package/node_modules/@oxygen/shared/dist/capability-discovery.js +277 -16
- 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-support.d.ts +117 -0
- package/node_modules/@oxygen/shared/dist/contracts/crm-support.js +43 -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/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/operations.js +8 -2
- package/node_modules/@oxygen/shared/dist/contracts/workspace-pages.d.ts +16 -0
- package/node_modules/@oxygen/shared/dist/contracts/workspace-pages.js +37 -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/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 +21 -0
- package/node_modules/@oxygen/shared/dist/plan-limits.js +41 -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 +5 -0
- package/package.json +1 -1
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** Complete native receipt sizing for optional bounded JSON reads. Binary
|
|
2
|
+
* windows have their own outer-envelope budget and must not use this helper.
|
|
3
|
+
* The surface is a formatting hint, never authorization or spend authority. */
|
|
4
|
+
export declare function boundedReadResultFits(command: string, data: Record<string, unknown>, maxChars: number | undefined, surface: string | null | undefined): boolean;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { success } from "./cli-result.js";
|
|
2
|
+
import { OXYGEN_VERSION } from "./version.js";
|
|
3
|
+
/** Complete native receipt sizing for optional bounded JSON reads. Binary
|
|
4
|
+
* windows have their own outer-envelope budget and must not use this helper.
|
|
5
|
+
* The surface is a formatting hint, never authorization or spend authority. */
|
|
6
|
+
export function boundedReadResultFits(command, data, maxChars, surface) {
|
|
7
|
+
// Preserve legacy unbounded native/CLI reads when no window was requested.
|
|
8
|
+
if (maxChars === undefined)
|
|
9
|
+
return true;
|
|
10
|
+
if (JSON.stringify(success(command, data)).length > maxChars)
|
|
11
|
+
return false;
|
|
12
|
+
// MCP jsonResult writes compact data to text and adds the version to its
|
|
13
|
+
// structured result. The unattended worker returns both; Strands serializes
|
|
14
|
+
// that complete host object before its 6k cap. Escapes in text count twice.
|
|
15
|
+
if (surface === "agent") {
|
|
16
|
+
const host = {
|
|
17
|
+
ok: true,
|
|
18
|
+
text: JSON.stringify(data),
|
|
19
|
+
structured: { ...data, oxygen_version: OXYGEN_VERSION },
|
|
20
|
+
};
|
|
21
|
+
if (JSON.stringify(host).length > 6_000)
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
@@ -97,6 +97,36 @@ export declare const CAPABILITY_ROUTE_MCP_CALLS: {
|
|
|
97
97
|
tool: string;
|
|
98
98
|
arguments: {};
|
|
99
99
|
};
|
|
100
|
+
connectedAppEvents: () => {
|
|
101
|
+
tool: string;
|
|
102
|
+
arguments: {
|
|
103
|
+
connection: string;
|
|
104
|
+
};
|
|
105
|
+
};
|
|
106
|
+
workspacePagesList: () => {
|
|
107
|
+
tool: string;
|
|
108
|
+
arguments: {};
|
|
109
|
+
};
|
|
110
|
+
functionsList: () => {
|
|
111
|
+
tool: string;
|
|
112
|
+
arguments: {
|
|
113
|
+
operation: string;
|
|
114
|
+
};
|
|
115
|
+
};
|
|
116
|
+
functionsDescribe: () => {
|
|
117
|
+
tool: string;
|
|
118
|
+
arguments: {
|
|
119
|
+
operation: string;
|
|
120
|
+
function: string;
|
|
121
|
+
};
|
|
122
|
+
};
|
|
123
|
+
functionsRuns: () => {
|
|
124
|
+
tool: string;
|
|
125
|
+
arguments: {
|
|
126
|
+
operation: string;
|
|
127
|
+
function: string;
|
|
128
|
+
};
|
|
129
|
+
};
|
|
100
130
|
sequenceSendingSchedule: () => {
|
|
101
131
|
tool: string;
|
|
102
132
|
arguments: {
|
|
@@ -22,16 +22,24 @@ export const OXYGEN_CAPABILITY_ROUTES = [
|
|
|
22
22
|
id: "workspace-access",
|
|
23
23
|
layer: "Control",
|
|
24
24
|
primitive: null,
|
|
25
|
-
owns: "Authentication, CLI identities, API keys, sessions, organizations, active-workspace selection,
|
|
26
|
-
notFor: "Workspace GTM data, provider credentials,
|
|
27
|
-
execution: "Resolve identity and select the hosted workspace before operating its primitives. Each app connected with OAuth keeps its own default workspace: `connectors list` shows them and `connectors set` changes one app only; orgs select changes only the app or CLI that calls it.",
|
|
25
|
+
owns: "Authentication, CLI identities, API keys, sessions, organizations, active-workspace selection, connected apps (ChatGPT, Claude, Codex…) with the default workspace each one works in and the OXYGEN events each one is subscribed to, and which web-app sidebar pages the workspace hides for every member (Settings → Customise).",
|
|
26
|
+
notFor: "Workspace GTM data, provider credentials, execution inside a primitive, or access control: a hidden sidebar page stays reachable by URL.",
|
|
27
|
+
execution: "Resolve identity and select the hosted workspace before operating its primitives. Each app connected with OAuth keeps its own default workspace: `connectors list` shows them and `connectors set` changes one app only; orgs select changes only the app or CLI that calls it. What OXYGEN sends an app (its event subscriptions, such as ChatGPT watching for classified replies, and every delivery with its outcome, never content): `connectors events get <app>`; `connectors events revoke <app> --subscription <id|all>` stops them for good. While an app holds event subscriptions, its paid calls are capped by its rolling 24-hour credit ceiling: the plan default, or `connectors set <app> --credit-ceiling <credits>` (above the default also needs --approve-above-default); `connectors get <app>` shows the ceiling and what it spent. Sidebar pages (Settings → Customise): `settings pages list` (oxygen_settings_pages_get) shows each page and whether it is hidden; an admin or owner hides or shows pages for everyone with `settings pages set --hide <pages>`, `--show <pages>` or `--show-all` (oxygen_settings_pages_update). Nothing is deleted.",
|
|
28
28
|
posture: "mixed",
|
|
29
|
-
gatewayTools: [
|
|
30
|
-
|
|
29
|
+
gatewayTools: [
|
|
30
|
+
"oxygen_whoami",
|
|
31
|
+
"oxygen_orgs_list",
|
|
32
|
+
"oxygen_orgs_select",
|
|
33
|
+
"oxygen_connector_list",
|
|
34
|
+
"oxygen_connector_update",
|
|
35
|
+
"oxygen_connector_events_get",
|
|
36
|
+
"oxygen_connector_events_revoke",
|
|
37
|
+
],
|
|
38
|
+
gatewayCommands: ["whoami", "orgs list", "orgs select", "connectors list", "connectors set", "connectors events get", "connectors events revoke"],
|
|
31
39
|
skills: ["oxygen-quickstart"],
|
|
32
40
|
// `mcp`: the host-driven MCP Events routes an OAuth connection's subscriptions go through (ADR 0030 §2).
|
|
33
41
|
endpointSections: ["api-keys", "auth", "connectors", "login-requests", "mcp", "orgs", "sessions", "settings", "whoami"],
|
|
34
|
-
intentTerms: ["login", "authenticate", "identity", "who am i", "workspace", "organization", "org", "api key", "session", "switch workspace", "connected app", "connected apps", "default workspace"],
|
|
42
|
+
intentTerms: ["login", "authenticate", "identity", "who am i", "workspace", "organization", "org", "api key", "session", "switch workspace", "connected app", "connected apps", "default workspace", "sidebar", "navigation", "hidden pages", "page visibility", "workspace settings", "organisation settings", "organization settings"],
|
|
35
43
|
},
|
|
36
44
|
{
|
|
37
45
|
id: "discovery-and-skills",
|
|
@@ -214,7 +222,7 @@ export const OXYGEN_CAPABILITY_ROUTES = [
|
|
|
214
222
|
layer: "Data",
|
|
215
223
|
primitive: "tables",
|
|
216
224
|
owns: "Typed working datasets, rows, formulas, AI/tool/waterfall columns, reusable Functions with isolated drafts and published versions, cell state, projects, and run provenance.",
|
|
217
|
-
notFor: "Canonical CRM truth, message cadence
|
|
225
|
+
notFor: "Canonical CRM truth: use Records via oxygen_crm_objects_list, oxygen_crm_record_get or oxygen_crm_record_search. Not message cadence or an off-platform spreadsheet runtime.",
|
|
218
226
|
execution: "Create and run work in hosted OXYGEN Tables; validate a small sample before bounded paid runs. To see what a table's own columns can be enriched with and what each costs per row before adding anything, run `tools search --for-table <table>` (MCP oxygen_tools_search with for_table): free, it returns priced suggestions with the exact add command. For standard person or company enrichment, `columns add <table> --preset person_enrich|company_enrich` (MCP oxygen_columns_add with preset) adds the maintained bundle in one call before any hand-built tool column. Person questions over that bundle's profile payload (skill set, grad school, location, job fit, current company) and person appearance research (events, keynotes, podcasts, GitHub profile) are `columns catalog --category people` templates, added with `columns add <table> --prompt-key <key> --input <name>=<column>`. For a company fact OXYGEN already knows how to research (founders, parent company, funding, cloud provider, offers demos, industry, NAICS, HQ, LinkedIn/Crunchbase page lookups) or a page extraction, `columns catalog` lists the ready-made template and `columns add <table> --prompt-key <key> --input <name>=<column>` (MCP oxygen_columns_add with prompt_key) adds it with no prompt to write. For ICP tiers, read the saved profile with `knowledge page get icp`, then add native Classify Score: `columns add <table> --label 'ICP fit' --score 'low,medium,high' --prompt '<ICP criteria using {{evidence_column}} tokens>' --grounding workspace`. It costs 0.075 credits/row; preview with `columns run --dry-run`. `columns catalog --family classification --json` puts Classify in `data.native`; `data.entries` holds separate prompt templates that can cost more.",
|
|
219
227
|
posture: "mixed",
|
|
220
228
|
gatewayTools: ["oxygen_tables_create", "oxygen_tools_search", "oxygen_columns_add", "oxygen_columns_catalog", "oxygen_enrich_column_preview", "oxygen_tables_link_bulk", "oxygen_callables_manage"],
|
|
@@ -260,7 +268,7 @@ export const OXYGEN_CAPABILITY_ROUTES = [
|
|
|
260
268
|
primitive: "posts",
|
|
261
269
|
owns: "Broadcast post artifacts, author/channel identity, provider IDs, comments, reactions, and performance history.",
|
|
262
270
|
notFor: "One-to-one conversations, delivery scheduling, or generic public LinkedIn provider search.",
|
|
263
|
-
execution: "Read or
|
|
271
|
+
execution: "Read hosted posts and their comments or performance. For queued scheduling and review use Publishing. oxygen_posts_create is a direct LinkedIn publish: preview first, then approved=true publishes immediately outside the Publishing approval queue.",
|
|
264
272
|
posture: "workspace_write",
|
|
265
273
|
gatewayTools: ["oxygen_publishing_comments", "oxygen_publishing_analytics", "oxygen_posts_get", "oxygen_posts_create"],
|
|
266
274
|
gatewayCommands: ["publishing comments list", "publishing analytics summary", "posts get", "posts create"],
|
|
@@ -368,7 +376,7 @@ export const OXYGEN_CAPABILITY_ROUTES = [
|
|
|
368
376
|
primitive: "publishing",
|
|
369
377
|
owns: "Approval-gated scheduling, dispatch, retries, review, and attempt provenance for broadcast Posts.",
|
|
370
378
|
notFor: "One-to-one messaging, outreach campaigns, or general automation.",
|
|
371
|
-
execution: "Create
|
|
379
|
+
execution: "Create a scheduled Publishing post, review it, then explicitly approve to release the hosted publisher. oxygen_posts_create instead publishes directly to LinkedIn after its own preview and approved=true; it does not enter this queue.",
|
|
372
380
|
posture: "external_write",
|
|
373
381
|
gatewayTools: ["oxygen_publishing_posts_create", "oxygen_publishing_posts_list", "oxygen_publishing_posts_approve", "oxygen_ugc_get"],
|
|
374
382
|
gatewayCommands: ["publishing posts create", "publishing posts list", "publishing posts approve", "ugc programs list", "ugc programs duplicate", "ugc programs archive"],
|
|
@@ -429,8 +437,8 @@ export const OXYGEN_CAPABILITY_ROUTES = [
|
|
|
429
437
|
notFor: "Enriching rows that already exist; use native table columns and waterfalls. Not for raw provider selection when a native gateway exists.",
|
|
430
438
|
execution: "Plan or preview the hosted search, then run with an explicit scope and credit ceiling; hydrate one provider descriptor only when needed.",
|
|
431
439
|
posture: "paid_read",
|
|
432
|
-
gatewayTools: ["
|
|
433
|
-
gatewayCommands: ["search plan", "
|
|
440
|
+
gatewayTools: ["oxygen_companies_search_plan", "oxygen_people_search_plan", "oxygen_tools_search", "oxygen_find_company"],
|
|
441
|
+
gatewayCommands: ["companies search plan", "people search plan", "tools search", "find company"],
|
|
434
442
|
skills: ["oxygen-gtm"],
|
|
435
443
|
endpointSections: ["companies", "find", "lead-sourcing", "people", "search", "sourcing", "tools", "verify"],
|
|
436
444
|
intentTerms: ["find companies", "find people", "source leads", "build a list", "tam", "prospect", "provider", "tool catalog", "find email", "find phone", "local businesses", "local business", "google maps", "storefronts"],
|
|
@@ -456,13 +464,13 @@ export const OXYGEN_CAPABILITY_ROUTES = [
|
|
|
456
464
|
primitive: null,
|
|
457
465
|
owns: "Connected SaaS accounts, OAuth/BYOK readiness, custom integration manifests, and provider actions that lack a native primitive gateway.",
|
|
458
466
|
notFor: "Recreating native Tables, Messages, Sequences, Publishing, or Workflows through a generic provider action.",
|
|
459
|
-
execution: "
|
|
467
|
+
execution: "For provider API keys, inspect the connect schema and omit credentials for setup requirements with no provider call or storage. Submitting credentials creates or replaces the connection immediately. Cloudflare account selection uses top-level account_id; BounceBan validates before storage. Provider actions keep their exact write/spend gate.",
|
|
460
468
|
posture: "mixed",
|
|
461
469
|
gatewayTools: ["oxygen_integrations_list", "oxygen_integrations_connect", "oxygen_integrations_list_actions"],
|
|
462
470
|
gatewayCommands: ["integrations list", "integrations connect", "custom-integrations list"],
|
|
463
471
|
skills: ["oxygen-gtm"],
|
|
464
472
|
endpointSections: ["custom-integrations", "integrations"],
|
|
465
|
-
intentTerms: ["integration", "integrations", "connect provider", "oauth", "byok", "custom http", "custom integration", "connection readiness"],
|
|
473
|
+
intentTerms: ["integration", "integrations", "connect provider", "oauth", "byok", "bring your own key", "provider key", "provider connection", "custom http", "custom integration", "connection readiness"],
|
|
466
474
|
},
|
|
467
475
|
{
|
|
468
476
|
id: "sending-infrastructure",
|
|
@@ -567,7 +575,9 @@ export function inferCapabilityRoute(query) {
|
|
|
567
575
|
// The card's own recommendations are a pinned contract (tool order, no
|
|
568
576
|
// exact command on plain enrichment asks); the catalogue path travels
|
|
569
577
|
// beside them in `catalogIntent`, never inside them.
|
|
570
|
-
|
|
578
|
+
// Sourcing filters belong to the planner, not per-company enrichment.
|
|
579
|
+
const catalogue = catalogRow && CATALOGUE_CARD_IDS.has(card.id) && !isCompanySourcingIntent(normalized)
|
|
580
|
+
? catalogueRecommendations(catalogRow, card) : null;
|
|
571
581
|
return {
|
|
572
582
|
card: routeCardFor(card, normalized),
|
|
573
583
|
recommendedTools: recommendations.tools,
|
|
@@ -765,8 +775,26 @@ function routeCardFor(card, query) {
|
|
|
765
775
|
return { ...card, ...UGC_ROUTE_VIEW };
|
|
766
776
|
if (card.id === "knowledge-graph" && isWorkspaceVoiceIntent(query))
|
|
767
777
|
return { ...card, execution: WORKSPACE_VOICE_EXECUTION };
|
|
778
|
+
if (card.primitive === "workflows" && isRecurringCompanyMonitoringIntent(query))
|
|
779
|
+
return {
|
|
780
|
+
...card,
|
|
781
|
+
execution: "Workflows own recurring execution. Inspect oxygen_blueprints_list, describe and preflight before authoring; a matching Blueprint is not guaranteed. Retain canonical company identities and facts in Records, and time-stamped observations in Signals. Use oxygen_crm_objects_list and oxygen_signals_list to inspect those destinations. Do not apply or enable automation before the required approval and credit scope.",
|
|
782
|
+
};
|
|
783
|
+
if (card.primitive === "tables" && isTableCapacityReadIntent(query))
|
|
784
|
+
return {
|
|
785
|
+
...card,
|
|
786
|
+
execution: "Read oxygen_limits_show for Tables capacity, largest_table and largest_table_rows. Use that returned table reference with oxygen_tables_query and a small limit to inspect sample rows; no enrichment run is needed.",
|
|
787
|
+
};
|
|
788
|
+
if (card.primitive === "tables" && isFunctionIntent(query))
|
|
789
|
+
return {
|
|
790
|
+
...card,
|
|
791
|
+
execution: "List, describe or inspect Function runs without executing. Draft edits are isolated; publish requires the inspected draft hash and changes future invocations. Bind adds a caller column for free; columns run previews cost before a bounded approved run. MCP uses the mixed-effect oxygen_callables_manage through oxygen_capabilities_call, including its read operations.",
|
|
792
|
+
};
|
|
768
793
|
return card;
|
|
769
794
|
}
|
|
795
|
+
function isFunctionIntent(query) {
|
|
796
|
+
return /\b(functions?|callables?)\b/.test(query) && !/\bformula functions?\b/.test(query);
|
|
797
|
+
}
|
|
770
798
|
function isLinkedInKeywordPostIntent(query) {
|
|
771
799
|
return /\blinkedin\b/.test(query)
|
|
772
800
|
&& /\b(posts?|posting)\b/.test(query)
|
|
@@ -829,6 +857,11 @@ export const SEQUENCE_UNSUBSCRIBE_COMMAND = "oxygen sequences update <sequence>
|
|
|
829
857
|
*/
|
|
830
858
|
export const CAPABILITY_ROUTE_MCP_CALLS = {
|
|
831
859
|
connectedAppsList: () => ({ tool: "oxygen_connector_list", arguments: {} }),
|
|
860
|
+
connectedAppEvents: () => ({ tool: "oxygen_connector_events_get", arguments: { connection: "<app>" } }),
|
|
861
|
+
workspacePagesList: () => ({ tool: "oxygen_settings_pages_get", arguments: {} }),
|
|
862
|
+
functionsList: () => ({ tool: "oxygen_callables_manage", arguments: { operation: "list_functions" } }),
|
|
863
|
+
functionsDescribe: () => ({ tool: "oxygen_callables_manage", arguments: { operation: "describe", function: "<function>" } }),
|
|
864
|
+
functionsRuns: () => ({ tool: "oxygen_callables_manage", arguments: { operation: "runs", function: "<function>" } }),
|
|
832
865
|
sequenceSendingSchedule: () => ({
|
|
833
866
|
tool: "oxygen_sequences_update",
|
|
834
867
|
arguments: { sequence: "<sequence>", sending_schedule: { timezone: "<IANA zone>", days: [1, 2, 3, 4, 5], start: "09:00", end: "17:00" } },
|
|
@@ -939,6 +972,12 @@ function isOpenLinkedInRequestsIntent(query) {
|
|
|
939
972
|
function isConnectedAppsIntent(query) {
|
|
940
973
|
if (/\bconnected apps?\b/.test(query))
|
|
941
974
|
return true;
|
|
975
|
+
// The command group's own noun. Tables' "connect" term prefix-matches it, so
|
|
976
|
+
// `commands search connectors` returned no `connectors` command at all
|
|
977
|
+
// (CLI acceptance judge, 2026-09-30). Bare noun only: a provider's connector
|
|
978
|
+
// ("hubspot connector") is never claimed here.
|
|
979
|
+
if (/^(?:(?:list|show|see|my|our|all|the|mcp|app|apps|ai|oauth)\s+)*connectors?$/.test(query))
|
|
980
|
+
return true;
|
|
942
981
|
const connection = /\b(oauth (?:apps?|clients?|connections?|grants?)|mcp (?:clients?|connections?|connectors?))\b/.test(query);
|
|
943
982
|
const app = connection || /\b(chatgpt|claude|codex|ai (?:apps?|assistants?|clients?))\b/.test(query);
|
|
944
983
|
if (!app)
|
|
@@ -949,9 +988,100 @@ function isConnectedAppsIntent(query) {
|
|
|
949
988
|
&& /\b(default|always|without asking|which|per (?:app|connection|client))\b/.test(query);
|
|
950
989
|
return workspaceChoice || (connection && /\b(list|show|see|which|my)\b/.test(query));
|
|
951
990
|
}
|
|
991
|
+
/**
|
|
992
|
+
* What OXYGEN sends a connected app (MCP Events, ADR 0030 §10): "what is
|
|
993
|
+
* ChatGPT subscribed to", "what did OXYGEN send it", "stop it". Both blind
|
|
994
|
+
* baselines of 2026-09-30 (OXP-11.5.22) searched exactly these words — connector
|
|
995
|
+
* event subscriptions, deliveries, webhook, notifications, push — and were
|
|
996
|
+
* handed the inbound provider-webhook tools instead. A billing subscription or a
|
|
997
|
+
* provider's events ("hubspot webhook") never matches.
|
|
998
|
+
*/
|
|
999
|
+
function isConnectedAppEventsIntent(query) {
|
|
1000
|
+
if (/\b(plans?|billing|invoices?|credits?|upgrade|downgrade|stripe|pricing|price)\b/.test(query))
|
|
1001
|
+
return false;
|
|
1002
|
+
if (/\b(hubspot|slack|gmail|calendly|cal\.?com|salesforce|pipedrive|zapier|integrations?|providers?|workflows?|triggers?)\b/.test(query))
|
|
1003
|
+
return false;
|
|
1004
|
+
const app = /\b(chatgpt|claude|codex|connected apps?|connectors?|connections?|apps?|ai (?:assistants?|clients?)|mcp)\b/.test(query);
|
|
1005
|
+
const events = /\b(subscri\w*|events?|webhooks?|notif\w*|push(?:es|ed)?|deliver(?:y|ies|ed)?|sen[dt]s?)\b/.test(query);
|
|
1006
|
+
if (!app || !events)
|
|
1007
|
+
return false;
|
|
1008
|
+
// "send a LinkedIn message from my app" is outreach, not what OXYGEN sends the app.
|
|
1009
|
+
return !/\b(linkedin|email|emails|whatsapp|message|messages|sequence|sequences|campaign|outreach|post|posts)\b/.test(query);
|
|
1010
|
+
}
|
|
1011
|
+
/**
|
|
1012
|
+
* What a connected app may spend (ADR 0030 §11): "how much can ChatGPT spend on
|
|
1013
|
+
* its own in a day", "cap it at 300 credits". Both blind baselines of
|
|
1014
|
+
* 2026-09-30 (OXP-11.5.23) searched for a per-connection daily credit limit and
|
|
1015
|
+
* found only workspace budgets. A sender's or channel's daily limit is not this.
|
|
1016
|
+
*/
|
|
1017
|
+
function isConnectedAppSpendIntent(query) {
|
|
1018
|
+
const app = /\b(chatgpt|claude|codex|connected apps?|connectors?|connections?|per[- ]connection|mcp)\b/.test(query);
|
|
1019
|
+
const spend = /\b(spend\w*|credits?|budgets?|ceilings?|caps?|capped|limits?)\b/.test(query);
|
|
1020
|
+
if (!app || !spend)
|
|
1021
|
+
return false;
|
|
1022
|
+
return !/\b(linkedin|senders?|mailbox(?:es)?|sequences?|email|emails|whatsapp|warm\s?up|invites?|rate)\b/.test(query);
|
|
1023
|
+
}
|
|
1024
|
+
/**
|
|
1025
|
+
* The web app's sidebar pages a workspace hides for every member (Settings →
|
|
1026
|
+
* Customise, `settings pages`). Both blind baselines of 2026-09-30 searched
|
|
1027
|
+
* "hide navigation pages sidebar", "customise pages", "pages visibility", "nav
|
|
1028
|
+
* items" and "workspace navigation hidden pages unibox publishing workflows",
|
|
1029
|
+
* and were routed to workspace access, Publishing or nowhere. A sidebar or
|
|
1030
|
+
* navigation noun is enough on its own; "pages" plus a hide/show word is not
|
|
1031
|
+
* when the pages are wiki, LinkedIn, web, PDF or result pages.
|
|
1032
|
+
*/
|
|
1033
|
+
function isWorkspacePagesIntent(query) {
|
|
1034
|
+
// "Sales Nav" is LinkedIn Sales Navigator.
|
|
1035
|
+
if (/\bsales ?nav/.test(query))
|
|
1036
|
+
return false;
|
|
1037
|
+
if (/\b(side ?bars?|side ?nav\w*|side ?menus?|nav ?bars?|nav|navigation|left (?:menu|nav\w*|rail|panel)|main menu)\b/.test(query))
|
|
1038
|
+
return true;
|
|
1039
|
+
// "Menu items" alone is as likely a restaurant's menu as the app's.
|
|
1040
|
+
if (/\bmenu items?\b/.test(query) && /\b(hid(?:e|es|den|ing)|unhide|show(?:s|n|ing)?|visib\w*|customi[sz]\w*)\b/.test(query))
|
|
1041
|
+
return true;
|
|
1042
|
+
if (/\bcustomi[sz](?:e|es|ed|ing|ation)\b/.test(query) && /\b(pages?|menus?)\b/.test(query))
|
|
1043
|
+
return true;
|
|
1044
|
+
// The web page's own name: Settings → Customise.
|
|
1045
|
+
if (/^customi[sz]e$|\bsettings?\W{1,5}customi[sz]e\b/.test(query))
|
|
1046
|
+
return true;
|
|
1047
|
+
if (/\b(wiki|linkedin|compan(?:y|ies)|landing|web ?pages?|websites?|carousels?|pdfs?|paginat\w*|next page|per page|page size|results?|dashboards?|rows?|columns?)\b/.test(query))
|
|
1048
|
+
return false;
|
|
1049
|
+
return /\bpages?\b/.test(query) && /\b(hid(?:e|es|den|ing)|unhide|show(?:s|n|ing)?|visib\w*|invisible)\b/.test(query);
|
|
1050
|
+
}
|
|
1051
|
+
/**
|
|
1052
|
+
* "Organisation settings" (the web's own name for /settings), "workspace
|
|
1053
|
+
* settings", "org settings": the CLI and MCP half of those settings is the
|
|
1054
|
+
* sidebar pages pair. A settings ask that names its own owner (billing, API
|
|
1055
|
+
* keys, members, a connected app, a provider) keeps that owner.
|
|
1056
|
+
*/
|
|
1057
|
+
function isWorkspaceSettingsIntent(query) {
|
|
1058
|
+
if (/\b(billing|plans?|credits?|invoices?|api keys?|members?|invit\w*|seats?|roles?|connected apps?|connectors?|chatgpt|claude|codex|integrations?|providers?|mailbox(?:es)?|senders?|sequences?|linkedin)\b/.test(query))
|
|
1059
|
+
return false;
|
|
1060
|
+
return /\b(workspace|organi[sz]ations?|orgs?|team)\s+settings?\b/.test(query)
|
|
1061
|
+
|| /\bsettings?\s+(?:for|of)\s+(?:the |my |our |this )?(workspace|organi[sz]ation|org|team)\b/.test(query);
|
|
1062
|
+
}
|
|
1063
|
+
function isTableCapacityReadIntent(query) {
|
|
1064
|
+
if (/\b(monitor|watch|workflow|automate|automation|increase|resize|upgrade)\b/.test(query))
|
|
1065
|
+
return false;
|
|
1066
|
+
return /\b(largest|biggest) tables?\b/.test(query)
|
|
1067
|
+
|| /\btables?\b.{0,30}\b(sizes?|row counts?)\b/.test(query)
|
|
1068
|
+
|| /\b(sizes?|row counts?)\b.{0,30}\btables?\b/.test(query);
|
|
1069
|
+
}
|
|
1070
|
+
function isCompanySourcingIntent(query) {
|
|
1071
|
+
if (/\b(enrich\w*|existing|these|those|rows?|columns?|verify|verification|emails?|phones?|contacts?|people|persons?)\b/.test(query))
|
|
1072
|
+
return false;
|
|
1073
|
+
return /\b(companies|businesses|firms|company search|company sourcing)\b/.test(query)
|
|
1074
|
+
&& /\b(search|plan|find|source|sourcing|discover|build|tam|prospect)\b/.test(query);
|
|
1075
|
+
}
|
|
952
1076
|
function explicitCapabilityIntent(query) {
|
|
953
|
-
if (isConnectedAppsIntent(query))
|
|
1077
|
+
if (isConnectedAppsIntent(query) || isConnectedAppEventsIntent(query) || isConnectedAppSpendIntent(query)) {
|
|
1078
|
+
return ROUTE_BY_ID.get("workspace-access") ?? null;
|
|
1079
|
+
}
|
|
1080
|
+
// Ahead of every primitive rule: the pages a workspace hides are NAMED after
|
|
1081
|
+
// primitives ("hide Publishing and Workflows"), which those rules would claim.
|
|
1082
|
+
if (isWorkspacePagesIntent(query) || isWorkspaceSettingsIntent(query)) {
|
|
954
1083
|
return ROUTE_BY_ID.get("workspace-access") ?? null;
|
|
1084
|
+
}
|
|
955
1085
|
if (/\b(infographic|graphic designer|render html|carousel pages|visual design|gtm flow image)\b/.test(query))
|
|
956
1086
|
return ROUTE_BY_ID.get("visual-rendering") ?? null;
|
|
957
1087
|
if (isUgcIntent(query))
|
|
@@ -962,6 +1092,8 @@ function explicitCapabilityIntent(query) {
|
|
|
962
1092
|
return ROUTE_BY_ID.get("connected-linkedin") ?? null;
|
|
963
1093
|
if (isCompanyPageFollowersIntent(query))
|
|
964
1094
|
return ROUTE_BY_PRIMITIVE.get("tables") ?? null;
|
|
1095
|
+
if (isTableCapacityReadIntent(query))
|
|
1096
|
+
return ROUTE_BY_PRIMITIVE.get("tables") ?? null;
|
|
965
1097
|
// A whole-motion ask ("set up inbound-led outbound for my posts") is a
|
|
966
1098
|
// Recipe kit + playbook, not the connected-LinkedIn signals card that the
|
|
967
1099
|
// "my LinkedIn … engagers" rule below would otherwise claim. Resolve it first.
|
|
@@ -998,6 +1130,10 @@ function explicitCapabilityIntent(query) {
|
|
|
998
1130
|
// claimed "a first comment on my LinkedIn post" and "... automatically".
|
|
999
1131
|
if (isFirstCommentIntent(query))
|
|
1000
1132
|
return ROUTE_BY_PRIMITIVE.get("publishing") ?? null;
|
|
1133
|
+
// Publish/approve are writes even when the noun is a public LinkedIn post.
|
|
1134
|
+
// The 2026-09-30 connector baseline offered the cookieless read owner first.
|
|
1135
|
+
if (isPublishingPostIntent(query))
|
|
1136
|
+
return ROUTE_BY_PRIMITIVE.get("publishing") ?? null;
|
|
1001
1137
|
if (isLinkedInKeywordPostIntent(query))
|
|
1002
1138
|
return ROUTE_BY_ID.get("signals") ?? null;
|
|
1003
1139
|
// Ahead of the workflow rule, whose "retry" would claim it. Why a post failed and how to get it out is Publishing's attempt ledger and
|
|
@@ -1014,6 +1150,8 @@ function explicitCapabilityIntent(query) {
|
|
|
1014
1150
|
return ROUTE_BY_PRIMITIVE.get("sequences") ?? null;
|
|
1015
1151
|
if (isHostedWorkflowIntent(query))
|
|
1016
1152
|
return ROUTE_BY_PRIMITIVE.get("workflows") ?? null;
|
|
1153
|
+
if (isCompanySourcingIntent(query))
|
|
1154
|
+
return ROUTE_BY_ID.get("sourcing-and-provider-tools") ?? null;
|
|
1017
1155
|
if (isOwnedPostCommentIntent(query))
|
|
1018
1156
|
return ROUTE_BY_PRIMITIVE.get("posts") ?? null;
|
|
1019
1157
|
// Asking a second party to decide is Collaboration even when the thing being
|
|
@@ -1202,6 +1340,12 @@ export const LOCAL_BUSINESS_SCRAPE_COMMAND = `oxygen companies search preview --
|
|
|
1202
1340
|
function isLocalBusinessIntent(query) {
|
|
1203
1341
|
return /\b(local business(?:es)?|google maps|maps listings?|storefronts?|near me|(?:dental|medical|law|veterinary) (?:practices?|offices?|clinics?)|dentists?|restaurants?|cafes?|coffee shops?|gyms?|salons?|plumbers?|electricians?|contractors?|hvac|auto repair|real estate agents?|businesses (?:in|near|around) [a-z])\b/.test(query);
|
|
1204
1342
|
}
|
|
1343
|
+
function isPublishingPostIntent(query) {
|
|
1344
|
+
return /\b(posts?|publishing|content calendar)\b/.test(query)
|
|
1345
|
+
&& /\b(publish|publishing|schedule|scheduled|approve|approval)\b/.test(query)
|
|
1346
|
+
&& !/\b(workflow|automation|automate|webhook|cron)\b/.test(query)
|
|
1347
|
+
&& !(/\b(find|search|scrape|research)\b/.test(query) && /\b(about|mention|containing)\b/.test(query));
|
|
1348
|
+
}
|
|
1205
1349
|
function recommendationsFor(card, query) {
|
|
1206
1350
|
// A program's lifecycle and a creator's voice are UGC work the Publishing card
|
|
1207
1351
|
// also claims ("archive program", "creator voice"); before these they got the
|
|
@@ -1261,6 +1405,22 @@ function recommendationsFor(card, query) {
|
|
|
1261
1405
|
exactMcpCall: CAPABILITY_ROUTE_MCP_CALLS.localBusinessScrape(),
|
|
1262
1406
|
};
|
|
1263
1407
|
}
|
|
1408
|
+
if (card.id === "workspace-access" && isConnectedAppSpendIntent(query)) {
|
|
1409
|
+
return {
|
|
1410
|
+
tools: ["oxygen_connector_list", "oxygen_connector_update", "oxygen_limits_show"],
|
|
1411
|
+
commands: ["connectors get", "connectors set", "limits show"],
|
|
1412
|
+
exactCommand: "oxygen connectors get <app> --json",
|
|
1413
|
+
exactMcpCall: CAPABILITY_ROUTE_MCP_CALLS.connectedAppsList(),
|
|
1414
|
+
};
|
|
1415
|
+
}
|
|
1416
|
+
if (card.id === "workspace-access" && isConnectedAppEventsIntent(query)) {
|
|
1417
|
+
return {
|
|
1418
|
+
tools: ["oxygen_connector_events_get", "oxygen_connector_events_revoke", "oxygen_connector_list"],
|
|
1419
|
+
commands: ["connectors events get", "connectors events revoke", "connectors list"],
|
|
1420
|
+
exactCommand: "oxygen connectors events get <app> --json",
|
|
1421
|
+
exactMcpCall: CAPABILITY_ROUTE_MCP_CALLS.connectedAppEvents(),
|
|
1422
|
+
};
|
|
1423
|
+
}
|
|
1264
1424
|
if (card.id === "workspace-access" && isConnectedAppsIntent(query)) {
|
|
1265
1425
|
return {
|
|
1266
1426
|
tools: ["oxygen_connector_list", "oxygen_connector_update"],
|
|
@@ -1269,6 +1429,43 @@ function recommendationsFor(card, query) {
|
|
|
1269
1429
|
exactMcpCall: CAPABILITY_ROUTE_MCP_CALLS.connectedAppsList(),
|
|
1270
1430
|
};
|
|
1271
1431
|
}
|
|
1432
|
+
if (card.id === "workspace-access" && isWorkspacePagesIntent(query)) {
|
|
1433
|
+
return {
|
|
1434
|
+
tools: ["oxygen_settings_pages_get", "oxygen_settings_pages_update"],
|
|
1435
|
+
commands: ["settings pages list", "settings pages set"],
|
|
1436
|
+
exactCommand: "oxygen settings pages list --json",
|
|
1437
|
+
exactMcpCall: CAPABILITY_ROUTE_MCP_CALLS.workspacePagesList(),
|
|
1438
|
+
};
|
|
1439
|
+
}
|
|
1440
|
+
// A general settings ask: the pages pair is the settings CLI and MCP can change.
|
|
1441
|
+
if (card.id === "workspace-access" && isWorkspaceSettingsIntent(query)) {
|
|
1442
|
+
return {
|
|
1443
|
+
tools: ["oxygen_settings_pages_get", "oxygen_settings_pages_update", ...card.gatewayTools],
|
|
1444
|
+
commands: ["settings pages list", "settings pages set", ...card.gatewayCommands],
|
|
1445
|
+
};
|
|
1446
|
+
}
|
|
1447
|
+
// Contact enrichment keeps its own gateway even when the input mentions
|
|
1448
|
+
// company names or domains; those words do not make it account sourcing.
|
|
1449
|
+
if (card.id === "sourcing-and-provider-tools" && /\bfind (?:work )?emails?\b/.test(query))
|
|
1450
|
+
return {
|
|
1451
|
+
tools: ["oxygen_find_email", "oxygen_tools_search"], commands: ["find email", "tools search"],
|
|
1452
|
+
};
|
|
1453
|
+
if (card.id === "sourcing-and-provider-tools" && /\bfind (?:mobile )?phones?\b/.test(query))
|
|
1454
|
+
return {
|
|
1455
|
+
tools: ["oxygen_find_phone", "oxygen_tools_search"], commands: ["find phone", "tools search"],
|
|
1456
|
+
};
|
|
1457
|
+
if (card.id === "sourcing-and-provider-tools" && (isCompanySourcingIntent(query) || /\b(companies|company search|company sourcing)\b/.test(query))) {
|
|
1458
|
+
return {
|
|
1459
|
+
tools: ["oxygen_companies_search_plan", "oxygen_companies_search_preview", "oxygen_companies_search_run", ...(/\b(people|contacts)\b/.test(query) ? ["oxygen_people_search_plan"] : [])],
|
|
1460
|
+
commands: ["companies search plan", "companies search preview", "companies search run", ...(/\b(people|contacts)\b/.test(query) ? ["people search plan"] : [])],
|
|
1461
|
+
};
|
|
1462
|
+
}
|
|
1463
|
+
if (card.id === "sourcing-and-provider-tools" && /\b(people|contacts|personas?)\b/.test(query)) {
|
|
1464
|
+
return {
|
|
1465
|
+
tools: ["oxygen_people_search_plan", "oxygen_people_search_preview", "oxygen_people_search_run"],
|
|
1466
|
+
commands: ["people search plan", "people search preview", "people search run"],
|
|
1467
|
+
};
|
|
1468
|
+
}
|
|
1272
1469
|
if (card.id === "connected-linkedin" && isLinkedInAccountConnectIntent(query)) {
|
|
1273
1470
|
return {
|
|
1274
1471
|
tools: ["oxygen_senders_connect", "oxygen_senders_list", "oxygen_billing_commitments"],
|
|
@@ -1371,6 +1568,56 @@ function recommendationsFor(card, query) {
|
|
|
1371
1568
|
};
|
|
1372
1569
|
}
|
|
1373
1570
|
if (card.primitive === "tables") {
|
|
1571
|
+
if (isTableCapacityReadIntent(query))
|
|
1572
|
+
return {
|
|
1573
|
+
tools: ["oxygen_limits_show", "oxygen_tables_query", "oxygen_tables_describe"],
|
|
1574
|
+
commands: ["limits show", "tables query", "tables describe"],
|
|
1575
|
+
exactMcpCall: { tool: "oxygen_limits_show", arguments: {} },
|
|
1576
|
+
};
|
|
1577
|
+
if (isFunctionIntent(query)) {
|
|
1578
|
+
if (/\b(?:list|show|read|see|my)\b.{0,30}\bfavou?rites?\b/.test(query))
|
|
1579
|
+
return {
|
|
1580
|
+
tools: ["oxygen_callables_manage"], commands: ["functions list", "functions describe"],
|
|
1581
|
+
exactMcpCall: { tool: "oxygen_callables_manage", arguments: { operation: "list_functions", filter: "favorites" } },
|
|
1582
|
+
};
|
|
1583
|
+
if (/\b(runs|invocations?|history)\b/.test(query))
|
|
1584
|
+
return {
|
|
1585
|
+
tools: ["oxygen_callables_manage"], commands: ["functions runs", "functions describe"],
|
|
1586
|
+
exactMcpCall: CAPABILITY_ROUTE_MCP_CALLS.functionsRuns(),
|
|
1587
|
+
};
|
|
1588
|
+
const functionMutation = [
|
|
1589
|
+
[/\b(publish)\b/, "functions publish"],
|
|
1590
|
+
[/\b(bind|attach)\b/, "functions bind"],
|
|
1591
|
+
[/\b(rename)\b/, "functions rename"],
|
|
1592
|
+
[/\b(delete|remove)\b/, "functions delete"],
|
|
1593
|
+
[/\b(duplicate|copy)\b/, "functions duplicate"],
|
|
1594
|
+
[/\b(unfavorite|unfavourite)\b/, "functions unfavorite"],
|
|
1595
|
+
[/\b(favorite|favourite)\b/, "functions favorite"],
|
|
1596
|
+
[/\b(enable|disable)\b/, /\bdisable\b/.test(query) ? "functions disable" : "functions enable"],
|
|
1597
|
+
[/\b(create|save|edit)\b/, "functions draft"],
|
|
1598
|
+
];
|
|
1599
|
+
const mutation = functionMutation.find(([pattern]) => pattern.test(query));
|
|
1600
|
+
if (mutation)
|
|
1601
|
+
return {
|
|
1602
|
+
tools: ["oxygen_callables_manage"],
|
|
1603
|
+
commands: [/\bcreate\b/.test(query) ? "functions list" : "functions describe", mutation[1]],
|
|
1604
|
+
exactMcpCall: /\bcreate\b/.test(query) ? CAPABILITY_ROUTE_MCP_CALLS.functionsList() : CAPABILITY_ROUTE_MCP_CALLS.functionsDescribe(),
|
|
1605
|
+
};
|
|
1606
|
+
if (/\b(run|execute|invoke)\b/.test(query))
|
|
1607
|
+
return {
|
|
1608
|
+
tools: ["oxygen_callables_manage", "oxygen_columns_run"], commands: ["functions describe", "columns run"],
|
|
1609
|
+
exactMcpCall: CAPABILITY_ROUTE_MCP_CALLS.functionsDescribe(),
|
|
1610
|
+
};
|
|
1611
|
+
if (/\b(describe|inspect|inputs?|outputs?|steps?|caps?|version|details?)\b/.test(query))
|
|
1612
|
+
return {
|
|
1613
|
+
tools: ["oxygen_callables_manage"], commands: ["functions describe", "functions runs"],
|
|
1614
|
+
exactMcpCall: CAPABILITY_ROUTE_MCP_CALLS.functionsDescribe(),
|
|
1615
|
+
};
|
|
1616
|
+
return {
|
|
1617
|
+
tools: ["oxygen_callables_manage"], commands: ["functions list", "functions describe"],
|
|
1618
|
+
exactMcpCall: { ...CAPABILITY_ROUTE_MCP_CALLS.functionsList(), ...(/\b(favorites|favourites)\b/.test(query) ? { arguments: { operation: "list_functions", filter: "favorites" } } : {}) },
|
|
1619
|
+
};
|
|
1620
|
+
}
|
|
1374
1621
|
if (isLinkedInProfileWatcherIntent(query)) {
|
|
1375
1622
|
return {
|
|
1376
1623
|
tools: ["oxygen_tables_watcher"],
|
|
@@ -1527,6 +1774,14 @@ function recommendationsFor(card, query) {
|
|
|
1527
1774
|
],
|
|
1528
1775
|
};
|
|
1529
1776
|
}
|
|
1777
|
+
// Inspect reusable bundles before authoring a new recurring monitor. This
|
|
1778
|
+
// does not assume a matching seed exists; list/describe/preflight establish
|
|
1779
|
+
// that. Existing run inspection still belongs to tail/list below.
|
|
1780
|
+
if (/\b(monitor|monitoring|watch|watching)\b/.test(query) && !/\b(existing|status|failed|failure|logs?|tail|cancel|pause|resume|disable|enable)\b/.test(query))
|
|
1781
|
+
return {
|
|
1782
|
+
tools: ["oxygen_blueprints_list", "oxygen_blueprints_describe", "oxygen_blueprints_preflight", "oxygen_workflows_schema", "oxygen_workflows_lint"],
|
|
1783
|
+
commands: ["blueprints list", "blueprints describe", "blueprints preflight", "workflows schema", "workflows lint"],
|
|
1784
|
+
};
|
|
1530
1785
|
if (/\b(workflow )?templates?\b/.test(query)) {
|
|
1531
1786
|
return {
|
|
1532
1787
|
tools: ["oxygen_workflow_templates_search", "oxygen_workflow_templates_describe", "oxygen_workflow_templates_preflight", "oxygen_workflow_templates_apply"],
|
|
@@ -1781,7 +2036,8 @@ function isOwnedPostCommentIntent(query) {
|
|
|
1781
2036
|
return owned || operatorWork;
|
|
1782
2037
|
}
|
|
1783
2038
|
function isHostedWorkflowIntent(query) {
|
|
1784
|
-
const strongWorkflowLanguage = /\b(workflow|automation|automate|automatically|webhook|cron|event trigger|branching?|retr(?:y|ies)|orchestrat(?:e|ion)|scheduled job|deterministic graph)\b/.test(query)
|
|
2039
|
+
const strongWorkflowLanguage = /\b(workflow|automation|automate|automatically|webhook|cron|event trigger|branching?|retr(?:y|ies)|orchestrat(?:e|ion)|scheduled job|deterministic graph)\b/.test(query)
|
|
2040
|
+
|| isRecurringCompanyMonitoringIntent(query);
|
|
1785
2041
|
const cadenceLanguage = /\b(sequence|campaign|cadence|day\s*\d+|multi[ -]step|rotate senders?|sender rotation|stop on reply|until (?:they )?reply)\b/.test(query);
|
|
1786
2042
|
const workflowMechanics = /\b(webhook|cron|event trigger|triggered by|branching?|retr(?:y|ies)|orchestrat(?:e|ion)|scheduled job|deterministic graph|automatically)\b/.test(query)
|
|
1787
2043
|
|| /\bwhen\b.{0,50}\b(signs? up|created|updated|changes?|happens?|received)\b/.test(query);
|
|
@@ -1794,6 +2050,11 @@ function isHostedWorkflowIntent(query) {
|
|
|
1794
2050
|
return /\b(nightly|hourly|daily|weekly|every (?:monday|tuesday|wednesday|thursday|friday|saturday|sunday|day|night|week|month))\b/.test(query)
|
|
1795
2051
|
|| (/\bschedule(?:d)?\b/.test(query) && !/\bpost|content\b/.test(query));
|
|
1796
2052
|
}
|
|
2053
|
+
function isRecurringCompanyMonitoringIntent(query) {
|
|
2054
|
+
return /\b(companies|company|competitors?)\b/.test(query)
|
|
2055
|
+
&& /\b(monitor(?:ing)?|watch(?:ing|list)?|track(?:ing)?)\b/.test(query)
|
|
2056
|
+
&& /\b(recurring|periodic|repeat(?:ed|able)?|over time|new observations?)\b/.test(query);
|
|
2057
|
+
}
|
|
1797
2058
|
function isPublicLinkedInRead(query) {
|
|
1798
2059
|
if (!query.includes("linkedin"))
|
|
1799
2060
|
return false;
|
|
@@ -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
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
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>;
|