@oxygen-agent/cli 1.1014.619 → 1.1014.771
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/command-manifest.js +15 -0
- package/dist/command-support.d.ts +5 -5
- package/dist/command-support.js +7 -7
- package/dist/commands/billing.js +12 -6
- package/dist/commands/columns.js +2 -2
- package/dist/commands/companies.js +1 -1
- package/dist/commands/copilot.js +1 -1
- package/dist/commands/dashboards.js +1 -1
- package/dist/commands/enrich-column.js +2 -2
- package/dist/commands/find.js +2 -2
- package/dist/commands/mailboxes.js +36 -0
- package/dist/commands/recipes.js +1 -1
- package/dist/commands/sequences.js +6 -6
- package/dist/commands/tables.js +1 -1
- package/dist/commands/verify.js +112 -11
- package/dist/http-client.js +1 -70
- package/dist/index.js +1 -1
- package/dist/refactor-internals/binary-download.d.ts +5 -0
- package/dist/refactor-internals/binary-download.js +71 -0
- package/node_modules/@oxygen/formula/dist/evaluate.js +2 -82
- package/node_modules/@oxygen/formula/dist/refactor-internals/novelty-score.d.ts +2 -0
- package/node_modules/@oxygen/formula/dist/refactor-internals/novelty-score.js +87 -0
- package/node_modules/@oxygen/shared/dist/billing.d.ts +15 -3
- package/node_modules/@oxygen/shared/dist/billing.js +19 -7
- package/node_modules/@oxygen/shared/dist/cancellation-reasons.d.ts +35 -0
- package/node_modules/@oxygen/shared/dist/cancellation-reasons.js +21 -0
- package/node_modules/@oxygen/shared/dist/capability-discovery.js +27 -1
- package/node_modules/@oxygen/shared/dist/contracts/browser-operations.js +6 -6
- package/node_modules/@oxygen/shared/dist/contracts/customer-operations.js +1 -1
- package/node_modules/@oxygen/shared/dist/contracts/limits-read.js +1 -0
- package/node_modules/@oxygen/shared/dist/contracts/teammates.js +41 -17
- package/node_modules/@oxygen/shared/dist/email-verification-batch.d.ts +26 -0
- package/node_modules/@oxygen/shared/dist/email-verification-batch.js +55 -0
- package/node_modules/@oxygen/shared/dist/knowledge-bootstrap.d.ts +3 -3
- package/node_modules/@oxygen/shared/dist/knowledge-bootstrap.js +3 -3
- package/node_modules/@oxygen/shared/dist/knowledge-brain-draft.d.ts +70 -0
- package/node_modules/@oxygen/shared/dist/knowledge-brain-draft.js +42 -0
- package/node_modules/@oxygen/shared/dist/plan-capabilities.js +1 -1
- package/node_modules/@oxygen/shared/dist/pricing-sheet.d.ts +1 -1
- package/node_modules/@oxygen/shared/dist/pricing-sheet.js +3 -1
- package/node_modules/@oxygen/shared/dist/product-doctrine.js +1 -1
- package/node_modules/@oxygen/shared/dist/sequence-internals/esp-policy.d.ts +225 -0
- package/node_modules/@oxygen/shared/dist/sequence-internals/esp-policy.js +578 -0
- package/node_modules/@oxygen/shared/dist/sequences.d.ts +1 -226
- package/node_modules/@oxygen/shared/dist/sequences.js +2 -576
- package/node_modules/@oxygen/shared/dist/teammate-groups.d.ts +103 -24
- package/node_modules/@oxygen/shared/dist/teammate-groups.js +125 -32
- package/node_modules/@oxygen/shared/dist/teammate-messages.d.ts +1 -1
- package/node_modules/@oxygen/shared/dist/teammates.d.ts +28 -2
- package/node_modules/@oxygen/shared/dist/teammates.js +32 -2
- package/node_modules/@oxygen/shared/dist/user-capability-routing.js +40 -8
- 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/workflows/dist/graph/expression.d.ts +1 -16
- package/node_modules/@oxygen/workflows/dist/graph/expression.js +4 -224
- package/node_modules/@oxygen/workflows/dist/graph/types.d.ts +2 -2
- package/node_modules/@oxygen/workflows/dist/index.d.ts +1 -63
- package/node_modules/@oxygen/workflows/dist/index.js +1 -193
- package/node_modules/@oxygen/workflows/dist/refactor-internals/condition-comparison.d.ts +18 -0
- package/node_modules/@oxygen/workflows/dist/refactor-internals/condition-comparison.js +222 -0
- package/node_modules/@oxygen/workflows/dist/refactor-internals/execution-policy.d.ts +64 -0
- package/node_modules/@oxygen/workflows/dist/refactor-internals/execution-policy.js +204 -0
- package/node_modules/@oxygen/workflows/package.json +4 -0
- package/package.json +1 -1
|
@@ -39,7 +39,7 @@ export const CUSTOMER_OPERATIONS = [
|
|
|
39
39
|
operation("members.client_role", "/api/cli/collab/members/role", "POST", "approvals client grant", "oxygen_members_client_role_set", "collaboration", "Set or clear the restricted client overlay; admin only. May read pending Clerk invitations; sends no invitation. Free.", { email: text(), role: nullable(enumOf(["client"])) }, ["email", "role"], { ...mcpOnly, annotations: { openWorldHint: true } }),
|
|
40
40
|
operation("members.workspace_role", "/api/cli/collab/members/workspace-role", "POST", "orgs member-role", "oxygen_members_workspace_role_set", "collaboration", "Change a member's workspace role in Clerk; admin only, with self-role and last-administrator protection. Free.", { email: text(), role: enumOf(["admin", "member"]) }, ["email", "role"], { ...mcpOnly, annotations: { openWorldHint: true } }),
|
|
41
41
|
operation("copilot.sessions.list", "/api/cli/copilot/sessions", "GET", "copilot list", "oxygen_copilot_sessions_list", "agents", "List attended Copilot sessions in this workspace.", COPILOT_SESSIONS_LIST_CONTRACT.properties, [], mcpOnly),
|
|
42
|
-
operation("copilot.sessions.update", "/api/cli/copilot/sessions/{session_id}", "PATCH", "copilot policy set", "oxygen_copilot_session_update", "agents", "Set an attended Copilot session's approval policy.
|
|
42
|
+
operation("copilot.sessions.update", "/api/cli/copilot/sessions/{session_id}", "PATCH", "copilot policy set", "oxygen_copilot_session_update", "agents", "Set an attended Copilot session's approval policy. `paid` (Auto-approve) is standing authorization for every action, paid and external ones included.", { auto_approve_policy: enumOf(["off", "paid"]) }, ["auto_approve_policy"], { spends: true }),
|
|
43
43
|
operation("copilot.attachments.list", "/api/cli/copilot/sessions/{session_id}/attachments", "GET", "copilot attachments list", "oxygen_copilot_attachments_list", "agents", "List sent and unsent attachments in one Copilot session.", {}, []),
|
|
44
44
|
operation("copilot.attachments.prepare", "/api/cli/copilot/sessions/{session_id}/attachments", "POST", "copilot attachments prepare", "oxygen_copilot_attachment_prepare", "agents", "Reserve a Copilot attachment and return its scoped upload URL; complete only after uploading the exact bytes.", { file_name: text(), content_type: text(), content_length: int({ minimum: 1 }) }, ["file_name", "content_length"]),
|
|
45
45
|
operation("copilot.attachments.complete", "/api/cli/copilot/sessions/{session_id}/attachments/{attachment_id}/complete", "POST", "copilot attachments complete", "oxygen_copilot_attachment_complete", "agents", "Verify and describe an uploaded Copilot attachment in its session.", {}, []),
|
|
@@ -119,6 +119,7 @@ export function projectLimitsRead(data, query) {
|
|
|
119
119
|
else if (section === "pricing") {
|
|
120
120
|
selected.plan_bands = bands.map(pricingBand);
|
|
121
121
|
selected.pricing_schedule = scheduleProjection(data, section);
|
|
122
|
+
selected.pricing_note = "Plan-band prices below are monthly. Full upfront yearly prices and terms: CLI billing balance --json; MCP oxygen_billing_balance (available_plans[].yearly and annual_terms).";
|
|
122
123
|
}
|
|
123
124
|
else
|
|
124
125
|
selected[SECTION_FIELDS[section]] = data[SECTION_FIELDS[section]];
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { TEAMMATE_GROUP_MAX_MEMBERS, TEAMMATE_GROUP_MIN_MEMBERS, TEAMMATE_GROUP_TITLE_MAX_CHARS } from "../teammate-groups.js";
|
|
1
|
+
import { TEAMMATE_GROUP_MAX_MEMBERS, TEAMMATE_GROUP_MAX_PEOPLE, TEAMMATE_GROUP_MIN_MEMBERS, TEAMMATE_GROUP_TITLE_MAX_CHARS } from "../teammate-groups.js";
|
|
2
2
|
import { TEAMMATE_SLUG_PATTERN } from "../teammate-messages.js";
|
|
3
3
|
import { TEAMMATE_TASK_LIMITS } from "../teammate-tasks.js";
|
|
4
|
-
import { NEW_TEAMMATE_NAME, TEAMMATE_AVATAR_COLORS, TEAMMATE_AVATAR_KEYS, TEAMMATE_DESCRIPTION_MAX_CHARS, TEAMMATE_NAME_MAX_CHARS, } from "../teammates.js";
|
|
4
|
+
import { NEW_TEAMMATE_NAME, TEAMMATE_AVATAR_COLORS, TEAMMATE_AVATAR_KEYS, TEAMMATE_DESCRIPTION_MAX_CHARS, TEAMMATE_NAME_MAX_CHARS, TEAMMATE_SHARE_ROLES, } from "../teammates.js";
|
|
5
5
|
import { arr, bool, enumOf, int, obj, str } from "./schema.js";
|
|
6
6
|
/**
|
|
7
7
|
* AI teammates (ADR 0032), branded Oxygents: Agents each person talks to in one
|
|
@@ -22,9 +22,9 @@ function teammateOperation(id, verb, method, suffix, summary, fields = {}, requi
|
|
|
22
22
|
};
|
|
23
23
|
}
|
|
24
24
|
/**
|
|
25
|
-
* Group chats (phase 7):
|
|
26
|
-
* the way Grok Bot's are. Their own route family, so a group
|
|
27
|
-
* teammate whose slug happens to read like a route word.
|
|
25
|
+
* Group chats (phase 7): a chat with up to six Oxygents and, since 2026-10-15,
|
|
26
|
+
* teammates too, the way Grok Bot's are. Their own route family, so a group
|
|
27
|
+
* never shadows a teammate whose slug happens to read like a route word.
|
|
28
28
|
*/
|
|
29
29
|
function teammateGroupOperation(id, verb, method, suffix, summary, fields = {}, required = [], spends = false) {
|
|
30
30
|
const route = `/api/cli/teammate-groups${suffix}`;
|
|
@@ -38,6 +38,7 @@ function teammateGroupOperation(id, verb, method, suffix, summary, fields = {},
|
|
|
38
38
|
};
|
|
39
39
|
}
|
|
40
40
|
const GROUP_MEMBER_SLUGS = (description) => arr(str({ minLength: 2, maxLength: 49, pattern: TEAMMATE_SLUG_PATTERN }), { maxItems: TEAMMATE_GROUP_MAX_MEMBERS, description });
|
|
41
|
+
const GROUP_PEOPLE = (description) => arr(str({ minLength: 3, maxLength: 320 }), { maxItems: TEAMMATE_GROUP_MAX_PEOPLE, description });
|
|
41
42
|
export const TEAMMATE_PROFILE_FIELDS = {
|
|
42
43
|
name: str({ minLength: 1, maxLength: TEAMMATE_NAME_MAX_CHARS, description: "What everyone calls it." }),
|
|
43
44
|
description: str({
|
|
@@ -48,26 +49,43 @@ export const TEAMMATE_PROFILE_FIELDS = {
|
|
|
48
49
|
avatar_color: enumOf([...TEAMMATE_AVATAR_COLORS], { description: "The colour of its face." }),
|
|
49
50
|
};
|
|
50
51
|
export const TEAMMATE_OPERATIONS = [
|
|
51
|
-
teammateOperation("teammates.list", "list", "GET", "", "List
|
|
52
|
+
teammateOperation("teammates.list", "list", "GET", "", "List the Oxygents you can use, the first one (is_default) on top: name, what each does, its look, what you are to it (access: owner, manager or collaborator) and your chat with each (working or waiting for you, unread, its latest words). Pinned ones follow the first; hidden ones are marked."),
|
|
52
53
|
// Adding a teammate (phase 7): a custom Agent that can chat at once and run
|
|
53
54
|
// on its own, under a policy that asks before any write, send or spend. As in
|
|
54
55
|
// Grok Bot, it can start as just "New Bot" and learn its job in the chat.
|
|
55
|
-
teammateOperation("teammates.create", "create", "POST", "", `Add an Oxygent to the workspace, named "${NEW_TEAMMATE_NAME}" unless you name it; tell it its job in your chat with it. It can chat at once and run on its own (background tasks, routines), reading freely and asking before anything that writes, sends or spends.
|
|
56
|
+
teammateOperation("teammates.create", "create", "POST", "", `Add an Oxygent to the workspace, named "${NEW_TEAMMATE_NAME}" unless you name it; tell it its job in your chat with it. It can chat at once and run on its own (background tasks, routines), reading freely and asking before anything that writes, sends or spends. You own it, and only you can use it until you share it. Free: adding one starts no inference.`, {
|
|
56
57
|
...TEAMMATE_PROFILE_FIELDS,
|
|
57
58
|
slug: str({ minLength: 2, maxLength: 49, pattern: TEAMMATE_SLUG_PATTERN, description: "Its permanent handle in commands and links; made from the name when omitted." }),
|
|
58
59
|
}),
|
|
59
60
|
teammateOperation("teammates.get", "get", "GET", "/{slug}", "Read one Oxygent's profile and your ongoing private chat with it."),
|
|
60
|
-
teammateOperation("teammates.update", "update", "PATCH", "/{slug}", "Edit an Oxygent's name, what it does (description) or its look (avatar_key, avatar_color). Its instructions, tools and versions are unchanged. Free.", TEAMMATE_PROFILE_FIELDS),
|
|
61
|
+
teammateOperation("teammates.update", "update", "PATCH", "/{slug}", "Edit an Oxygent's name, what it does (description) or its look (avatar_key, avatar_color): its owner, its managers or a workspace admin. Its instructions, tools and versions are unchanged. Free.", TEAMMATE_PROFILE_FIELDS),
|
|
62
|
+
// Sharing (Tim, 2026-10-14: "make agents accessible to your team mates"), the
|
|
63
|
+
// way Grok Bot shares a Bot: everyone in the workspace, or people by email,
|
|
64
|
+
// each as a collaborator or a manager. Everyone still has a chat of their own.
|
|
65
|
+
teammateOperation("teammates.access", "access", "GET", "/{slug}/access", "Read who can use an Oxygent: its owner, what everyone in the workspace may do with it, and the people it is shared with. A collaborator chats with it in a chat of their own; a manager also changes its profile and who has access. Free."),
|
|
66
|
+
teammateOperation("teammates.share", "share", "POST", "/{slug}/access", "Share an Oxygent with teammates, or stop sharing it: with everyone in the workspace (everyone), or with people by their workspace email (add, as role; remove). Each person gets their own private chat with it; nobody reads anyone else's. Its owner, its managers or a workspace admin only; never the first Oxygent, which is everyone's. Free.", {
|
|
67
|
+
everyone: enumOf([...TEAMMATE_SHARE_ROLES, "off"], {
|
|
68
|
+
description: "What everyone in the workspace may do with it: collaborator, manager, or off (only its owner and the people it is shared with).",
|
|
69
|
+
}),
|
|
70
|
+
add: arr(str({ minLength: 3, maxLength: 320 }), { maxItems: 50, description: "People to share it with, by their workspace email." }),
|
|
71
|
+
role: enumOf([...TEAMMATE_SHARE_ROLES], {
|
|
72
|
+
description: "What the people in add become: collaborator (the default), who chats with it in a chat of their own, or manager, who also changes its profile and who has access. Adding someone already listed changes their role.",
|
|
73
|
+
}),
|
|
74
|
+
remove: arr(str({ minLength: 3, maxLength: 320 }), {
|
|
75
|
+
maxItems: 50,
|
|
76
|
+
description: "People to stop sharing it with, by their workspace email; for someone who has left the workspace, the user_id that access lists for them. Their chat with it stays, closed to them until it is shared with them again.",
|
|
77
|
+
}),
|
|
78
|
+
}),
|
|
61
79
|
// Copy and delete (Tim, 2026-10-13: "CRUD actions ... through the right
|
|
62
80
|
// click"; "'delete' should be 'full delete'"), as Grok Bot's Bot menu has.
|
|
63
|
-
teammateOperation("teammates.duplicate", "duplicate", "POST", "/{slug}/duplicate", `Copy an Oxygent as a new one you own, named "<name> copy" unless you name it: its job, look, instructions, skills and tool settings, but not its chats, memory or
|
|
81
|
+
teammateOperation("teammates.duplicate", "duplicate", "POST", "/{slug}/duplicate", `Copy an Oxygent as a new one you own, named "<name> copy" unless you name it: its job, look, instructions, skills and tool settings, but not its chats, memory, routines or who it is shared with. Only you can use the copy until you share it. Free.`, {
|
|
64
82
|
name: str({
|
|
65
83
|
minLength: 1, maxLength: TEAMMATE_NAME_MAX_CHARS,
|
|
66
84
|
description: "What everyone calls the copy. Its slug is made from the name, and a deleted Oxygent's slug stays taken, so a copy can get a numbered one (scout-2).",
|
|
67
85
|
}),
|
|
68
86
|
}),
|
|
69
|
-
teammateOperation("teammates.delete", "delete", "POST", "/{slug}/delete", "Delete an Oxygent for good, for everyone: its profile, every chat with it (group chats
|
|
70
|
-
preview: bool({ description: "Only say what would go: its chats and the people they belong to, group chats, routines, runs, attached files and team memory entries." }),
|
|
87
|
+
teammateOperation("teammates.delete", "delete", "POST", "/{slug}/delete", "Delete an Oxygent for good, for everyone: its profile, every chat with it (its group chats too, except those other people are in, which it leaves and where only its answers go), its routines, team memory and runs. What it made in the workspace stays. Its owner or a workspace admin only; never the first Oxygent. Preview first to see what would go, then delete with confirm set to its slug. Its slug stays taken afterwards. Free; cannot be undone.", {
|
|
88
|
+
preview: bool({ description: "Only say what would go: its chats and the people they belong to, group chats, the group chats with other people it would leave, routines, runs, attached files and team memory entries." }),
|
|
71
89
|
confirm: str({ maxLength: 49, description: "Its slug, repeated, to delete it." }),
|
|
72
90
|
}),
|
|
73
91
|
teammateOperation("teammates.chat", "chat", "POST", "/{slug}/chat", "Open your ongoing private chat with an Oxygent, creating it the first time. Starts no inference."),
|
|
@@ -98,18 +116,24 @@ export const TEAMMATE_OPERATIONS = [
|
|
|
98
116
|
teammateOperation("teammates.notes", "notes", "GET", "/{slug}/notes", "Read what an Oxygent keeps about you: private to you, read only in your own chat with it."),
|
|
99
117
|
teammateOperation("teammates.notes_set", "notes_set", "POST", "/{slug}/notes", "Replace what an Oxygent keeps about you; empty clears it. Private to you.", { notes: str({ maxLength: 4000 }) }, ["notes"]),
|
|
100
118
|
teammateOperation("teammates.activity", "activity", "GET", "/{slug}/activity", "List an Oxygent's recent work: its runs and the actions taken in its chats, as metadata only (no goals or messages)."),
|
|
101
|
-
teammateGroupOperation("teammate_groups.list", "groups", "GET", "", "List
|
|
102
|
-
teammateGroupOperation("teammate_groups.create", "group_create", "POST", "", `Start a
|
|
119
|
+
teammateGroupOperation("teammate_groups.list", "groups", "GET", "", "List the group chats you are in: name, Oxygents, people (each an admin or member) and the chat (working or waiting for you, unread, the latest words and who said them). Candidates are the teammates a new group chat could bring in."),
|
|
120
|
+
teammateGroupOperation("teammate_groups.create", "group_create", "POST", "", `Start a group chat with a name, Oxygents (members, by slug) and, if you like, teammates (people, by workspace email): ${TEAMMATE_GROUP_MIN_MEMBERS} to ${TEAMMATE_GROUP_MAX_MEMBERS} Oxygents with only you, 1 to ${TEAMMATE_GROUP_MAX_MEMBERS} with others. You are its admin. Every Oxygent must be shared with everyone in it. Starts no inference.`, {
|
|
103
121
|
name: str({ minLength: 1, maxLength: TEAMMATE_GROUP_TITLE_MAX_CHARS }),
|
|
104
122
|
members: GROUP_MEMBER_SLUGS("The Oxygents in it, by slug, in the order they show."),
|
|
123
|
+
people: GROUP_PEOPLE("Teammates to bring in, by their workspace email; they see the whole chat."),
|
|
105
124
|
}, ["name", "members"]),
|
|
106
|
-
teammateGroupOperation("teammate_groups.get", "group", "GET", "/{group_id}", "Read
|
|
107
|
-
teammateGroupOperation("teammate_groups.update", "group_update", "PATCH", "/{group_id}", `
|
|
125
|
+
teammateGroupOperation("teammate_groups.get", "group", "GET", "/{group_id}", "Read a group chat you are in: its name, Oxygents, people and the chat's state. Its admins also see who else could be brought in (candidates)."),
|
|
126
|
+
teammateGroupOperation("teammate_groups.update", "group_update", "PATCH", "/{group_id}", `Change a group chat, as one of its admins: add or remove people (by workspace email), make them admins or members, rename it, or add or remove Oxygents (by slug). It keeps ${TEAMMATE_GROUP_MIN_MEMBERS} to ${TEAMMATE_GROUP_MAX_MEMBERS} Oxygents with only you, 1 to ${TEAMMATE_GROUP_MAX_MEMBERS} with others. Someone added sees the whole chat; removed people and Oxygents keep their earlier messages.`, {
|
|
108
127
|
name: str({ minLength: 1, maxLength: TEAMMATE_GROUP_TITLE_MAX_CHARS }),
|
|
109
128
|
add: GROUP_MEMBER_SLUGS("Oxygents to add, by slug."),
|
|
110
129
|
remove: GROUP_MEMBER_SLUGS("Oxygents to remove, by slug."),
|
|
130
|
+
add_people: GROUP_PEOPLE("People to add, by their workspace email."),
|
|
131
|
+
remove_people: GROUP_PEOPLE("People to remove, by their workspace email; for someone who has left the workspace, the user_id the group lists for them."),
|
|
132
|
+
make_admin: GROUP_PEOPLE("People in it to make admins, by workspace email."),
|
|
133
|
+
remove_admin: GROUP_PEOPLE("Admins to make members again, by workspace email; a group keeps at least one admin."),
|
|
111
134
|
}),
|
|
112
|
-
teammateGroupOperation("teammate_groups.message", "group_message", "POST", "/{group_id}/messages", "Send a message in a group chat. The
|
|
135
|
+
teammateGroupOperation("teammate_groups.message", "group_message", "POST", "/{group_id}/messages", "Send a message in a group chat. The Oxygents it @mentions answer, in order; with no mention, the Oxygents it is for answer, or, in a group of only you, whoever answered last. A message that @mentions only people goes to them. In a group with other people, each answer waits for the one before it, and paid or external actions ask whoever sent the message. Each answer is a turn billed from workspace credits.", { message: str({ minLength: 1, maxLength: 16000 }) }, ["message"], true),
|
|
113
136
|
teammateGroupOperation("teammate_groups.read", "group_read", "POST", "/{group_id}/read", "Mark a group chat read up to its newest turn, or up to turn_index.", { turn_index: int({ minimum: 0 }) }),
|
|
114
|
-
teammateGroupOperation("teammate_groups.
|
|
137
|
+
teammateGroupOperation("teammate_groups.leave", "group_leave", "POST", "/{group_id}/leave", "Leave a group chat: it disappears for you and its Oxygents stop answering your waiting messages. If you were its last admin, whoever has been in it longest becomes one; if you were the last person, it ends."),
|
|
138
|
+
teammateGroupOperation("teammate_groups.end", "group_end", "POST", "/{group_id}/end", "End a group chat for everyone in it, as one of its admins: nobody answers in it again, and its messages stay readable."),
|
|
115
139
|
];
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How a batch of email verifications is sized and read. `/api/cli/verify/run`
|
|
3
|
+
* and the CLI that pages a longer list through it share this, so a one-page and
|
|
4
|
+
* a many-page run can never disagree about the summary or the leading next action.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Addresses one live request verifies. Each one is a paid provider call made in
|
|
8
|
+
* sequence, so the CLI sends a longer list in pages under one credit ceiling.
|
|
9
|
+
*/
|
|
10
|
+
export declare const EMAIL_VERIFICATION_LIVE_PAGE_MAX = 100;
|
|
11
|
+
/**
|
|
12
|
+
* Addresses one `verify email` command takes. The free preview prices the whole
|
|
13
|
+
* list in one request, so this also bounds that request body.
|
|
14
|
+
*/
|
|
15
|
+
export declare const EMAIL_VERIFICATION_LIST_MAX = 5000;
|
|
16
|
+
type VerificationRow = Readonly<Record<string, unknown>>;
|
|
17
|
+
export declare function summarizeEmailVerificationResults(results: ReadonlyArray<VerificationRow>): {
|
|
18
|
+
total: number;
|
|
19
|
+
valid: number;
|
|
20
|
+
invalid: number;
|
|
21
|
+
catch_all: number;
|
|
22
|
+
unknown: number;
|
|
23
|
+
};
|
|
24
|
+
/** The one per-address `next_action` worth lifting to the top of the envelope. */
|
|
25
|
+
export declare function leadingEmailVerificationNextAction(results: ReadonlyArray<VerificationRow>): string | null;
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How a batch of email verifications is sized and read. `/api/cli/verify/run`
|
|
3
|
+
* and the CLI that pages a longer list through it share this, so a one-page and
|
|
4
|
+
* a many-page run can never disagree about the summary or the leading next action.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Addresses one live request verifies. Each one is a paid provider call made in
|
|
8
|
+
* sequence, so the CLI sends a longer list in pages under one credit ceiling.
|
|
9
|
+
*/
|
|
10
|
+
export const EMAIL_VERIFICATION_LIVE_PAGE_MAX = 100;
|
|
11
|
+
/**
|
|
12
|
+
* Addresses one `verify email` command takes. The free preview prices the whole
|
|
13
|
+
* list in one request, so this also bounds that request body.
|
|
14
|
+
*/
|
|
15
|
+
export const EMAIL_VERIFICATION_LIST_MAX = 5_000;
|
|
16
|
+
export function summarizeEmailVerificationResults(results) {
|
|
17
|
+
const count = (verdict) => results.filter((row) => row.verdict === verdict).length;
|
|
18
|
+
return {
|
|
19
|
+
total: results.length,
|
|
20
|
+
valid: count("valid"),
|
|
21
|
+
invalid: count("invalid"),
|
|
22
|
+
catch_all: count("catch_all"),
|
|
23
|
+
unknown: count("unknown"),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
// Rank order for the batch-level next action: the condition a human has to act
|
|
27
|
+
// on outranks the ones that resolve themselves on a re-run.
|
|
28
|
+
const NEXT_ACTION_RANK = {
|
|
29
|
+
// A held escalation outranks everything: re-running it, as the other skips
|
|
30
|
+
// suggest, could charge the same address twice.
|
|
31
|
+
"escalation_unavailable:outcome_unknown": 7,
|
|
32
|
+
"escalation_unavailable:provider_account_held": 6,
|
|
33
|
+
"escalation_unavailable:provider_account_dry": 5,
|
|
34
|
+
"escalation_unavailable:not_configured": 4,
|
|
35
|
+
"escalation_unavailable:provider_error": 3,
|
|
36
|
+
budget_exhausted: 2,
|
|
37
|
+
not_configured: 1,
|
|
38
|
+
};
|
|
39
|
+
/** The one per-address `next_action` worth lifting to the top of the envelope. */
|
|
40
|
+
export function leadingEmailVerificationNextAction(results) {
|
|
41
|
+
let best = null;
|
|
42
|
+
for (const row of results) {
|
|
43
|
+
const text = typeof row.next_action === "string" ? row.next_action : null;
|
|
44
|
+
if (!text)
|
|
45
|
+
continue;
|
|
46
|
+
const skipped = typeof row.escalation_skipped === "string" ? row.escalation_skipped : "";
|
|
47
|
+
const unavailable = typeof row.escalation_unavailable_reason === "string"
|
|
48
|
+
? row.escalation_unavailable_reason
|
|
49
|
+
: null;
|
|
50
|
+
const rank = NEXT_ACTION_RANK[unavailable ? `${skipped}:${unavailable}` : skipped] ?? 0;
|
|
51
|
+
if (!best || rank > best.rank)
|
|
52
|
+
best = { rank, text };
|
|
53
|
+
}
|
|
54
|
+
return best?.text ?? null;
|
|
55
|
+
}
|
|
@@ -70,9 +70,9 @@ export declare const KNOWLEDGE_BOOTSTRAP_ENRICHMENT_MAX_CREDITS = 6;
|
|
|
70
70
|
*/
|
|
71
71
|
export declare const KNOWLEDGE_BOOTSTRAP_SYNTHESIS_TIER: HostedAiLevel;
|
|
72
72
|
/**
|
|
73
|
-
* Most URLs whose text the pass may read
|
|
74
|
-
*
|
|
75
|
-
*
|
|
73
|
+
* Most URLs whose text the pass may read inside ONE `exa.contents` call. Each URL
|
|
74
|
+
* is billed, so raising this raises the read ceiling as well as latency and prompt
|
|
75
|
+
* size. The credit ceilings above remain the money guard.
|
|
76
76
|
*/
|
|
77
77
|
export declare const KNOWLEDGE_BOOTSTRAP_MAX_PAGES_READ = 5;
|
|
78
78
|
/**
|
|
@@ -71,9 +71,9 @@ export const KNOWLEDGE_BOOTSTRAP_ENRICHMENT_MAX_CREDITS = 6;
|
|
|
71
71
|
*/
|
|
72
72
|
export const KNOWLEDGE_BOOTSTRAP_SYNTHESIS_TIER = "medium";
|
|
73
73
|
/**
|
|
74
|
-
* Most URLs whose text the pass may read
|
|
75
|
-
*
|
|
76
|
-
*
|
|
74
|
+
* Most URLs whose text the pass may read inside ONE `exa.contents` call. Each URL
|
|
75
|
+
* is billed, so raising this raises the read ceiling as well as latency and prompt
|
|
76
|
+
* size. The credit ceilings above remain the money guard.
|
|
77
77
|
*/
|
|
78
78
|
export const KNOWLEDGE_BOOTSTRAP_MAX_PAGES_READ = 5;
|
|
79
79
|
/**
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/** The draft's centre page: the company itself. Stable, so a rerun never mints a second one. */
|
|
2
|
+
export declare const KNOWLEDGE_BRAIN_DRAFT_COMPANY_SLUG = "company";
|
|
3
|
+
/** What marks a page as written by the draft; the onboarding graph watches for it. */
|
|
4
|
+
export declare const KNOWLEDGE_BRAIN_DRAFT_TAG = "onboarding-draft";
|
|
5
|
+
/** Tags every drafted page carries. */
|
|
6
|
+
export declare const KNOWLEDGE_BRAIN_DRAFT_TAGS: readonly ["agent-derived", "onboarding-draft"];
|
|
7
|
+
/** The hub pages, revealed right after the company and kept at the explorer's root. */
|
|
8
|
+
export declare const KNOWLEDGE_BRAIN_DRAFT_HUBS: readonly ["offers", "icp", "messaging"];
|
|
9
|
+
/** Leaf-page kinds by slug prefix, in the order onboarding reveals them after the hubs. */
|
|
10
|
+
export declare const KNOWLEDGE_BRAIN_DRAFT_KINDS: readonly [{
|
|
11
|
+
readonly prefix: "segment-";
|
|
12
|
+
readonly folder: "Segments";
|
|
13
|
+
readonly type: "strategy";
|
|
14
|
+
readonly tag: "segment";
|
|
15
|
+
}, {
|
|
16
|
+
readonly prefix: "persona-";
|
|
17
|
+
readonly folder: "Personas";
|
|
18
|
+
readonly type: "persona";
|
|
19
|
+
readonly tag: "persona";
|
|
20
|
+
}, {
|
|
21
|
+
readonly prefix: "product-";
|
|
22
|
+
readonly folder: "Products";
|
|
23
|
+
readonly type: "entity";
|
|
24
|
+
readonly tag: "product";
|
|
25
|
+
}, {
|
|
26
|
+
readonly prefix: "use-case-";
|
|
27
|
+
readonly folder: "Use cases";
|
|
28
|
+
readonly type: "topic";
|
|
29
|
+
readonly tag: "use-case";
|
|
30
|
+
}, {
|
|
31
|
+
readonly prefix: "pain-";
|
|
32
|
+
readonly folder: "Pains";
|
|
33
|
+
readonly type: "topic";
|
|
34
|
+
readonly tag: "pain";
|
|
35
|
+
}, {
|
|
36
|
+
readonly prefix: "trigger-";
|
|
37
|
+
readonly folder: "Buying triggers";
|
|
38
|
+
readonly type: "topic";
|
|
39
|
+
readonly tag: "trigger";
|
|
40
|
+
}, {
|
|
41
|
+
readonly prefix: "angle-";
|
|
42
|
+
readonly folder: "Messaging";
|
|
43
|
+
readonly type: "message_playbook";
|
|
44
|
+
readonly tag: "angle";
|
|
45
|
+
}, {
|
|
46
|
+
readonly prefix: "objection-";
|
|
47
|
+
readonly folder: "Messaging";
|
|
48
|
+
readonly type: "message_playbook";
|
|
49
|
+
readonly tag: "objection";
|
|
50
|
+
}, {
|
|
51
|
+
readonly prefix: "filter-";
|
|
52
|
+
readonly folder: "Search filters";
|
|
53
|
+
readonly type: "strategy";
|
|
54
|
+
readonly tag: "filter";
|
|
55
|
+
}, {
|
|
56
|
+
readonly prefix: "customer-";
|
|
57
|
+
readonly folder: "Customers";
|
|
58
|
+
readonly type: "entity";
|
|
59
|
+
readonly tag: "customer";
|
|
60
|
+
}, {
|
|
61
|
+
readonly prefix: "competitor-";
|
|
62
|
+
readonly folder: "Competitors";
|
|
63
|
+
readonly type: "competitor";
|
|
64
|
+
readonly tag: "competitor";
|
|
65
|
+
}];
|
|
66
|
+
/**
|
|
67
|
+
* Where a page falls in the reveal: the company, the hubs, then each leaf kind in turn,
|
|
68
|
+
* then any other page the workspace already holds (the research note, a seeded page).
|
|
69
|
+
*/
|
|
70
|
+
export declare function knowledgeBrainDraftRevealRank(slug: string): number;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// The second-brain draft's page vocabulary (Tim, 2026-10-14/15): which pages a new
|
|
2
|
+
// workspace's homepage draft writes, the folder each kind is filed in, and the order
|
|
3
|
+
// onboarding's second-brain step reveals them. One browser-safe owner, so the writer
|
|
4
|
+
// (@oxygen/integrations knowledge-brain-draft) and the step that draws the graph
|
|
5
|
+
// (apps/web onboarding-brain) can never disagree.
|
|
6
|
+
/** The draft's centre page: the company itself. Stable, so a rerun never mints a second one. */
|
|
7
|
+
export const KNOWLEDGE_BRAIN_DRAFT_COMPANY_SLUG = "company";
|
|
8
|
+
/** What marks a page as written by the draft; the onboarding graph watches for it. */
|
|
9
|
+
export const KNOWLEDGE_BRAIN_DRAFT_TAG = "onboarding-draft";
|
|
10
|
+
/** Tags every drafted page carries. */
|
|
11
|
+
export const KNOWLEDGE_BRAIN_DRAFT_TAGS = ["agent-derived", KNOWLEDGE_BRAIN_DRAFT_TAG];
|
|
12
|
+
/** The hub pages, revealed right after the company and kept at the explorer's root. */
|
|
13
|
+
export const KNOWLEDGE_BRAIN_DRAFT_HUBS = ["offers", "icp", "messaging"];
|
|
14
|
+
/** Leaf-page kinds by slug prefix, in the order onboarding reveals them after the hubs. */
|
|
15
|
+
export const KNOWLEDGE_BRAIN_DRAFT_KINDS = [
|
|
16
|
+
{ prefix: "segment-", folder: "Segments", type: "strategy", tag: "segment" },
|
|
17
|
+
{ prefix: "persona-", folder: "Personas", type: "persona", tag: "persona" },
|
|
18
|
+
{ prefix: "product-", folder: "Products", type: "entity", tag: "product" },
|
|
19
|
+
{ prefix: "use-case-", folder: "Use cases", type: "topic", tag: "use-case" },
|
|
20
|
+
{ prefix: "pain-", folder: "Pains", type: "topic", tag: "pain" },
|
|
21
|
+
{ prefix: "trigger-", folder: "Buying triggers", type: "topic", tag: "trigger" },
|
|
22
|
+
{ prefix: "angle-", folder: "Messaging", type: "message_playbook", tag: "angle" },
|
|
23
|
+
{ prefix: "objection-", folder: "Messaging", type: "message_playbook", tag: "objection" },
|
|
24
|
+
{ prefix: "filter-", folder: "Search filters", type: "strategy", tag: "filter" },
|
|
25
|
+
{ prefix: "customer-", folder: "Customers", type: "entity", tag: "customer" },
|
|
26
|
+
{ prefix: "competitor-", folder: "Competitors", type: "competitor", tag: "competitor" },
|
|
27
|
+
];
|
|
28
|
+
/**
|
|
29
|
+
* Where a page falls in the reveal: the company, the hubs, then each leaf kind in turn,
|
|
30
|
+
* then any other page the workspace already holds (the research note, a seeded page).
|
|
31
|
+
*/
|
|
32
|
+
export function knowledgeBrainDraftRevealRank(slug) {
|
|
33
|
+
if (slug === KNOWLEDGE_BRAIN_DRAFT_COMPANY_SLUG)
|
|
34
|
+
return 0;
|
|
35
|
+
const hub = KNOWLEDGE_BRAIN_DRAFT_HUBS.indexOf(slug);
|
|
36
|
+
if (hub >= 0)
|
|
37
|
+
return 1 + hub;
|
|
38
|
+
const kind = KNOWLEDGE_BRAIN_DRAFT_KINDS.findIndex((entry) => slug.startsWith(entry.prefix));
|
|
39
|
+
if (kind >= 0)
|
|
40
|
+
return 1 + KNOWLEDGE_BRAIN_DRAFT_HUBS.length + kind;
|
|
41
|
+
return 1 + KNOWLEDGE_BRAIN_DRAFT_HUBS.length + KNOWLEDGE_BRAIN_DRAFT_KINDS.length;
|
|
42
|
+
}
|
|
@@ -97,7 +97,7 @@ export const PLAN_GATED_CAPABILITY_COPY = {
|
|
|
97
97
|
},
|
|
98
98
|
publishing_deliver: {
|
|
99
99
|
label: "Publishing a post",
|
|
100
|
-
freeAlternative: "You can draft
|
|
100
|
+
freeAlternative: "You can draft and review posts on Free. Approving one for delivery to a live account is what needs a plan.",
|
|
101
101
|
deepLinkPath: "/publishing",
|
|
102
102
|
},
|
|
103
103
|
managed_email_infrastructure: {
|
|
@@ -155,7 +155,7 @@ export declare const RESEARCH_DEPTH_GROUNDING_CREDITS: {
|
|
|
155
155
|
};
|
|
156
156
|
readonly deep: {
|
|
157
157
|
readonly typical: 2.4;
|
|
158
|
-
readonly reserved:
|
|
158
|
+
readonly reserved: 22.4;
|
|
159
159
|
};
|
|
160
160
|
};
|
|
161
161
|
/** Typical per-row totals at each depth's default tier (founder-ratified 2026-09-26). */
|
|
@@ -147,7 +147,9 @@ export const RESEARCH_DEPTH_MODEL_CREDITS = { standard: 4.3, deep: 7.6 };
|
|
|
147
147
|
*/
|
|
148
148
|
export const RESEARCH_DEPTH_GROUNDING_CREDITS = {
|
|
149
149
|
standard: { typical: 1.2, reserved: 7.4 },
|
|
150
|
-
|
|
150
|
+
// Each of the two site_pages calls can fetch its root plus five subpages:
|
|
151
|
+
// 6 x 0.5 credits per call, rather than one 0.5-credit page per call.
|
|
152
|
+
deep: { typical: 2.4, reserved: 22.4 },
|
|
151
153
|
};
|
|
152
154
|
/** Typical per-row totals at each depth's default tier (founder-ratified 2026-09-26). */
|
|
153
155
|
export const RESEARCH_DEPTH_TYPICAL_ROW_CREDITS = { quick: 2.1, standard: 5.5, deep: 10 };
|
|
@@ -49,7 +49,7 @@ function rosterLines(routes) {
|
|
|
49
49
|
* a grown or shrunk route array and watching the output follow.
|
|
50
50
|
*/
|
|
51
51
|
export function renderOxygenProductDoctrine(routes = OXYGEN_PRIMITIVE_ROUTES) {
|
|
52
|
-
return `OXYGEN is
|
|
52
|
+
return `OXYGEN is the agentic GTM platform for B2B GTM teams; OXYGEN OS has five layers. Control (CLI, MCP, web, desktop, Copilot) calls one contract, owns no state; External holds integrations. Between them, the ${routes.length} primitives, each owns its facts:
|
|
53
53
|
|
|
54
54
|
${rosterLines(routes)}
|
|
55
55
|
|