@oxygen-agent/cli 1.632.3 → 1.662.0
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 +10 -3
- package/dist/index.js +1106 -195
- package/node_modules/@oxygen/shared/dist/axiom-field-budget.d.ts +91 -0
- package/node_modules/@oxygen/shared/dist/axiom-field-budget.js +262 -0
- package/node_modules/@oxygen/shared/dist/capability-discovery.js +59 -4
- package/node_modules/@oxygen/shared/dist/collab.d.ts +228 -0
- package/node_modules/@oxygen/shared/dist/collab.js +410 -0
- package/node_modules/@oxygen/shared/dist/column-types.d.ts +3 -3
- package/node_modules/@oxygen/shared/dist/column-types.js +26 -1
- package/node_modules/@oxygen/shared/dist/index.d.ts +2 -0
- package/node_modules/@oxygen/shared/dist/index.js +2 -0
- package/node_modules/@oxygen/shared/dist/pricing-sheet.d.ts +30 -0
- package/node_modules/@oxygen/shared/dist/pricing-sheet.js +30 -0
- package/node_modules/@oxygen/shared/dist/social-capabilities.d.ts +7 -6
- package/node_modules/@oxygen/shared/dist/social-capabilities.js +72 -11
- package/node_modules/@oxygen/shared/dist/tags.d.ts +2 -2
- package/node_modules/@oxygen/shared/dist/tags.js +2 -5
- package/node_modules/@oxygen/shared/dist/version.d.ts +1 -1
- package/node_modules/@oxygen/shared/dist/version.js +1 -1
- package/node_modules/@oxygen/shared/package.json +5 -0
- package/package.json +1 -1
|
@@ -14,6 +14,7 @@ export const RETYPEABLE_DATA_TYPES = [
|
|
|
14
14
|
"text",
|
|
15
15
|
"numeric",
|
|
16
16
|
"boolean",
|
|
17
|
+
"jsonb",
|
|
17
18
|
"timestamptz",
|
|
18
19
|
];
|
|
19
20
|
// Excel/Sheets store dates as a serial number of days since 1899-12-30.
|
|
@@ -134,7 +135,17 @@ value, dataType) {
|
|
|
134
135
|
}
|
|
135
136
|
switch (dataType) { // skipcq: JS-0047
|
|
136
137
|
case "text":
|
|
137
|
-
|
|
138
|
+
if (typeof value === "string")
|
|
139
|
+
return { ok: true, value };
|
|
140
|
+
if (typeof value === "object") {
|
|
141
|
+
try {
|
|
142
|
+
return { ok: true, value: JSON.stringify(value) };
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
return { ok: false, reason: "not JSON-serializable text" };
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return { ok: true, value: String(value) };
|
|
138
149
|
case "timestamptz": {
|
|
139
150
|
const iso = parseDateValueToIso(value, { allowExcelSerial: true });
|
|
140
151
|
return iso
|
|
@@ -157,5 +168,19 @@ value, dataType) {
|
|
|
157
168
|
}
|
|
158
169
|
return { ok: false, reason: "not a recognized boolean" };
|
|
159
170
|
}
|
|
171
|
+
case "jsonb": {
|
|
172
|
+
try {
|
|
173
|
+
if (typeof value === "string") {
|
|
174
|
+
return { ok: true, value: JSON.parse(value.trim()) };
|
|
175
|
+
}
|
|
176
|
+
const serialized = JSON.stringify(value);
|
|
177
|
+
if (serialized === undefined)
|
|
178
|
+
return { ok: false, reason: "not valid JSON" };
|
|
179
|
+
return { ok: true, value: JSON.parse(serialized) };
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
return { ok: false, reason: "not valid JSON" };
|
|
183
|
+
}
|
|
184
|
+
}
|
|
160
185
|
}
|
|
161
186
|
}
|
|
@@ -11,6 +11,7 @@ export * from "./cell-format.js";
|
|
|
11
11
|
export * from "./cli-envelope.js";
|
|
12
12
|
export * from "./cli-login-code.js";
|
|
13
13
|
export * from "./cli-result.js";
|
|
14
|
+
export * from "./collab.js";
|
|
14
15
|
export * from "./crm-reply-events.js";
|
|
15
16
|
export * from "./crm-activity-events.js";
|
|
16
17
|
export * from "./column-types.js";
|
|
@@ -45,6 +46,7 @@ export * from "./sequences.js";
|
|
|
45
46
|
export * from "./suppression-entries.js";
|
|
46
47
|
export * from "./table-limits.js";
|
|
47
48
|
export * from "./log.js";
|
|
49
|
+
export * from "./axiom-field-budget.js";
|
|
48
50
|
export { sanitizeLogFields } from "./redaction.js";
|
|
49
51
|
export * from "./provider-request-outcomes.js";
|
|
50
52
|
export * from "./schedule-label.js";
|
|
@@ -11,6 +11,7 @@ export * from "./cell-format.js";
|
|
|
11
11
|
export * from "./cli-envelope.js";
|
|
12
12
|
export * from "./cli-login-code.js";
|
|
13
13
|
export * from "./cli-result.js";
|
|
14
|
+
export * from "./collab.js";
|
|
14
15
|
export * from "./crm-reply-events.js";
|
|
15
16
|
export * from "./crm-activity-events.js";
|
|
16
17
|
export * from "./column-types.js";
|
|
@@ -45,6 +46,7 @@ export * from "./sequences.js";
|
|
|
45
46
|
export * from "./suppression-entries.js";
|
|
46
47
|
export * from "./table-limits.js";
|
|
47
48
|
export * from "./log.js";
|
|
49
|
+
export * from "./axiom-field-budget.js";
|
|
48
50
|
// Narrow, deliberate export (ADR 0014): lets telemetry emitters regression-test
|
|
49
51
|
// their field names against the REAL log sanitizer — the unanchored
|
|
50
52
|
// SECRET_KEY_PATTERN redacts any name containing "token", which mocked loggers
|
|
@@ -90,6 +90,36 @@ export declare const VOICE_CREDITS_PER_AMD_CALL = 38;
|
|
|
90
90
|
/** Managed domains: registrar at-cost × 1.25 (≈ a $10.44 .com → ~13,050 credits/yr). */
|
|
91
91
|
export declare const MANAGED_DOMAIN_MARKUP = 1.25;
|
|
92
92
|
export declare const MANAGED_DOMAIN_CREDITS_PER_YEAR_TYPICAL = 13050;
|
|
93
|
+
/**
|
|
94
|
+
* Inbox deliverability (EmailGuard placement seat). A flat monthly price per
|
|
95
|
+
* SUBSCRIBED inbox covering continuous deliverability monitoring (blacklist,
|
|
96
|
+
* SPF/DKIM/DMARC, domain reputation) plus an included allowance of
|
|
97
|
+
* inbox-placement (spam) tests; tests beyond the allowance bill the per-test
|
|
98
|
+
* price.
|
|
99
|
+
*
|
|
100
|
+
* All three are DISPLAY mirrors, per this file's contract. The canonical values
|
|
101
|
+
* live where they are enforced, and seed-parity.test.ts binds them so a mirror
|
|
102
|
+
* can never quietly drift from the number actually billed:
|
|
103
|
+
* seat DELIVERABILITY_UNIT_MONTHLY_CREDITS (@oxygen/control-db,
|
|
104
|
+
* also PRICING_SEED commitment.deliverability_unit) — 1,000 credits
|
|
105
|
+
* ($1.00), restored by the founder on 2026-07-30 after reviewing the
|
|
106
|
+
* Agency-plan unit economics, superseding the 2026-07-26 signature
|
|
107
|
+
* of 2,000.
|
|
108
|
+
* allowance DELIVERABILITY_INCLUDED_TESTS_PER_INBOX (@oxygen/control-db)
|
|
109
|
+
* overage EMAILGUARD_MANAGED_PLACEMENT_CREDITS (@oxygen/providers,
|
|
110
|
+
* derived from the Agency plan rather than typed in)
|
|
111
|
+
*
|
|
112
|
+
* THE ALLOWANCE IS LOAD-BEARING, not a perk. Placement COGS is per TEST
|
|
113
|
+
* ($0.1327 on EmailGuard's Agency plan), not per inbox, so an unbounded seat
|
|
114
|
+
* inverts its own margin: at $1.00/inbox-month the EIGHTH test in a cycle is
|
|
115
|
+
* already sold at a loss. Two included tests cost $0.265 against $1.00 of
|
|
116
|
+
* revenue — a ~73% margin — and everything past them bills
|
|
117
|
+
* PLACEMENT_TEST_OVERAGE_CREDITS. Orgs on their own EmailGuard key (BYOK) pay 0.
|
|
118
|
+
*/
|
|
119
|
+
export declare const DELIVERABILITY_SEAT_CREDITS_PER_MONTH = 1000;
|
|
120
|
+
export declare const DELIVERABILITY_INCLUDED_TESTS_PER_INBOX = 2;
|
|
121
|
+
/** Overage placement test: $0.1327 EmailGuard COGS × 1.25, rounded up. */
|
|
122
|
+
export declare const PLACEMENT_TEST_OVERAGE_CREDITS = 166;
|
|
93
123
|
/**
|
|
94
124
|
* LinkedIn accounts: founder decision (2026-07-25) — a PURE seat model. The
|
|
95
125
|
* flat monthly connection fee per connected account is now the WHOLE LinkedIn
|
|
@@ -82,6 +82,36 @@ export const VOICE_CREDITS_PER_AMD_CALL = 38;
|
|
|
82
82
|
/** Managed domains: registrar at-cost × 1.25 (≈ a $10.44 .com → ~13,050 credits/yr). */
|
|
83
83
|
export const MANAGED_DOMAIN_MARKUP = 1.25;
|
|
84
84
|
export const MANAGED_DOMAIN_CREDITS_PER_YEAR_TYPICAL = 13_050;
|
|
85
|
+
/**
|
|
86
|
+
* Inbox deliverability (EmailGuard placement seat). A flat monthly price per
|
|
87
|
+
* SUBSCRIBED inbox covering continuous deliverability monitoring (blacklist,
|
|
88
|
+
* SPF/DKIM/DMARC, domain reputation) plus an included allowance of
|
|
89
|
+
* inbox-placement (spam) tests; tests beyond the allowance bill the per-test
|
|
90
|
+
* price.
|
|
91
|
+
*
|
|
92
|
+
* All three are DISPLAY mirrors, per this file's contract. The canonical values
|
|
93
|
+
* live where they are enforced, and seed-parity.test.ts binds them so a mirror
|
|
94
|
+
* can never quietly drift from the number actually billed:
|
|
95
|
+
* seat DELIVERABILITY_UNIT_MONTHLY_CREDITS (@oxygen/control-db,
|
|
96
|
+
* also PRICING_SEED commitment.deliverability_unit) — 1,000 credits
|
|
97
|
+
* ($1.00), restored by the founder on 2026-07-30 after reviewing the
|
|
98
|
+
* Agency-plan unit economics, superseding the 2026-07-26 signature
|
|
99
|
+
* of 2,000.
|
|
100
|
+
* allowance DELIVERABILITY_INCLUDED_TESTS_PER_INBOX (@oxygen/control-db)
|
|
101
|
+
* overage EMAILGUARD_MANAGED_PLACEMENT_CREDITS (@oxygen/providers,
|
|
102
|
+
* derived from the Agency plan rather than typed in)
|
|
103
|
+
*
|
|
104
|
+
* THE ALLOWANCE IS LOAD-BEARING, not a perk. Placement COGS is per TEST
|
|
105
|
+
* ($0.1327 on EmailGuard's Agency plan), not per inbox, so an unbounded seat
|
|
106
|
+
* inverts its own margin: at $1.00/inbox-month the EIGHTH test in a cycle is
|
|
107
|
+
* already sold at a loss. Two included tests cost $0.265 against $1.00 of
|
|
108
|
+
* revenue — a ~73% margin — and everything past them bills
|
|
109
|
+
* PLACEMENT_TEST_OVERAGE_CREDITS. Orgs on their own EmailGuard key (BYOK) pay 0.
|
|
110
|
+
*/
|
|
111
|
+
export const DELIVERABILITY_SEAT_CREDITS_PER_MONTH = 1_000;
|
|
112
|
+
export const DELIVERABILITY_INCLUDED_TESTS_PER_INBOX = 2;
|
|
113
|
+
/** Overage placement test: $0.1327 EmailGuard COGS × 1.25, rounded up. */
|
|
114
|
+
export const PLACEMENT_TEST_OVERAGE_CREDITS = 166;
|
|
85
115
|
/**
|
|
86
116
|
* LinkedIn accounts: founder decision (2026-07-25) — a PURE seat model. The
|
|
87
117
|
* flat monthly connection fee per connected account is now the WHOLE LinkedIn
|
|
@@ -2,13 +2,12 @@
|
|
|
2
2
|
* Social channel capability registry.
|
|
3
3
|
*
|
|
4
4
|
* Channel, provider rail, and operation support are deliberately independent.
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* channel later means registering a real adapter profile, not adding placeholder UI.
|
|
5
|
+
* Callers resolve capabilities through this contract instead of branching on a
|
|
6
|
+
* channel name. A channel is registered only when a real adapter exists.
|
|
8
7
|
*/
|
|
9
|
-
export declare const SOCIAL_CHANNELS: readonly ["linkedin"];
|
|
8
|
+
export declare const SOCIAL_CHANNELS: readonly ["linkedin", "x"];
|
|
10
9
|
export type SocialChannel = (typeof SOCIAL_CHANNELS)[number];
|
|
11
|
-
export declare const SOCIAL_PROVIDER_RAILS: readonly ["unipile"];
|
|
10
|
+
export declare const SOCIAL_PROVIDER_RAILS: readonly ["unipile", "composio"];
|
|
12
11
|
export type SocialProviderRail = (typeof SOCIAL_PROVIDER_RAILS)[number];
|
|
13
12
|
export declare const SOCIAL_OPERATIONS: readonly ["list_owned_posts", "read_post_metrics", "list_comments", "reply_to_comment"];
|
|
14
13
|
export type SocialOperation = (typeof SOCIAL_OPERATIONS)[number];
|
|
@@ -24,7 +23,7 @@ export type SocialOperationCapability = {
|
|
|
24
23
|
limitation: string | null;
|
|
25
24
|
};
|
|
26
25
|
export type SocialMetricCapability = {
|
|
27
|
-
status:
|
|
26
|
+
status: SocialCapabilityStatus;
|
|
28
27
|
provider_field: string | null;
|
|
29
28
|
reason: string | null;
|
|
30
29
|
};
|
|
@@ -41,3 +40,5 @@ export type SocialCapabilityProfile = {
|
|
|
41
40
|
};
|
|
42
41
|
export declare function listSocialCapabilityProfiles(): readonly SocialCapabilityProfile[];
|
|
43
42
|
export declare function getSocialCapabilityProfile(channel: string, providerRail: string): SocialCapabilityProfile | null;
|
|
43
|
+
/** Resolve the first configured rail that can perform an operation for a channel. */
|
|
44
|
+
export declare function getSocialCapabilityProfileForOperation(channel: string, operation: SocialOperation): SocialCapabilityProfile | null;
|
|
@@ -2,12 +2,11 @@
|
|
|
2
2
|
* Social channel capability registry.
|
|
3
3
|
*
|
|
4
4
|
* Channel, provider rail, and operation support are deliberately independent.
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* channel later means registering a real adapter profile, not adding placeholder UI.
|
|
5
|
+
* Callers resolve capabilities through this contract instead of branching on a
|
|
6
|
+
* channel name. A channel is registered only when a real adapter exists.
|
|
8
7
|
*/
|
|
9
|
-
export const SOCIAL_CHANNELS = ["linkedin"];
|
|
10
|
-
export const SOCIAL_PROVIDER_RAILS = ["unipile"];
|
|
8
|
+
export const SOCIAL_CHANNELS = ["linkedin", "x"];
|
|
9
|
+
export const SOCIAL_PROVIDER_RAILS = ["unipile", "composio"];
|
|
11
10
|
export const SOCIAL_OPERATIONS = [
|
|
12
11
|
"list_owned_posts",
|
|
13
12
|
"read_post_metrics",
|
|
@@ -32,10 +31,10 @@ const LINKEDIN_UNIPILE_CAPABILITIES = {
|
|
|
32
31
|
operations: {
|
|
33
32
|
list_owned_posts: {
|
|
34
33
|
status: "limited",
|
|
35
|
-
source: "
|
|
36
|
-
provider_operation:
|
|
34
|
+
source: "provider",
|
|
35
|
+
provider_operation: "linkedin.users_posts",
|
|
37
36
|
external_write: false,
|
|
38
|
-
limitation: "
|
|
37
|
+
limitation: "recent_owned_posts_30_day_window",
|
|
39
38
|
},
|
|
40
39
|
read_post_metrics: {
|
|
41
40
|
status: "limited",
|
|
@@ -61,9 +60,9 @@ const LINKEDIN_UNIPILE_CAPABILITIES = {
|
|
|
61
60
|
},
|
|
62
61
|
metrics: {
|
|
63
62
|
impressions: { status: "unavailable", provider_field: null, reason: NOT_EXPOSED_BY_UNIPILE },
|
|
64
|
-
reactions: { status: "available", provider_field: "
|
|
65
|
-
comments: { status: "available", provider_field: "
|
|
66
|
-
reposts: { status: "available", provider_field: "
|
|
63
|
+
reactions: { status: "available", provider_field: "reaction_counter", reason: null },
|
|
64
|
+
comments: { status: "available", provider_field: "comment_counter", reason: null },
|
|
65
|
+
reposts: { status: "available", provider_field: "repost_counter", reason: null },
|
|
67
66
|
saves: { status: "unavailable", provider_field: null, reason: NOT_EXPOSED_BY_UNIPILE },
|
|
68
67
|
sends: { status: "unavailable", provider_field: null, reason: NOT_EXPOSED_BY_UNIPILE },
|
|
69
68
|
clicks: { status: "unavailable", provider_field: null, reason: NOT_EXPOSED_BY_UNIPILE },
|
|
@@ -74,8 +73,66 @@ const LINKEDIN_UNIPILE_CAPABILITIES = {
|
|
|
74
73
|
webhooks: false,
|
|
75
74
|
},
|
|
76
75
|
};
|
|
76
|
+
const X_COMPOSIO_CAPABILITIES = {
|
|
77
|
+
version: 1,
|
|
78
|
+
channel: "x",
|
|
79
|
+
provider_rail: "composio",
|
|
80
|
+
operations: {
|
|
81
|
+
list_owned_posts: {
|
|
82
|
+
status: "unavailable",
|
|
83
|
+
source: "provider",
|
|
84
|
+
provider_operation: null,
|
|
85
|
+
external_write: false,
|
|
86
|
+
limitation: "oxygen_published_posts_only",
|
|
87
|
+
},
|
|
88
|
+
read_post_metrics: {
|
|
89
|
+
status: "limited",
|
|
90
|
+
source: "provider",
|
|
91
|
+
provider_operation: "TWITTER_POST_LOOKUP_BY_POST_ID",
|
|
92
|
+
external_write: false,
|
|
93
|
+
limitation: "connected_user_oauth_owned_posts",
|
|
94
|
+
},
|
|
95
|
+
list_comments: {
|
|
96
|
+
status: "unavailable",
|
|
97
|
+
source: "provider",
|
|
98
|
+
provider_operation: null,
|
|
99
|
+
external_write: false,
|
|
100
|
+
limitation: "not_implemented_for_x",
|
|
101
|
+
},
|
|
102
|
+
reply_to_comment: {
|
|
103
|
+
status: "unavailable",
|
|
104
|
+
source: "provider",
|
|
105
|
+
provider_operation: null,
|
|
106
|
+
external_write: true,
|
|
107
|
+
limitation: "not_implemented_for_x",
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
metrics: {
|
|
111
|
+
impressions: { status: "available", provider_field: "public_metrics.impression_count", reason: null },
|
|
112
|
+
reactions: { status: "available", provider_field: "public_metrics.like_count", reason: null },
|
|
113
|
+
comments: { status: "available", provider_field: "public_metrics.reply_count", reason: null },
|
|
114
|
+
reposts: { status: "available", provider_field: "public_metrics.retweet_count", reason: null },
|
|
115
|
+
saves: { status: "available", provider_field: "public_metrics.bookmark_count", reason: null },
|
|
116
|
+
sends: { status: "unavailable", provider_field: null, reason: "not_exposed_by_x_post_lookup" },
|
|
117
|
+
clicks: {
|
|
118
|
+
status: "limited",
|
|
119
|
+
provider_field: "non_public_metrics.url_link_clicks",
|
|
120
|
+
reason: "owned_posts_user_context_30_day_window",
|
|
121
|
+
},
|
|
122
|
+
video_views: {
|
|
123
|
+
status: "limited",
|
|
124
|
+
provider_field: "includes.media[].public_metrics.view_count",
|
|
125
|
+
reason: "video_media_only",
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
ingestion: {
|
|
129
|
+
polling: true,
|
|
130
|
+
webhooks: false,
|
|
131
|
+
},
|
|
132
|
+
};
|
|
77
133
|
const SOCIAL_CAPABILITY_PROFILES = [
|
|
78
134
|
LINKEDIN_UNIPILE_CAPABILITIES,
|
|
135
|
+
X_COMPOSIO_CAPABILITIES,
|
|
79
136
|
];
|
|
80
137
|
export function listSocialCapabilityProfiles() {
|
|
81
138
|
return SOCIAL_CAPABILITY_PROFILES;
|
|
@@ -83,3 +140,7 @@ export function listSocialCapabilityProfiles() {
|
|
|
83
140
|
export function getSocialCapabilityProfile(channel, providerRail) {
|
|
84
141
|
return SOCIAL_CAPABILITY_PROFILES.find((profile) => profile.channel === channel && profile.provider_rail === providerRail) ?? null;
|
|
85
142
|
}
|
|
143
|
+
/** Resolve the first configured rail that can perform an operation for a channel. */
|
|
144
|
+
export function getSocialCapabilityProfileForOperation(channel, operation) {
|
|
145
|
+
return SOCIAL_CAPABILITY_PROFILES.find((profile) => profile.channel === channel && profile.operations[operation].status !== "unavailable") ?? null;
|
|
146
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { TagColor } from "./select-options.js";
|
|
2
2
|
/** Primitive kinds that participate in the workspace tag union today. */
|
|
3
|
-
export declare const TAG_KINDS: readonly ["knowledge_page", "publishing_post", "sequence", "table", "workflow", "recipe", "conversation", "mailbox", "sender", "record", "domain", "project"
|
|
3
|
+
export declare const TAG_KINDS: readonly ["knowledge_page", "publishing_post", "sequence", "table", "workflow", "recipe", "conversation", "mailbox", "sender", "record", "domain", "project"];
|
|
4
4
|
export type TagKind = (typeof TAG_KINDS)[number];
|
|
5
5
|
/**
|
|
6
6
|
* The taggable kinds in prose, for CLI `--help` and MCP tool descriptions.
|
|
@@ -8,7 +8,7 @@ export type TagKind = (typeof TAG_KINDS)[number];
|
|
|
8
8
|
* Lives next to {@link TAG_KINDS} because those descriptions are the *discovery*
|
|
9
9
|
* surface: a blind-user eval (2026-07-21) found the tags help still advertising
|
|
10
10
|
* the original seven kinds, so a user reading `tags --help` had no way to learn
|
|
11
|
-
* that domains
|
|
11
|
+
* that domains or projects were taggable at all — they had
|
|
12
12
|
* to stumble on each owning group's own help. One string, one import, and
|
|
13
13
|
* `TAG_KIND_PROSE_MARKERS` fails the build/test if a new kind skips it.
|
|
14
14
|
*/
|
|
@@ -24,7 +24,6 @@ export const TAG_KINDS = [
|
|
|
24
24
|
"record",
|
|
25
25
|
"domain",
|
|
26
26
|
"project",
|
|
27
|
-
"engagement_watch",
|
|
28
27
|
];
|
|
29
28
|
/**
|
|
30
29
|
* The taggable kinds in prose, for CLI `--help` and MCP tool descriptions.
|
|
@@ -32,13 +31,13 @@ export const TAG_KINDS = [
|
|
|
32
31
|
* Lives next to {@link TAG_KINDS} because those descriptions are the *discovery*
|
|
33
32
|
* surface: a blind-user eval (2026-07-21) found the tags help still advertising
|
|
34
33
|
* the original seven kinds, so a user reading `tags --help` had no way to learn
|
|
35
|
-
* that domains
|
|
34
|
+
* that domains or projects were taggable at all — they had
|
|
36
35
|
* to stumble on each owning group's own help. One string, one import, and
|
|
37
36
|
* `TAG_KIND_PROSE_MARKERS` fails the build/test if a new kind skips it.
|
|
38
37
|
*/
|
|
39
38
|
export const TAG_KINDS_PROSE = "publishing posts, knowledge pages, sequences, tables, workflows, recipes, " +
|
|
40
39
|
"inbox conversations, CRM records, mailboxes, sender accounts, sending domains, " +
|
|
41
|
-
"
|
|
40
|
+
"and projects";
|
|
42
41
|
/**
|
|
43
42
|
* The phrase each kind must contribute to {@link TAG_KINDS_PROSE}. Typed as a
|
|
44
43
|
* total map over TagKind, so adding a kind is a compile error until it is named
|
|
@@ -57,7 +56,6 @@ export const TAG_KIND_PROSE_MARKERS = {
|
|
|
57
56
|
record: "CRM record",
|
|
58
57
|
domain: "sending domain",
|
|
59
58
|
project: "project",
|
|
60
|
-
engagement_watch: "engagement watch",
|
|
61
59
|
};
|
|
62
60
|
export function isTagKind(value) {
|
|
63
61
|
return typeof value === "string" && TAG_KINDS.includes(value);
|
|
@@ -87,7 +85,6 @@ export const TAG_KIND_LABELS = {
|
|
|
87
85
|
record: { one: "CRM record", many: "CRM records" },
|
|
88
86
|
domain: { one: "domain", many: "domains" },
|
|
89
87
|
project: { one: "project", many: "projects" },
|
|
90
|
-
engagement_watch: { one: "engagement watch", many: "engagement watches" },
|
|
91
88
|
};
|
|
92
89
|
/** Inline label for a count: `tagKindLabel("sequence", 1)` → "sequence". */
|
|
93
90
|
export function tagKindLabel(kind, count) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const OXYGEN_VERSION = "1.
|
|
1
|
+
export const OXYGEN_VERSION = "1.662.0";
|
|
2
2
|
// The GLOBAL CLI compatibility floor: the oldest CLI allowed to call any
|
|
3
3
|
// operational route. Raising it hard-rejects every older CLI from the entire
|
|
4
4
|
// product, so it obeys one law, enforced by scripts/ci/cli-min-version-gate.mjs:
|
|
@@ -111,6 +111,11 @@
|
|
|
111
111
|
"import": "./dist/tags.js",
|
|
112
112
|
"default": "./dist/tags.js"
|
|
113
113
|
},
|
|
114
|
+
"./collab": {
|
|
115
|
+
"types": "./dist/collab.d.ts",
|
|
116
|
+
"import": "./dist/collab.js",
|
|
117
|
+
"default": "./dist/collab.js"
|
|
118
|
+
},
|
|
114
119
|
"./schedule-label": {
|
|
115
120
|
"types": "./dist/schedule-label.d.ts",
|
|
116
121
|
"import": "./dist/schedule-label.js",
|