@oxygen-agent/cli 1.1014.136 → 1.1014.619
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-primary-providers-render.js +27 -19
- package/dist/cli-output.d.ts +12 -0
- package/dist/cli-output.js +395 -0
- package/dist/cli-paths.d.ts +1 -0
- package/dist/cli-paths.js +3 -0
- package/dist/cli-profile-context.d.ts +3 -0
- package/dist/cli-profile-context.js +13 -0
- package/dist/command-manifest.d.ts +15 -0
- package/dist/command-manifest.js +23 -1
- package/dist/command-support.d.ts +438 -0
- package/dist/command-support.js +1610 -0
- package/dist/commands/action-column.d.ts +3 -0
- package/dist/commands/action-column.js +43 -0
- package/dist/commands/activation.d.ts +3 -0
- package/dist/commands/activation.js +24 -0
- package/dist/commands/admin.d.ts +3 -0
- package/dist/commands/admin.js +347 -0
- package/dist/commands/ads.d.ts +3 -0
- package/dist/commands/ads.js +62 -0
- package/dist/commands/agent.d.ts +3 -0
- package/dist/commands/agent.js +274 -0
- package/dist/commands/api-keys.d.ts +3 -0
- package/dist/commands/api-keys.js +77 -0
- package/dist/commands/approvals.d.ts +3 -0
- package/dist/commands/approvals.js +518 -0
- package/dist/commands/auth.d.ts +3 -0
- package/dist/commands/auth.js +230 -0
- package/dist/commands/billing.d.ts +3 -0
- package/dist/commands/billing.js +357 -0
- package/dist/commands/blueprints.d.ts +3 -0
- package/dist/commands/blueprints.js +312 -0
- package/dist/commands/budget.d.ts +3 -0
- package/dist/commands/budget.js +55 -0
- package/dist/commands/callables.d.ts +3 -0
- package/dist/commands/callables.js +111 -0
- package/dist/commands/capabilities.d.ts +3 -0
- package/dist/commands/capabilities.js +44 -0
- package/dist/commands/cells.d.ts +3 -0
- package/dist/commands/cells.js +94 -0
- package/dist/commands/columns.d.ts +3 -0
- package/dist/commands/columns.js +1628 -0
- package/dist/commands/commands.d.ts +3 -0
- package/dist/commands/commands.js +45 -0
- package/dist/commands/comments.d.ts +3 -0
- package/dist/commands/comments.js +188 -0
- package/dist/commands/companies.d.ts +3 -0
- package/dist/commands/companies.js +312 -0
- package/dist/commands/connections.d.ts +3 -0
- package/dist/commands/connections.js +39 -0
- package/dist/commands/context.d.ts +3 -0
- package/dist/commands/context.js +170 -0
- package/dist/commands/copilot.d.ts +3 -0
- package/dist/commands/copilot.js +565 -0
- package/dist/commands/crm.d.ts +3 -0
- package/dist/commands/crm.js +1672 -0
- package/dist/commands/custom-integrations.d.ts +3 -0
- package/dist/commands/custom-integrations.js +140 -0
- package/dist/commands/dashboards.d.ts +3 -0
- package/dist/commands/dashboards.js +240 -0
- package/dist/commands/db.d.ts +3 -0
- package/dist/commands/db.js +190 -0
- package/dist/commands/deliverability.d.ts +3 -0
- package/dist/commands/deliverability.js +90 -0
- package/dist/commands/directory.d.ts +3 -0
- package/dist/commands/directory.js +101 -0
- package/dist/commands/domains.d.ts +3 -0
- package/dist/commands/domains.js +604 -0
- package/dist/commands/egress.d.ts +3 -0
- package/dist/commands/egress.js +130 -0
- package/dist/commands/email.d.ts +3 -0
- package/dist/commands/email.js +49 -0
- package/dist/commands/engagement.d.ts +3 -0
- package/dist/commands/engagement.js +189 -0
- package/dist/commands/enrich-column.d.ts +3 -0
- package/dist/commands/enrich-column.js +149 -0
- package/dist/commands/enrichment.d.ts +3 -0
- package/dist/commands/enrichment.js +49 -0
- package/dist/commands/feedback.d.ts +3 -0
- package/dist/commands/feedback.js +96 -0
- package/dist/commands/feeds.d.ts +3 -0
- package/dist/commands/feeds.js +486 -0
- package/dist/commands/find.d.ts +3 -0
- package/dist/commands/find.js +159 -0
- package/dist/commands/followers.d.ts +3 -0
- package/dist/commands/followers.js +39 -0
- package/dist/commands/formulas.d.ts +3 -0
- package/dist/commands/formulas.js +43 -0
- package/dist/commands/home.d.ts +3 -0
- package/dist/commands/home.js +22 -0
- package/dist/commands/inbox.d.ts +3 -0
- package/dist/commands/inbox.js +779 -0
- package/dist/commands/integrations.d.ts +3 -0
- package/dist/commands/integrations.js +290 -0
- package/dist/commands/knowledge.d.ts +3 -0
- package/dist/commands/knowledge.js +874 -0
- package/dist/commands/lead-sourcing.d.ts +3 -0
- package/dist/commands/lead-sourcing.js +52 -0
- package/dist/commands/limits.d.ts +3 -0
- package/dist/commands/limits.js +54 -0
- package/dist/commands/linkedin.d.ts +3 -0
- package/dist/commands/linkedin.js +275 -0
- package/dist/commands/login.d.ts +3 -0
- package/dist/commands/login.js +347 -0
- package/dist/commands/logout.d.ts +3 -0
- package/dist/commands/logout.js +12 -0
- package/dist/commands/mailboxes.d.ts +3 -0
- package/dist/commands/mailboxes.js +1290 -0
- package/dist/commands/managed-inboxes.d.ts +3 -0
- package/dist/commands/managed-inboxes.js +361 -0
- package/dist/commands/messages.d.ts +3 -0
- package/dist/commands/messages.js +78 -0
- package/dist/commands/notetaker.d.ts +3 -0
- package/dist/commands/notetaker.js +79 -0
- package/dist/commands/observability.d.ts +3 -0
- package/dist/commands/observability.js +125 -0
- package/dist/commands/orgs.d.ts +3 -0
- package/dist/commands/orgs.js +237 -0
- package/dist/commands/people.d.ts +3 -0
- package/dist/commands/people.js +353 -0
- package/dist/commands/posts.d.ts +3 -0
- package/dist/commands/posts.js +139 -0
- package/dist/commands/profiles.d.ts +3 -0
- package/dist/commands/profiles.js +250 -0
- package/dist/commands/projects.d.ts +3 -0
- package/dist/commands/projects.js +94 -0
- package/dist/commands/prompts.d.ts +3 -0
- package/dist/commands/prompts.js +84 -0
- package/dist/commands/publishing.d.ts +3 -0
- package/dist/commands/publishing.js +1419 -0
- package/dist/commands/recipes.d.ts +3 -0
- package/dist/commands/recipes.js +120 -0
- package/dist/commands/reviews.d.ts +3 -0
- package/dist/commands/reviews.js +75 -0
- package/dist/commands/rows.d.ts +3 -0
- package/dist/commands/rows.js +27 -0
- package/dist/commands/runs.d.ts +3 -0
- package/dist/commands/runs.js +37 -0
- package/dist/commands/search.d.ts +3 -0
- package/dist/commands/search.js +182 -0
- package/dist/commands/senders.d.ts +3 -0
- package/dist/commands/senders.js +393 -0
- package/dist/commands/sequences.d.ts +3 -0
- package/dist/commands/sequences.js +2322 -0
- package/dist/commands/session.d.ts +3 -0
- package/dist/commands/session.js +109 -0
- package/dist/commands/signals.d.ts +3 -0
- package/dist/commands/signals.js +289 -0
- package/dist/commands/signup-leads.d.ts +3 -0
- package/dist/commands/signup-leads.js +46 -0
- package/dist/commands/skills.d.ts +3 -0
- package/dist/commands/skills.js +50 -0
- package/dist/commands/sourcing.d.ts +3 -0
- package/dist/commands/sourcing.js +27 -0
- package/dist/commands/status.d.ts +3 -0
- package/dist/commands/status.js +51 -0
- package/dist/commands/supabase.d.ts +3 -0
- package/dist/commands/supabase.js +128 -0
- package/dist/commands/support.d.ts +3 -0
- package/dist/commands/support.js +651 -0
- package/dist/commands/suppressions.d.ts +3 -0
- package/dist/commands/suppressions.js +577 -0
- package/dist/commands/table-ingestions.d.ts +3 -0
- package/dist/commands/table-ingestions.js +145 -0
- package/dist/commands/table-runs.d.ts +3 -0
- package/dist/commands/table-runs.js +277 -0
- package/dist/commands/tables.d.ts +3 -0
- package/dist/commands/tables.js +3505 -0
- package/dist/commands/tags.d.ts +3 -0
- package/dist/commands/tags.js +147 -0
- package/dist/commands/tools.d.ts +3 -0
- package/dist/commands/tools.js +246 -0
- package/dist/commands/update.d.ts +3 -0
- package/dist/commands/update.js +106 -0
- package/dist/commands/verify.d.ts +3 -0
- package/dist/commands/verify.js +27 -0
- package/dist/commands/viewers.d.ts +3 -0
- package/dist/commands/viewers.js +72 -0
- package/dist/commands/voice.d.ts +3 -0
- package/dist/commands/voice.js +351 -0
- package/dist/commands/whatsapp.d.ts +3 -0
- package/dist/commands/whatsapp.js +226 -0
- package/dist/commands/whoami.d.ts +3 -0
- package/dist/commands/whoami.js +110 -0
- package/dist/commands/worker.d.ts +3 -0
- package/dist/commands/worker.js +60 -0
- package/dist/commands/workflows.d.ts +3 -0
- package/dist/commands/workflows.js +1752 -0
- package/dist/commands/workspace.d.ts +3 -0
- package/dist/commands/workspace.js +94 -0
- package/dist/compact-list-flags.d.ts +7 -0
- package/dist/compact-list-flags.js +12 -0
- package/dist/crm-support-flags.js +14 -5
- package/dist/customer-operation-commands.js +8 -6
- package/dist/diagnostic-uploader.d.ts +3 -1
- package/dist/diagnostic-uploader.js +29 -8
- package/dist/help.d.ts +5 -0
- package/dist/help.js +22 -0
- package/dist/index.d.ts +98 -1
- package/dist/index.js +331 -30719
- package/dist/local-module-loader.d.ts +4 -0
- package/dist/local-module-loader.js +156 -0
- package/dist/visual-commands.js +9 -5
- package/node_modules/@oxygen/cli-ugc/dist/commands.js +2 -2
- package/node_modules/@oxygen/shared/dist/agent-session-schedule.d.ts +36 -0
- package/node_modules/@oxygen/shared/dist/agent-session-schedule.js +69 -0
- package/node_modules/@oxygen/shared/dist/agent-sessions.d.ts +14 -5
- package/node_modules/@oxygen/shared/dist/agent-sessions.js +14 -3
- package/node_modules/@oxygen/shared/dist/capability-discovery.js +175 -14
- package/node_modules/@oxygen/shared/dist/compact-list-result.d.ts +6 -0
- package/node_modules/@oxygen/shared/dist/compact-list-result.js +27 -0
- package/node_modules/@oxygen/shared/dist/contracts/agent-sessions.d.ts +12 -1
- package/node_modules/@oxygen/shared/dist/contracts/agent-sessions.js +5 -2
- package/node_modules/@oxygen/shared/dist/contracts/browser-operations.js +4 -2
- package/node_modules/@oxygen/shared/dist/contracts/compact-list-reads.d.ts +57 -0
- package/node_modules/@oxygen/shared/dist/contracts/compact-list-reads.js +23 -0
- package/node_modules/@oxygen/shared/dist/contracts/crm-support.d.ts +52 -0
- package/node_modules/@oxygen/shared/dist/contracts/crm-support.js +43 -2
- package/node_modules/@oxygen/shared/dist/contracts/customer-operations.js +20 -16
- package/node_modules/@oxygen/shared/dist/contracts/knowledge-content-reads.js +1 -1
- package/node_modules/@oxygen/shared/dist/contracts/knowledge-proposal-reads.d.ts +49 -0
- package/node_modules/@oxygen/shared/dist/contracts/knowledge-proposal-reads.js +14 -0
- package/node_modules/@oxygen/shared/dist/contracts/knowledge-sync.js +1 -1
- package/node_modules/@oxygen/shared/dist/contracts/limits-read.js +60 -7
- package/node_modules/@oxygen/shared/dist/contracts/operations.d.ts +9 -1
- package/node_modules/@oxygen/shared/dist/contracts/operations.js +13 -5
- package/node_modules/@oxygen/shared/dist/contracts/publishing-reads.js +1 -1
- package/node_modules/@oxygen/shared/dist/contracts/teammates.d.ts +16 -0
- package/node_modules/@oxygen/shared/dist/contracts/teammates.js +115 -0
- package/node_modules/@oxygen/shared/dist/cost-estimate-view.js +21 -3
- package/node_modules/@oxygen/shared/dist/cost-estimate.d.ts +31 -1
- package/node_modules/@oxygen/shared/dist/cost-estimate.js +56 -15
- package/node_modules/@oxygen/shared/dist/diagnostic-credentials.d.ts +2 -0
- package/node_modules/@oxygen/shared/dist/diagnostic-credentials.js +2 -0
- package/node_modules/@oxygen/shared/dist/diagnostic-lock.js +71 -44
- package/node_modules/@oxygen/shared/dist/diagnostic-spool.d.ts +18 -0
- package/node_modules/@oxygen/shared/dist/diagnostic-spool.js +348 -0
- package/node_modules/@oxygen/shared/dist/diagnostic-storage-failure.d.ts +10 -0
- package/node_modules/@oxygen/shared/dist/diagnostic-storage-failure.js +42 -0
- package/node_modules/@oxygen/shared/dist/diagnostic-storage.d.ts +1 -1
- package/node_modules/@oxygen/shared/dist/diagnostic-storage.js +59 -213
- package/node_modules/@oxygen/shared/dist/diagnostics.js +3 -2
- package/node_modules/@oxygen/shared/dist/email-dsn.d.ts +16 -5
- package/node_modules/@oxygen/shared/dist/email-dsn.js +97 -1
- package/node_modules/@oxygen/shared/dist/emailguard-placement-probe.js +5 -0
- package/node_modules/@oxygen/shared/dist/enrichment-intents.js +4 -5
- package/node_modules/@oxygen/shared/dist/file-import.d.ts +8 -0
- package/node_modules/@oxygen/shared/dist/file-import.js +21 -2
- package/node_modules/@oxygen/shared/dist/hosted-ai.d.ts +30 -0
- package/node_modules/@oxygen/shared/dist/hosted-ai.js +20 -0
- package/node_modules/@oxygen/shared/dist/knowledge-bootstrap.d.ts +6 -2
- package/node_modules/@oxygen/shared/dist/knowledge-seed-content.d.ts +17 -7
- package/node_modules/@oxygen/shared/dist/knowledge-seed-content.js +81 -17
- package/node_modules/@oxygen/shared/dist/langfuse.js +8 -4
- package/node_modules/@oxygen/shared/dist/mailbox-egress-ownership.d.ts +1 -1
- package/node_modules/@oxygen/shared/dist/mailbox-import.d.ts +6 -3
- package/node_modules/@oxygen/shared/dist/mailbox-import.js +9 -9
- package/node_modules/@oxygen/shared/dist/mcp-server-info.d.ts +8 -0
- package/node_modules/@oxygen/shared/dist/mcp-server-info.js +10 -0
- package/node_modules/@oxygen/shared/dist/object-storage.d.ts +10 -0
- package/node_modules/@oxygen/shared/dist/object-storage.js +14 -0
- package/node_modules/@oxygen/shared/dist/plan-limits-view.d.ts +5 -0
- package/node_modules/@oxygen/shared/dist/plan-limits-view.js +17 -1
- package/node_modules/@oxygen/shared/dist/pricing-sheet.d.ts +1 -1
- package/node_modules/@oxygen/shared/dist/pricing-sheet.js +1 -1
- package/node_modules/@oxygen/shared/dist/provider-selection.d.ts +15 -0
- package/node_modules/@oxygen/shared/dist/provider-selection.js +3 -0
- package/node_modules/@oxygen/shared/dist/repricing.d.ts +1 -1
- package/node_modules/@oxygen/shared/dist/repricing.js +2 -2
- package/node_modules/@oxygen/shared/dist/schedule-label.d.ts +6 -0
- package/node_modules/@oxygen/shared/dist/schedule-label.js +12 -0
- package/node_modules/@oxygen/shared/dist/sequence-failures.d.ts +1 -0
- package/node_modules/@oxygen/shared/dist/sequence-failures.js +20 -6
- package/node_modules/@oxygen/shared/dist/teammate-groups.d.ts +55 -0
- package/node_modules/@oxygen/shared/dist/teammate-groups.js +74 -0
- package/node_modules/@oxygen/shared/dist/teammate-messages.d.ts +52 -0
- package/node_modules/@oxygen/shared/dist/teammate-messages.js +88 -0
- package/node_modules/@oxygen/shared/dist/teammate-notes.d.ts +58 -0
- package/node_modules/@oxygen/shared/dist/teammate-notes.js +73 -0
- package/node_modules/@oxygen/shared/dist/teammate-routines.d.ts +95 -0
- package/node_modules/@oxygen/shared/dist/teammate-routines.js +266 -0
- package/node_modules/@oxygen/shared/dist/teammate-tasks.d.ts +56 -0
- package/node_modules/@oxygen/shared/dist/teammate-tasks.js +114 -0
- package/node_modules/@oxygen/shared/dist/teammates.d.ts +78 -0
- package/node_modules/@oxygen/shared/dist/teammates.js +140 -0
- package/node_modules/@oxygen/shared/dist/user-capability-routing.js +120 -0
- package/node_modules/@oxygen/shared/dist/version.generated.d.ts +1 -1
- package/node_modules/@oxygen/shared/dist/version.generated.js +1 -1
- package/node_modules/@oxygen/shared/dist/visual-render.d.ts +9 -1
- package/node_modules/@oxygen/shared/dist/visual-render.js +12 -5
- package/node_modules/@oxygen/shared/dist/warmup-metrics.d.ts +5 -0
- package/node_modules/@oxygen/shared/dist/warmup-metrics.js +44 -0
- package/package.json +1 -1
|
@@ -151,14 +151,18 @@ export type KnowledgeBootstrapMarker = {
|
|
|
151
151
|
completed_at: string | null;
|
|
152
152
|
/** `ox_runs.runs` id (source_type `system`) carrying the observable run. */
|
|
153
153
|
run_id: string | null;
|
|
154
|
-
/** Managed
|
|
154
|
+
/** Managed accounting total across every phase. When effect_outcome is unknown,
|
|
155
|
+
* this is a conservative bound rather than measured spend. Never exceeds the cap. */
|
|
155
156
|
credits_used: number;
|
|
156
157
|
/**
|
|
157
158
|
* `unknown` when the pass stopped with no record of which provider calls it made: a
|
|
158
159
|
* legacy attempt closed as `interrupted_without_checkpoint`. `credits_used` is then
|
|
159
|
-
* not a measurement
|
|
160
|
+
* not a measurement. A customer read can also qualify saved research whose
|
|
161
|
+
* current checkpoint retains an unconfirmed paid lookup.
|
|
160
162
|
*/
|
|
161
163
|
effect_outcome?: "unknown";
|
|
164
|
+
/** Read projection only: saved research remains available despite an unconfirmed lookup. */
|
|
165
|
+
research_available?: boolean;
|
|
162
166
|
/**
|
|
163
167
|
* The workspace domain researched (from organizations.iconDomain). Null (stored
|
|
164
168
|
* as "", the key the execution and onboarding checks compare on) for a company
|
|
@@ -2,14 +2,18 @@ import type { KnowledgePageType, KnowledgePageStatus } from "./knowledge-constan
|
|
|
2
2
|
/** Monotonic scaffold cursor stored in knowledge_state.scaffold_version. Bump to ship a
|
|
3
3
|
* new wave of starter pages (tag them with a higher minScaffoldVersion).
|
|
4
4
|
* v1: the 9-page core. v2: twelve GTM stubs (voice/brand/messaging/objections, three
|
|
5
|
-
* motion playbooks + qualification, and the personas/customers/research/metrics hubs).
|
|
5
|
+
* motion playbooks + qualification, and the personas/customers/research/metrics hubs).
|
|
6
|
+
* On 2026-10-12 both waves were retired for the two-page set below and the cursor stayed
|
|
7
|
+
* at 2: it is stored per workspace and never moves backwards, so a workspace already at
|
|
8
|
+
* 2 keeps what it has, one at 1 receives nothing more, and a fresh one seeds the two
|
|
9
|
+
* pages and records 2. The next wave is minScaffoldVersion 3. */
|
|
6
10
|
export declare const KNOWLEDGE_SCAFFOLD_VERSION = 2;
|
|
7
11
|
export type KnowledgeScaffoldPage = {
|
|
8
12
|
/** Immutable slug; must be valid kebab grammar and NOT a reserved slug. */
|
|
9
13
|
slug: string;
|
|
10
14
|
type: KnowledgePageType;
|
|
11
15
|
title: string;
|
|
12
|
-
/**
|
|
16
|
+
/** Seeded pages ship draft so they never ground AI copy; only the retired nav pages shipped active. */
|
|
13
17
|
status: Extract<KnowledgePageStatus, "active" | "draft">;
|
|
14
18
|
tags: string[];
|
|
15
19
|
summary: string;
|
|
@@ -24,11 +28,17 @@ export type KnowledgeScaffoldPage = {
|
|
|
24
28
|
researchable?: boolean;
|
|
25
29
|
};
|
|
26
30
|
/**
|
|
27
|
-
* The 21-page starter
|
|
28
|
-
* schema page), then nineteen draft stub
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
31
|
+
* The 21-page starter set workspaces were seeded with until 2026-10-12, verbatim: two
|
|
32
|
+
* active nav pages (start-here + the conventions schema page), then nineteen draft stub
|
|
33
|
+
* hubs (tag `seed`) — seven from wave 1 and twelve from wave 2. No longer seeded.
|
|
34
|
+
* Workspaces created before then still hold every copy nobody edited, so readers of
|
|
35
|
+
* stored pages (the ChatGPT profile's sanitizer) are tested against these exact bodies,
|
|
36
|
+
* and any cleanup of untouched copies must compare against them rather than guess.
|
|
37
|
+
*/
|
|
38
|
+
export declare const RETIRED_KNOWLEDGE_SEED_PAGES: readonly KnowledgeScaffoldPage[];
|
|
39
|
+
/**
|
|
40
|
+
* The starter set: the ICP and Offers documents, each a draft stub (tag `seed`) linked to
|
|
41
|
+
* the other, so a fresh workspace's graph is two connected files instead of a scaffold.
|
|
32
42
|
*/
|
|
33
43
|
export declare const KNOWLEDGE_SEED_PAGES: readonly KnowledgeScaffoldPage[];
|
|
34
44
|
/**
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
// Knowledge Graph starter
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
1
|
+
// Knowledge Graph starter set. A fresh workspace self-seeds these pages at tenant
|
|
2
|
+
// provisioning / first onboarding / `oxygen knowledge seed`: the ICP and Offers documents,
|
|
3
|
+
// as draft stubs. They are the two the onboarding conversation fills first (offer → ICP)
|
|
4
|
+
// and the two every GTM motion reads. Nothing else is seeded (Tim, 2026-10-12): the
|
|
5
|
+
// earlier 21-page set — a start-here guide, a conventions schema page and nineteen hub
|
|
6
|
+
// stubs — read as bloat and confused new users. Agents and users create any other page
|
|
7
|
+
// when there is something real to put in it.
|
|
6
8
|
//
|
|
7
9
|
// The seeder (tenant-db `ensureKnowledgeScaffold`) is purely additive and version-gated:
|
|
8
10
|
// it creates a page only when its slug is free (never overwriting a user's edits) and
|
|
@@ -11,9 +13,8 @@
|
|
|
11
13
|
// never rewritten by the scaffold. Bodies are the single source of truth for the starter
|
|
12
14
|
// content — keep them dense and wikilinked.
|
|
13
15
|
//
|
|
14
|
-
// BINDING RULE —
|
|
15
|
-
// `status: "draft"` with `seed` in its tags
|
|
16
|
-
// are written full rather than as stubs. `retrieveWorkspaceKnowledge` selects on
|
|
16
|
+
// BINDING RULE — the scaffold adds ZERO active pages. Every seeded page ships
|
|
17
|
+
// `status: "draft"` with `seed` in its tags. `retrieveWorkspaceKnowledge` selects on
|
|
17
18
|
// `status = 'active'` with MIN_BODY_CHARS = 80, so an ACTIVE stub is grounding material:
|
|
18
19
|
// "Stub — fill me. ## Firmographics —" would be injected verbatim into a customer's cold
|
|
19
20
|
// email as company knowledge. Promoting a stub to active is the user's act, never the
|
|
@@ -22,12 +23,15 @@
|
|
|
22
23
|
// NEVER SEED `outreach-learnings`, `won-lost-learnings`, or `meeting-learnings`. tenant-db
|
|
23
24
|
// `ensureLearningsPage` get-or-creates them as `active` on the first reply, deal, or
|
|
24
25
|
// meeting and returns an existing row UNTOUCHED — seeding them as draft stubs would pin
|
|
25
|
-
// them draft forever and silently break the learning loop's read half.
|
|
26
|
-
// unresolved links in [[campaign-learnings]] until the loop creates them for real.
|
|
26
|
+
// them draft forever and silently break the learning loop's read half.
|
|
27
27
|
/** Monotonic scaffold cursor stored in knowledge_state.scaffold_version. Bump to ship a
|
|
28
28
|
* new wave of starter pages (tag them with a higher minScaffoldVersion).
|
|
29
29
|
* v1: the 9-page core. v2: twelve GTM stubs (voice/brand/messaging/objections, three
|
|
30
|
-
* motion playbooks + qualification, and the personas/customers/research/metrics hubs).
|
|
30
|
+
* motion playbooks + qualification, and the personas/customers/research/metrics hubs).
|
|
31
|
+
* On 2026-10-12 both waves were retired for the two-page set below and the cursor stayed
|
|
32
|
+
* at 2: it is stored per workspace and never moves backwards, so a workspace already at
|
|
33
|
+
* 2 keeps what it has, one at 1 receives nothing more, and a fresh one seeds the two
|
|
34
|
+
* pages and records 2. The next wave is minScaffoldVersion 3. */
|
|
31
35
|
// KNOWN LIMITATION of a create-only seeder, accepted deliberately: on a workspace
|
|
32
36
|
// UPGRADED from an earlier wave, the new pages get no inbound links, because the hub that
|
|
33
37
|
// would link them (start-here) already exists and the scaffold never rewrites an existing
|
|
@@ -472,13 +476,14 @@ This page holds definitions and targets — argued over once, then reused. The v
|
|
|
472
476
|
Moving a target is a call: record it in [[decisions]] with its reversal condition. Why it moved is evidence: that goes to [[campaign-learnings]].
|
|
473
477
|
`;
|
|
474
478
|
/**
|
|
475
|
-
* The 21-page starter
|
|
476
|
-
* schema page), then nineteen draft stub
|
|
477
|
-
*
|
|
478
|
-
*
|
|
479
|
-
*
|
|
479
|
+
* The 21-page starter set workspaces were seeded with until 2026-10-12, verbatim: two
|
|
480
|
+
* active nav pages (start-here + the conventions schema page), then nineteen draft stub
|
|
481
|
+
* hubs (tag `seed`) — seven from wave 1 and twelve from wave 2. No longer seeded.
|
|
482
|
+
* Workspaces created before then still hold every copy nobody edited, so readers of
|
|
483
|
+
* stored pages (the ChatGPT profile's sanitizer) are tested against these exact bodies,
|
|
484
|
+
* and any cleanup of untouched copies must compare against them rather than guess.
|
|
480
485
|
*/
|
|
481
|
-
export const
|
|
486
|
+
export const RETIRED_KNOWLEDGE_SEED_PAGES = [
|
|
482
487
|
{
|
|
483
488
|
slug: "start-here",
|
|
484
489
|
type: "topic",
|
|
@@ -698,6 +703,65 @@ export const KNOWLEDGE_SEED_PAGES = [
|
|
|
698
703
|
minScaffoldVersion: 2,
|
|
699
704
|
},
|
|
700
705
|
];
|
|
706
|
+
const STARTER_ICP_BODY = `# ICP — ideal customer profile
|
|
707
|
+
|
|
708
|
+
> **Stub — fill me.** Replace this with real, cited content, then set \`status: active\`. No approval needed; a draft never grounds AI copy.
|
|
709
|
+
|
|
710
|
+
## Firmographics
|
|
711
|
+
- Company type / size / stage:
|
|
712
|
+
- Industry / vertical:
|
|
713
|
+
- Geography:
|
|
714
|
+
|
|
715
|
+
## Buyers
|
|
716
|
+
- Who signs, who champions, who uses it day to day:
|
|
717
|
+
|
|
718
|
+
## Triggers (why now)
|
|
719
|
+
- Signals that a fit account is in-market:
|
|
720
|
+
|
|
721
|
+
## Disqualifiers (hard no)
|
|
722
|
+
- Who we should NOT pursue and why:
|
|
723
|
+
|
|
724
|
+
## Basis
|
|
725
|
+
- Cite the deals, calls, or market data this is drawn from. What we sell them is in [[offers]].
|
|
726
|
+
`;
|
|
727
|
+
const STARTER_OFFERS_BODY = `# Offers
|
|
728
|
+
|
|
729
|
+
> **Stub — fill me.** Replace this with real, cited content, then set \`status: active\`. No approval needed; a draft never grounds AI copy.
|
|
730
|
+
|
|
731
|
+
## Offers
|
|
732
|
+
For each: name, who it's for ([[icp]]), price/packaging, the outcome it delivers, and qualifying criteria.
|
|
733
|
+
|
|
734
|
+
- Offer 1 —
|
|
735
|
+
- Offer 2 —
|
|
736
|
+
`;
|
|
737
|
+
/**
|
|
738
|
+
* The starter set: the ICP and Offers documents, each a draft stub (tag `seed`) linked to
|
|
739
|
+
* the other, so a fresh workspace's graph is two connected files instead of a scaffold.
|
|
740
|
+
*/
|
|
741
|
+
export const KNOWLEDGE_SEED_PAGES = [
|
|
742
|
+
{
|
|
743
|
+
slug: "icp",
|
|
744
|
+
type: "strategy",
|
|
745
|
+
title: "ICP — ideal customer profile",
|
|
746
|
+
status: "draft",
|
|
747
|
+
tags: ["seed", "icp"],
|
|
748
|
+
summary: "Stub: the ideal customer profile — firmographics, buyers, triggers, and disqualifiers that define who we sell to. Fill with cited content and set active.",
|
|
749
|
+
body: STARTER_ICP_BODY,
|
|
750
|
+
minScaffoldVersion: 1,
|
|
751
|
+
researchable: true,
|
|
752
|
+
},
|
|
753
|
+
{
|
|
754
|
+
slug: "offers",
|
|
755
|
+
type: "strategy",
|
|
756
|
+
title: "Offers",
|
|
757
|
+
status: "draft",
|
|
758
|
+
tags: ["seed", "offers"],
|
|
759
|
+
summary: "Stub: what we sell — packages, pricing, and the qualifying criteria per offer. Fill with cited content and set active.",
|
|
760
|
+
body: STARTER_OFFERS_BODY,
|
|
761
|
+
minScaffoldVersion: 1,
|
|
762
|
+
researchable: true,
|
|
763
|
+
},
|
|
764
|
+
];
|
|
701
765
|
/**
|
|
702
766
|
* Seed slugs a domain-grounded research pass could genuinely draft from the company's
|
|
703
767
|
* PUBLIC web presence — what they sell, who they say they sell to, how they sound, who
|
|
@@ -287,6 +287,7 @@ function createOtelEmitter(env, warn, summary) {
|
|
|
287
287
|
let status;
|
|
288
288
|
let failureKind = "transport_failed";
|
|
289
289
|
let attempts = 0;
|
|
290
|
+
let deliveryPhase = "request";
|
|
290
291
|
for (let attempt = 0; attempt < 3; attempt++) {
|
|
291
292
|
const remaining = LANGFUSE_EXPORT_BUDGET_MS - (Date.now() - startedAt);
|
|
292
293
|
if (remaining <= 0)
|
|
@@ -295,6 +296,7 @@ function createOtelEmitter(env, warn, summary) {
|
|
|
295
296
|
status = undefined;
|
|
296
297
|
const signal = AbortSignal.timeout(Math.min(LANGFUSE_EXPORT_TIMEOUT_SECONDS * 1000, remaining));
|
|
297
298
|
let response;
|
|
299
|
+
deliveryPhase = "request";
|
|
298
300
|
try {
|
|
299
301
|
try {
|
|
300
302
|
response = await fetch(exportUrl, { method: "POST", headers: exportHeaders, body, signal, redirect: "error" });
|
|
@@ -307,6 +309,7 @@ function createOtelEmitter(env, warn, summary) {
|
|
|
307
309
|
await response.body?.cancel().catch(() => { });
|
|
308
310
|
throw new Error("http_rejected");
|
|
309
311
|
}
|
|
312
|
+
deliveryPhase = "acknowledgement";
|
|
310
313
|
const chunks = [];
|
|
311
314
|
let bytes = 0;
|
|
312
315
|
const reader = response.body?.getReader();
|
|
@@ -358,11 +361,12 @@ function createOtelEmitter(env, warn, summary) {
|
|
|
358
361
|
catch (error) {
|
|
359
362
|
failureKind = error instanceof Error ? error.message : "transport_failed";
|
|
360
363
|
const retryable = ["deadline_exceeded", "network_failed", "response_read_failed"].includes(failureKind)
|
|
361
|
-
|
|
364
|
+
// Langfuse surfaces temporary S3 upload refusals as HTTP 500.
|
|
365
|
+
|| (failureKind === "http_rejected" && [429, 500, 502, 503, 504].includes(status ?? 0));
|
|
362
366
|
if (!retryable || attempt === 2) {
|
|
363
367
|
// Carry fixed classifications and numbers only, never an SDK or
|
|
364
368
|
// receiver error that could quote the request/response payload.
|
|
365
|
-
throw Object.assign(new Error(failureKind), { attempts: attempt + 1, status });
|
|
369
|
+
throw Object.assign(new Error(failureKind), { attempts: attempt + 1, status, deliveryPhase, elapsedMs: Date.now() - startedAt });
|
|
366
370
|
}
|
|
367
371
|
const pause = 100 * (attempt + 1);
|
|
368
372
|
if (LANGFUSE_EXPORT_BUDGET_MS - (Date.now() - startedAt) <= pause)
|
|
@@ -371,7 +375,7 @@ function createOtelEmitter(env, warn, summary) {
|
|
|
371
375
|
await new Promise((resolve) => setTimeout(resolve, pause));
|
|
372
376
|
}
|
|
373
377
|
}
|
|
374
|
-
throw Object.assign(new Error(failureKind), { attempts, status });
|
|
378
|
+
throw Object.assign(new Error(failureKind), { attempts, status, deliveryPhase, elapsedMs: Date.now() - startedAt });
|
|
375
379
|
};
|
|
376
380
|
const privateExporter = {
|
|
377
381
|
export: (spans, done) => {
|
|
@@ -391,7 +395,7 @@ function createOtelEmitter(env, warn, summary) {
|
|
|
391
395
|
summary.maybeReport();
|
|
392
396
|
const details = error;
|
|
393
397
|
warn(error, { stage: "export", observation_count: spans.length, failure_kind: failureKind,
|
|
394
|
-
attempts: details.attempts, http_status: details.status });
|
|
398
|
+
attempts: details.attempts, http_status: details.status, delivery_phase: details.deliveryPhase, elapsed_ms: details.elapsedMs });
|
|
395
399
|
});
|
|
396
400
|
pendingExports.add(pending);
|
|
397
401
|
// Even an unexpected SDK callback failure must not create a rejected
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export declare const MAILBOX_EGRESS_MODE_ENV = "OXYGEN_MAILBOX_EGRESS_MODE";
|
|
2
2
|
export type MailboxEgressMode = "direct" | "proxy";
|
|
3
3
|
/** `proxy` only when explicitly selected; anything else keeps today's transport. */
|
|
4
|
-
export declare function readMailboxEgressMode(env?:
|
|
4
|
+
export declare function readMailboxEgressMode(env?: Readonly<Record<string, string | undefined>>): MailboxEgressMode;
|
|
5
5
|
export type DedicatedEgressInventoryRow = {
|
|
6
6
|
id: string;
|
|
7
7
|
organizationId: string | null;
|
|
@@ -44,7 +44,7 @@ export type MailboxImportValidationSummary = {
|
|
|
44
44
|
};
|
|
45
45
|
export type MailboxOAuthProviderReviewPlan = {
|
|
46
46
|
mailboxes: number;
|
|
47
|
-
authorization_mode: "individual"
|
|
47
|
+
authorization_mode: "individual";
|
|
48
48
|
batch_size: number;
|
|
49
49
|
batches: number;
|
|
50
50
|
batch_sizes: number[];
|
|
@@ -56,6 +56,7 @@ export type MailboxOAuthReviewPlan = {
|
|
|
56
56
|
existing_grants_checked: false;
|
|
57
57
|
/** Backward-compatible individual OAuth review size. */
|
|
58
58
|
batch_size: number;
|
|
59
|
+
/** Address limit of the agent-only Microsoft tenant connection; no planned batch uses it. */
|
|
59
60
|
tenant_batch_size: number;
|
|
60
61
|
total_batches: number;
|
|
61
62
|
providers: {
|
|
@@ -93,8 +94,10 @@ export declare function summarizeMailboxImportValidation(mailboxes: readonly Nor
|
|
|
93
94
|
* authorization. This is safe during local file validation: it uses only
|
|
94
95
|
* normalized provider counts, performs no directory discovery, and does not
|
|
95
96
|
* claim to know whether a workspace already holds a usable grant for an address.
|
|
96
|
-
*
|
|
97
|
-
*
|
|
97
|
+
* Google and Microsoft plan the same individual sign-in batches: the app connects
|
|
98
|
+
* both one way (decision 2026-10-14). The one-administrator Microsoft tenant
|
|
99
|
+
* connection is an explicit agent option (`connect-oauth --vendor oxygen
|
|
100
|
+
* --authorization-mode tenant`, up to `tenant_batch_size` addresses), never planned.
|
|
98
101
|
*/
|
|
99
102
|
export declare function planMailboxOAuthReviews(mailboxes: readonly Pick<NormalizedMailboxImportRow, "provider">[]): MailboxOAuthReviewPlan;
|
|
100
103
|
export declare function normalizeMailboxImportVendor(raw: string | null | undefined, from: string | null | undefined): string | null;
|
|
@@ -233,18 +233,17 @@ export function summarizeMailboxImportValidation(mailboxes, input) {
|
|
|
233
233
|
* authorization. This is safe during local file validation: it uses only
|
|
234
234
|
* normalized provider counts, performs no directory discovery, and does not
|
|
235
235
|
* claim to know whether a workspace already holds a usable grant for an address.
|
|
236
|
-
*
|
|
237
|
-
*
|
|
236
|
+
* Google and Microsoft plan the same individual sign-in batches: the app connects
|
|
237
|
+
* both one way (decision 2026-10-14). The one-administrator Microsoft tenant
|
|
238
|
+
* connection is an explicit agent option (`connect-oauth --vendor oxygen
|
|
239
|
+
* --authorization-mode tenant`, up to `tenant_batch_size` addresses), never planned.
|
|
238
240
|
*/
|
|
239
241
|
export function planMailboxOAuthReviews(mailboxes) {
|
|
240
242
|
const counts = { google: 0, microsoft: 0 };
|
|
241
243
|
for (const mailbox of mailboxes)
|
|
242
244
|
counts[mailbox.provider] += 1;
|
|
243
|
-
const google = planProviderOAuthReviews(counts.google
|
|
244
|
-
const
|
|
245
|
-
const microsoft = planProviderOAuthReviews(counts.microsoft, microsoftMode === "tenant"
|
|
246
|
-
? MAILBOX_IMPORT_ROW_LIMIT
|
|
247
|
-
: MAILBOX_OAUTH_REVIEW_BATCH_SIZE, microsoftMode);
|
|
245
|
+
const google = planProviderOAuthReviews(counts.google);
|
|
246
|
+
const microsoft = planProviderOAuthReviews(counts.microsoft);
|
|
248
247
|
return {
|
|
249
248
|
authorization: "exact_account_oauth",
|
|
250
249
|
scope: "validated_addresses",
|
|
@@ -256,7 +255,8 @@ export function planMailboxOAuthReviews(mailboxes) {
|
|
|
256
255
|
providers: { google, microsoft },
|
|
257
256
|
};
|
|
258
257
|
}
|
|
259
|
-
function planProviderOAuthReviews(mailboxes
|
|
258
|
+
function planProviderOAuthReviews(mailboxes) {
|
|
259
|
+
const batchSize = MAILBOX_OAUTH_REVIEW_BATCH_SIZE;
|
|
260
260
|
const fullBatches = Math.floor(mailboxes / batchSize);
|
|
261
261
|
const remainder = mailboxes % batchSize;
|
|
262
262
|
const batchSizes = Array.from({ length: fullBatches }, () => batchSize);
|
|
@@ -264,7 +264,7 @@ function planProviderOAuthReviews(mailboxes, batchSize, authorizationMode) {
|
|
|
264
264
|
batchSizes.push(remainder);
|
|
265
265
|
return {
|
|
266
266
|
mailboxes,
|
|
267
|
-
authorization_mode:
|
|
267
|
+
authorization_mode: "individual",
|
|
268
268
|
batch_size: batchSize,
|
|
269
269
|
batches: batchSizes.length,
|
|
270
270
|
batch_sizes: batchSizes,
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare const OXYGEN_MCP_SERVER_NAME = "oxygen";
|
|
2
|
+
export declare const OXYGEN_MCP_SERVER_TITLE = "Oxygen GTM";
|
|
3
|
+
export declare const MCP_SERVER_INFO_META_KEY = "io.modelcontextprotocol/serverInfo";
|
|
4
|
+
export declare const OXYGEN_MCP_SERVER_INFO: {
|
|
5
|
+
name: string;
|
|
6
|
+
version: string;
|
|
7
|
+
title: string;
|
|
8
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { OXYGEN_VERSION } from "./version.js";
|
|
2
|
+
// Shared by the serving MCP transport and native result-window projections.
|
|
3
|
+
export const OXYGEN_MCP_SERVER_NAME = "oxygen";
|
|
4
|
+
export const OXYGEN_MCP_SERVER_TITLE = "Oxygen GTM";
|
|
5
|
+
export const MCP_SERVER_INFO_META_KEY = "io.modelcontextprotocol/serverInfo";
|
|
6
|
+
export const OXYGEN_MCP_SERVER_INFO = {
|
|
7
|
+
name: OXYGEN_MCP_SERVER_NAME,
|
|
8
|
+
version: OXYGEN_VERSION,
|
|
9
|
+
title: OXYGEN_MCP_SERVER_TITLE,
|
|
10
|
+
};
|
|
@@ -231,3 +231,13 @@ export declare function deleteInboxAvatarObject(input: {
|
|
|
231
231
|
export declare function deleteImportObject(input: {
|
|
232
232
|
storageKey: string;
|
|
233
233
|
}): Promise<void>;
|
|
234
|
+
/**
|
|
235
|
+
* Delete a file a person attached in a Copilot chat, when the chat itself is
|
|
236
|
+
* deleted (an Oxygent deleted for good, ADR 0032). The organization's own
|
|
237
|
+
* prefix is required, for the reason `deleteInboxAvatarObject` gives: one bucket
|
|
238
|
+
* holds every tenant's uploads, and these keys come back out of durable state.
|
|
239
|
+
*/
|
|
240
|
+
export declare function deleteCopilotAttachmentObject(input: {
|
|
241
|
+
storageKey: string;
|
|
242
|
+
organizationId: string;
|
|
243
|
+
}): Promise<void>;
|
|
@@ -464,6 +464,20 @@ export async function deleteImportObject(input) {
|
|
|
464
464
|
const { client, config } = resolveClient();
|
|
465
465
|
await client.send(new DeleteObjectCommand({ Bucket: config.bucket, Key: input.storageKey }));
|
|
466
466
|
}
|
|
467
|
+
/**
|
|
468
|
+
* Delete a file a person attached in a Copilot chat, when the chat itself is
|
|
469
|
+
* deleted (an Oxygent deleted for good, ADR 0032). The organization's own
|
|
470
|
+
* prefix is required, for the reason `deleteInboxAvatarObject` gives: one bucket
|
|
471
|
+
* holds every tenant's uploads, and these keys come back out of durable state.
|
|
472
|
+
*/
|
|
473
|
+
export async function deleteCopilotAttachmentObject(input) {
|
|
474
|
+
assertAppStorageWriteAllowed();
|
|
475
|
+
if (!isCopilotAttachmentObjectKeyForOrganization(input.storageKey, input.organizationId)) {
|
|
476
|
+
throw new OxygenError("invalid_object_key", "Refusing to delete an object outside this organization's Copilot attachments.", { details: { prefix: input.storageKey.split("/")[0] ?? "" }, exitCode: 1 });
|
|
477
|
+
}
|
|
478
|
+
const { client, config } = resolveClient();
|
|
479
|
+
await client.send(new DeleteObjectCommand({ Bucket: config.bucket, Key: input.storageKey }));
|
|
480
|
+
}
|
|
467
481
|
function sanitizeFileName(fileName) {
|
|
468
482
|
if (!fileName)
|
|
469
483
|
return "";
|
|
@@ -70,6 +70,9 @@ export type PlanLimitsWorkflowLimits = {
|
|
|
70
70
|
run_attempt_timeout_minutes?: number;
|
|
71
71
|
};
|
|
72
72
|
export type PlanLimitsStorageCapacity = {
|
|
73
|
+
status?: string;
|
|
74
|
+
effective_at?: string | null;
|
|
75
|
+
target?: PlanLimitsStorageTarget | null;
|
|
73
76
|
platform_guard?: {
|
|
74
77
|
table_row_limit?: number;
|
|
75
78
|
workspace_row_limit?: number;
|
|
@@ -179,6 +182,8 @@ export declare function planLimitsLadder(payload: PlanLimitsEnvelope): PlanLimit
|
|
|
179
182
|
* named, so a full one is identifiable (decision F.2).
|
|
180
183
|
*/
|
|
181
184
|
export declare function planLimitsStorageUsageLine(storage: PlanLimitsStorageCapacity | undefined): string | null;
|
|
185
|
+
/** Pending capacity never supplies current headroom or an inferred date. */
|
|
186
|
+
export declare function planLimitsStoragePendingLine(storage: PlanLimitsStorageCapacity | undefined): string | null;
|
|
182
187
|
/** Status of the largest active Table, from the same flags CLI and MCP read. */
|
|
183
188
|
export declare function planLimitsTableStatus(storage: PlanLimitsStorageCapacity | undefined): "full" | "nearly full" | null;
|
|
184
189
|
/** Sending limits are the same on every plan: one row per channel. */
|
|
@@ -180,7 +180,7 @@ export function planLimitsLadder(payload) {
|
|
|
180
180
|
notes.push(`"→" marks a limit that changes on ${payload.pricing_schedule.effective_at.slice(0, 10)}.`);
|
|
181
181
|
}
|
|
182
182
|
if (bands.some(awaitingCapacityTest)) {
|
|
183
|
-
notes.push(`"${AWAITING_TEST_MARK}"
|
|
183
|
+
notes.push(`"${AWAITING_TEST_MARK}" is planned capacity, not in force. It requires a capacity test at that plan size; no activation date is set.`);
|
|
184
184
|
}
|
|
185
185
|
return {
|
|
186
186
|
bands: bands.map((row) => ({ band: row.band ?? "", label: row.label ?? row.band ?? "", current: row.current === true })),
|
|
@@ -207,8 +207,24 @@ export function planLimitsStorageUsageLine(storage) {
|
|
|
207
207
|
`workspace ${formatLimitCount(usage.workspace_rows)} / ${formatLimitCount(guard.workspace_row_limit)} rows`,
|
|
208
208
|
`database ${formatLimitBytes(usage.workspace_database_bytes)} / ${formatLimitBytes(guard.workspace_database_limit_bytes)}`,
|
|
209
209
|
];
|
|
210
|
+
if (typeof usage.workspace_rows === "number" && typeof guard.workspace_row_limit === "number") {
|
|
211
|
+
parts.push(`${formatLimitCount(Math.max(0, guard.workspace_row_limit - usage.workspace_rows))} workspace rows remaining`);
|
|
212
|
+
}
|
|
210
213
|
return `Your storage: ${parts.join(" · ")}`;
|
|
211
214
|
}
|
|
215
|
+
/** Pending capacity never supplies current headroom or an inferred date. */
|
|
216
|
+
export function planLimitsStoragePendingLine(storage) {
|
|
217
|
+
const target = storage?.target;
|
|
218
|
+
if (!target)
|
|
219
|
+
return null;
|
|
220
|
+
if (storage.status === "awaiting_capacity_test" && typeof target.table_row_limit === "number") {
|
|
221
|
+
return `A rise to ${formatLimitCount(target.table_row_limit)} rows per Table is planned but not in force. It requires a capacity test at this plan size; no activation date is set.`;
|
|
222
|
+
}
|
|
223
|
+
if (storage.status === "scheduled" && storage.effective_at) {
|
|
224
|
+
return `From ${storage.effective_at.slice(0, 10)}: ${formatLimitCount(target.table_row_limit)} rows per Table, ${formatLimitCount(target.workspace_row_limit)} in the workspace and ${formatLimitBytes(target.workspace_database_limit_bytes)} of Table data.`;
|
|
225
|
+
}
|
|
226
|
+
return null;
|
|
227
|
+
}
|
|
212
228
|
/** Status of the largest active Table, from the same flags CLI and MCP read. */
|
|
213
229
|
export function planLimitsTableStatus(storage) {
|
|
214
230
|
if (storage?.usage?.table_limit_reached === true)
|
|
@@ -219,7 +219,7 @@ export declare const SENDING_DOMAIN_CREDITS_PER_YEAR_TYPICAL = 1250;
|
|
|
219
219
|
* inverts its own margin: at $1.00/inbox-month the EIGHTH test in a cycle was
|
|
220
220
|
* already sold at a loss. Two included tests cost $0.265 against $1.00 of
|
|
221
221
|
* revenue at today's price, and everything past them bills
|
|
222
|
-
* PLACEMENT_TEST_OVERAGE_CREDITS.
|
|
222
|
+
* PLACEMENT_TEST_OVERAGE_CREDITS. Own-key tests pay the separate OXYGEN platform fee, without consuming this allowance.
|
|
223
223
|
*
|
|
224
224
|
* Monitoring is 100 credits per inbox-month (founder, 2026-10-07; the 2026-09
|
|
225
225
|
* repricing had set 135). The extra test is the RATIFIED 66 (slice S30), whose rise
|
|
@@ -206,7 +206,7 @@ export const SENDING_DOMAIN_CREDITS_PER_YEAR_TYPICAL = SNAPSHOT_SENDING_DOMAIN_C
|
|
|
206
206
|
* inverts its own margin: at $1.00/inbox-month the EIGHTH test in a cycle was
|
|
207
207
|
* already sold at a loss. Two included tests cost $0.265 against $1.00 of
|
|
208
208
|
* revenue at today's price, and everything past them bills
|
|
209
|
-
* PLACEMENT_TEST_OVERAGE_CREDITS.
|
|
209
|
+
* PLACEMENT_TEST_OVERAGE_CREDITS. Own-key tests pay the separate OXYGEN platform fee, without consuming this allowance.
|
|
210
210
|
*
|
|
211
211
|
* Monitoring is 100 credits per inbox-month (founder, 2026-10-07; the 2026-09
|
|
212
212
|
* repricing had set 135). The extra test is the RATIFIED 66 (slice S30), whose rise
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** Staff inventory metadata; configuration is not a health or entitlement verdict. */
|
|
2
|
+
export type ProductProviderRail = {
|
|
3
|
+
provider: string;
|
|
4
|
+
supplier: string;
|
|
5
|
+
uses: string[];
|
|
6
|
+
selection: "default" | "conditional" | "legacy";
|
|
7
|
+
condition: string;
|
|
8
|
+
source: string;
|
|
9
|
+
required_env: string[];
|
|
10
|
+
/** At least one alternative is required, in addition to every required_env. */
|
|
11
|
+
required_env_any?: string[];
|
|
12
|
+
key_configured: boolean;
|
|
13
|
+
economics: string;
|
|
14
|
+
};
|
|
15
|
+
export declare function formatProviderEnvRequirements(required: readonly string[], alternatives?: readonly string[]): string;
|
|
@@ -123,7 +123,7 @@ export declare function deliverabilitySeatCredits(): number;
|
|
|
123
123
|
/**
|
|
124
124
|
* S30 (decision 3.6; flat literal, proposal P-29): one managed placement test
|
|
125
125
|
* past an inbox's included allowance, or on an inbox with no monitoring
|
|
126
|
-
* subscription, 16.6 -> 66 credits.
|
|
126
|
+
* subscription, 16.6 -> 66 credits. Own-key calls pay the separate platform fee.
|
|
127
127
|
*/
|
|
128
128
|
export declare const PLACEMENT_TEST_REPRICING: RepricedValue<16.6 | 66>;
|
|
129
129
|
/** One managed placement test beyond the included allowance, in credits, at the price in force. */
|
|
@@ -300,7 +300,7 @@ export function deliverabilitySeatCredits() {
|
|
|
300
300
|
/**
|
|
301
301
|
* S30 (decision 3.6; flat literal, proposal P-29): one managed placement test
|
|
302
302
|
* past an inbox's included allowance, or on an inbox with no monitoring
|
|
303
|
-
* subscription, 16.6 -> 66 credits.
|
|
303
|
+
* subscription, 16.6 -> 66 credits. Own-key calls pay the separate platform fee.
|
|
304
304
|
*/
|
|
305
305
|
export const PLACEMENT_TEST_REPRICING = defineRepricedValue({
|
|
306
306
|
key: "overage.placement_test",
|
|
@@ -308,7 +308,7 @@ export const PLACEMENT_TEST_REPRICING = defineRepricedValue({
|
|
|
308
308
|
slice: "S30",
|
|
309
309
|
decision: "3.6",
|
|
310
310
|
unit: "credits_per_test",
|
|
311
|
-
description: "One managed inbox-placement test beyond an inbox's included tests.
|
|
311
|
+
description: "One managed inbox-placement test beyond an inbox's included tests. Own-key calls pay the separate OXYGEN platform fee.",
|
|
312
312
|
before: 16.6,
|
|
313
313
|
after: SNAPSHOT_PLACEMENT_TEST_CREDITS,
|
|
314
314
|
});
|
|
@@ -1 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether `cron` is five fields in the grammar above (`*`, `N`, `N-M`, `/step`,
|
|
3
|
+
* comma lists). A syntax check only: whether a schedule ever fires, and how
|
|
4
|
+
* often, is the Workflows scheduler's to answer (`nextCronRunAfter`).
|
|
5
|
+
*/
|
|
6
|
+
export declare function isCronSyntax(cron: string): boolean;
|
|
1
7
|
export declare function humanizeCronSchedule(cron: string): string | null;
|
|
@@ -86,6 +86,18 @@ function dayNames(days) {
|
|
|
86
86
|
.map((day) => DAY_NAMES[day])
|
|
87
87
|
.join(", ");
|
|
88
88
|
}
|
|
89
|
+
/**
|
|
90
|
+
* Whether `cron` is five fields in the grammar above (`*`, `N`, `N-M`, `/step`,
|
|
91
|
+
* comma lists). A syntax check only: whether a schedule ever fires, and how
|
|
92
|
+
* often, is the Workflows scheduler's to answer (`nextCronRunAfter`).
|
|
93
|
+
*/
|
|
94
|
+
export function isCronSyntax(cron) {
|
|
95
|
+
const fields = cron.trim().split(/\s+/);
|
|
96
|
+
if (fields.length !== 5)
|
|
97
|
+
return false;
|
|
98
|
+
const ranges = [MINUTE_RANGE, HOUR_RANGE, DAY_OF_MONTH_RANGE, MONTH_RANGE, DAY_OF_WEEK_RANGE];
|
|
99
|
+
return fields.every((field, index) => expandCronField(field, ranges[index]) !== null);
|
|
100
|
+
}
|
|
89
101
|
export function humanizeCronSchedule(cron) {
|
|
90
102
|
const fields = cron.trim().split(/\s+/);
|
|
91
103
|
if (fields.length !== 5)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export declare const SEQUENCE_FAILURE_SCHEMA_VERSION = 1;
|
|
2
2
|
export declare const SEQUENCE_FAILURE_RETRY_AFTER_MAX_MS: number;
|
|
3
|
+
export declare const WHATSAPP_UNCERTAIN_DELIVERY_MESSAGE = "WhatsApp delivery is uncertain. Automatic resending is blocked.";
|
|
3
4
|
export declare const SEQUENCE_FAILURE_CLASSES: readonly ["capacity", "recipient", "authorization_scope", "funding", "validation", "provider", "internal", "effect_unknown", "unknown"];
|
|
4
5
|
export type SequenceFailureClass = (typeof SEQUENCE_FAILURE_CLASSES)[number];
|
|
5
6
|
export type SequenceFailureEffectOutcome = "not_applied" | "applied" | "unknown";
|
|
@@ -3,6 +3,7 @@ import { isProviderFundingErrorCode, isProviderRateLimitErrorCode, } from "./pro
|
|
|
3
3
|
import { asRecordOrNull as asRecord } from "./type-guards.js";
|
|
4
4
|
export const SEQUENCE_FAILURE_SCHEMA_VERSION = 1;
|
|
5
5
|
export const SEQUENCE_FAILURE_RETRY_AFTER_MAX_MS = 24 * 60 * 60 * 1000;
|
|
6
|
+
export const WHATSAPP_UNCERTAIN_DELIVERY_MESSAGE = "WhatsApp delivery is uncertain. Automatic resending is blocked.";
|
|
6
7
|
export const SEQUENCE_FAILURE_CLASSES = [
|
|
7
8
|
"capacity",
|
|
8
9
|
"recipient",
|
|
@@ -122,15 +123,28 @@ export function readSequenceFailure(error, overrides = {}) {
|
|
|
122
123
|
"provider_status",
|
|
123
124
|
"providerStatus",
|
|
124
125
|
]));
|
|
125
|
-
|
|
126
|
-
|
|
126
|
+
let retryable = overrides.retryable ?? firstBoolean(records, ["retryable"]);
|
|
127
|
+
let effectOutcome = overrides.effectOutcome ?? readEffectOutcome(records);
|
|
127
128
|
const retryAfterMs = normalizeRetryAfterMs(overrides.retryAfterMs ?? readRetryAfterMs(records));
|
|
128
|
-
|
|
129
|
+
let hardBounce = overrides.hardBounce ??
|
|
129
130
|
firstBoolean(records, ["hard_bounce", "hardBounce"]);
|
|
131
|
+
// Older WhatsApp clients treated every provider/* response as proof that no
|
|
132
|
+
// message was sent, including gateway failures after dispatch. Neither the
|
|
133
|
+
// HTTP response nor that stale v1 envelope makes another write safe.
|
|
134
|
+
const uncertainWhatsAppGateway = rawCode === "whatsapp_conversation_unavailable"
|
|
135
|
+
&& httpStatus !== null && httpStatus >= 500 && effectOutcome !== "applied";
|
|
136
|
+
const fault = uncertainWhatsAppGateway
|
|
137
|
+
? { code: "provider_write_ambiguous", message: WHATSAPP_UNCERTAIN_DELIVERY_MESSAGE }
|
|
138
|
+
: redacted;
|
|
139
|
+
if (uncertainWhatsAppGateway) {
|
|
140
|
+
effectOutcome = "unknown";
|
|
141
|
+
retryable = false;
|
|
142
|
+
hardBounce = false;
|
|
143
|
+
}
|
|
130
144
|
const existingClass = firstString(records, ["failure_class"]);
|
|
131
145
|
const existingVersion = firstNumber(records, ["failure_schema_version"]);
|
|
132
146
|
const classified = classifySequenceFailure({
|
|
133
|
-
code:
|
|
147
|
+
code: fault.code,
|
|
134
148
|
providerSubtype,
|
|
135
149
|
provider,
|
|
136
150
|
httpStatus,
|
|
@@ -153,8 +167,8 @@ export function readSequenceFailure(error, overrides = {}) {
|
|
|
153
167
|
return {
|
|
154
168
|
failure_schema_version: SEQUENCE_FAILURE_SCHEMA_VERSION,
|
|
155
169
|
failure_class: failureClass,
|
|
156
|
-
code:
|
|
157
|
-
message:
|
|
170
|
+
code: fault.code,
|
|
171
|
+
message: fault.message,
|
|
158
172
|
...(provider ? { provider } : {}),
|
|
159
173
|
...(operation ? { operation } : {}),
|
|
160
174
|
...(providerSubtype ? { provider_subtype: providerSubtype } : {}),
|