rivet-design 0.28.2 → 0.28.3

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.
Files changed (51) hide show
  1. package/dist/cli/commands/libraryOpen.js +1 -0
  2. package/dist/cli/commands/mcpServe.js +5 -1
  3. package/dist/cli/commands/open.js +13 -4
  4. package/dist/cli/commands/profile.js +8 -1
  5. package/dist/cli/commands/profileDisconnect.d.ts +3 -0
  6. package/dist/cli/commands/profileDisconnect.js +34 -0
  7. package/dist/cli/commands/serve.js +1 -0
  8. package/dist/cli/commands/shared.js +4 -1
  9. package/dist/cli/envelope.d.ts +1 -0
  10. package/dist/cli/router.js +8 -2
  11. package/dist/library/browserLaunch.d.ts +2 -1
  12. package/dist/library/browserLaunch.js +3 -2
  13. package/dist/routes/referenceProfiles.js +3 -3
  14. package/dist/server.js +2 -1
  15. package/dist/services/IntegrationsClient.d.ts +2 -1
  16. package/dist/services/IntegrationsClient.js +46 -20
  17. package/dist/services/TelemetryService.d.ts +16 -2
  18. package/dist/services/TelemetryService.js +18 -0
  19. package/dist/services/accessTokenRefresh.js +2 -2
  20. package/dist/services/profiles/DesignProfiles.d.ts +16 -0
  21. package/dist/services/profiles/DesignProfiles.js +78 -17
  22. package/dist/services/profiles/ProfileAnalysis.d.ts +3 -0
  23. package/dist/services/profiles/ProfileAnalysis.js +66 -1
  24. package/dist/services/profiles/ProfileImports.d.ts +2 -0
  25. package/dist/services/profiles/ProfileImports.js +2 -0
  26. package/dist/storage/profiles/ProfileRecords.d.ts +17 -0
  27. package/dist/storage/profiles/ProfileRecords.js +45 -7
  28. package/dist/storage/profiles/migrations.d.ts +2 -2
  29. package/dist/storage/profiles/migrations.js +7 -0
  30. package/dist/storage/profiles/schema.d.ts +48 -0
  31. package/dist/storage/profiles/schema.js +3 -0
  32. package/dist/types/api-responses.d.ts +39 -0
  33. package/dist/types/api-responses.js +12 -1
  34. package/dist/types/design-profile.d.ts +12 -0
  35. package/dist/types/design-profile.js +10 -1
  36. package/dist/utils/failureReason.js +1 -1
  37. package/dist/utils/hostedLogPrivacy.js +1 -1
  38. package/dist/utils/launchRuntime.d.ts +2 -0
  39. package/dist/utils/launchRuntime.js +12 -0
  40. package/dist/utils/skills/cli-guidance.d.ts +1 -1
  41. package/dist/utils/skills/cli-guidance.js +2 -1
  42. package/package.json +2 -2
  43. package/src/ui/dist/assets/LibraryEntry-CSU5OJwC.js +2 -0
  44. package/src/ui/dist/assets/main-B89lcZEY.css +1 -0
  45. package/src/ui/dist/assets/main-DeCxjHC1.js +204 -0
  46. package/src/ui/dist/index.html +2 -2
  47. package/src/ui/dist/pages/empty-project.html +1 -1
  48. package/src/ui/dist/pages/rivet-page.html +2 -2
  49. package/src/ui/dist/assets/LibraryEntry-B8-RtQpK.js +0 -2
  50. package/src/ui/dist/assets/main-11-ME6E3.css +0 -1
  51. package/src/ui/dist/assets/main-BGCGsyhl.js +0 -204
@@ -93,6 +93,7 @@ const handleLibraryOpen = async (args, io, options = {}) => {
93
93
  const editorUrl = await (0, browserLaunch_1.createLibraryLaunchUrl)({
94
94
  hub,
95
95
  path: `/rivet/library${projectSuffix}`,
96
+ callerAgent: context.handoff?.agent,
96
97
  });
97
98
  const browser = await (0, browser_1.requestBrowserOpen)({
98
99
  url: editorUrl,
@@ -184,6 +184,7 @@ const buildMcpServer = async (options = {}) => {
184
184
  ...(0, telemetry_1.variantContextMetadataForArgs)(command, rest),
185
185
  ...(0, telemetry_1.verificationMetadataForEnvelope)(result.envelope),
186
186
  ...callerFields,
187
+ error: result.cause,
187
188
  source: 'mcp',
188
189
  });
189
190
  }
@@ -455,7 +456,10 @@ const handleMcpServe = async (rest, io) => {
455
456
  await built.mcp.connect(new StdioServerTransport());
456
457
  }
457
458
  catch (error) {
458
- return (0, envelope_1.errorResult)('mcp', 'OPERATION_FAILED', `Could not start the MCP server: ${(0, errorMessage_1.errorMessage)(error)}`);
459
+ return {
460
+ ...(0, envelope_1.errorResult)('mcp', 'OPERATION_FAILED', `Could not start the MCP server: ${(0, errorMessage_1.errorMessage)(error)}`),
461
+ cause: error,
462
+ };
459
463
  }
460
464
  let isClosing = false;
461
465
  const shutdown = () => {
@@ -40,6 +40,7 @@ exports.ensureProjectRuntime = exports.validateProjectOpen = exports.PROJECT_RUN
40
40
  const projectRuntimeUpgrade_1 = require("../projectRuntimeUpgrade");
41
41
  const child_process_1 = require("child_process");
42
42
  const subprocessEnvironment_1 = require("../../utils/subprocessEnvironment");
43
+ const launchRuntime_1 = require("../../utils/launchRuntime");
43
44
  const fs_1 = __importDefault(require("fs"));
44
45
  const path_1 = __importDefault(require("path"));
45
46
  const envelope_1 = require("../envelope");
@@ -173,7 +174,7 @@ const serveEnvFor = (handoff, baseEnv) => ({
173
174
  }
174
175
  : {}),
175
176
  });
176
- const openedData = async (attached, wasAlreadyRunning) => {
177
+ const openedData = async ({ attached, wasAlreadyRunning, callerAgent, }) => {
177
178
  let session;
178
179
  try {
179
180
  const status = await (0, client_1.requestServer)(attached, '/api/cli/status');
@@ -186,7 +187,7 @@ const openedData = async (attached, wasAlreadyRunning) => {
186
187
  attached: true,
187
188
  alreadyRunning: wasAlreadyRunning,
188
189
  rivetPort: attached.handshake.rivetPort,
189
- editorUrl: (0, client_1.editorUrlFor)(attached),
190
+ editorUrl: (0, launchRuntime_1.withLaunchRuntime)((0, client_1.editorUrlFor)(attached), callerAgent),
190
191
  sessionId: session?.sessionId ?? attached.handshake.sessionId,
191
192
  applyMode: attached.handshake.applyMode,
192
193
  resolvedRunner: session?.resolvedRunner ?? null,
@@ -296,7 +297,11 @@ const ensureProjectRuntime = async (context, io, dependencies = {}) => {
296
297
  if (replacement.outcome === 'attach') {
297
298
  const readinessError = await verifyRuntimeReadiness(existing, appHealthTimeoutMs);
298
299
  if (!readinessError) {
299
- return finishProjectOpen(await openedData(existing, true), io);
300
+ return finishProjectOpen(await openedData({
301
+ attached: existing,
302
+ wasAlreadyRunning: true,
303
+ callerAgent: context.handoff?.agent,
304
+ }), io);
300
305
  }
301
306
  if ((0, telemetry_1.serverUnavailableReasonForEnvelope)(readinessError.envelope) !==
302
307
  'app_health_failed')
@@ -351,7 +356,11 @@ const ensureProjectRuntime = async (context, io, dependencies = {}) => {
351
356
  const readinessError = await verifyRuntimeReadiness(attached, appHealthTimeoutMs);
352
357
  if (readinessError)
353
358
  return readinessError;
354
- const data = await openedData(attached, false);
359
+ const data = await openedData({
360
+ attached,
361
+ wasAlreadyRunning: false,
362
+ callerAgent: context.handoff?.agent,
363
+ });
355
364
  return finishProjectOpen({ ...data, ...(interruptedWork ? { interruptedWork } : {}) }, io);
356
365
  }
357
366
  finally {
@@ -16,11 +16,18 @@ const envelope_1 = require("../envelope");
16
16
  const callerRunnerPaths_1 = require("../callerRunnerPaths");
17
17
  const errorMessage_1 = require("../../utils/errorMessage");
18
18
  const subprocessEnvironment_1 = require("../../utils/subprocessEnvironment");
19
+ const profileDisconnect_1 = require("./profileDisconnect");
19
20
  const PROFILE_REQUEST_TIMEOUT_MS = 55_000;
20
21
  const PROFILE_SEARCH_TIMEOUT_MS = 120_000;
21
22
  const handleProfile = async (args) => {
22
23
  const action = args[0] ?? 'status';
23
24
  const command = `profile.${action}`;
25
+ if (action === 'disconnect') {
26
+ const context = (0, shared_1.parseCommandContext)(command, args.slice(1));
27
+ return (0, shared_1.isCommandResult)(context)
28
+ ? context
29
+ : (0, profileDisconnect_1.handleProfileDisconnect)(context.flags.positionals);
30
+ }
24
31
  const context = (0, shared_1.parseCommandContext)(command, args.slice(1), {
25
32
  runtime: { takesValue: true },
26
33
  detail: { takesValue: false },
@@ -266,7 +273,7 @@ const handleProfile = async (args) => {
266
273
  };
267
274
  break;
268
275
  default:
269
- return (0, envelope_1.errorResult)(command, 'USAGE_ERROR', 'Usage: rivet profile <status|diagnostics|discover|plan|import|onboarding|rebuild-index|enable|disable|connect|refresh|pause|resume|retry|add-text|add-images|pins|add-variant|inspect|references|reference|search|include|exclude|remove|suggest>');
276
+ return (0, envelope_1.errorResult)(command, 'USAGE_ERROR', 'Usage: rivet profile <status|diagnostics|discover|plan|import|onboarding|rebuild-index|enable|disable|connect|disconnect|refresh|pause|resume|retry|add-text|add-images|pins|add-variant|inspect|references|reference|search|include|exclude|remove|suggest>');
270
277
  }
271
278
  const hub = await (0, HubClient_1.ensureHub)({
272
279
  root: (0, ProjectLibrary_1.currentLibraryRoot)(),
@@ -0,0 +1,3 @@
1
+ import { type CliCommandResult } from '../envelope';
2
+ export declare const handleProfileDisconnect: (positionals: string[]) => Promise<CliCommandResult>;
3
+ //# sourceMappingURL=profileDisconnect.d.ts.map
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleProfileDisconnect = void 0;
4
+ const zod_1 = require("zod");
5
+ const ConfigManager_1 = require("../../services/ConfigManager");
6
+ const IntegrationsClient_1 = require("../../services/IntegrationsClient");
7
+ const reference_connectors_1 = require("../../types/reference-connectors");
8
+ const envelope_1 = require("../envelope");
9
+ const COMMAND = 'profile.disconnect';
10
+ const handleProfileDisconnect = async (positionals) => {
11
+ const selected = zod_1.z
12
+ .tuple([reference_connectors_1.AuthenticatedReferenceProviderSchema])
13
+ .safeParse(positionals);
14
+ if (!selected.success)
15
+ return (0, envelope_1.errorResult)(COMMAND, 'USAGE_ERROR', 'Usage: rivet profile disconnect <pinterest|arena|x>');
16
+ try {
17
+ const config = (0, ConfigManager_1.getConfigManager)();
18
+ const accountId = config.getUserId();
19
+ if (!accountId || !config.isAuthenticated())
20
+ return (0, envelope_1.errorResult)(COMMAND, 'AUTH_REQUIRED', 'Sign in to Rivet before disconnecting a reference account.');
21
+ const provider = selected.data[0];
22
+ const result = await new IntegrationsClient_1.IntegrationsClient().disconnect(provider, accountId);
23
+ if (result.status === 'ok')
24
+ return (0, envelope_1.okResult)(COMMAND, { provider, isDisconnected: true });
25
+ if (config.getUserId() !== accountId)
26
+ return (0, envelope_1.errorResult)(COMMAND, 'OPERATION_FAILED', 'Rivet account changed. Retry with the intended account.', { reason: 'account_changed' });
27
+ return (0, envelope_1.errorResult)(COMMAND, result.reason === 'auth_required' ? 'AUTH_REQUIRED' : 'OPERATION_FAILED', result.message, { reason: result.reason });
28
+ }
29
+ catch {
30
+ return (0, envelope_1.errorResult)(COMMAND, 'OPERATION_FAILED', 'Could not confirm reference account disconnection. Check your Rivet sign-in and connection, then retry.');
31
+ }
32
+ };
33
+ exports.handleProfileDisconnect = handleProfileDisconnect;
34
+ //# sourceMappingURL=profileDisconnect.js.map
@@ -213,6 +213,7 @@ const handleServe = async (args, io) => {
213
213
  return null;
214
214
  return (0, browserLaunch_1.createLibraryLaunchUrl)({
215
215
  hub,
216
+ callerAgent: handoff?.agent,
216
217
  path: view === 'references'
217
218
  ? '/rivet/library/references'
218
219
  : '/rivet/library',
@@ -17,7 +17,10 @@ const pluginContext_1 = require("../../hosts/pluginContext");
17
17
  const commandErrorResult = (command, error) => error instanceof pluginContext_1.PluginContextMismatchError ||
18
18
  error instanceof telemetryPolicy_1.TelemetryPolicyMismatchError
19
19
  ? (0, envelope_1.errorResult)(command, 'SERVER_UNAVAILABLE', error.message, { serverUnavailableReason: error.reason }, { isRecoverable: false })
20
- : (0, envelope_1.errorResult)(command, 'OPERATION_FAILED', (0, errorMessage_1.errorMessage)(error));
20
+ : {
21
+ ...(0, envelope_1.errorResult)(command, 'OPERATION_FAILED', (0, errorMessage_1.errorMessage)(error)),
22
+ cause: error,
23
+ };
21
24
  exports.commandErrorResult = commandErrorResult;
22
25
  exports.SHARED_FLAG_SPEC = {
23
26
  project: { takesValue: true },
@@ -55,6 +55,7 @@ export type CliEnvelope<TData = unknown> = CliOkEnvelope<TData> | CliErrorEnvelo
55
55
  export type CliCommandResult = {
56
56
  envelope: CliEnvelope;
57
57
  exitCode: CliExitCode;
58
+ cause?: unknown;
58
59
  };
59
60
  export declare const okResult: (command: string, data: unknown) => CliCommandResult;
60
61
  export declare const loginRecovery: (authUrl?: string) => CliErrorRecovery;
@@ -52,8 +52,9 @@ const COMMAND_USAGE = {
52
52
  'resolve [--guidance auto|off] [--exclude-guidance <JSON IDs>] returns current effective text and native paths without a model call. inspect <workId> --project <path> reads retained generation context. Guidance above 32 KiB emits an advisory warning, not a truncation or rejection. The HTTP request limit remains 50 MiB.',
53
53
  ],
54
54
  profile: [
55
- 'rivet profile <status|diagnostics|discover|plan|import|onboarding|rebuild-index|enable|disable|connect|refresh|pause|resume|retry|add-text|add-images|pins|add-variant|inspect|references|reference|search|include|exclude|remove|suggest> [options]',
55
+ 'rivet profile <status|diagnostics|discover|plan|import|onboarding|rebuild-index|enable|disable|connect|disconnect|refresh|pause|resume|retry|add-text|add-images|pins|add-variant|inspect|references|reference|search|include|exclude|remove|suggest> [options]',
56
56
  'Search saved references by design intent with rivet profile search "<query>" [--source <sourceId>] [--limit N]. Results include stable keys for exact profile reference lookup and whether each source is included in automatic generation.',
57
+ 'Disconnect a linked account with rivet profile disconnect <pinterest|arena|x>. This removes the signed-in Rivet account’s provider connection and keeps saved references. Exactly one provider is required. It needs no running editor or worker runtime. Provider authorization revocation varies by provider.',
57
58
  'Resolve copied references in one batch with rivet profile reference <profileId> <shortId@revision>... . Default output is compact metadata. Add --detail only when full text, analysis, sources, and validated image paths are needed. No model work.',
58
59
  'Manage saved design references, including Pinterest, Are.na, public Cosmos collections, and X bookmarks (https://x.com/i/bookmarks). A disconnected X account returns an authorization URL; sign in and repeat connect. Connect reference accounts with discover pinterest|arena|x, or discover <public Cosmos profile URL>. Complete OAuth if requested and repeat discovery. Use plan <discoveryId> --collections <JSON>, then import <planId> --revision <revision> --approve after user consent. Onboarding preferences accept --provider cosmos|pinterest|arena|x. Read a saved preview with plan <planId>. Model work uses the selected agent runtime.',
59
60
  ],
@@ -264,6 +265,10 @@ const dispatch = async (command, rest, io, options = {}) => {
264
265
  return (0, envelope_1.errorResult)(command, 'USAGE_ERROR', `Unknown command: ${command}`);
265
266
  };
266
267
  exports.dispatch = dispatch;
268
+ const stdoutReservedForProtocolIO = (io) => ({
269
+ ...io,
270
+ writeEnvelope: (envelope) => io.writeProgress((0, envelope_1.serializeEnvelope)(envelope)),
271
+ });
267
272
  const runCliControlCommand = async (args, io = io_1.processCliIO) => {
268
273
  const { redirectLogsToStderr } = await Promise.resolve().then(() => __importStar(require('../utils/logger')));
269
274
  redirectLogsToStderr();
@@ -290,7 +295,7 @@ const runCliControlCommand = async (args, io = io_1.processCliIO) => {
290
295
  catch (error) {
291
296
  result = (0, shared_1.commandErrorResult)(command, error);
292
297
  }
293
- const exitCode = (0, io_1.emitResult)(io, result);
298
+ const exitCode = (0, io_1.emitResult)(command === 'mcp' ? stdoutReservedForProtocolIO(io) : io, result);
294
299
  if (!rest.includes('--no-telemetry') &&
295
300
  !(command === '__hub' && process.env.RIVET_LIBRARY_TELEMETRY === '0')) {
296
301
  try {
@@ -311,6 +316,7 @@ const runCliControlCommand = async (args, io = io_1.processCliIO) => {
311
316
  ...(0, telemetry_1.browserMetadataForEnvelope)(result.envelope),
312
317
  ...(0, telemetry_1.verificationMetadataForEnvelope)(result.envelope),
313
318
  ...(0, handoff_1.callerTelemetryFieldsFromArgs)(rest),
319
+ error: result.cause,
314
320
  });
315
321
  telemetry.reportInstallRefActivations();
316
322
  await telemetry.shutdown(result.envelope.command === 'variants.get'
@@ -1,6 +1,7 @@
1
1
  import { type ConnectedHub } from './HubClient';
2
- export declare const createLibraryLaunchUrl: ({ hub, path, }: {
2
+ export declare const createLibraryLaunchUrl: ({ hub, path, callerAgent, }: {
3
3
  hub: ConnectedHub;
4
4
  path: string;
5
+ callerAgent?: string;
5
6
  }) => Promise<string>;
6
7
  //# sourceMappingURL=browserLaunch.d.ts.map
@@ -2,7 +2,8 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createLibraryLaunchUrl = void 0;
4
4
  const HubClient_1 = require("./HubClient");
5
- const createLibraryLaunchUrl = async ({ hub, path, }) => {
5
+ const launchRuntime_1 = require("../utils/launchRuntime");
6
+ const createLibraryLaunchUrl = async ({ hub, path, callerAgent, }) => {
6
7
  const { code } = await (0, HubClient_1.requestHub)({
7
8
  hub,
8
9
  endpoint: '/launch-codes',
@@ -11,7 +12,7 @@ const createLibraryLaunchUrl = async ({ hub, path, }) => {
11
12
  const url = new URL(path, hub.url);
12
13
  url.hostname = 'localhost';
13
14
  url.hash = new URLSearchParams({ code }).toString();
14
- return url.toString();
15
+ return (0, launchRuntime_1.withLaunchRuntime)(url.toString(), callerAgent);
15
16
  };
16
17
  exports.createLibraryLaunchUrl = createLibraryLaunchUrl;
17
18
  //# sourceMappingURL=browserLaunch.js.map
@@ -6,7 +6,7 @@ const zod_1 = require("zod");
6
6
  const HubClient_1 = require("../library/HubClient");
7
7
  const ProjectLibrary_1 = require("../services/ProjectLibrary");
8
8
  const ConfigManager_1 = require("../services/ConfigManager");
9
- const cosmos_1 = require("../types/cosmos");
9
+ const reference_connectors_1 = require("../types/reference-connectors");
10
10
  const reference_onboarding_1 = require("../types/reference-onboarding");
11
11
  const design_profile_1 = require("../types/design-profile");
12
12
  const errorMessage_1 = require("../utils/errorMessage");
@@ -28,11 +28,11 @@ const createReferenceProfilesRouter = () => {
28
28
  }));
29
29
  });
30
30
  router.post('/reference-profiles/discoveries', async (req, res) => {
31
- const url = cosmos_1.CosmosProfileUrlSchema.parse(req.body?.url);
31
+ const input = reference_connectors_1.ReferenceDiscoveryRequestSchema.parse(req.body);
32
32
  res.status(201).json(await (0, HubClient_1.requestHub)({
33
33
  hub: await connectedHub(),
34
34
  endpoint: '/profile/discoveries',
35
- body: { url },
35
+ body: input,
36
36
  }));
37
37
  });
38
38
  router.post('/reference-profiles/import-plans', async (req, res) => {
package/dist/server.js CHANGED
@@ -487,13 +487,14 @@ const startServer = async (options) => {
487
487
  app.get('/api/config', async (_req, res) => {
488
488
  const configManager = (0, ConfigManager_1.getConfigManager)();
489
489
  const livePath = sessionBridge?.getProjectPath() ?? projectPath;
490
+ const initiator = sessionBridge?.getSessionRuntimeInfo().sessionInitiator;
490
491
  res.json({
491
492
  agentModeAvailable: configManager.isAuthenticated(),
492
493
  email: configManager.getEmail(),
493
494
  userId: configManager.getUserId(),
494
495
  name: configManager.getDisplayName(),
495
496
  isMCPSession: sessionBridge?.isActive() ?? false,
496
- mcpEditor: mcpEditor ?? null,
497
+ mcpEditor: mcpEditor ?? (initiator?.kind === 'agent' ? initiator.agent : null),
497
498
  agentApplyMode: sessionBridge?.isActive()
498
499
  ? (agentApplyMode ?? 'external')
499
500
  : null,
@@ -114,6 +114,7 @@ export type IntegrationDisconnectResult = {
114
114
  status: 'ok';
115
115
  } | {
116
116
  status: 'error';
117
+ reason: 'auth_required' | 'account_changed' | 'request_failed';
117
118
  message: string;
118
119
  };
119
120
  export type IntegrationProvider = 'pinterest' | 'arena' | 'x';
@@ -213,6 +214,6 @@ export declare class IntegrationsClient {
213
214
  }): Promise<XBookmarksResult>;
214
215
  listIntegrations(): Promise<IntegrationListResult>;
215
216
  connect(provider: IntegrationProvider): Promise<IntegrationConnectResult>;
216
- disconnect(provider: IntegrationProvider): Promise<IntegrationDisconnectResult>;
217
+ disconnect(provider: IntegrationProvider, expectedAccountId?: string): Promise<IntegrationDisconnectResult>;
217
218
  }
218
219
  //# sourceMappingURL=IntegrationsClient.d.ts.map
@@ -17,6 +17,7 @@ const RequestAuthContext_1 = require("./RequestAuthContext");
17
17
  const errorMessage_1 = require("../utils/errorMessage");
18
18
  const log = (0, logger_1.createLogger)('IntegrationsClient');
19
19
  const REQUEST_TIMEOUT_MS = 30_000;
20
+ const ACCOUNT_CHANGED_MESSAGE = 'Rivet account changed. Retry with the intended account.';
20
21
  const NormalizedPinSchema = zod_1.z.object({
21
22
  id: zod_1.z.string(),
22
23
  image_urls: zod_1.z.array(zod_1.z.string()),
@@ -132,6 +133,8 @@ const IntegrationConnectBodySchema = zod_1.z.object({
132
133
  message: zod_1.z.string().optional(),
133
134
  error: zod_1.z.string().optional(),
134
135
  });
136
+ const IntegrationDisconnectBodySchema = zod_1.z.object({ success: zod_1.z.literal(true) });
137
+ const XDisconnectBodySchema = zod_1.z.object({ status: zod_1.z.literal('ok') });
135
138
  const INTEGRATION_PROVIDERS = [
136
139
  'pinterest',
137
140
  'arena',
@@ -160,7 +163,7 @@ class IntegrationsClient {
160
163
  }
161
164
  return token;
162
165
  }
163
- async requestWithBearer(request) {
166
+ async requestWithBearer(request, expectedAccountId) {
164
167
  const token = await this.getBearerToken();
165
168
  if (!token) {
166
169
  return null;
@@ -182,6 +185,9 @@ class IntegrationsClient {
182
185
  if (!refreshed) {
183
186
  return response;
184
187
  }
188
+ if (expectedAccountId !== undefined &&
189
+ this.configManager.getUserId() !== expectedAccountId)
190
+ throw new Error(ACCOUNT_CHANGED_MESSAGE);
185
191
  updateAuth(refreshed);
186
192
  return request(refreshed.token);
187
193
  }
@@ -492,31 +498,51 @@ class IntegrationsClient {
492
498
  };
493
499
  }
494
500
  }
495
- async disconnect(provider) {
496
- const del = async (bearer) => fetch(`${this.proxyUrl}/api/integrations/${provider}`, {
497
- method: 'DELETE',
498
- headers: { Authorization: `Bearer ${bearer}` },
499
- });
501
+ async disconnect(provider, expectedAccountId) {
502
+ const isAccountCurrent = () => expectedAccountId === undefined ||
503
+ this.configManager.getUserId() === expectedAccountId;
504
+ const accountChanged = {
505
+ status: 'error',
506
+ reason: 'account_changed',
507
+ message: ACCOUNT_CHANGED_MESSAGE,
508
+ };
509
+ const requestFailed = {
510
+ status: 'error',
511
+ reason: 'request_failed',
512
+ message: 'Could not confirm reference account disconnection. Check your Rivet sign-in and connection, then retry.',
513
+ };
514
+ const del = async (bearer) => {
515
+ if (!isAccountCurrent())
516
+ throw new Error(accountChanged.message);
517
+ return fetch(`${this.proxyUrl}/api/integrations/${provider}`, {
518
+ method: 'DELETE',
519
+ headers: { Authorization: `Bearer ${bearer}` },
520
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
521
+ });
522
+ };
500
523
  try {
501
- const response = await this.requestWithBearer(del);
502
- if (!response) {
503
- return { status: 'error', message: 'Not authenticated' };
504
- }
505
- if (!response.ok) {
506
- const text = await response.text().catch(() => '');
524
+ if (!isAccountCurrent())
525
+ return accountChanged;
526
+ const response = await this.requestWithBearer(del, expectedAccountId);
527
+ if (!response || response.status === 401)
507
528
  return {
508
529
  status: 'error',
509
- message: `Disconnect failed (${response.status}): ${text.slice(0, 200)}`,
530
+ reason: 'auth_required',
531
+ message: 'Sign in to Rivet before disconnecting a reference account.',
510
532
  };
511
- }
533
+ if (!response.ok)
534
+ return requestFailed;
535
+ const acknowledgement = await response.json();
536
+ const schema = provider === 'x'
537
+ ? XDisconnectBodySchema
538
+ : IntegrationDisconnectBodySchema;
539
+ if (!schema.safeParse(acknowledgement).success)
540
+ return requestFailed;
512
541
  return { status: 'ok' };
513
542
  }
514
- catch (error) {
515
- log.warn('Integration disconnect error:', error);
516
- return {
517
- status: 'error',
518
- message: (0, errorMessage_1.errorMessage)(error, 'Unknown error'),
519
- };
543
+ catch {
544
+ log.warn('Integration disconnect request failed');
545
+ return isAccountCurrent() ? requestFailed : accountChanged;
520
546
  }
521
547
  }
522
548
  }
@@ -1,6 +1,7 @@
1
1
  import { type AccountIdentity } from './ConfigManager';
2
2
  import type { BrowserMetadata, DesignContextKind, ServerUnavailableReason, VariantContextMetadata, VerificationMetadata } from '../cli/telemetry';
3
3
  import type { GuidanceErrorCode, GuidanceSelection } from '../types/guidance';
4
+ import { type ProfileImportKind, type ProfileImportStep, type ProfileMedia, type ProfilePreparationOffReason, type ProfileProvider } from '../types/design-profile';
4
5
  import type { MCPAuthMethod, MCPAuthState, MCPOnboardingCorrelation, MCPOAuthCallbackResult } from './MCPOnboardingTelemetry';
5
6
  import { type MCPVariantsTelemetryMetadata } from './MCPVariantsTelemetry';
6
7
  export type RequestRejectionReason = 'host_not_allowed' | 'origin_not_allowed' | 'editor_token_on_preview';
@@ -21,13 +22,25 @@ export interface LibraryOperation {
21
22
  error?: unknown;
22
23
  }
23
24
  export interface ProfileOperation {
24
- stage: 'action' | 'import' | 'preparation' | 'maintenance';
25
- operation: 'reference_discovery' | 'reference_lookup' | 'reference_search' | 'reference_plan' | 'reference_approval' | 'reference_onboarding' | 'reference_onboarding_offered' | 'enable' | 'disable' | 'text_import' | 'image_import' | 'variant_import' | 'source_connect' | 'source_refresh' | 'job_control' | 'source_control' | 'index_rebuild' | 'import' | 'preparation';
25
+ stage: 'action' | 'import' | 'preparation' | 'maintenance' | 'analysis';
26
+ operation: 'reference_discovery' | 'reference_lookup' | 'reference_search' | 'reference_plan' | 'reference_approval' | 'reference_onboarding' | 'reference_onboarding_offered' | 'enable' | 'disable' | 'text_import' | 'image_import' | 'variant_import' | 'source_connect' | 'source_refresh' | 'job_control' | 'source_control' | 'index_rebuild' | 'import' | 'preparation' | 'analysis';
26
27
  outcome: 'completed' | 'failed' | 'deferred';
27
28
  durationMs: number;
28
29
  referenceCount?: number;
29
30
  status?: 'selected' | 'empty' | 'off' | 'unavailable' | 'timeout';
30
31
  error?: unknown;
32
+ provider?: ProfileProvider;
33
+ importKind?: ProfileImportKind;
34
+ failedStep?: ProfileImportStep;
35
+ addedCount?: number;
36
+ removedCount?: number;
37
+ staleHours?: number;
38
+ mediaKind?: ProfileMedia['representation'] | 'text' | 'mixed';
39
+ candidateCount?: number;
40
+ providerMix?: ProfileProvider[];
41
+ offReason?: ProfilePreparationOffReason;
42
+ providerCount?: number;
43
+ sourceCount?: number;
31
44
  }
32
45
  export interface GuidanceOperation {
33
46
  operation: 'add' | 'update' | 'remove' | 'resolve' | 'delivery' | 'verifier';
@@ -78,6 +91,7 @@ export declare class TelemetryService {
78
91
  callerRunId?: string;
79
92
  designContextKind?: DesignContextKind;
80
93
  source?: 'cli' | 'mcp';
94
+ error?: unknown;
81
95
  } & VariantContextMetadata & BrowserMetadata & VerificationMetadata): void;
82
96
  trackAuthStarted(data: {
83
97
  surface: AuthTelemetrySurface;
@@ -13,6 +13,7 @@ const telemetryContract_1 = require("../config/telemetryContract");
13
13
  const failureReason_1 = require("../utils/failureReason");
14
14
  const posthog_1 = require("../config/posthog");
15
15
  const proxy_1 = require("../config/proxy");
16
+ const design_profile_1 = require("../types/design-profile");
16
17
  const MCPVariantsTelemetry_1 = require("./MCPVariantsTelemetry");
17
18
  const errorMessage_1 = require("../utils/errorMessage");
18
19
  const serverUnavailable_1 = require("../cli/serverUnavailable");
@@ -43,6 +44,7 @@ const mcpEditorEventValue = (editor) => {
43
44
  return 'other';
44
45
  };
45
46
  const HASH_PREFIX_LENGTH = 12;
47
+ const optionalProperty = (key, value) => value === undefined ? {} : { [key]: value };
46
48
  class TelemetryService {
47
49
  trackGuidanceOperation(data) {
48
50
  this.track(`mcp_guidance_${data.operation}_${data.outcome}`, {
@@ -62,7 +64,20 @@ class TelemetryService {
62
64
  ...(data.referenceCount !== undefined
63
65
  ? { reference_count: data.referenceCount }
64
66
  : {}),
67
+ ...optionalProperty('candidate_count', data.candidateCount),
65
68
  ...(data.status ? { status: data.status } : {}),
69
+ ...optionalProperty('off_reason', data.offReason),
70
+ ...optionalProperty('provider_mix', data.providerMix),
71
+ ...optionalProperty('provider', data.provider),
72
+ ...optionalProperty('media_kind', data.mediaKind),
73
+ ...optionalProperty('job_kind', data.importKind),
74
+ ...optionalProperty('trigger', data.importKind && design_profile_1.PROFILE_IMPORT_TRIGGERS[data.importKind]),
75
+ ...optionalProperty('failed_step', data.failedStep),
76
+ ...optionalProperty('added_count', data.addedCount),
77
+ ...optionalProperty('removed_count', data.removedCount),
78
+ ...optionalProperty('stale_hours', data.staleHours),
79
+ ...optionalProperty('provider_count', data.providerCount),
80
+ ...optionalProperty('source_count', data.sourceCount),
66
81
  ...(0, failureReason_1.failureReasonCodeProperties)(data.error),
67
82
  });
68
83
  }
@@ -306,6 +321,9 @@ class TelemetryService {
306
321
  error_code: data.errorCode,
307
322
  is_recoverable: data.isRecoverable,
308
323
  server_unavailable_reason: data.serverUnavailableReason,
324
+ ...(data.command === 'mcp'
325
+ ? (0, failureReason_1.failureReasonProperties)(data.error)
326
+ : (0, failureReason_1.failureReasonCodeProperties)(data.error)),
309
327
  duration_ms: data.durationMs,
310
328
  caller_agent: data.callerAgent,
311
329
  caller_model: data.callerModel,
@@ -79,8 +79,8 @@ const refreshAccessTokenViaProxy = async (params) => {
79
79
  }
80
80
  return null;
81
81
  }
82
- catch (error) {
83
- log.warn('Proxy token refresh request failed', { error });
82
+ catch {
83
+ log.warn('Proxy token refresh request failed');
84
84
  return null;
85
85
  }
86
86
  };
@@ -74,6 +74,7 @@ export declare class DesignProfiles {
74
74
  revision: number;
75
75
  stage: "download" | "analysis";
76
76
  error: string;
77
+ reasonCode: "timeout" | "unknown" | "aborted" | "multiple_lockfiles" | "unsupported_package_manager" | "invalid_package_manager_field" | "invalid_manifest" | "invalid_workspace" | "path_outside_workspace" | "dangling_symlink" | "version_unreadable" | "version_mismatch" | "no_install_command" | "install_failed" | "lockfile_outdated" | "engine_incompatible" | "install_script_failed" | "installer_unstoppable" | "inputs_changed" | "ENOENT" | "EACCES" | "EPERM" | "EEXIST" | "ENOTDIR" | "EISDIR" | "ELOOP" | "ENOSPC" | "EMFILE" | "EADDRINUSE" | "ECONNREFUSED" | "ECONNRESET" | "ETIMEDOUT" | "EBUSY" | "ENOTSUP" | "EINVAL" | "ENOTEMPTY" | "EROFS" | "EAI_AGAIN" | null;
77
78
  attempts: number;
78
79
  updatedAt: string;
79
80
  }[];
@@ -88,6 +89,8 @@ export declare class DesignProfiles {
88
89
  total: number | null;
89
90
  error: string | null;
90
91
  updatedAt: string;
92
+ addedCount: number;
93
+ removedCount: number;
91
94
  }[];
92
95
  id: string;
93
96
  revision: string;
@@ -687,6 +690,8 @@ export declare class DesignProfiles {
687
690
  total: number | null;
688
691
  error: string | null;
689
692
  updatedAt: string;
693
+ addedCount: number;
694
+ removedCount: number;
690
695
  }[];
691
696
  rebuild: {
692
697
  singleton: number;
@@ -720,6 +725,7 @@ export declare class DesignProfiles {
720
725
  revision: number;
721
726
  stage: "download" | "analysis";
722
727
  error: string;
728
+ reasonCode: "timeout" | "unknown" | "aborted" | "multiple_lockfiles" | "unsupported_package_manager" | "invalid_package_manager_field" | "invalid_manifest" | "invalid_workspace" | "path_outside_workspace" | "dangling_symlink" | "version_unreadable" | "version_mismatch" | "no_install_command" | "install_failed" | "lockfile_outdated" | "engine_incompatible" | "install_script_failed" | "installer_unstoppable" | "inputs_changed" | "ENOENT" | "EACCES" | "EPERM" | "EEXIST" | "ENOTDIR" | "EISDIR" | "ELOOP" | "ENOSPC" | "EMFILE" | "EADDRINUSE" | "ECONNREFUSED" | "ECONNRESET" | "ETIMEDOUT" | "EBUSY" | "ENOTSUP" | "EINVAL" | "ENOTEMPTY" | "EROFS" | "EAI_AGAIN" | null;
723
729
  attempts: number;
724
730
  updatedAt: string;
725
731
  }[];
@@ -768,6 +774,8 @@ export declare class DesignProfiles {
768
774
  total: number | null;
769
775
  error: string | null;
770
776
  updatedAt: string;
777
+ addedCount: number;
778
+ removedCount: number;
771
779
  }[];
772
780
  rebuild: {
773
781
  singleton: number;
@@ -828,6 +836,8 @@ export declare class DesignProfiles {
828
836
  total: number | null;
829
837
  error: string | null;
830
838
  updatedAt: string;
839
+ addedCount: number;
840
+ removedCount: number;
831
841
  }[];
832
842
  rebuild: {
833
843
  singleton: number;
@@ -965,6 +975,8 @@ export declare class DesignProfiles {
965
975
  total: number | null;
966
976
  error: string | null;
967
977
  updatedAt: string;
978
+ addedCount: number;
979
+ removedCount: number;
968
980
  };
969
981
  } | {
970
982
  status: "authorization_required";
@@ -1003,6 +1015,8 @@ export declare class DesignProfiles {
1003
1015
  total: number | null;
1004
1016
  error: string | null;
1005
1017
  updatedAt: string;
1018
+ addedCount: number;
1019
+ removedCount: number;
1006
1020
  }[];
1007
1021
  rebuild: {
1008
1022
  singleton: number;
@@ -1049,6 +1063,8 @@ export declare class DesignProfiles {
1049
1063
  total: number | null;
1050
1064
  error: string | null;
1051
1065
  updatedAt: string;
1066
+ addedCount: number;
1067
+ removedCount: number;
1052
1068
  };
1053
1069
  }>;
1054
1070
  updateSource({ id, isIncluded, isRemoved, runtime, }: {