@apex-inc/mcp-server 0.33.0 → 0.34.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 +19 -18
- package/dist/api-client.d.ts +5 -0
- package/dist/api-client.d.ts.map +1 -1
- package/dist/api-client.js +40 -24
- package/dist/api-client.js.map +1 -1
- package/dist/index.js +7 -4
- package/dist/index.js.map +1 -1
- package/dist/prompts.d.ts.map +1 -1
- package/dist/prompts.js +5 -7
- package/dist/prompts.js.map +1 -1
- package/dist/setup-catchup-tools.d.ts.map +1 -1
- package/dist/setup-catchup-tools.js +15 -3
- package/dist/setup-catchup-tools.js.map +1 -1
- package/dist/smoke-tools.d.ts +56 -0
- package/dist/smoke-tools.d.ts.map +1 -0
- package/dist/smoke-tools.js +261 -0
- package/dist/smoke-tools.js.map +1 -0
- package/dist/tool-catalog.d.ts +10 -0
- package/dist/tool-catalog.d.ts.map +1 -0
- package/dist/tool-catalog.js +36 -0
- package/dist/tool-catalog.js.map +1 -0
- package/dist/tool-groups.d.ts +5 -0
- package/dist/tool-groups.d.ts.map +1 -0
- package/dist/tool-groups.js +206 -0
- package/dist/tool-groups.js.map +1 -0
- package/dist/tool-shared.d.ts +300 -0
- package/dist/tool-shared.d.ts.map +1 -0
- package/dist/tool-shared.js +319 -0
- package/dist/tool-shared.js.map +1 -0
- package/dist/tools/accounts.d.ts +124 -0
- package/dist/tools/accounts.d.ts.map +1 -0
- package/dist/tools/accounts.js +99 -0
- package/dist/tools/accounts.js.map +1 -0
- package/dist/tools/adoption.d.ts +499 -0
- package/dist/tools/adoption.d.ts.map +1 -0
- package/dist/tools/adoption.js +447 -0
- package/dist/tools/adoption.js.map +1 -0
- package/dist/tools/context.d.ts +216 -0
- package/dist/tools/context.d.ts.map +1 -0
- package/dist/tools/context.js +328 -0
- package/dist/tools/context.js.map +1 -0
- package/dist/tools/experiments.d.ts +1066 -0
- package/dist/tools/experiments.d.ts.map +1 -0
- package/dist/tools/experiments.js +2090 -0
- package/dist/tools/experiments.js.map +1 -0
- package/dist/tools/letters.d.ts +1107 -0
- package/dist/tools/letters.d.ts.map +1 -0
- package/dist/tools/letters.js +1324 -0
- package/dist/tools/letters.js.map +1 -0
- package/dist/tools/measurement.d.ts +886 -0
- package/dist/tools/measurement.d.ts.map +1 -0
- package/dist/tools/measurement.js +1353 -0
- package/dist/tools/measurement.js.map +1 -0
- package/dist/tools/partners.d.ts +364 -0
- package/dist/tools/partners.d.ts.map +1 -0
- package/dist/tools/partners.js +199 -0
- package/dist/tools/partners.js.map +1 -0
- package/dist/tools.d.ts +3161 -2826
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +26 -6112
- package/dist/tools.js.map +1 -1
- package/package.json +3 -2
- package/skills/apex-communications/SKILL.md +5 -5
- package/skills/apex-experimentation/SKILL.md +8 -11
- package/skills/apex-growth-intelligence/SKILL.md +1 -1
- package/skills/apex-integration-cookbook/SKILL.md +1 -1
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export interface Belief {
|
|
3
|
+
id: string;
|
|
4
|
+
statement: string;
|
|
5
|
+
confidence: number;
|
|
6
|
+
evidenceSupporting: unknown[];
|
|
7
|
+
evidenceContradicting: unknown[];
|
|
8
|
+
parentBeliefId?: string;
|
|
9
|
+
createdAt: string;
|
|
10
|
+
updatedAt: string;
|
|
11
|
+
validationState?: "unvalidated" | "validated";
|
|
12
|
+
generatedFromExperimentId?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface MetricCatalogEntry {
|
|
15
|
+
key: string;
|
|
16
|
+
label: string;
|
|
17
|
+
type: "rate" | "count" | "revenue" | "duration";
|
|
18
|
+
outcomeTier: "outcome" | "proximal" | "internal";
|
|
19
|
+
measurable: boolean;
|
|
20
|
+
wired: "detected" | "waiting";
|
|
21
|
+
trailingVolume?: number;
|
|
22
|
+
}
|
|
23
|
+
export interface Hypothesis {
|
|
24
|
+
id: string;
|
|
25
|
+
beliefId: string;
|
|
26
|
+
statement: string;
|
|
27
|
+
predictedEffect: string;
|
|
28
|
+
confidence: number;
|
|
29
|
+
status: string;
|
|
30
|
+
}
|
|
31
|
+
export interface Prediction {
|
|
32
|
+
id: string;
|
|
33
|
+
hypothesisId: string;
|
|
34
|
+
beliefId: string;
|
|
35
|
+
metric: string;
|
|
36
|
+
expectedChange: number;
|
|
37
|
+
direction: "increase" | "decrease" | "no_change";
|
|
38
|
+
expectedRange: {
|
|
39
|
+
low: number;
|
|
40
|
+
high: number;
|
|
41
|
+
};
|
|
42
|
+
confidence: number;
|
|
43
|
+
timeHorizon: number;
|
|
44
|
+
evaluationWindow: number;
|
|
45
|
+
actualChange?: number;
|
|
46
|
+
accuracyScore?: number;
|
|
47
|
+
}
|
|
48
|
+
export interface DOMChange {
|
|
49
|
+
selector: string;
|
|
50
|
+
type: string;
|
|
51
|
+
value: string;
|
|
52
|
+
originalValue?: string;
|
|
53
|
+
}
|
|
54
|
+
export interface UnifiedVariant {
|
|
55
|
+
id: string;
|
|
56
|
+
key: string;
|
|
57
|
+
label: string;
|
|
58
|
+
surface: string;
|
|
59
|
+
createdAt: string;
|
|
60
|
+
description?: string;
|
|
61
|
+
mode?: "snippet" | "redirect" | "server_side" | "manual" | "sdk";
|
|
62
|
+
changes?: DOMChange[];
|
|
63
|
+
redirectUrl?: string;
|
|
64
|
+
screenshotUrl?: string;
|
|
65
|
+
}
|
|
66
|
+
export interface UnifiedExperiment {
|
|
67
|
+
id: string;
|
|
68
|
+
workspaceKey: string;
|
|
69
|
+
name: string;
|
|
70
|
+
surface: string;
|
|
71
|
+
status: string;
|
|
72
|
+
createdAt: string;
|
|
73
|
+
startedAt?: string;
|
|
74
|
+
completedAt?: string;
|
|
75
|
+
variants: UnifiedVariant[];
|
|
76
|
+
primaryMetric: {
|
|
77
|
+
key: string;
|
|
78
|
+
label: string;
|
|
79
|
+
type: string;
|
|
80
|
+
unit: string;
|
|
81
|
+
direction: string;
|
|
82
|
+
source: {
|
|
83
|
+
kind: string;
|
|
84
|
+
eventType?: string;
|
|
85
|
+
property?: string;
|
|
86
|
+
};
|
|
87
|
+
};
|
|
88
|
+
allocation: {
|
|
89
|
+
strategy: string;
|
|
90
|
+
weights?: Record<string, number>;
|
|
91
|
+
thompsonPrior?: unknown;
|
|
92
|
+
};
|
|
93
|
+
hypothesis: string;
|
|
94
|
+
prediction: {
|
|
95
|
+
direction: string;
|
|
96
|
+
magnitude: string;
|
|
97
|
+
};
|
|
98
|
+
confidence: number;
|
|
99
|
+
beliefId?: string;
|
|
100
|
+
hypothesisId?: string;
|
|
101
|
+
predictionId?: string;
|
|
102
|
+
winner?: string;
|
|
103
|
+
winnerConfidence?: number;
|
|
104
|
+
results?: {
|
|
105
|
+
perVariant: Record<string, {
|
|
106
|
+
assigned: number;
|
|
107
|
+
participated: number;
|
|
108
|
+
converted: number;
|
|
109
|
+
conversionRate?: number;
|
|
110
|
+
}>;
|
|
111
|
+
winner?: string;
|
|
112
|
+
winnerConfidence?: number;
|
|
113
|
+
};
|
|
114
|
+
targetUrl?: string;
|
|
115
|
+
targetAnchor?: string;
|
|
116
|
+
createdFrom?: "dashboard" | "api" | "sdk" | "mcp" | "cursor";
|
|
117
|
+
previewUrl?: string;
|
|
118
|
+
deploymentCommit?: string;
|
|
119
|
+
deploymentStatus?: "pending" | "building" | "deployed" | "failed";
|
|
120
|
+
deployedAt?: string;
|
|
121
|
+
deployedBranch?: string;
|
|
122
|
+
graduated?: boolean;
|
|
123
|
+
promoted?: boolean;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Wiring verdict from `GET /api/experiments/{id}/wiring`.
|
|
127
|
+
*
|
|
128
|
+
* "Wiring" = are `experiment_exposure` events actually arriving for BOTH arms?
|
|
129
|
+
* An experiment can be configured perfectly but collect zero data if the
|
|
130
|
+
* variant-serving code (useApexVariant / Apex.getVariant) isn't deployed or
|
|
131
|
+
* running yet. This is the pre-launch safety check.
|
|
132
|
+
*/
|
|
133
|
+
export interface WiringResult {
|
|
134
|
+
experimentId: string;
|
|
135
|
+
surface: string;
|
|
136
|
+
status: string;
|
|
137
|
+
perArm: Array<{
|
|
138
|
+
variantKey: string;
|
|
139
|
+
label: string;
|
|
140
|
+
exposures: number;
|
|
141
|
+
lastSeenAt?: string;
|
|
142
|
+
}>;
|
|
143
|
+
armsLive: number;
|
|
144
|
+
totalArms: number;
|
|
145
|
+
bothArmsLive: boolean;
|
|
146
|
+
totalExposures: number;
|
|
147
|
+
/** Pageviews on the experiment's target page in the last 7 days. */
|
|
148
|
+
targetPageviews7d?: number;
|
|
149
|
+
lastTargetVisitAt?: string;
|
|
150
|
+
/** All web variants are SDK-hook wired — exposures need deployed code. */
|
|
151
|
+
sdkMode?: boolean;
|
|
152
|
+
/** All web variants are snippet-applied — exposures only exist once running,
|
|
153
|
+
* so activation must not require pre-exposures (applied on activation). */
|
|
154
|
+
snippetMode?: boolean;
|
|
155
|
+
verdict: "wired" | "partial" | "no_exposures";
|
|
156
|
+
}
|
|
157
|
+
export interface GraduationRecipe {
|
|
158
|
+
experimentId: string;
|
|
159
|
+
experimentName: string;
|
|
160
|
+
mode: string;
|
|
161
|
+
targetUrl: string;
|
|
162
|
+
winner: string;
|
|
163
|
+
changes: DOMChange[];
|
|
164
|
+
graduatedAt: string | null;
|
|
165
|
+
}
|
|
166
|
+
export interface LedgerEntry {
|
|
167
|
+
id: string;
|
|
168
|
+
beliefId: string;
|
|
169
|
+
decision: string;
|
|
170
|
+
reasoning: string;
|
|
171
|
+
beliefUpdateFrom: number;
|
|
172
|
+
beliefUpdateTo: number;
|
|
173
|
+
createdAt: string;
|
|
174
|
+
}
|
|
175
|
+
export declare const APEX = "Apex";
|
|
176
|
+
/**
|
|
177
|
+
* MOBX-006 — stable synthetic visitor id for agent-fired events.
|
|
178
|
+
*
|
|
179
|
+
* `/api/events` only counts an event toward wiring detection when it
|
|
180
|
+
* carries a top-level `visitorId`. A per-process random suffix keeps
|
|
181
|
+
* the id stable for the MCP server's lifetime (so repeated track_event
|
|
182
|
+
* calls roll up to one synthetic "visitor") while distinguishing
|
|
183
|
+
* separate agent sessions from each other.
|
|
184
|
+
*/
|
|
185
|
+
export declare const MCP_AGENT_VISITOR_ID: string;
|
|
186
|
+
/** Control traffic % derived from the unified allocation weights (default 50). */
|
|
187
|
+
export declare function controlPctOf(exp: UnifiedExperiment): number;
|
|
188
|
+
/**
|
|
189
|
+
* Days running, derived locally from startedAt/createdAt → completedAt/now.
|
|
190
|
+
* The legacy web shape carried a server-computed `daysRunning`; the unified
|
|
191
|
+
* shape does not, so we compute it from the lifecycle timestamps.
|
|
192
|
+
*/
|
|
193
|
+
export declare function daysRunningOf(exp: UnifiedExperiment): number;
|
|
194
|
+
/** Find a unified variant by its key (e.g. "control", "variant_a"). */
|
|
195
|
+
export declare function findVariant(exp: UnifiedExperiment, key: string): UnifiedVariant | undefined;
|
|
196
|
+
/** Render a per-arm exposure line for wiring summaries. */
|
|
197
|
+
export declare function formatArmLine(arm: WiringResult["perArm"][number]): string;
|
|
198
|
+
/** "add_to_cart" → "Add To Cart" (for primaryMetric labels). */
|
|
199
|
+
export declare function titleCaseEvent(event: string): string;
|
|
200
|
+
export declare function activeWorkspaceSiteUrl(): string | null;
|
|
201
|
+
export declare function assertTargetUrlForActiveWorkspace(targetUrl: string): Promise<{
|
|
202
|
+
ok: true;
|
|
203
|
+
} | {
|
|
204
|
+
ok: false;
|
|
205
|
+
message: string;
|
|
206
|
+
}>;
|
|
207
|
+
/**
|
|
208
|
+
* Query string for the pack report windows: relative (`days` / `months`)
|
|
209
|
+
* or explicit `start` + `end` (YYYY-MM-DD, both required together —
|
|
210
|
+
* explicit bounds win server-side).
|
|
211
|
+
*/
|
|
212
|
+
export declare function windowQuery(opts: {
|
|
213
|
+
days?: number;
|
|
214
|
+
months?: number;
|
|
215
|
+
start?: string;
|
|
216
|
+
end?: string;
|
|
217
|
+
}): string;
|
|
218
|
+
export declare function errMsg(err: unknown): string;
|
|
219
|
+
/** Build a dashboard deep link on the same host the MCP talks to (app origin). */
|
|
220
|
+
export declare function appUrl(path: string): string;
|
|
221
|
+
export declare function journeyLink(id: string): string;
|
|
222
|
+
/**
|
|
223
|
+
* Detect a MOBILE experiment surface from repo signals (the MCP runs in the
|
|
224
|
+
* merchant's repo). Walks up a few dirs looking for capacitor.config.* or a
|
|
225
|
+
* Capacitor/RN dependency. Returns null when there's no mobile signal (web is
|
|
226
|
+
* the safe default — a website repo carries no special marker). QA 2026-06-18.
|
|
227
|
+
*/
|
|
228
|
+
export declare function detectSurfaceFromRepo(): "mobile" | null;
|
|
229
|
+
/**
|
|
230
|
+
* Resolve the experiment surface. Explicit wins; otherwise detect from repo
|
|
231
|
+
* signals, then the workspace's registered data sources. Returns an `ambiguous`
|
|
232
|
+
* error only when both web and mobile data sources exist and there's no repo
|
|
233
|
+
* signal — in that case the agent must choose. (QA: stop defaulting to web.)
|
|
234
|
+
*/
|
|
235
|
+
export declare function resolveCreateSurface(explicit?: "web" | "mobile"): Promise<{
|
|
236
|
+
surface: "web" | "mobile";
|
|
237
|
+
} | {
|
|
238
|
+
ambiguous: true;
|
|
239
|
+
}>;
|
|
240
|
+
/**
|
|
241
|
+
* Tenant echo (council CISO): never report a mutation as successful for a record
|
|
242
|
+
* outside the active workspace (guards a leaked/cross-workspace key).
|
|
243
|
+
*/
|
|
244
|
+
export declare function tenantOk(workspaceKey?: string): boolean;
|
|
245
|
+
export declare function tenantMismatch(): {
|
|
246
|
+
content: {
|
|
247
|
+
type: "text";
|
|
248
|
+
text: string;
|
|
249
|
+
}[];
|
|
250
|
+
isError: boolean;
|
|
251
|
+
};
|
|
252
|
+
/**
|
|
253
|
+
* Shared schema + handler for `switch_workspace` (canonical) and its
|
|
254
|
+
* deprecated alias `switch_project`. Both register against the same handler
|
|
255
|
+
* so existing agent calls keep working through the project→workspace rename.
|
|
256
|
+
*
|
|
257
|
+
* After updating the active workspace locally, we VALIDATE the switch with an
|
|
258
|
+
* authed read against `/api/setup-state` (which `apiGet` scopes to the active
|
|
259
|
+
* workspace). Validation is non-fatal: the local switch always succeeds, but
|
|
260
|
+
* we surface an auth/reachability warning so the user knows to connect or
|
|
261
|
+
* fix the workspace key.
|
|
262
|
+
*/
|
|
263
|
+
export declare const switchWorkspaceSchema: z.ZodObject<{
|
|
264
|
+
workspaceKey: z.ZodOptional<z.ZodString>;
|
|
265
|
+
projectKey: z.ZodOptional<z.ZodString>;
|
|
266
|
+
}, "strip", z.ZodTypeAny, {
|
|
267
|
+
workspaceKey?: string | undefined;
|
|
268
|
+
projectKey?: string | undefined;
|
|
269
|
+
}, {
|
|
270
|
+
workspaceKey?: string | undefined;
|
|
271
|
+
projectKey?: string | undefined;
|
|
272
|
+
}>;
|
|
273
|
+
export declare function switchWorkspaceHandler(args: {
|
|
274
|
+
workspaceKey?: string;
|
|
275
|
+
projectKey?: string;
|
|
276
|
+
}): Promise<{
|
|
277
|
+
content: {
|
|
278
|
+
type: "text";
|
|
279
|
+
text: string;
|
|
280
|
+
}[];
|
|
281
|
+
isError: boolean;
|
|
282
|
+
} | {
|
|
283
|
+
content: {
|
|
284
|
+
type: "text";
|
|
285
|
+
text: string;
|
|
286
|
+
}[];
|
|
287
|
+
isError?: undefined;
|
|
288
|
+
}>;
|
|
289
|
+
/**
|
|
290
|
+
* Shared handler for `list_workspaces` (canonical) and its deprecated alias
|
|
291
|
+
* `list_projects`. Both register against the same handler so existing agent
|
|
292
|
+
* calls keep working through the project→workspace rename.
|
|
293
|
+
*/
|
|
294
|
+
export declare function listWorkspacesHandler(): Promise<{
|
|
295
|
+
content: {
|
|
296
|
+
type: "text";
|
|
297
|
+
text: string;
|
|
298
|
+
}[];
|
|
299
|
+
}>;
|
|
300
|
+
//# sourceMappingURL=tool-shared.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-shared.d.ts","sourceRoot":"","sources":["../src/tool-shared.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
3
|
+
import { join, dirname } from "node:path";
|
|
4
|
+
import { apiGet, setActiveWorkspace, getActiveWorkspace, getUserContext } from "./api-client.js";
|
|
5
|
+
import { collectHosts, evaluateTargetUrl } from "./workspace-target-url.js";
|
|
6
|
+
export const APEX = "Apex";
|
|
7
|
+
/**
|
|
8
|
+
* MOBX-006 — stable synthetic visitor id for agent-fired events.
|
|
9
|
+
*
|
|
10
|
+
* `/api/events` only counts an event toward wiring detection when it
|
|
11
|
+
* carries a top-level `visitorId`. A per-process random suffix keeps
|
|
12
|
+
* the id stable for the MCP server's lifetime (so repeated track_event
|
|
13
|
+
* calls roll up to one synthetic "visitor") while distinguishing
|
|
14
|
+
* separate agent sessions from each other.
|
|
15
|
+
*/
|
|
16
|
+
export const MCP_AGENT_VISITOR_ID = `mcp-agent-${Math.random().toString(36).slice(2, 10)}`;
|
|
17
|
+
/** Control traffic % derived from the unified allocation weights (default 50). */
|
|
18
|
+
export function controlPctOf(exp) {
|
|
19
|
+
const w = exp.allocation?.weights?.control;
|
|
20
|
+
return typeof w === "number" ? Math.round(w * 100) : 50;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Days running, derived locally from startedAt/createdAt → completedAt/now.
|
|
24
|
+
* The legacy web shape carried a server-computed `daysRunning`; the unified
|
|
25
|
+
* shape does not, so we compute it from the lifecycle timestamps.
|
|
26
|
+
*/
|
|
27
|
+
export function daysRunningOf(exp) {
|
|
28
|
+
const start = exp.startedAt || exp.createdAt;
|
|
29
|
+
if (!start)
|
|
30
|
+
return 0;
|
|
31
|
+
const startMs = new Date(start).getTime();
|
|
32
|
+
if (Number.isNaN(startMs))
|
|
33
|
+
return 0;
|
|
34
|
+
const endMs = exp.completedAt ? new Date(exp.completedAt).getTime() : Date.now();
|
|
35
|
+
return Math.max(0, Math.floor((endMs - startMs) / 86_400_000));
|
|
36
|
+
}
|
|
37
|
+
/** Find a unified variant by its key (e.g. "control", "variant_a"). */
|
|
38
|
+
export function findVariant(exp, key) {
|
|
39
|
+
return exp.variants?.find((v) => v.key === key);
|
|
40
|
+
}
|
|
41
|
+
/** Render a per-arm exposure line for wiring summaries. */
|
|
42
|
+
export function formatArmLine(arm) {
|
|
43
|
+
const live = arm.exposures > 0;
|
|
44
|
+
const dot = live ? "●" : "○";
|
|
45
|
+
const seen = arm.lastSeenAt ? `, last seen ${arm.lastSeenAt}` : "";
|
|
46
|
+
return ` ${dot} ${arm.label} (${arm.variantKey}): ${arm.exposures} exposure${arm.exposures === 1 ? "" : "s"}${seen}`;
|
|
47
|
+
}
|
|
48
|
+
/** "add_to_cart" → "Add To Cart" (for primaryMetric labels). */
|
|
49
|
+
export function titleCaseEvent(event) {
|
|
50
|
+
return event
|
|
51
|
+
.split(/[_\s]+/)
|
|
52
|
+
.filter(Boolean)
|
|
53
|
+
.map((w) => w.charAt(0).toUpperCase() + w.slice(1))
|
|
54
|
+
.join(" ");
|
|
55
|
+
}
|
|
56
|
+
export function activeWorkspaceSiteUrl() {
|
|
57
|
+
const ctx = getUserContext();
|
|
58
|
+
const key = getActiveWorkspace();
|
|
59
|
+
if (!ctx || !key)
|
|
60
|
+
return null;
|
|
61
|
+
for (const org of ctx.orgs) {
|
|
62
|
+
const match = org.workspaces.find((w) => w.workspaceKey === key);
|
|
63
|
+
if (match?.url)
|
|
64
|
+
return match.url;
|
|
65
|
+
}
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
export async function assertTargetUrlForActiveWorkspace(targetUrl) {
|
|
69
|
+
const namedSites = [];
|
|
70
|
+
let workspaceUrl = activeWorkspaceSiteUrl();
|
|
71
|
+
let catalogUnreadable = false;
|
|
72
|
+
try {
|
|
73
|
+
const env = await apiGet("/api/workspace/environments");
|
|
74
|
+
namedSites.push(...(env.data.production_hosts ?? []), ...(env.data.beta_hosts ?? []));
|
|
75
|
+
for (const row of env.data.known_hosts ?? []) {
|
|
76
|
+
namedSites.push(typeof row === "string" ? row : row.hostname ?? "");
|
|
77
|
+
}
|
|
78
|
+
if (env.data.workspace_url)
|
|
79
|
+
workspaceUrl = env.data.workspace_url;
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
catalogUnreadable = true;
|
|
83
|
+
}
|
|
84
|
+
let analyticsHosts = [];
|
|
85
|
+
try {
|
|
86
|
+
const json = await apiGet("/api/analytics/hostnames?limit=100");
|
|
87
|
+
analyticsHosts = json.data ?? [];
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
/* analytics is a supplement, not the source of truth */
|
|
91
|
+
}
|
|
92
|
+
const allowed = collectHosts({
|
|
93
|
+
analyticsHosts,
|
|
94
|
+
namedSites,
|
|
95
|
+
workspaceUrl,
|
|
96
|
+
});
|
|
97
|
+
if (allowed.length === 0 && catalogUnreadable) {
|
|
98
|
+
return {
|
|
99
|
+
ok: false,
|
|
100
|
+
message: "Could not load this workspace's sites (list_workspace_environments failed). Name the site with set_workspace_environments before setting target_url. Do not guess a brand domain or a sibling workspace's site.",
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
return evaluateTargetUrl(targetUrl, allowed);
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Query string for the pack report windows: relative (`days` / `months`)
|
|
107
|
+
* or explicit `start` + `end` (YYYY-MM-DD, both required together —
|
|
108
|
+
* explicit bounds win server-side).
|
|
109
|
+
*/
|
|
110
|
+
export function windowQuery(opts) {
|
|
111
|
+
const params = new URLSearchParams();
|
|
112
|
+
if (opts.days)
|
|
113
|
+
params.set("days", String(opts.days));
|
|
114
|
+
if (opts.months)
|
|
115
|
+
params.set("months", String(opts.months));
|
|
116
|
+
if (opts.start && opts.end) {
|
|
117
|
+
params.set("start", opts.start);
|
|
118
|
+
params.set("end", opts.end);
|
|
119
|
+
}
|
|
120
|
+
const qs = params.toString();
|
|
121
|
+
return qs ? `?${qs}` : "";
|
|
122
|
+
}
|
|
123
|
+
export function errMsg(err) {
|
|
124
|
+
return err instanceof Error ? err.message : String(err);
|
|
125
|
+
}
|
|
126
|
+
/** Build a dashboard deep link on the same host the MCP talks to (app origin). */
|
|
127
|
+
export function appUrl(path) {
|
|
128
|
+
const base = process.env.APEX_URL || process.env.APEX_API_URL || "http://localhost:3001";
|
|
129
|
+
return `${base.replace(/\/$/, "")}${path}`;
|
|
130
|
+
}
|
|
131
|
+
export function journeyLink(id) {
|
|
132
|
+
return appUrl(`/dashboard/communications/journeys/${id}`);
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Detect a MOBILE experiment surface from repo signals (the MCP runs in the
|
|
136
|
+
* merchant's repo). Walks up a few dirs looking for capacitor.config.* or a
|
|
137
|
+
* Capacitor/RN dependency. Returns null when there's no mobile signal (web is
|
|
138
|
+
* the safe default — a website repo carries no special marker). QA 2026-06-18.
|
|
139
|
+
*/
|
|
140
|
+
export function detectSurfaceFromRepo() {
|
|
141
|
+
try {
|
|
142
|
+
let dir = process.cwd();
|
|
143
|
+
for (let i = 0; i < 4; i++) {
|
|
144
|
+
for (const f of [
|
|
145
|
+
"capacitor.config.ts",
|
|
146
|
+
"capacitor.config.js",
|
|
147
|
+
"capacitor.config.json",
|
|
148
|
+
"capacitor.config.mjs",
|
|
149
|
+
]) {
|
|
150
|
+
if (existsSync(join(dir, f)))
|
|
151
|
+
return "mobile";
|
|
152
|
+
}
|
|
153
|
+
const pkgPath = join(dir, "package.json");
|
|
154
|
+
if (existsSync(pkgPath)) {
|
|
155
|
+
try {
|
|
156
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf8"));
|
|
157
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
158
|
+
if (deps["@apex-inc/capacitor-plugin"] ||
|
|
159
|
+
deps["@capacitor/core"] ||
|
|
160
|
+
deps["react-native"]) {
|
|
161
|
+
return "mobile";
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
catch {
|
|
165
|
+
/* unreadable package.json — keep walking */
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
const parent = dirname(dir);
|
|
169
|
+
if (parent === dir)
|
|
170
|
+
break;
|
|
171
|
+
dir = parent;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
/* fs not available — fall through */
|
|
176
|
+
}
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Resolve the experiment surface. Explicit wins; otherwise detect from repo
|
|
181
|
+
* signals, then the workspace's registered data sources. Returns an `ambiguous`
|
|
182
|
+
* error only when both web and mobile data sources exist and there's no repo
|
|
183
|
+
* signal — in that case the agent must choose. (QA: stop defaulting to web.)
|
|
184
|
+
*/
|
|
185
|
+
export async function resolveCreateSurface(explicit) {
|
|
186
|
+
if (explicit)
|
|
187
|
+
return { surface: explicit };
|
|
188
|
+
const repo = detectSurfaceFromRepo();
|
|
189
|
+
if (repo)
|
|
190
|
+
return { surface: repo };
|
|
191
|
+
try {
|
|
192
|
+
const ws = getActiveWorkspace();
|
|
193
|
+
if (ws) {
|
|
194
|
+
const r = await apiGet(`/api/workspaces/${encodeURIComponent(ws)}/readiness`);
|
|
195
|
+
const sources = r.data?.sources ?? [];
|
|
196
|
+
const hasMobile = sources.some((s) => s.kind === "ios" || s.kind === "android");
|
|
197
|
+
const hasWeb = sources.some((s) => s.kind === "website");
|
|
198
|
+
if (hasMobile && !hasWeb)
|
|
199
|
+
return { surface: "mobile" };
|
|
200
|
+
if (hasWeb && !hasMobile)
|
|
201
|
+
return { surface: "web" };
|
|
202
|
+
if (hasMobile && hasWeb)
|
|
203
|
+
return { ambiguous: true };
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
catch {
|
|
207
|
+
/* readiness unavailable — fall back to web */
|
|
208
|
+
}
|
|
209
|
+
return { surface: "web" };
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Tenant echo (council CISO): never report a mutation as successful for a record
|
|
213
|
+
* outside the active workspace (guards a leaked/cross-workspace key).
|
|
214
|
+
*/
|
|
215
|
+
export function tenantOk(workspaceKey) {
|
|
216
|
+
const active = getActiveWorkspace();
|
|
217
|
+
return !active || !workspaceKey || workspaceKey === active;
|
|
218
|
+
}
|
|
219
|
+
export function tenantMismatch() {
|
|
220
|
+
return {
|
|
221
|
+
content: [
|
|
222
|
+
{
|
|
223
|
+
type: "text",
|
|
224
|
+
text: `${APEX} Refusing to confirm: the affected record belongs to a different workspace.`,
|
|
225
|
+
},
|
|
226
|
+
],
|
|
227
|
+
isError: true,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Shared schema + handler for `switch_workspace` (canonical) and its
|
|
232
|
+
* deprecated alias `switch_project`. Both register against the same handler
|
|
233
|
+
* so existing agent calls keep working through the project→workspace rename.
|
|
234
|
+
*
|
|
235
|
+
* After updating the active workspace locally, we VALIDATE the switch with an
|
|
236
|
+
* authed read against `/api/setup-state` (which `apiGet` scopes to the active
|
|
237
|
+
* workspace). Validation is non-fatal: the local switch always succeeds, but
|
|
238
|
+
* we surface an auth/reachability warning so the user knows to connect or
|
|
239
|
+
* fix the workspace key.
|
|
240
|
+
*/
|
|
241
|
+
export const switchWorkspaceSchema = z.object({
|
|
242
|
+
workspaceKey: z.string().optional().describe("The workspace key to switch to."),
|
|
243
|
+
projectKey: z
|
|
244
|
+
.string()
|
|
245
|
+
.optional()
|
|
246
|
+
.describe("Deprecated alias of workspaceKey. Use workspaceKey."),
|
|
247
|
+
});
|
|
248
|
+
export async function switchWorkspaceHandler(args) {
|
|
249
|
+
const key = args.workspaceKey ?? args.projectKey;
|
|
250
|
+
if (!key) {
|
|
251
|
+
return {
|
|
252
|
+
content: [{
|
|
253
|
+
type: "text",
|
|
254
|
+
text: "Provide a workspaceKey to switch to (projectKey is accepted as a deprecated alias).",
|
|
255
|
+
}],
|
|
256
|
+
isError: true,
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
setActiveWorkspace(key);
|
|
260
|
+
const deprecationNote = !args.workspaceKey && args.projectKey
|
|
261
|
+
? " (note: `projectKey` is deprecated — use `workspaceKey`.)"
|
|
262
|
+
: "";
|
|
263
|
+
// Validate the switch by reading setup-state for the now-active workspace.
|
|
264
|
+
let validation = " Verified — Apex can read this workspace.";
|
|
265
|
+
try {
|
|
266
|
+
await apiGet("/api/setup-state");
|
|
267
|
+
}
|
|
268
|
+
catch (err) {
|
|
269
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
270
|
+
if (/\(401\)|\(403\)|authentication failed/i.test(message)) {
|
|
271
|
+
validation =
|
|
272
|
+
"\n\n⚠️ Switched locally, but could not verify the workspace — authentication failed. " +
|
|
273
|
+
"Connect the MCP server to Apex (run any Apex tool to get a one-time approval link), " +
|
|
274
|
+
"or regenerate APEX_API_KEY in Apex → Settings → AI Agents, then try again.";
|
|
275
|
+
}
|
|
276
|
+
else if (/\(404\)/.test(message)) {
|
|
277
|
+
validation =
|
|
278
|
+
`\n\n⚠️ Switched locally, but Apex returned 404 for "${key}" — the workspace key may be wrong. ` +
|
|
279
|
+
"Use list_workspaces to see the valid keys for your API key.";
|
|
280
|
+
}
|
|
281
|
+
else {
|
|
282
|
+
validation = `\n\n⚠️ Switched locally, but could not reach Apex to verify it (${message}).`;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
return {
|
|
286
|
+
content: [{
|
|
287
|
+
type: "text",
|
|
288
|
+
text: `Switched to workspace: ${key}. All subsequent calls will use this workspace.${deprecationNote}${validation}`,
|
|
289
|
+
}],
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Shared handler for `list_workspaces` (canonical) and its deprecated alias
|
|
294
|
+
* `list_projects`. Both register against the same handler so existing agent
|
|
295
|
+
* calls keep working through the project→workspace rename.
|
|
296
|
+
*/
|
|
297
|
+
export async function listWorkspacesHandler() {
|
|
298
|
+
// NOTE: `/api/projects` is the PERMANENT alias path this tool has shipped
|
|
299
|
+
// against — it returns the flat row shape below. Do not point at
|
|
300
|
+
// `/api/workspaces` (different response shape).
|
|
301
|
+
const workspaces = await apiGet("/api/projects");
|
|
302
|
+
const current = getActiveWorkspace();
|
|
303
|
+
if (!workspaces.length) {
|
|
304
|
+
return {
|
|
305
|
+
content: [{ type: "text", text: "No workspaces found for this API key." }],
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
const lines = workspaces.map((p) => {
|
|
309
|
+
const active = p.workspaceKey === current ? " ← active" : "";
|
|
310
|
+
return ` ${p.workspaceKey} — ${p.name} (${p.url})${active}`;
|
|
311
|
+
});
|
|
312
|
+
return {
|
|
313
|
+
content: [{
|
|
314
|
+
type: "text",
|
|
315
|
+
text: [`Workspaces (${workspaces.length}):`, ...lines].join("\n"),
|
|
316
|
+
}],
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
//# sourceMappingURL=tool-shared.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-shared.js","sourceRoot":"","sources":["../src/tool-shared.ts"],"names":[],"mappings":"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"}
|