@vibekiln/cutline-mcp-cli 0.12.0 → 0.14.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 +15 -0
- package/dist/auth/callback.d.ts +1 -1
- package/dist/auth/callback.js +9 -1
- package/dist/commands/login.js +4 -1
- package/dist/commands/serve.d.ts +4 -0
- package/dist/commands/serve.js +19 -6
- package/dist/commands/setup.js +7 -4
- package/dist/index.js +4 -2
- package/dist/servers/{chunk-RUCYK3TR.js → chunk-EWUELVO2.js} +341 -89
- package/dist/servers/chunk-Q5V4VTF5.js +3180 -0
- package/dist/servers/{chunk-KMUSQOTJ.js → chunk-WTLGBZBN.js} +15 -1
- package/dist/servers/cutline-server.js +1236 -4066
- package/dist/servers/{data-client-RY2DCLME.js → data-client-OIQ6SINO.js} +41 -3
- package/dist/servers/exploration-server.js +1 -1
- package/dist/servers/integrations-server.js +2 -2
- package/dist/servers/output-server.js +1 -1
- package/dist/servers/premortem-server.js +30 -65
- package/dist/servers/slopburn-server.js +10069 -0
- package/dist/servers/tools-server.js +2 -2
- package/package.json +5 -3
- package/server.json +1 -1
|
@@ -3,6 +3,21 @@ import { McpError, ErrorCode } from "@modelcontextprotocol/sdk/types.js";
|
|
|
3
3
|
import fs from "fs";
|
|
4
4
|
import path from "path";
|
|
5
5
|
import os from "os";
|
|
6
|
+
|
|
7
|
+
// ../mcp/dist/mcp/src/auth-cache.js
|
|
8
|
+
function buildTokenCredentialKey(refreshToken, environment) {
|
|
9
|
+
return `${environment ?? "production"}:${refreshToken}`;
|
|
10
|
+
}
|
|
11
|
+
function shouldReuseResolvedAuthCache(options) {
|
|
12
|
+
const now = options.now ?? Date.now();
|
|
13
|
+
if (!options.cachedIdToken || !options.cachedBaseUrl)
|
|
14
|
+
return false;
|
|
15
|
+
if (!options.tokenExpiresAt || now >= options.tokenExpiresAt)
|
|
16
|
+
return false;
|
|
17
|
+
return options.cachedCredentialKey === buildTokenCredentialKey(options.refreshToken, options.environment);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// ../mcp/dist/mcp/src/utils.js
|
|
6
21
|
function decodeIdTokenLocally(idToken) {
|
|
7
22
|
const parts = idToken.split(".");
|
|
8
23
|
if (parts.length !== 3) {
|
|
@@ -162,34 +177,63 @@ function cleanupTokenCache() {
|
|
|
162
177
|
}
|
|
163
178
|
lastCleanup = now;
|
|
164
179
|
}
|
|
165
|
-
function getCachedToken(refreshToken) {
|
|
180
|
+
function getCachedToken(refreshToken, environment) {
|
|
181
|
+
const cacheKey = buildTokenCredentialKey(refreshToken, environment);
|
|
166
182
|
if (Date.now() - lastCleanup > CACHE_CLEANUP_INTERVAL) {
|
|
167
183
|
cleanupTokenCache();
|
|
168
184
|
}
|
|
169
|
-
const cached = tokenCache.get(
|
|
185
|
+
const cached = tokenCache.get(cacheKey);
|
|
170
186
|
if (!cached) {
|
|
171
187
|
return null;
|
|
172
188
|
}
|
|
173
189
|
if (Date.now() >= cached.expiresAt) {
|
|
174
|
-
tokenCache.delete(
|
|
190
|
+
tokenCache.delete(cacheKey);
|
|
175
191
|
return null;
|
|
176
192
|
}
|
|
177
193
|
cached.lastUsed = Date.now();
|
|
178
|
-
tokenCache.delete(
|
|
179
|
-
tokenCache.set(
|
|
194
|
+
tokenCache.delete(cacheKey);
|
|
195
|
+
tokenCache.set(cacheKey, cached);
|
|
180
196
|
return cached.idToken;
|
|
181
197
|
}
|
|
182
|
-
function setCachedToken(refreshToken, idToken, expiresAt) {
|
|
198
|
+
function setCachedToken(refreshToken, idToken, expiresAt, environment) {
|
|
199
|
+
const cacheKey = buildTokenCredentialKey(refreshToken, environment);
|
|
183
200
|
if (tokenCache.size >= MAX_CACHE_SIZE) {
|
|
184
201
|
cleanupTokenCache();
|
|
185
202
|
}
|
|
186
|
-
tokenCache.delete(
|
|
187
|
-
tokenCache.set(
|
|
203
|
+
tokenCache.delete(cacheKey);
|
|
204
|
+
tokenCache.set(cacheKey, {
|
|
188
205
|
idToken,
|
|
189
206
|
expiresAt,
|
|
190
207
|
lastUsed: Date.now()
|
|
191
208
|
});
|
|
192
209
|
}
|
|
210
|
+
function clearCachedAutoAuthState(options) {
|
|
211
|
+
if (!options?.refreshToken) {
|
|
212
|
+
tokenCache.clear();
|
|
213
|
+
cachedApiKey = null;
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
tokenCache.delete(buildTokenCredentialKey(options.refreshToken, options.environment));
|
|
217
|
+
}
|
|
218
|
+
async function resolveStoredIdToken(options) {
|
|
219
|
+
const { refreshToken, environment, forceRefresh = false } = options;
|
|
220
|
+
if (!forceRefresh) {
|
|
221
|
+
const cached = getCachedToken(refreshToken, environment);
|
|
222
|
+
if (cached) {
|
|
223
|
+
return cached;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
const apiKeyToUse = await getFirebaseApiKey(environment);
|
|
227
|
+
try {
|
|
228
|
+
const idToken = await exchangeRefreshToken(refreshToken, apiKeyToUse);
|
|
229
|
+
setCachedToken(refreshToken, idToken, Date.now() + 50 * 60 * 1e3, environment);
|
|
230
|
+
return idToken;
|
|
231
|
+
} catch (e) {
|
|
232
|
+
console.error("Token exchange failed:", e);
|
|
233
|
+
clearCachedAutoAuthState({ refreshToken, environment });
|
|
234
|
+
return void 0;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
193
237
|
var cachedApiKey = null;
|
|
194
238
|
var API_KEY_CACHE_TTL = 36e5;
|
|
195
239
|
async function getFirebaseApiKey(environment) {
|
|
@@ -354,53 +398,82 @@ async function getStoredToken() {
|
|
|
354
398
|
}
|
|
355
399
|
return null;
|
|
356
400
|
}
|
|
401
|
+
function getForcedEnvironment() {
|
|
402
|
+
const raw = process.env.CUTLINE_ENV?.trim().toLowerCase();
|
|
403
|
+
if (raw === "staging")
|
|
404
|
+
return "staging";
|
|
405
|
+
if (raw === "production" || raw === "prod")
|
|
406
|
+
return "production";
|
|
407
|
+
return void 0;
|
|
408
|
+
}
|
|
409
|
+
function mergeEnvironmentOrThrow(resolved, sourceLabel) {
|
|
410
|
+
const forced = getForcedEnvironment();
|
|
411
|
+
if (!forced)
|
|
412
|
+
return resolved;
|
|
413
|
+
if (resolved && resolved !== forced) {
|
|
414
|
+
throw new McpError(ErrorCode.InvalidRequest, `Environment mismatch: CUTLINE_ENV=${forced} but ${sourceLabel} is ${resolved}. ` + `Run cutline-mcp login ${forced === "staging" ? "--staging" : ""}`.trim());
|
|
415
|
+
}
|
|
416
|
+
return forced;
|
|
417
|
+
}
|
|
357
418
|
async function requirePremiumWithAutoAuth(authToken) {
|
|
358
419
|
let idToken = authToken;
|
|
359
|
-
let environment;
|
|
420
|
+
let environment = getForcedEnvironment();
|
|
421
|
+
let storedTokenInfo = null;
|
|
360
422
|
if (!idToken) {
|
|
361
|
-
|
|
362
|
-
environment = storedTokenInfo?.environment;
|
|
423
|
+
storedTokenInfo = await getStoredToken();
|
|
424
|
+
environment = mergeEnvironmentOrThrow(storedTokenInfo?.environment, "stored refresh token");
|
|
363
425
|
if (storedTokenInfo) {
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
}
|
|
426
|
+
idToken = await resolveStoredIdToken({
|
|
427
|
+
refreshToken: storedTokenInfo.refreshToken,
|
|
428
|
+
environment: environment || "production"
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
try {
|
|
433
|
+
return await requirePremium(idToken, environment);
|
|
434
|
+
} catch (error) {
|
|
435
|
+
if (!authToken && storedTokenInfo) {
|
|
436
|
+
clearCachedAutoAuthState({
|
|
437
|
+
refreshToken: storedTokenInfo.refreshToken,
|
|
438
|
+
environment: environment || "production"
|
|
439
|
+
});
|
|
440
|
+
const refreshedIdToken = await resolveStoredIdToken({
|
|
441
|
+
refreshToken: storedTokenInfo.refreshToken,
|
|
442
|
+
environment: environment || "production",
|
|
443
|
+
forceRefresh: true
|
|
444
|
+
});
|
|
445
|
+
return await requirePremium(refreshedIdToken, environment);
|
|
378
446
|
}
|
|
447
|
+
throw error;
|
|
379
448
|
}
|
|
380
|
-
return await requirePremium(idToken, environment);
|
|
381
449
|
}
|
|
382
450
|
async function requireAuthOnly(authToken) {
|
|
383
451
|
let idToken = authToken;
|
|
452
|
+
let storedTokenInfo = null;
|
|
453
|
+
let environment;
|
|
384
454
|
if (!idToken) {
|
|
385
|
-
|
|
455
|
+
storedTokenInfo = await getStoredToken();
|
|
386
456
|
if (storedTokenInfo) {
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
} else {
|
|
393
|
-
try {
|
|
394
|
-
idToken = await exchangeRefreshToken(refreshToken, apiKeyToUse);
|
|
395
|
-
setCachedToken(refreshToken, idToken, Date.now() + 50 * 60 * 1e3);
|
|
396
|
-
} catch (e) {
|
|
397
|
-
console.error("Token exchange failed:", e);
|
|
398
|
-
tokenCache.delete(refreshToken);
|
|
399
|
-
}
|
|
400
|
-
}
|
|
457
|
+
environment = mergeEnvironmentOrThrow(storedTokenInfo.environment, "stored refresh token");
|
|
458
|
+
idToken = await resolveStoredIdToken({
|
|
459
|
+
refreshToken: storedTokenInfo.refreshToken,
|
|
460
|
+
environment: environment || "production"
|
|
461
|
+
});
|
|
401
462
|
}
|
|
402
463
|
}
|
|
403
|
-
|
|
464
|
+
let decoded = await validateAuth(idToken);
|
|
465
|
+
if (!decoded && !authToken && storedTokenInfo) {
|
|
466
|
+
clearCachedAutoAuthState({
|
|
467
|
+
refreshToken: storedTokenInfo.refreshToken,
|
|
468
|
+
environment: environment || "production"
|
|
469
|
+
});
|
|
470
|
+
const refreshedIdToken = await resolveStoredIdToken({
|
|
471
|
+
refreshToken: storedTokenInfo.refreshToken,
|
|
472
|
+
environment: environment || "production",
|
|
473
|
+
forceRefresh: true
|
|
474
|
+
});
|
|
475
|
+
decoded = await validateAuth(refreshedIdToken);
|
|
476
|
+
}
|
|
404
477
|
if (!decoded) {
|
|
405
478
|
throw new McpError(ErrorCode.InvalidRequest, "Authentication required. Run 'cutline-mcp login' to authenticate.");
|
|
406
479
|
}
|
|
@@ -420,10 +493,59 @@ async function resolveAuthContextFree(authToken) {
|
|
|
420
493
|
function getBaseUrl(environment) {
|
|
421
494
|
return environment === "staging" ? "https://us-central1-cutline-staging.cloudfunctions.net" : "https://us-central1-cutline-prod.cloudfunctions.net";
|
|
422
495
|
}
|
|
496
|
+
var STAGING_UNSUFFIXED_FUNCTIONS = /* @__PURE__ */ new Set([
|
|
497
|
+
// Intentionally deployed without env suffix in staging.
|
|
498
|
+
"applyWikiEdits",
|
|
499
|
+
"mcpGenerateTokenG2",
|
|
500
|
+
"mcpSubscriptionStatus"
|
|
501
|
+
]);
|
|
502
|
+
function resolveFunctionEndpointName(functionName, environment) {
|
|
503
|
+
if (environment !== "staging")
|
|
504
|
+
return functionName;
|
|
505
|
+
if (STAGING_UNSUFFIXED_FUNCTIONS.has(functionName))
|
|
506
|
+
return functionName;
|
|
507
|
+
return `${functionName}-stg`;
|
|
508
|
+
}
|
|
423
509
|
function getSiteUrl(environment) {
|
|
424
510
|
return environment === "staging" ? "https://cutline-staging.web.app" : "https://thecutline.ai";
|
|
425
511
|
}
|
|
512
|
+
function getAppApiBaseUrl(environment) {
|
|
513
|
+
const override = process.env.CUTLINE_APP_API_BASE_URL?.trim() || process.env.CUTLINE_SSR_BASE_URL?.trim() || process.env.SSR_BASE_URL?.trim();
|
|
514
|
+
if (override) {
|
|
515
|
+
return override.replace(/\/+$/, "");
|
|
516
|
+
}
|
|
517
|
+
return environment === "staging" ? "https://ssrcutlinestaging-vi2gngz52a-uc.a.run.app" : "https://ssrcutline-y74odqxy3q-uc.a.run.app";
|
|
518
|
+
}
|
|
519
|
+
function getForcedEnvironment2() {
|
|
520
|
+
const raw = process.env.CUTLINE_ENV?.trim().toLowerCase();
|
|
521
|
+
if (raw === "staging")
|
|
522
|
+
return "staging";
|
|
523
|
+
if (raw === "production" || raw === "prod")
|
|
524
|
+
return "production";
|
|
525
|
+
return void 0;
|
|
526
|
+
}
|
|
527
|
+
function mergeEnvironment(resolved, sourceLabel) {
|
|
528
|
+
const forced = getForcedEnvironment2();
|
|
529
|
+
if (!forced) {
|
|
530
|
+
return resolved || "production";
|
|
531
|
+
}
|
|
532
|
+
if (resolved && resolved !== forced) {
|
|
533
|
+
throw new Error(`Environment mismatch: CUTLINE_ENV=${forced} but ${sourceLabel} is ${resolved}. ` + `Run cutline-mcp login ${forced === "staging" ? "--staging" : ""}`.trim());
|
|
534
|
+
}
|
|
535
|
+
return forced;
|
|
536
|
+
}
|
|
537
|
+
var __dataClientInternals = {
|
|
538
|
+
getBaseUrl,
|
|
539
|
+
resolveFunctionEndpointName,
|
|
540
|
+
getSiteUrl,
|
|
541
|
+
getAppApiBaseUrl,
|
|
542
|
+
mergeEnvironment
|
|
543
|
+
};
|
|
426
544
|
async function getPublicSiteUrlForCurrentAuth() {
|
|
545
|
+
const forced = getForcedEnvironment2();
|
|
546
|
+
if (forced) {
|
|
547
|
+
return getSiteUrl(forced);
|
|
548
|
+
}
|
|
427
549
|
const stored = await getStoredToken();
|
|
428
550
|
if (stored?.environment) {
|
|
429
551
|
return getSiteUrl(stored.environment);
|
|
@@ -436,7 +558,14 @@ async function getPublicSiteUrlForCurrentAuth() {
|
|
|
436
558
|
}
|
|
437
559
|
var cachedBaseUrl;
|
|
438
560
|
var cachedIdToken;
|
|
561
|
+
var cachedCredentialKey;
|
|
439
562
|
var tokenExpiresAt = 0;
|
|
563
|
+
function clearResolvedAuthCache() {
|
|
564
|
+
cachedBaseUrl = void 0;
|
|
565
|
+
cachedIdToken = void 0;
|
|
566
|
+
cachedCredentialKey = void 0;
|
|
567
|
+
tokenExpiresAt = 0;
|
|
568
|
+
}
|
|
440
569
|
var FIREBASE_API_KEY_CACHE = {};
|
|
441
570
|
async function getFirebaseApiKey2(environment) {
|
|
442
571
|
const envKey = process.env.FIREBASE_API_KEY || process.env.NEXT_PUBLIC_FIREBASE_API_KEY;
|
|
@@ -478,50 +607,76 @@ async function exchangeRefreshForId(refreshToken, environment) {
|
|
|
478
607
|
async function resolveAuth() {
|
|
479
608
|
const envApiKeyInfo = getStoredApiKey({ includeConfig: false });
|
|
480
609
|
if (envApiKeyInfo) {
|
|
610
|
+
const env = mergeEnvironment(envApiKeyInfo.environment, "CUTLINE_API_KEY credentials");
|
|
481
611
|
return {
|
|
482
|
-
baseUrl: getBaseUrl(
|
|
483
|
-
idToken: envApiKeyInfo.apiKey
|
|
612
|
+
baseUrl: getBaseUrl(env),
|
|
613
|
+
idToken: envApiKeyInfo.apiKey,
|
|
614
|
+
environment: env
|
|
484
615
|
};
|
|
485
616
|
}
|
|
486
|
-
if (cachedIdToken && Date.now() < tokenExpiresAt && cachedBaseUrl) {
|
|
487
|
-
return { baseUrl: cachedBaseUrl, idToken: cachedIdToken };
|
|
488
|
-
}
|
|
489
617
|
const stored = await getStoredToken();
|
|
490
618
|
if (stored) {
|
|
491
|
-
const env = stored.environment
|
|
619
|
+
const env = mergeEnvironment(stored.environment, "stored refresh token");
|
|
620
|
+
const credentialKey = buildTokenCredentialKey(stored.refreshToken, env);
|
|
621
|
+
if (shouldReuseResolvedAuthCache({
|
|
622
|
+
cachedCredentialKey,
|
|
623
|
+
cachedIdToken,
|
|
624
|
+
cachedBaseUrl,
|
|
625
|
+
tokenExpiresAt,
|
|
626
|
+
refreshToken: stored.refreshToken,
|
|
627
|
+
environment: env
|
|
628
|
+
})) {
|
|
629
|
+
return { baseUrl: getBaseUrl(env), idToken: cachedIdToken, environment: env };
|
|
630
|
+
}
|
|
631
|
+
if (cachedCredentialKey && cachedCredentialKey !== credentialKey) {
|
|
632
|
+
clearResolvedAuthCache();
|
|
633
|
+
}
|
|
492
634
|
const baseUrl = getBaseUrl(env);
|
|
493
635
|
const idToken = await exchangeRefreshForId(stored.refreshToken, env);
|
|
494
636
|
cachedBaseUrl = baseUrl;
|
|
495
637
|
cachedIdToken = idToken;
|
|
638
|
+
cachedCredentialKey = credentialKey;
|
|
496
639
|
tokenExpiresAt = Date.now() + 50 * 60 * 1e3;
|
|
497
|
-
return { baseUrl, idToken };
|
|
640
|
+
return { baseUrl, idToken, environment: env };
|
|
641
|
+
}
|
|
642
|
+
if (cachedCredentialKey) {
|
|
643
|
+
clearResolvedAuthCache();
|
|
498
644
|
}
|
|
499
645
|
const configApiKeyInfo = getStoredApiKey();
|
|
500
646
|
if (configApiKeyInfo) {
|
|
647
|
+
const env = mergeEnvironment(configApiKeyInfo.environment, "stored API key");
|
|
501
648
|
return {
|
|
502
|
-
baseUrl: getBaseUrl(
|
|
503
|
-
idToken: configApiKeyInfo.apiKey
|
|
649
|
+
baseUrl: getBaseUrl(env),
|
|
650
|
+
idToken: configApiKeyInfo.apiKey,
|
|
651
|
+
environment: env
|
|
504
652
|
};
|
|
505
653
|
}
|
|
506
654
|
throw new Error("Not authenticated. Run 'cutline-mcp login' or set CUTLINE_API_KEY.");
|
|
507
655
|
}
|
|
656
|
+
async function performAuthedRequest(makeRequest) {
|
|
657
|
+
let auth = await resolveAuth();
|
|
658
|
+
let response = await makeRequest(auth);
|
|
659
|
+
if (response.status === 401) {
|
|
660
|
+
clearResolvedAuthCache();
|
|
661
|
+
auth = await resolveAuth();
|
|
662
|
+
response = await makeRequest(auth);
|
|
663
|
+
}
|
|
664
|
+
return response;
|
|
665
|
+
}
|
|
508
666
|
async function proxy(action, params = {}) {
|
|
509
|
-
const { baseUrl, idToken }
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
667
|
+
const res = await performAuthedRequest(async ({ baseUrl, idToken, environment }) => {
|
|
668
|
+
const endpoint = resolveFunctionEndpointName("mcpDataProxy", environment);
|
|
669
|
+
return fetch(`${baseUrl}/${endpoint}`, {
|
|
670
|
+
method: "POST",
|
|
671
|
+
headers: {
|
|
672
|
+
"Content-Type": "application/json",
|
|
673
|
+
Authorization: `Bearer ${idToken}`
|
|
674
|
+
},
|
|
675
|
+
body: JSON.stringify({ action, params }),
|
|
676
|
+
signal: AbortSignal.timeout(3e4)
|
|
677
|
+
});
|
|
518
678
|
});
|
|
519
679
|
if (!res.ok) {
|
|
520
|
-
if (res.status === 401) {
|
|
521
|
-
cachedIdToken = void 0;
|
|
522
|
-
tokenExpiresAt = 0;
|
|
523
|
-
throw new Error("Authentication expired \u2014 retrying on next call");
|
|
524
|
-
}
|
|
525
680
|
const body = await res.text().catch(() => "");
|
|
526
681
|
throw new Error(`mcpDataProxy ${action} failed (${res.status}): ${body.slice(0, 200)}`);
|
|
527
682
|
}
|
|
@@ -569,6 +724,30 @@ async function listExplorationSessions(collection, limit) {
|
|
|
569
724
|
const res = await proxy("exploration.list", { collection, limit });
|
|
570
725
|
return res.docs;
|
|
571
726
|
}
|
|
727
|
+
async function listEngagements(opts) {
|
|
728
|
+
const res = await proxy("engagement.list", opts || {});
|
|
729
|
+
return res.docs;
|
|
730
|
+
}
|
|
731
|
+
async function getEngagement(id) {
|
|
732
|
+
const res = await proxy("engagement.get", { id });
|
|
733
|
+
return res.doc;
|
|
734
|
+
}
|
|
735
|
+
async function createEngagement(data) {
|
|
736
|
+
return proxy("engagement.create", data);
|
|
737
|
+
}
|
|
738
|
+
async function updateEngagement(id, data) {
|
|
739
|
+
return proxy("engagement.update", { id, ...data });
|
|
740
|
+
}
|
|
741
|
+
async function attachDeepDiveToEngagement(engagementId, deepDiveId) {
|
|
742
|
+
return proxy("engagement.attachDeepDive", { engagementId, deepDiveId });
|
|
743
|
+
}
|
|
744
|
+
async function summarizeEngagement(id) {
|
|
745
|
+
const res = await proxy("engagement.summarize", { id });
|
|
746
|
+
return res.doc;
|
|
747
|
+
}
|
|
748
|
+
async function selectEngagementProduct(id, primaryProductId) {
|
|
749
|
+
return proxy("engagement.selectProduct", { id, primaryProductId });
|
|
750
|
+
}
|
|
572
751
|
async function getAllEntities(productId) {
|
|
573
752
|
const res = await proxy("graph.getEntities", { productId });
|
|
574
753
|
return res.docs.map((d) => ({ ...d, ingested_at: new Date(d.ingested_at?._seconds ? d.ingested_at._seconds * 1e3 : d.ingested_at) }));
|
|
@@ -846,44 +1025,60 @@ async function getPersona(personaId) {
|
|
|
846
1025
|
return res.doc;
|
|
847
1026
|
}
|
|
848
1027
|
async function callCF(functionName, body, timeoutMs = 6e4) {
|
|
849
|
-
const { baseUrl, idToken }
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
1028
|
+
const res = await performAuthedRequest(async ({ baseUrl, idToken, environment }) => {
|
|
1029
|
+
const endpoint = resolveFunctionEndpointName(functionName, environment);
|
|
1030
|
+
return fetch(`${baseUrl}/${endpoint}`, {
|
|
1031
|
+
method: "POST",
|
|
1032
|
+
headers: {
|
|
1033
|
+
"Content-Type": "application/json",
|
|
1034
|
+
Authorization: `Bearer ${idToken}`
|
|
1035
|
+
},
|
|
1036
|
+
body: JSON.stringify(body),
|
|
1037
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
1038
|
+
});
|
|
858
1039
|
});
|
|
859
1040
|
if (!res.ok) {
|
|
860
|
-
if (res.status === 401) {
|
|
861
|
-
cachedIdToken = void 0;
|
|
862
|
-
tokenExpiresAt = 0;
|
|
863
|
-
}
|
|
864
1041
|
const text = await res.text().catch(() => "");
|
|
865
1042
|
throw new Error(`CF ${functionName} failed (${res.status}): ${text.slice(0, 300)}`);
|
|
866
1043
|
}
|
|
867
1044
|
return res.json();
|
|
868
1045
|
}
|
|
869
1046
|
async function callCFGet(functionName, query, timeoutMs = 3e4) {
|
|
870
|
-
const { baseUrl, idToken }
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
1047
|
+
const res = await performAuthedRequest(async ({ baseUrl, idToken, environment }) => {
|
|
1048
|
+
const endpoint = resolveFunctionEndpointName(functionName, environment);
|
|
1049
|
+
const qs = new URLSearchParams(query).toString();
|
|
1050
|
+
return fetch(`${baseUrl}/${endpoint}?${qs}`, {
|
|
1051
|
+
method: "GET",
|
|
1052
|
+
headers: { Authorization: `Bearer ${idToken}` },
|
|
1053
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
1054
|
+
});
|
|
876
1055
|
});
|
|
877
1056
|
if (!res.ok) {
|
|
878
|
-
if (res.status === 401) {
|
|
879
|
-
cachedIdToken = void 0;
|
|
880
|
-
tokenExpiresAt = 0;
|
|
881
|
-
}
|
|
882
1057
|
const text = await res.text().catch(() => "");
|
|
883
1058
|
throw new Error(`CF ${functionName} failed (${res.status}): ${text.slice(0, 300)}`);
|
|
884
1059
|
}
|
|
885
1060
|
return res.json();
|
|
886
1061
|
}
|
|
1062
|
+
async function callAppApi(apiPath, body, timeoutMs = 12e4) {
|
|
1063
|
+
const normalizedPath = apiPath.startsWith("/") ? apiPath : `/${apiPath}`;
|
|
1064
|
+
const response = await performAuthedRequest(async ({ idToken, environment }) => {
|
|
1065
|
+
const appBaseUrl = getAppApiBaseUrl(environment);
|
|
1066
|
+
return fetch(`${appBaseUrl}${normalizedPath}`, {
|
|
1067
|
+
method: "POST",
|
|
1068
|
+
headers: {
|
|
1069
|
+
"Content-Type": "application/json",
|
|
1070
|
+
Authorization: `Bearer ${idToken}`
|
|
1071
|
+
},
|
|
1072
|
+
body: JSON.stringify(body),
|
|
1073
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
1074
|
+
});
|
|
1075
|
+
});
|
|
1076
|
+
if (!response.ok) {
|
|
1077
|
+
const text = await response.text().catch(() => "");
|
|
1078
|
+
throw new Error(`API ${normalizedPath} failed (${response.status}): ${text.slice(0, 300)}`);
|
|
1079
|
+
}
|
|
1080
|
+
return response.json();
|
|
1081
|
+
}
|
|
887
1082
|
async function cfGenerateTrialRun(prompt) {
|
|
888
1083
|
const res = await callCF("trialRun", { prompt });
|
|
889
1084
|
return res.text;
|
|
@@ -923,6 +1118,9 @@ async function cfPremortemRun(input) {
|
|
|
923
1118
|
async function cfPremortemStart(input) {
|
|
924
1119
|
return callCF("premortemStart", input, 3e4);
|
|
925
1120
|
}
|
|
1121
|
+
async function cfPremortemStatus(jobId) {
|
|
1122
|
+
return callCFGet("premortemStatus", { id: jobId }, 3e4);
|
|
1123
|
+
}
|
|
926
1124
|
async function cfPremortemKick(jobId) {
|
|
927
1125
|
return callCF("premortemKick", { id: jobId }, 6e5);
|
|
928
1126
|
}
|
|
@@ -1017,6 +1215,41 @@ async function getPodcastIntroductions(productId, format = "json") {
|
|
|
1017
1215
|
}
|
|
1018
1216
|
return { format: "json", participants: introductions };
|
|
1019
1217
|
}
|
|
1218
|
+
async function upsertSlopburnRun(runId, data) {
|
|
1219
|
+
return proxy("slopburn.upsertRun", { runId, data });
|
|
1220
|
+
}
|
|
1221
|
+
async function getSlopburnRun(runId) {
|
|
1222
|
+
const res = await proxy("slopburn.getRun", { runId });
|
|
1223
|
+
return res.doc;
|
|
1224
|
+
}
|
|
1225
|
+
async function listSlopburnRuns(limit = 20) {
|
|
1226
|
+
const res = await proxy("slopburn.listRuns", { limit });
|
|
1227
|
+
return res.docs;
|
|
1228
|
+
}
|
|
1229
|
+
async function getGeneratedTestArtifactBundle(artifactBundleId) {
|
|
1230
|
+
const res = await proxy("verification.getGeneratedTestArtifactBundle", { artifactBundleId });
|
|
1231
|
+
return res.doc;
|
|
1232
|
+
}
|
|
1233
|
+
async function enqueueVerificationCycleJob(input) {
|
|
1234
|
+
return proxy("verification.enqueueCycleJob", input);
|
|
1235
|
+
}
|
|
1236
|
+
async function getVerificationCycleJob(jobId) {
|
|
1237
|
+
const res = await proxy("verification.getCycleJob", { jobId });
|
|
1238
|
+
return res.doc;
|
|
1239
|
+
}
|
|
1240
|
+
async function getVerificationTestExecutionJob(jobId) {
|
|
1241
|
+
const res = await proxy("verification.getTestExecutionJob", { jobId });
|
|
1242
|
+
return res.doc;
|
|
1243
|
+
}
|
|
1244
|
+
async function submitVerificationTestExecution(input) {
|
|
1245
|
+
return proxy("verification.submitTestExecution", input);
|
|
1246
|
+
}
|
|
1247
|
+
async function runVerificationCycle(input) {
|
|
1248
|
+
return callAppApi("/api/verification/cycle", input, 6e5);
|
|
1249
|
+
}
|
|
1250
|
+
async function ingestVerificationIntent(input) {
|
|
1251
|
+
return callAppApi("/api/verification/ingest-intent", input, 12e4);
|
|
1252
|
+
}
|
|
1020
1253
|
|
|
1021
1254
|
export {
|
|
1022
1255
|
validateRequestSize,
|
|
@@ -1027,6 +1260,7 @@ export {
|
|
|
1027
1260
|
getStoredInstallId,
|
|
1028
1261
|
requirePremiumWithAutoAuth,
|
|
1029
1262
|
resolveAuthContextFree,
|
|
1263
|
+
__dataClientInternals,
|
|
1030
1264
|
getPublicSiteUrlForCurrentAuth,
|
|
1031
1265
|
listPremortems,
|
|
1032
1266
|
getPremortem,
|
|
@@ -1040,6 +1274,13 @@ export {
|
|
|
1040
1274
|
getExplorationSession,
|
|
1041
1275
|
updateExplorationSession,
|
|
1042
1276
|
listExplorationSessions,
|
|
1277
|
+
listEngagements,
|
|
1278
|
+
getEngagement,
|
|
1279
|
+
createEngagement,
|
|
1280
|
+
updateEngagement,
|
|
1281
|
+
attachDeepDiveToEngagement,
|
|
1282
|
+
summarizeEngagement,
|
|
1283
|
+
selectEngagementProduct,
|
|
1043
1284
|
getAllEntities,
|
|
1044
1285
|
upsertEntities,
|
|
1045
1286
|
addEntity,
|
|
@@ -1096,6 +1337,7 @@ export {
|
|
|
1096
1337
|
cfApplyEdits,
|
|
1097
1338
|
cfPremortemRun,
|
|
1098
1339
|
cfPremortemStart,
|
|
1340
|
+
cfPremortemStatus,
|
|
1099
1341
|
cfPremortemKick,
|
|
1100
1342
|
cfPremortemChatAgent,
|
|
1101
1343
|
cfRegenAssumptions,
|
|
@@ -1105,5 +1347,15 @@ export {
|
|
|
1105
1347
|
cfExplorationAgent,
|
|
1106
1348
|
cfConsultingDiscoveryAgent,
|
|
1107
1349
|
cfCreateLinearIssues,
|
|
1108
|
-
getPodcastIntroductions
|
|
1350
|
+
getPodcastIntroductions,
|
|
1351
|
+
upsertSlopburnRun,
|
|
1352
|
+
getSlopburnRun,
|
|
1353
|
+
listSlopburnRuns,
|
|
1354
|
+
getGeneratedTestArtifactBundle,
|
|
1355
|
+
enqueueVerificationCycleJob,
|
|
1356
|
+
getVerificationCycleJob,
|
|
1357
|
+
getVerificationTestExecutionJob,
|
|
1358
|
+
submitVerificationTestExecution,
|
|
1359
|
+
runVerificationCycle,
|
|
1360
|
+
ingestVerificationIntent
|
|
1109
1361
|
};
|