@oxygen-agent/cli 1.1011.855 → 1.1011.1091
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/admin-lead-magnet-commands.d.ts +7 -0
- package/dist/admin-lead-magnet-commands.js +128 -0
- 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/functions-commands.js +1 -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 +444 -208
- package/dist/sender-limits-flags.d.ts +7 -0
- package/dist/sender-limits-flags.js +13 -0
- package/dist/workspace-utility-flags.d.ts +7 -0
- package/dist/workspace-utility-flags.js +45 -0
- package/node_modules/@oxygen/shared/dist/attempt-provenance.d.ts +22 -0
- package/node_modules/@oxygen/shared/dist/attempt-provenance.js +83 -0
- package/node_modules/@oxygen/shared/dist/billing-anchors.d.ts +6 -0
- package/node_modules/@oxygen/shared/dist/billing-anchors.js +7 -1
- package/node_modules/@oxygen/shared/dist/capability-discovery.d.ts +6 -0
- package/node_modules/@oxygen/shared/dist/capability-discovery.js +279 -13
- package/node_modules/@oxygen/shared/dist/cli-result.js +6 -0
- package/node_modules/@oxygen/shared/dist/contracts/browser-operations.js +21 -9
- 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 +13 -11
- package/node_modules/@oxygen/shared/dist/contracts/limits-read.js +11 -1
- package/node_modules/@oxygen/shared/dist/contracts/operations.d.ts +6 -0
- package/node_modules/@oxygen/shared/dist/contracts/publishing-reads.js +1 -0
- package/node_modules/@oxygen/shared/dist/contracts/schema.js +10 -6
- package/node_modules/@oxygen/shared/dist/contracts/spintax.d.ts +18 -0
- package/node_modules/@oxygen/shared/dist/contracts/spintax.js +11 -0
- package/node_modules/@oxygen/shared/dist/contracts/table-row-removal.d.ts +8 -0
- package/node_modules/@oxygen/shared/dist/contracts/table-row-removal.js +21 -0
- package/node_modules/@oxygen/shared/dist/contracts/workspace-utilities.d.ts +162 -0
- package/node_modules/@oxygen/shared/dist/contracts/workspace-utilities.js +46 -0
- package/node_modules/@oxygen/shared/dist/credit-topup-review.d.ts +11 -0
- package/node_modules/@oxygen/shared/dist/credit-topup-review.js +3 -0
- package/node_modules/@oxygen/shared/dist/emailguard-placement-probe.d.ts +70 -0
- package/node_modules/@oxygen/shared/dist/emailguard-placement-probe.js +161 -0
- package/node_modules/@oxygen/shared/dist/future-signup-events.d.ts +1 -1
- package/node_modules/@oxygen/shared/dist/future-signup-events.js +4 -0
- package/node_modules/@oxygen/shared/dist/knowledge-seed-content.js +2 -2
- 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/partner-coupon-bonus.d.ts +45 -0
- package/node_modules/@oxygen/shared/dist/partner-coupon-bonus.js +57 -0
- package/node_modules/@oxygen/shared/dist/provider-balance-signal.js +3 -2
- package/node_modules/@oxygen/shared/dist/table-filter-operators.d.ts +6 -0
- package/node_modules/@oxygen/shared/dist/table-filter-operators.js +50 -0
- package/node_modules/@oxygen/shared/dist/telemetry.js +4 -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 +42 -0
- package/node_modules/@oxygen/shared/dist/whatsapp-sender-limits.js +68 -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 +5 -5
- package/node_modules/@oxygen/workflows/dist/index.d.ts +1 -0
- package/node_modules/@oxygen/workflows/dist/index.js +1 -0
- package/node_modules/@oxygen/workflows/dist/recipe-timestamp.d.ts +22 -0
- package/node_modules/@oxygen/workflows/dist/recipe-timestamp.js +72 -0
- 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,
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Command } from "commander";
|
|
2
|
+
/** Existing native leaves retain their names and default-list alias. */
|
|
3
|
+
export declare function addProviderLimitFlags(command: Command, operation: "list" | "set" | "delete"): Command;
|
|
4
|
+
export declare function providerLimitBody(options: object): Record<string, unknown>;
|
|
5
|
+
export declare function providerLimitQuery(options: object, operation: "list" | "delete"): string;
|
|
6
|
+
export declare function addSuppressionListFlags(command: Command, kind: "addresses" | "domains"): Command;
|
|
7
|
+
export declare function suppressionListQuery(options: object, kind: "addresses" | "domains"): string;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { OxygenError } from "@oxygen/shared/cli-result";
|
|
2
|
+
import { validateContract } from "@oxygen/shared/contracts/schema";
|
|
3
|
+
import { emailDomainSuppressionListContract, emailSuppressionListContract, providerLimitListContract, providerLimitSelectorContract, providerLimitUpdateContract } from "@oxygen/shared/contracts/workspace-utilities";
|
|
4
|
+
import { addContractFlags, readContractFlags } from "./contract-flags.js";
|
|
5
|
+
/** Existing native leaves retain their names and default-list alias. */
|
|
6
|
+
export function addProviderLimitFlags(command, operation) {
|
|
7
|
+
const contract = operation === "set" ? providerLimitUpdateContract : operation === "delete" ? providerLimitSelectorContract : providerLimitListContract;
|
|
8
|
+
addContractFlags(command, contract, {
|
|
9
|
+
provider: { valueName: "<provider>" }, operation: { valueName: "<operation>" },
|
|
10
|
+
limit: { valueName: "<n>" }, window_seconds: { valueName: "<n>" }, offset: { valueName: "<n>" }, max_chars: { valueName: "<n>" },
|
|
11
|
+
});
|
|
12
|
+
for (const field of contract.required ?? [])
|
|
13
|
+
command.options.find((option) => option.long === `--${field.replace(/_/g, "-")}`)?.makeOptionMandatory();
|
|
14
|
+
return command;
|
|
15
|
+
}
|
|
16
|
+
export function providerLimitBody(options) {
|
|
17
|
+
const body = readContractFlags(options, providerLimitUpdateContract);
|
|
18
|
+
const parsed = validateContract(providerLimitUpdateContract, body, { unknown: "reject", overMax: "reject" });
|
|
19
|
+
if (!parsed.ok)
|
|
20
|
+
throw new OxygenError("invalid_request", parsed.issues.map((issue) => issue.message).join(" "), { exitCode: 2 });
|
|
21
|
+
return body;
|
|
22
|
+
}
|
|
23
|
+
export function providerLimitQuery(options, operation) {
|
|
24
|
+
return query(input(options, operation === "list" ? providerLimitListContract : providerLimitSelectorContract));
|
|
25
|
+
}
|
|
26
|
+
export function addSuppressionListFlags(command, kind) {
|
|
27
|
+
return addContractFlags(command, suppressionContract(kind), {
|
|
28
|
+
reason: { valueName: "<reason>" }, search: { valueName: "<text>" }, limit: { valueName: "<n>" }, offset: { valueName: "<n>" }, max_chars: { valueName: "<n>" },
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
export function suppressionListQuery(options, kind) {
|
|
32
|
+
return query(input(options, suppressionContract(kind)));
|
|
33
|
+
}
|
|
34
|
+
function suppressionContract(kind) {
|
|
35
|
+
return kind === "addresses" ? emailSuppressionListContract : emailDomainSuppressionListContract;
|
|
36
|
+
}
|
|
37
|
+
function input(options, contract) {
|
|
38
|
+
const parsed = validateContract(contract, readContractFlags(options, contract), { unknown: "reject", overMax: "clamp" });
|
|
39
|
+
if (!parsed.ok)
|
|
40
|
+
throw new OxygenError("invalid_request", parsed.issues.map((issue) => issue.message).join(" "), { exitCode: 2 });
|
|
41
|
+
return parsed.value;
|
|
42
|
+
}
|
|
43
|
+
function query(args) {
|
|
44
|
+
return new URLSearchParams(Object.entries(args).filter(([, value]) => value !== null).map(([key, value]) => [key, String(value)])).toString();
|
|
45
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
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;
|
|
@@ -0,0 +1,83 @@
|
|
|
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
|
+
}
|
|
@@ -50,6 +50,12 @@ export declare function occurrencesInPeriod(from: Date, to: Date, anchorDay: num
|
|
|
50
50
|
* not such a period: it grants monthly slices, so its caller passes the current
|
|
51
51
|
* slice's length (see recomputeOrgCommitmentBlock, P-23).
|
|
52
52
|
*
|
|
53
|
+
* A calendar month runs 28-31 days, so months are counted in 31-day steps: every
|
|
54
|
+
* monthly period holds one month, as OXYGEN_PRODUCT.md states ("one more month of
|
|
55
|
+
* every fixed resource"). Counting in 30-day steps held two months through every
|
|
56
|
+
* 31-day period, refusing customers' own credits as committed (staff decision
|
|
57
|
+
* 2026-10-06).
|
|
58
|
+
*
|
|
53
59
|
* Returns at least 1 — a missing/zero/garbage period length must never collapse
|
|
54
60
|
* the block to nothing, which would silently disable the whole feature.
|
|
55
61
|
*/
|
|
@@ -113,6 +113,12 @@ export function occurrencesInPeriod(from, to, anchorDay) {
|
|
|
113
113
|
* not such a period: it grants monthly slices, so its caller passes the current
|
|
114
114
|
* slice's length (see recomputeOrgCommitmentBlock, P-23).
|
|
115
115
|
*
|
|
116
|
+
* A calendar month runs 28-31 days, so months are counted in 31-day steps: every
|
|
117
|
+
* monthly period holds one month, as OXYGEN_PRODUCT.md states ("one more month of
|
|
118
|
+
* every fixed resource"). Counting in 30-day steps held two months through every
|
|
119
|
+
* 31-day period, refusing customers' own credits as committed (staff decision
|
|
120
|
+
* 2026-10-06).
|
|
121
|
+
*
|
|
116
122
|
* Returns at least 1 — a missing/zero/garbage period length must never collapse
|
|
117
123
|
* the block to nothing, which would silently disable the whole feature.
|
|
118
124
|
*/
|
|
@@ -120,7 +126,7 @@ export function blockPeriodsForSubscription(periodDays) {
|
|
|
120
126
|
if (typeof periodDays !== "number" || !Number.isFinite(periodDays) || periodDays <= 0) {
|
|
121
127
|
return 1;
|
|
122
128
|
}
|
|
123
|
-
return Math.max(1, Math.ceil(periodDays /
|
|
129
|
+
return Math.max(1, Math.ceil(periodDays / 31));
|
|
124
130
|
}
|
|
125
131
|
/**
|
|
126
132
|
* Days between two instants, floored. Small helper so callers deriving
|
|
@@ -119,6 +119,12 @@ export declare const SEQUENCE_UNSUBSCRIBE_COMMAND = "oxygen sequences update <se
|
|
|
119
119
|
* Factories, so a caller can edit the object it gets.
|
|
120
120
|
*/
|
|
121
121
|
export declare const CAPABILITY_ROUTE_MCP_CALLS: {
|
|
122
|
+
connectionPrices: () => {
|
|
123
|
+
tool: string;
|
|
124
|
+
arguments: {
|
|
125
|
+
view: string;
|
|
126
|
+
};
|
|
127
|
+
};
|
|
122
128
|
connectedAppsList: () => {
|
|
123
129
|
tool: string;
|
|
124
130
|
arguments: {};
|