@oxygen-agent/cli 1.1011.974 → 1.1012.2
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.d.ts +3 -1
- package/dist/command-manifest.js +29 -0
- package/dist/crm-support-flags.d.ts +1 -0
- package/dist/crm-support-flags.js +5 -1
- package/dist/customer-operation-commands.js +30 -1
- package/dist/help.js +10 -2
- package/dist/http-client.d.ts +4 -0
- package/dist/http-client.js +21 -10
- package/dist/index.js +326 -111
- package/dist/sender-limits-flags.d.ts +7 -0
- package/dist/sender-limits-flags.js +13 -0
- package/dist/transcript.js +1 -1
- package/node_modules/@oxygen/formula/dist/expression.js +16 -0
- package/node_modules/@oxygen/shared/dist/attempt-provenance.d.ts +30 -0
- package/node_modules/@oxygen/shared/dist/attempt-provenance.js +98 -0
- package/node_modules/@oxygen/shared/dist/byok-connect.js +2 -0
- package/node_modules/@oxygen/shared/dist/capability-discovery.d.ts +8 -1
- package/node_modules/@oxygen/shared/dist/capability-discovery.js +172 -13
- package/node_modules/@oxygen/shared/dist/cli-result.js +6 -0
- package/node_modules/@oxygen/shared/dist/contracts/browser-operations.js +19 -7
- package/node_modules/@oxygen/shared/dist/contracts/crm-attributes.d.ts +7 -1
- package/node_modules/@oxygen/shared/dist/contracts/crm-attributes.js +5 -1
- package/node_modules/@oxygen/shared/dist/contracts/crm-support.d.ts +14 -0
- package/node_modules/@oxygen/shared/dist/contracts/crm-support.js +4 -0
- package/node_modules/@oxygen/shared/dist/contracts/customer-operations.js +5 -5
- package/node_modules/@oxygen/shared/dist/contracts/geo.d.ts +2 -0
- package/node_modules/@oxygen/shared/dist/contracts/geo.js +138 -0
- package/node_modules/@oxygen/shared/dist/contracts/operations.d.ts +6 -0
- package/node_modules/@oxygen/shared/dist/contracts/operations.js +4 -3
- package/node_modules/@oxygen/shared/dist/contracts/publishing-reads.js +1 -0
- package/node_modules/@oxygen/shared/dist/contracts/table-row-removal.d.ts +16 -0
- package/node_modules/@oxygen/shared/dist/contracts/table-row-removal.js +27 -0
- package/node_modules/@oxygen/shared/dist/cost-estimate.d.ts +6 -0
- package/node_modules/@oxygen/shared/dist/cost-estimate.js +23 -8
- package/node_modules/@oxygen/shared/dist/enrichment-intents.js +2 -1
- package/node_modules/@oxygen/shared/dist/external-effect-arming.d.ts +54 -0
- package/node_modules/@oxygen/shared/dist/external-effect-arming.js +90 -0
- package/node_modules/@oxygen/shared/dist/geo.d.ts +247 -0
- package/node_modules/@oxygen/shared/dist/geo.js +314 -0
- package/node_modules/@oxygen/shared/dist/knowledge-seed-content.js +2 -2
- package/node_modules/@oxygen/shared/dist/linkedin-countries.d.ts +9 -0
- package/node_modules/@oxygen/shared/dist/linkedin-countries.js +1 -1
- package/node_modules/@oxygen/shared/dist/linkedin-quota-denial.d.ts +48 -0
- package/node_modules/@oxygen/shared/dist/linkedin-quota-denial.js +94 -0
- package/node_modules/@oxygen/shared/dist/managed-email-branding.d.ts +15 -0
- package/node_modules/@oxygen/shared/dist/managed-email-branding.js +81 -0
- package/node_modules/@oxygen/shared/dist/pricing-sheet.d.ts +20 -24
- package/node_modules/@oxygen/shared/dist/pricing-sheet.js +15 -16
- package/node_modules/@oxygen/shared/dist/pricing-snapshot.generated.d.ts +3 -3
- package/node_modules/@oxygen/shared/dist/pricing-snapshot.generated.js +3 -3
- package/node_modules/@oxygen/shared/dist/product-doctrine.js +6 -5
- package/node_modules/@oxygen/shared/dist/provider-balance-signal.js +3 -2
- package/node_modules/@oxygen/shared/dist/recipes.d.ts +1 -1
- package/node_modules/@oxygen/shared/dist/recipes.js +1 -0
- package/node_modules/@oxygen/shared/dist/repricing.d.ts +4 -14
- package/node_modules/@oxygen/shared/dist/repricing.js +25 -64
- package/node_modules/@oxygen/shared/dist/research-depth.d.ts +11 -0
- package/node_modules/@oxygen/shared/dist/research-depth.js +7 -0
- package/node_modules/@oxygen/shared/dist/version.d.ts +1 -1
- 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/dist/version.js +1 -1
- package/node_modules/@oxygen/shared/dist/whatsapp-sender-limits.d.ts +88 -0
- package/node_modules/@oxygen/shared/dist/whatsapp-sender-limits.js +118 -0
- package/node_modules/@oxygen/shared/dist/workflow-trigger-metadata.d.ts +15 -0
- package/node_modules/@oxygen/shared/dist/workflow-trigger-metadata.js +33 -0
- package/node_modules/@oxygen/shared/package.json +15 -5
- package/node_modules/@oxygen/workflows/dist/usage-estimate.js +9 -5
- package/package.json +1 -1
- package/node_modules/@oxygen/shared/dist/vercel-sandbox-fetch.d.ts +0 -9
- package/node_modules/@oxygen/shared/dist/vercel-sandbox-fetch.js +0 -33
|
@@ -1,4 +1,11 @@
|
|
|
1
|
+
import type { Command } from "commander";
|
|
1
2
|
import { type ContractFlagOverlay } from "./contract-flags.js";
|
|
3
|
+
/**
|
|
4
|
+
* `whatsapp limits set`: one flag per key the WhatsApp limits route keeps, with
|
|
5
|
+
* the WhatsApp defaults and maximums from the shared owner (OXP-11.3.19). The
|
|
6
|
+
* body is still built by buildSenderLimitsBody, which reads the same flag names.
|
|
7
|
+
*/
|
|
8
|
+
export declare function addWhatsAppLimitFlags(command: Command): Command;
|
|
2
9
|
/**
|
|
3
10
|
* `--working-days` → ISO weekday numbers. Accepts day names or 1-7, comma
|
|
4
11
|
* separated, and ranges (`mon-fri`, `1-5`). A token it cannot read is sent as
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import { OxygenError } from "@oxygen/shared/cli-result";
|
|
6
6
|
import { LINKEDIN_SENDER_LIMIT_DEFAULTS, LINKEDIN_SENDER_LIMIT_MAXIMUMS, linkedInSenderLimitCautionLevel, } from "@oxygen/shared/linkedin-sequences";
|
|
7
7
|
import { SENDER_LIMITS_PATCH_CONTRACT } from "@oxygen/shared/contracts/sender-limits";
|
|
8
|
+
import { WHATSAPP_SENDER_LIMIT_DEFAULTS, WHATSAPP_SENDER_LIMIT_KEYS, WHATSAPP_SENDER_LIMIT_MAXIMUMS, WHATSAPP_SENDER_LIMIT_NOTES, } from "@oxygen/shared/whatsapp-sender-limits";
|
|
8
9
|
import { readContractFlags } from "./contract-flags.js";
|
|
9
10
|
/** "<text> (default N, max M)." for a LinkedIn sender limit flag, from the enforced constants. */
|
|
10
11
|
function linkedInLimitHelp(key, text) {
|
|
@@ -48,6 +49,18 @@ const LIMIT_FLAG_NAMES = {
|
|
|
48
49
|
min_action_spacing_seconds: "min-spacing-seconds",
|
|
49
50
|
action_spacing_jitter_seconds: "spacing-jitter-seconds",
|
|
50
51
|
};
|
|
52
|
+
/**
|
|
53
|
+
* `whatsapp limits set`: one flag per key the WhatsApp limits route keeps, with
|
|
54
|
+
* the WhatsApp defaults and maximums from the shared owner (OXP-11.3.19). The
|
|
55
|
+
* body is still built by buildSenderLimitsBody, which reads the same flag names.
|
|
56
|
+
*/
|
|
57
|
+
export function addWhatsAppLimitFlags(command) {
|
|
58
|
+
for (const key of WHATSAPP_SENDER_LIMIT_KEYS) {
|
|
59
|
+
const flag = LIMIT_FLAG_NAMES[key] ?? key.replace(/_/g, "-");
|
|
60
|
+
command.option(`--${flag} <n>`, `${WHATSAPP_SENDER_LIMIT_NOTES[key]} (default ${WHATSAPP_SENDER_LIMIT_DEFAULTS[key]}, max ${WHATSAPP_SENDER_LIMIT_MAXIMUMS[key]}; higher values are clamped).`);
|
|
61
|
+
}
|
|
62
|
+
return command;
|
|
63
|
+
}
|
|
51
64
|
const WORKING_DAY_NAMES = {
|
|
52
65
|
mon: 1, monday: 1, tue: 2, tues: 2, tuesday: 2, wed: 3, wednesday: 3, thu: 4, thur: 4, thurs: 4, thursday: 4,
|
|
53
66
|
fri: 5, friday: 5, sat: 6, saturday: 6, sun: 7, sunday: 7,
|
package/dist/transcript.js
CHANGED
|
@@ -129,7 +129,7 @@ const SECRET_PATTERNS = [
|
|
|
129
129
|
[/\bgh[pousr]_[A-Za-z0-9]{20,}/g, "ghx_[REDACTED]"],
|
|
130
130
|
[/\bxox[baprs]-[A-Za-z0-9-]{10,}/g, "xox-[REDACTED]"],
|
|
131
131
|
[/\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{6,}/g, "[REDACTED_JWT]"],
|
|
132
|
-
[/\/skills-access\/
|
|
132
|
+
[/\/skills-access\/v[12]\.[A-Za-z0-9_-]+\.\d+\.(?:[A-Za-z0-9_-]+\.)?[A-Za-z0-9_-]+/g, "/skills-access/[REDACTED_GRANT]"],
|
|
133
133
|
[/\b(Bearer|Basic)\s+[A-Za-z0-9._~+/=-]{16,}/gi, "$1 [REDACTED]"],
|
|
134
134
|
// "secret-ish key": "value" / secret_ish_key=value (JSON + env shapes)
|
|
135
135
|
[/("?(?:api[_-]?key|apikey|secret|password|passwd|token|access[_-]?token|refresh[_-]?token|client[_-]?secret|authorization|auth[_-]?token|private[_-]?key)"?\s*[:=]\s*"?)([^"\s,}]{6,})/gi, "$1[REDACTED]"],
|
|
@@ -403,6 +403,22 @@ function tokenize(expression, options = {}) {
|
|
|
403
403
|
index += 1;
|
|
404
404
|
continue;
|
|
405
405
|
}
|
|
406
|
+
// A `{{column}}` template token is the most common paste from another tool
|
|
407
|
+
// (and from an AI or tool column's prompt here). It stays the same typed
|
|
408
|
+
// syntax error at the same position; the hint names the bare-identifier form
|
|
409
|
+
// and the expression with every token unwrapped. Nothing is accepted:
|
|
410
|
+
// `{{` is still not formula syntax (OXP-1.27.6 AC4).
|
|
411
|
+
if (char === "{" && expression[index + 1] === "{") {
|
|
412
|
+
const suggested = expression.replace(/\{\{\s*([A-Za-z_][A-Za-z0-9_]*)\s*\}\}/g, "$1");
|
|
413
|
+
const example = suggested !== expression ? suggested : "upper(company_name)";
|
|
414
|
+
throw formulaExpressionError(`Unexpected character in formula expression. Formulas name columns as bare identifiers, not {{templates}}: write ${example}.`, {
|
|
415
|
+
position: index,
|
|
416
|
+
character: char,
|
|
417
|
+
expression,
|
|
418
|
+
hint: "Formulas read columns by bare key (company_name), not {{company_name}}; {{ }} is template syntax for AI and tool column prompts.",
|
|
419
|
+
...(suggested !== expression ? { suggested_expression: suggested } : {}),
|
|
420
|
+
});
|
|
421
|
+
}
|
|
406
422
|
throw formulaExpressionError("Unexpected character in formula expression.", {
|
|
407
423
|
position: index,
|
|
408
424
|
character: char,
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The identity a request asked about versus the one a provider answered with.
|
|
3
|
+
* Present on a refused attempt; `matched` is `false` whenever it is recorded.
|
|
4
|
+
*/
|
|
5
|
+
export type AttemptIdentityMatch = {
|
|
6
|
+
matched?: boolean;
|
|
7
|
+
requested?: string | null;
|
|
8
|
+
returned?: string | null;
|
|
9
|
+
};
|
|
10
|
+
/** Label for a skipped attempt's reason. Unknown reasons stay generic. */
|
|
11
|
+
export declare function describeSkipReason(reason: string): string;
|
|
12
|
+
/**
|
|
13
|
+
* Label for a `no_result` attempt whose answer was refused rather than absent,
|
|
14
|
+
* or `null` for an ordinary empty answer (which still reads "No result").
|
|
15
|
+
*/
|
|
16
|
+
export declare function describeRejectedAnswer(reason: string | null | undefined): string | null;
|
|
17
|
+
/**
|
|
18
|
+
* One-line requested-vs-returned evidence for a refused attempt, for the cell's
|
|
19
|
+
* hover title. `null` when neither side named an identity — there is nothing to
|
|
20
|
+
* show and an empty tooltip is worse than none.
|
|
21
|
+
*/
|
|
22
|
+
export declare function describeIdentityMatch(identityMatch: AttemptIdentityMatch | null | undefined): string | null;
|
|
23
|
+
/**
|
|
24
|
+
* One provider attempt with its lane named the same way for every waterfall.
|
|
25
|
+
* Person waterfalls name a lane by `operation`; the company waterfall names it
|
|
26
|
+
* by `toolId`. Readers that key on `operation` dropped every company attempt,
|
|
27
|
+
* and with it the identity evidence the attempt carried (OXP-7.3.40), so each
|
|
28
|
+
* cell renderer normalizes through here before validating an attempt.
|
|
29
|
+
*/
|
|
30
|
+
export declare function normalizeAttemptLane(value: unknown): unknown;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Human labels for a waterfall attempt's recorded `reason`. Single source of
|
|
3
|
+
* truth for the /tables data grid (`tables-workspace.tsx`) and the MCP
|
|
4
|
+
* enrichment-cell-detail widget, so an attempt explains itself one way wherever
|
|
5
|
+
* it is shown (OXP-7.3.40).
|
|
6
|
+
*
|
|
7
|
+
* Every label is grid-cell sized — these render inside a truncated attempt cell,
|
|
8
|
+
* not a detail panel.
|
|
9
|
+
*/
|
|
10
|
+
const ATTEMPT_REASON_LABELS = {
|
|
11
|
+
missing_input: "Run condition not met",
|
|
12
|
+
// The company waterfall's spelling of `missing_input`: it needs at least one
|
|
13
|
+
// of domain / name / linkedin_url before any lane can be dispatched.
|
|
14
|
+
missing_identity_input: "Missing identity",
|
|
15
|
+
byok_not_connected: "Not connected",
|
|
16
|
+
byok_requires_paid_plan: "Plan required",
|
|
17
|
+
step_disabled: "Step disabled",
|
|
18
|
+
unsupported_credential_mode: "Mode unsupported",
|
|
19
|
+
unknown_capability: "Unknown provider",
|
|
20
|
+
// A provider answered about a DIFFERENT company than the request named. The
|
|
21
|
+
// answer was refused rather than written to the row (Plain T-111), so calling
|
|
22
|
+
// it "skipped" would describe the wrong event entirely.
|
|
23
|
+
identity_mismatch: "Wrong company",
|
|
24
|
+
// A search-shaped lane returned no identity at all, so its answer could not be
|
|
25
|
+
// checked against the requested company and was not trusted.
|
|
26
|
+
identity_unverifiable: "Identity unverified",
|
|
27
|
+
// A pre-step that ran only to resolve an identity (e.g. a company LinkedIn
|
|
28
|
+
// URL) a later requested field needs. It owns no target column and writes no
|
|
29
|
+
// cell — recorded so the extra provider call is visible, never silent.
|
|
30
|
+
identity_prerequisite: "Identity step",
|
|
31
|
+
// Bring-your-own-key lane with no usable connection for this workspace:
|
|
32
|
+
// not connected, unhealthy, missing secret, or plan-gated.
|
|
33
|
+
provider_credentials_unavailable: "No credentials",
|
|
34
|
+
// Priced above the run's approved credit ceiling, so it was never dispatched.
|
|
35
|
+
credit_ceiling_reached: "Credit cap reached",
|
|
36
|
+
// An identity pre-step lane the run stood down: the ceiling had no headroom
|
|
37
|
+
// above what the requested fields themselves need, so resolving the identity
|
|
38
|
+
// would have spent the answer-bearing lane's budget.
|
|
39
|
+
identity_prerequisite_unaffordable: "Identity step unfunded",
|
|
40
|
+
// Oxygen could not resolve a managed price for the lane, so it never ran.
|
|
41
|
+
managed_price_unavailable: "Price unavailable",
|
|
42
|
+
// The row's person LinkedIn input is a company or school page, or no profile
|
|
43
|
+
// link at all, so the row was refused before any lane ran.
|
|
44
|
+
linkedin_url_not_a_profile: "Not a profile URL",
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Reasons that mean "we got an answer and refused it", not "there was nothing
|
|
48
|
+
* to find". They arrive on an attempt whose status is `no_result`, where the
|
|
49
|
+
* bare "No result" reads as an absent answer and hides the rejection.
|
|
50
|
+
*/
|
|
51
|
+
const REJECTED_ANSWER_REASONS = new Set([
|
|
52
|
+
"identity_mismatch",
|
|
53
|
+
"identity_unverifiable",
|
|
54
|
+
]);
|
|
55
|
+
/** Label for a skipped attempt's reason. Unknown reasons stay generic. */
|
|
56
|
+
export function describeSkipReason(reason) {
|
|
57
|
+
return ATTEMPT_REASON_LABELS[reason] ?? "Skipped";
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Label for a `no_result` attempt whose answer was refused rather than absent,
|
|
61
|
+
* or `null` for an ordinary empty answer (which still reads "No result").
|
|
62
|
+
*/
|
|
63
|
+
export function describeRejectedAnswer(reason) {
|
|
64
|
+
if (!reason || !REJECTED_ANSWER_REASONS.has(reason))
|
|
65
|
+
return null;
|
|
66
|
+
return ATTEMPT_REASON_LABELS[reason] ?? null;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* One-line requested-vs-returned evidence for a refused attempt, for the cell's
|
|
70
|
+
* hover title. `null` when neither side named an identity — there is nothing to
|
|
71
|
+
* show and an empty tooltip is worse than none.
|
|
72
|
+
*/
|
|
73
|
+
export function describeIdentityMatch(identityMatch) {
|
|
74
|
+
if (!identityMatch)
|
|
75
|
+
return null;
|
|
76
|
+
const requested = typeof identityMatch.requested === "string" ? identityMatch.requested.trim() : "";
|
|
77
|
+
const returned = typeof identityMatch.returned === "string" ? identityMatch.returned.trim() : "";
|
|
78
|
+
if (!requested && !returned)
|
|
79
|
+
return null;
|
|
80
|
+
const asked = requested ? `Requested ${requested}` : "Requested company";
|
|
81
|
+
const got = returned ? `provider returned ${returned}` : "provider returned no identity";
|
|
82
|
+
return `${asked}; ${got}`;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* One provider attempt with its lane named the same way for every waterfall.
|
|
86
|
+
* Person waterfalls name a lane by `operation`; the company waterfall names it
|
|
87
|
+
* by `toolId`. Readers that key on `operation` dropped every company attempt,
|
|
88
|
+
* and with it the identity evidence the attempt carried (OXP-7.3.40), so each
|
|
89
|
+
* cell renderer normalizes through here before validating an attempt.
|
|
90
|
+
*/
|
|
91
|
+
export function normalizeAttemptLane(value) {
|
|
92
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
93
|
+
return value;
|
|
94
|
+
const record = value;
|
|
95
|
+
if (typeof record.operation === "string" || typeof record.toolId !== "string")
|
|
96
|
+
return value;
|
|
97
|
+
return { ...record, operation: record.toolId };
|
|
98
|
+
}
|
|
@@ -90,10 +90,11 @@ export declare function inferPrimitiveRoute(query: string): PrimitiveRouteMatch
|
|
|
90
90
|
*/
|
|
91
91
|
export declare const RETIRED_PRODUCT_SKILLS: readonly string[];
|
|
92
92
|
/** Current hosted instruction audiences, shared by discovery and Agent snapshots. */
|
|
93
|
-
export declare const OXYGEN_PRODUCT_SKILL_AUDIENCES: Readonly<Record<string, "workspace" | "agency_partner">>;
|
|
93
|
+
export declare const OXYGEN_PRODUCT_SKILL_AUDIENCES: Readonly<Record<string, "workspace" | "agency_partner" | "internal_dev">>;
|
|
94
94
|
export declare function canReadProductSkillInstructions(name: string, entitlements: {
|
|
95
95
|
authenticated?: boolean;
|
|
96
96
|
agencyPartner: boolean;
|
|
97
|
+
internalDev?: boolean;
|
|
97
98
|
}): boolean;
|
|
98
99
|
/** Identify hosted instruction bodies by native tool lineage, never by user prose. */
|
|
99
100
|
export declare function readProductSkillInstructionResult(capabilityName: string, result: unknown): {
|
|
@@ -119,6 +120,12 @@ export declare const SEQUENCE_UNSUBSCRIBE_COMMAND = "oxygen sequences update <se
|
|
|
119
120
|
* Factories, so a caller can edit the object it gets.
|
|
120
121
|
*/
|
|
121
122
|
export declare const CAPABILITY_ROUTE_MCP_CALLS: {
|
|
123
|
+
connectionPrices: () => {
|
|
124
|
+
tool: string;
|
|
125
|
+
arguments: {
|
|
126
|
+
view: string;
|
|
127
|
+
};
|
|
128
|
+
};
|
|
122
129
|
connectedAppsList: () => {
|
|
123
130
|
tool: string;
|
|
124
131
|
arguments: {};
|