rivet-design 0.27.0 → 0.28.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/dist/agent-variants/DirectionRefReservations.d.ts +11 -0
- package/dist/agent-variants/DirectionRefReservations.js +47 -0
- package/dist/agent-variants/PreviewRuntime.d.ts +4 -0
- package/dist/agent-variants/PreviewRuntime.js +5 -3
- package/dist/agent-variants/SessionStore.d.ts +10 -1
- package/dist/agent-variants/SessionStore.js +25 -2
- package/dist/agent-variants/WorkItemRequestTimes.d.ts +6 -0
- package/dist/agent-variants/WorkItemRequestTimes.js +21 -0
- package/dist/agent-variants/WorktreeOrchestrator.d.ts +2 -1
- package/dist/agent-variants/WorktreeOrchestrator.js +92 -78
- package/dist/agent-variants/contracts.d.ts +8 -0
- package/dist/agent-variants/existingStaticEntry.d.ts +34 -0
- package/dist/agent-variants/existingStaticEntry.js +136 -0
- package/dist/agent-variants/staticPreviewFiles.js +1 -1
- package/dist/agent-variants/variant-project-runtime.d.ts +2 -1
- package/dist/agent-variants/variantsTelemetry.d.ts +4 -0
- package/dist/agent-variants/variantsTelemetry.js +2 -0
- package/dist/agent-variants/workItemInput.d.ts +22 -0
- package/dist/agent-variants/workItemInput.js +12 -1
- package/dist/cli/commands/directionTarget.d.ts +23 -0
- package/dist/cli/commands/directionTarget.js +87 -0
- package/dist/cli/commands/open.js +28 -4
- package/dist/cli/commands/variants.js +36 -43
- package/dist/cli/envelope.d.ts +1 -1
- package/dist/cli/envelope.js +1 -0
- package/dist/cli/projectRuntimeUpgrade.d.ts +11 -0
- package/dist/cli/projectRuntimeUpgrade.js +43 -11
- package/dist/config/pluginMetrics.js +2 -0
- package/dist/config/posthog.d.ts +2 -0
- package/dist/config/posthog.js +5 -0
- package/dist/mcp/explorationSchema.js +1 -1
- package/dist/mcp/getExploration.js +11 -5
- package/dist/proxy-middleware/proxy-config.js +7 -0
- package/dist/routes/agentVariants.js +4 -0
- package/dist/routes/cli.js +10 -1
- package/dist/server.js +12 -6
- package/dist/services/DependencyPreparationService.js +44 -6
- package/dist/services/FeatureFlagService.js +2 -2
- package/dist/services/ProjectLibrary.d.ts +4 -1
- package/dist/services/ProjectLibrary.js +14 -9
- package/dist/services/ProjectRuntimeService.d.ts +8 -0
- package/dist/services/ProjectRuntimeService.js +15 -2
- package/dist/services/TelemetryService.d.ts +5 -0
- package/dist/services/TelemetryService.js +21 -2
- package/dist/services/VariantHistoryService.d.ts +8 -0
- package/dist/services/VariantHistoryService.js +40 -0
- package/dist/services/WorktreeManager.d.ts +1 -0
- package/dist/services/WorktreeManager.js +12 -0
- package/dist/services/createAgentVariantsOrchestrator.js +9 -2
- package/dist/services/directionRefs.d.ts +21 -0
- package/dist/services/directionRefs.js +148 -0
- package/dist/services/projectDirections.d.ts +22 -0
- package/dist/services/projectDirections.js +38 -0
- package/dist/types/direction-ref.d.ts +36 -0
- package/dist/types/direction-ref.js +3 -0
- package/dist/types/variant-history.d.ts +3 -1
- package/dist/utils/failureReason.d.ts +1 -1
- package/dist/utils/failureReason.js +3 -0
- package/dist/utils/skills/cli-guidance.js +4 -3
- package/dist/utils/subprocessEnvironment.d.ts +1 -1
- package/dist/utils/subprocessEnvironment.js +0 -1
- package/package.json +4 -4
- package/src/ui/dist/assets/LibraryEntry-BE8nZneH.js +37 -0
- package/src/ui/dist/assets/logo.png +0 -0
- package/src/ui/dist/assets/main-1EDrDqgn.js +498 -0
- package/src/ui/dist/assets/main-qgqnlUkI.css +1 -0
- package/src/ui/dist/assets/rivet-wordmark-orange-CYKVQDmG.svg +7 -0
- package/src/ui/dist/index.html +2 -2
- package/dist/services/StaticPreviewServer.d.ts +0 -8
- package/dist/services/StaticPreviewServer.js +0 -207
- package/src/ui/dist/assets/LibraryEntry-RI9Lc7P3.js +0 -37
- package/src/ui/dist/assets/main-D0UmAaUe.css +0 -1
- package/src/ui/dist/assets/main-DgrLzS5j.js +0 -497
- package/src/ui/dist/assets/rivet.svg +0 -3
- package/src/ui/dist/fonts/Goldman-Bold.woff2 +0 -0
- package/src/ui/dist/fonts/Goldman-Regular.woff2 +0 -0
|
@@ -543,6 +543,7 @@ const createAgentVariantsRouter = (orchestrator, bridge, telemetry, variantHisto
|
|
|
543
543
|
filesDir,
|
|
544
544
|
entryPath: preview.entryPath,
|
|
545
545
|
label: detail.manifest.label,
|
|
546
|
+
directionRef: detail.manifest.directionRef,
|
|
546
547
|
description: detail.manifest.brief,
|
|
547
548
|
references: detail.manifest.references,
|
|
548
549
|
previewRoutes: detail.manifest.previewRoutes,
|
|
@@ -1058,6 +1059,7 @@ const createAgentVariantsRouter = (orchestrator, bridge, telemetry, variantHisto
|
|
|
1058
1059
|
sessionId: entry.manifest.sessionId,
|
|
1059
1060
|
variantId: entry.manifest.variantId,
|
|
1060
1061
|
requestId: entry.manifest.requestId,
|
|
1062
|
+
directionRef: entry.manifest.directionRef,
|
|
1061
1063
|
label: entry.manifest.label,
|
|
1062
1064
|
brief: entry.manifest.brief,
|
|
1063
1065
|
references: entry.manifest.references,
|
|
@@ -1507,6 +1509,7 @@ const createAgentVariantsRouter = (orchestrator, bridge, telemetry, variantHisto
|
|
|
1507
1509
|
filesDir,
|
|
1508
1510
|
entryPath: preview.entryPath,
|
|
1509
1511
|
label: detail.manifest.label,
|
|
1512
|
+
directionRef: detail.manifest.directionRef,
|
|
1510
1513
|
description: detail.manifest.brief,
|
|
1511
1514
|
references: detail.manifest.references,
|
|
1512
1515
|
previewRoutes: detail.manifest.previewRoutes,
|
|
@@ -1580,6 +1583,7 @@ const createAgentVariantsRouter = (orchestrator, bridge, telemetry, variantHisto
|
|
|
1580
1583
|
filesDir,
|
|
1581
1584
|
entryPath: preview.entryPath,
|
|
1582
1585
|
label: detail.manifest.label,
|
|
1586
|
+
directionRef: detail.manifest.directionRef,
|
|
1583
1587
|
description: detail.manifest.brief,
|
|
1584
1588
|
references: detail.manifest.references,
|
|
1585
1589
|
previewRoutes: detail.manifest.previewRoutes,
|
package/dist/routes/cli.js
CHANGED
|
@@ -102,8 +102,17 @@ const createCliRouter = (options) => {
|
|
|
102
102
|
setImmediate(() => options.onShutdown?.());
|
|
103
103
|
return;
|
|
104
104
|
}
|
|
105
|
+
const isIdleRequired = req.body?.requireIdle === true;
|
|
105
106
|
const activity = (0, runtimeActivity_1.classifyRuntimeActivity)(readStatus());
|
|
106
|
-
if (!admission.beginRetirement(activity,
|
|
107
|
+
if (!admission.beginRetirement(activity, !isIdleRequired)) {
|
|
108
|
+
if (isIdleRequired) {
|
|
109
|
+
res.status(409).json({
|
|
110
|
+
reason: 'active_work',
|
|
111
|
+
error: 'Rivet left the server running because it has active work or is already restarting.',
|
|
112
|
+
upgrade: admission.status(),
|
|
113
|
+
});
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
107
116
|
res.status(409).json({
|
|
108
117
|
reason: 'server_retiring',
|
|
109
118
|
error: 'Rivet is already restarting. Retry after the runtime handoff completes.',
|
package/dist/server.js
CHANGED
|
@@ -212,6 +212,7 @@ const startServer = async (options) => {
|
|
|
212
212
|
? (0, crypto_1.randomBytes)(QUEUE_ACCESS_TOKEN_BYTES).toString('base64url')
|
|
213
213
|
: null;
|
|
214
214
|
const variantsOrchestrator = options.variantsRuntime?.orchestrator ?? options.agentVariantsOrchestrator;
|
|
215
|
+
await variantsOrchestrator?.loadDirectionRefs();
|
|
215
216
|
const inlineStartTracker = (0, inlineStartTracker_1.createInlineStartTracker)();
|
|
216
217
|
const runtimeAdmission = new RuntimeAdmission_1.RuntimeAdmission(telemetry_2.RIVET_VERSION);
|
|
217
218
|
const variantsBridge = options.variantsRuntime?.bridge ?? sessionBridge;
|
|
@@ -251,11 +252,16 @@ const startServer = async (options) => {
|
|
|
251
252
|
const editorHost = () => `${EMBEDDED_AGENT_LISTEN_HOST}:${listenPort}`;
|
|
252
253
|
const isPreviewRequest = (req) => req.headers.host === new URL(previewOrigin).host &&
|
|
253
254
|
(previewPort === undefined || req.socket.localPort === previewPort);
|
|
255
|
+
const rejectRequest = ({ req, res, reason, }) => {
|
|
256
|
+
log.warn(`Rejected ${req.method} ${req.path} with 403: ${reason}`);
|
|
257
|
+
telemetry?.trackRequestRejected(reason);
|
|
258
|
+
res.sendStatus(403);
|
|
259
|
+
};
|
|
254
260
|
app.use((req, res, next) => {
|
|
255
261
|
const requestHost = req.headers.host;
|
|
256
262
|
const isEditorRequest = requestHost === editorHost() && req.socket.localPort === listenPort;
|
|
257
263
|
if (!isEditorRequest && !isPreviewRequest(req)) {
|
|
258
|
-
res
|
|
264
|
+
rejectRequest({ req, res, reason: 'host_not_allowed' });
|
|
259
265
|
return;
|
|
260
266
|
}
|
|
261
267
|
next();
|
|
@@ -293,7 +299,7 @@ const startServer = async (options) => {
|
|
|
293
299
|
return;
|
|
294
300
|
}
|
|
295
301
|
if (req.headers[editorAccess_2.EDITOR_ACCESS_TOKEN_HEADER]) {
|
|
296
|
-
res
|
|
302
|
+
rejectRequest({ req, res, reason: 'editor_token_on_preview' });
|
|
297
303
|
return;
|
|
298
304
|
}
|
|
299
305
|
const isAppApi = req.path.toLowerCase().startsWith('/api/') &&
|
|
@@ -438,7 +444,7 @@ const startServer = async (options) => {
|
|
|
438
444
|
PREVIEW_PORT_ALLOWED_API_RE.test(req.path.toLowerCase());
|
|
439
445
|
if (!isPreviewRequest(req) && isPreviewPath) {
|
|
440
446
|
if (req.headers[editorAccess_2.EDITOR_ACCESS_TOKEN_HEADER]) {
|
|
441
|
-
res
|
|
447
|
+
rejectRequest({ req, res, reason: 'editor_token_on_preview' });
|
|
442
448
|
return;
|
|
443
449
|
}
|
|
444
450
|
res.redirect(302, `${previewOrigin}${req.originalUrl}`);
|
|
@@ -511,7 +517,7 @@ const startServer = async (options) => {
|
|
|
511
517
|
});
|
|
512
518
|
app.post('/api/library/browser-launches', express_1.default.urlencoded({ extended: false }), async (req, res) => {
|
|
513
519
|
if (!(0, middleware_1.isLocalBrowserRequest)(req))
|
|
514
|
-
return res
|
|
520
|
+
return rejectRequest({ req, res, reason: 'origin_not_allowed' });
|
|
515
521
|
const view = req.body?.view;
|
|
516
522
|
if (view !== 'projects' && view !== 'references')
|
|
517
523
|
return res.sendStatus(400);
|
|
@@ -591,14 +597,14 @@ const startServer = async (options) => {
|
|
|
591
597
|
return;
|
|
592
598
|
}
|
|
593
599
|
if (req.headers[editorAccess_2.EDITOR_ACCESS_TOKEN_HEADER]) {
|
|
594
|
-
res
|
|
600
|
+
rejectRequest({ req, res, reason: 'editor_token_on_preview' });
|
|
595
601
|
return;
|
|
596
602
|
}
|
|
597
603
|
res.redirect(302, `${previewOrigin}${req.originalUrl}`);
|
|
598
604
|
return;
|
|
599
605
|
}
|
|
600
606
|
if (req.headers[editorAccess_2.EDITOR_ACCESS_TOKEN_HEADER]) {
|
|
601
|
-
res
|
|
607
|
+
rejectRequest({ req, res, reason: 'editor_token_on_preview' });
|
|
602
608
|
return;
|
|
603
609
|
}
|
|
604
610
|
next();
|
|
@@ -38,17 +38,40 @@ const INSTALL_ENVIRONMENT_PREFIXES = [
|
|
|
38
38
|
'corepack_',
|
|
39
39
|
];
|
|
40
40
|
const INSTALL_ENVIRONMENT_KEYS = new Set(['node_options', 'path']);
|
|
41
|
+
const INSTALL_FAILURE_CAUSES = [
|
|
42
|
+
{
|
|
43
|
+
reasonCode: 'lockfile_outdated',
|
|
44
|
+
pattern: /^error Your lockfile needs to be updated, but yarn was run with `--frozen-lockfile`/m,
|
|
45
|
+
guidance: 'The lockfile does not match package.json. Update the lockfile in the project, commit it, then retry the preview.',
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
reasonCode: 'engine_incompatible',
|
|
49
|
+
pattern: /^error .+: The engine "node" is incompatible with this module/m,
|
|
50
|
+
guidance: 'The project or one of its dependencies does not support the active Node.js version. Switch to a Node.js version the project supports, then retry the preview.',
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
reasonCode: 'install_script_failed',
|
|
54
|
+
pattern: /^error .+: Command failed\.$/m,
|
|
55
|
+
guidance: 'A dependency install script failed. If it builds a native addon, switch to a Node.js version the project supports, then retry the preview.',
|
|
56
|
+
},
|
|
57
|
+
];
|
|
58
|
+
const UNRECOGNIZED_INSTALL_FAILURE = {
|
|
59
|
+
reasonCode: 'install_failed',
|
|
60
|
+
guidance: 'Fix the installation error, then retry the preview.',
|
|
61
|
+
};
|
|
62
|
+
const installFailureCause = (output) => INSTALL_FAILURE_CAUSES.find(({ pattern }) => pattern.test(output));
|
|
41
63
|
const isInstallEnvironmentKey = (key) => {
|
|
42
64
|
const lower = key.toLowerCase();
|
|
43
65
|
return (INSTALL_ENVIRONMENT_PREFIXES.some((prefix) => lower.startsWith(prefix)) ||
|
|
44
66
|
INSTALL_ENVIRONMENT_KEYS.has(lower));
|
|
45
67
|
};
|
|
46
68
|
const yarnAgentForVersion = (version) => Number.parseInt(version, 10) > 1 ? 'yarn@berry' : 'yarn';
|
|
47
|
-
const preparationError = ({ reasonCode, message, detail = '', }) => new devServerError_1.DevServerStartError({
|
|
69
|
+
const preparationError = ({ reasonCode, message, detail = '', exitCode, }) => new devServerError_1.DevServerStartError({
|
|
48
70
|
message: detail ? `${message}\n${detail}` : message,
|
|
49
71
|
reason: 'dependency_install_failed',
|
|
50
72
|
portInUse: false,
|
|
51
73
|
detail,
|
|
74
|
+
exitCode,
|
|
52
75
|
reasonCode,
|
|
53
76
|
summary: message,
|
|
54
77
|
});
|
|
@@ -309,10 +332,13 @@ class DependencyPreparationService {
|
|
|
309
332
|
stdio: 'pipe',
|
|
310
333
|
});
|
|
311
334
|
let output = '';
|
|
335
|
+
let failureCause;
|
|
312
336
|
let interruption;
|
|
313
337
|
let settleTimer;
|
|
314
338
|
const drain = (chunk) => {
|
|
315
|
-
|
|
339
|
+
const received = output + chunk.toString();
|
|
340
|
+
failureCause ??= installFailureCause(received);
|
|
341
|
+
output = received.slice(-OUTPUT_TAIL_LIMIT);
|
|
316
342
|
};
|
|
317
343
|
proc.stdout?.on('data', drain);
|
|
318
344
|
proc.stderr?.on('data', drain);
|
|
@@ -351,14 +377,26 @@ class DependencyPreparationService {
|
|
|
351
377
|
});
|
|
352
378
|
proc.once('close', (code) => {
|
|
353
379
|
cleanup();
|
|
354
|
-
if (code === 0 && !interruption)
|
|
380
|
+
if (code === 0 && !interruption) {
|
|
355
381
|
resolve(output);
|
|
356
|
-
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
const command = `${project.name} ${args.join(' ')}`;
|
|
385
|
+
if (interruption) {
|
|
357
386
|
reject(preparationError({
|
|
358
|
-
reasonCode: interruption
|
|
359
|
-
message: `Dependency preparation failed: ${
|
|
387
|
+
reasonCode: interruption,
|
|
388
|
+
message: `Dependency preparation failed: ${command} (cancelled or timed out). ${UNRECOGNIZED_INSTALL_FAILURE.guidance}`,
|
|
360
389
|
detail: output.trim(),
|
|
361
390
|
}));
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
const { reasonCode, guidance } = failureCause ?? UNRECOGNIZED_INSTALL_FAILURE;
|
|
394
|
+
reject(preparationError({
|
|
395
|
+
reasonCode,
|
|
396
|
+
message: `Dependency preparation failed: ${command} (exit ${code}). ${guidance}`,
|
|
397
|
+
detail: output.trim(),
|
|
398
|
+
exitCode: code,
|
|
399
|
+
}));
|
|
362
400
|
});
|
|
363
401
|
});
|
|
364
402
|
}
|
|
@@ -5,9 +5,9 @@ const telemetryPolicy_1 = require("../config/telemetryPolicy");
|
|
|
5
5
|
const posthog_node_1 = require("posthog-node");
|
|
6
6
|
const logger_1 = require("../utils/logger");
|
|
7
7
|
const ConfigManager_1 = require("./ConfigManager");
|
|
8
|
+
const posthog_1 = require("../config/posthog");
|
|
8
9
|
const proxy_1 = require("../config/proxy");
|
|
9
10
|
const log = (0, logger_1.createLogger)('FeatureFlagService');
|
|
10
|
-
const POSTHOG_PUBLIC_API_KEY = 'phc_Ntj9tXHbS64XgYxlTfhglRmFivFsfm0AERph4ZlnNH';
|
|
11
11
|
const remoteFlagsDisabled = () => {
|
|
12
12
|
const v = process.env.RIVET_DISABLE_REMOTE_FLAGS;
|
|
13
13
|
return v !== undefined && v !== 'false' && v !== '0';
|
|
@@ -20,7 +20,7 @@ class FeatureFlagService {
|
|
|
20
20
|
return;
|
|
21
21
|
}
|
|
22
22
|
try {
|
|
23
|
-
this.posthog = new posthog_node_1.PostHog(POSTHOG_PUBLIC_API_KEY, {
|
|
23
|
+
this.posthog = new posthog_node_1.PostHog(posthog_1.POSTHOG_PUBLIC_API_KEY, {
|
|
24
24
|
host: proxy_1.POSTHOG_HOST,
|
|
25
25
|
flushAt: 1,
|
|
26
26
|
flushInterval: 0,
|
|
@@ -12,6 +12,9 @@ interface VariantReference {
|
|
|
12
12
|
sessionId: string;
|
|
13
13
|
variantId: string;
|
|
14
14
|
}
|
|
15
|
+
interface LibraryListOptions {
|
|
16
|
+
isRemovedIncluded?: boolean;
|
|
17
|
+
}
|
|
15
18
|
export declare const currentLibraryRoot: (env?: NodeJS.ProcessEnv) => string;
|
|
16
19
|
export declare class ProjectLibrary {
|
|
17
20
|
readonly registry: ProjectRegistry;
|
|
@@ -45,7 +48,7 @@ export declare class ProjectLibrary {
|
|
|
45
48
|
projectPath: string;
|
|
46
49
|
}): Promise<void>;
|
|
47
50
|
private listProject;
|
|
48
|
-
listVariants(projectId?: string): Promise<LibraryVariant[]>;
|
|
51
|
+
listVariants(projectId?: string, options?: LibraryListOptions): Promise<LibraryVariant[]>;
|
|
49
52
|
private findVariant;
|
|
50
53
|
variantSummary(reference: VariantReference): Promise<{
|
|
51
54
|
summary: VariantHistorySummary;
|
|
@@ -23,6 +23,11 @@ const currentLibraryRoot = (env = process.env) => {
|
|
|
23
23
|
: (0, ProjectRegistry_1.libraryRoot)({ channel });
|
|
24
24
|
};
|
|
25
25
|
exports.currentLibraryRoot = currentLibraryRoot;
|
|
26
|
+
const isSameDirection = (left, right) => (!left.directionRef ||
|
|
27
|
+
!right.directionRef ||
|
|
28
|
+
left.directionRef === right.directionRef) &&
|
|
29
|
+
JSON.stringify({ ...left, directionRef: undefined }) ===
|
|
30
|
+
JSON.stringify({ ...right, directionRef: undefined });
|
|
26
31
|
class ProjectLibrary {
|
|
27
32
|
registry;
|
|
28
33
|
isReadOnly;
|
|
@@ -158,7 +163,7 @@ class ProjectLibrary {
|
|
|
158
163
|
});
|
|
159
164
|
}
|
|
160
165
|
}
|
|
161
|
-
async listProject(projectId) {
|
|
166
|
+
async listProject(projectId, options) {
|
|
162
167
|
const project = this.registry.get(projectId);
|
|
163
168
|
if (!project.isAvailable && project.storageKind === 'project')
|
|
164
169
|
throw new Error('Working folder and project-local history are unavailable');
|
|
@@ -171,23 +176,23 @@ class ProjectLibrary {
|
|
|
171
176
|
: history.listVariantsFromIndex({ projectPath }))).map((entry) => ({ ...entry, projectId, projectPath }))))).flat();
|
|
172
177
|
const unique = new Map();
|
|
173
178
|
for (const entry of entries) {
|
|
174
|
-
if (
|
|
175
|
-
entry.manifest.status === '
|
|
179
|
+
if (!options.isRemovedIncluded &&
|
|
180
|
+
(entry.manifest.status === 'removed' ||
|
|
181
|
+
entry.manifest.status === 'cancelled'))
|
|
176
182
|
continue;
|
|
177
183
|
const key = `${entry.manifest.sessionId}:${entry.manifest.variantId}`;
|
|
178
184
|
const existing = unique.get(key);
|
|
179
|
-
if (existing &&
|
|
180
|
-
JSON.stringify(existing.manifest) !== JSON.stringify(entry.manifest))
|
|
185
|
+
if (existing && !isSameDirection(existing.manifest, entry.manifest))
|
|
181
186
|
throw new Error('Conflicting history identities across attached roots');
|
|
182
|
-
unique.set(key, entry);
|
|
187
|
+
unique.set(key, existing?.manifest.directionRef ? existing : entry);
|
|
183
188
|
}
|
|
184
189
|
return [...unique.values()];
|
|
185
190
|
}
|
|
186
|
-
async listVariants(projectId) {
|
|
191
|
+
async listVariants(projectId, options = {}) {
|
|
187
192
|
if (projectId)
|
|
188
|
-
return this.listProject(projectId);
|
|
193
|
+
return this.listProject(projectId, options);
|
|
189
194
|
const projects = this.registry.list();
|
|
190
|
-
const results = await Promise.allSettled(projects.map((project) => this.listProject(project.id)));
|
|
195
|
+
const results = await Promise.allSettled(projects.map((project) => this.listProject(project.id, options)));
|
|
191
196
|
return results
|
|
192
197
|
.flatMap((result, index) => {
|
|
193
198
|
if (result.status === 'fulfilled') {
|
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
import type { ProjectRegistry } from './ProjectRegistry';
|
|
2
|
+
import { type ServerUnavailableReason } from '../cli/telemetry';
|
|
2
3
|
interface ProjectRuntime {
|
|
3
4
|
editorUrl: string;
|
|
4
5
|
}
|
|
6
|
+
export declare class ProjectRuntimeUnavailable extends Error {
|
|
7
|
+
readonly serverUnavailableReason?: ServerUnavailableReason;
|
|
8
|
+
constructor({ message, serverUnavailableReason, }: {
|
|
9
|
+
message: string;
|
|
10
|
+
serverUnavailableReason?: ServerUnavailableReason;
|
|
11
|
+
});
|
|
12
|
+
}
|
|
5
13
|
export declare class ProjectRuntimeService {
|
|
6
14
|
private readonly registry;
|
|
7
15
|
private readonly activations;
|
|
@@ -36,14 +36,24 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
36
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
37
|
};
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.ProjectRuntimeService = void 0;
|
|
39
|
+
exports.ProjectRuntimeService = exports.ProjectRuntimeUnavailable = void 0;
|
|
40
40
|
const fs_1 = __importDefault(require("fs"));
|
|
41
41
|
const zod_1 = require("zod");
|
|
42
42
|
const installationChannel_1 = require("../install/installationChannel");
|
|
43
43
|
const libraryErrors_1 = require("./libraryErrors");
|
|
44
44
|
const serverHandshake_1 = require("../cli/serverHandshake");
|
|
45
45
|
const shared_1 = require("../cli/commands/shared");
|
|
46
|
+
const telemetry_1 = require("../cli/telemetry");
|
|
46
47
|
const HEALTH_TIMEOUT_MS = 2_000;
|
|
48
|
+
class ProjectRuntimeUnavailable extends Error {
|
|
49
|
+
serverUnavailableReason;
|
|
50
|
+
constructor({ message, serverUnavailableReason, }) {
|
|
51
|
+
super(message);
|
|
52
|
+
this.name = 'ProjectRuntimeUnavailable';
|
|
53
|
+
this.serverUnavailableReason = serverUnavailableReason;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
exports.ProjectRuntimeUnavailable = ProjectRuntimeUnavailable;
|
|
47
57
|
class ProjectRuntimeService {
|
|
48
58
|
registry;
|
|
49
59
|
activations = new Map();
|
|
@@ -118,7 +128,10 @@ class ProjectRuntimeService {
|
|
|
118
128
|
writeEnvelope: () => { },
|
|
119
129
|
});
|
|
120
130
|
if (!result.envelope.ok)
|
|
121
|
-
throw new
|
|
131
|
+
throw new ProjectRuntimeUnavailable({
|
|
132
|
+
message: result.envelope.error.message,
|
|
133
|
+
serverUnavailableReason: (0, telemetry_1.serverUnavailableReasonForEnvelope)(result.envelope),
|
|
134
|
+
});
|
|
122
135
|
const data = zod_1.z
|
|
123
136
|
.object({ editorUrl: zod_1.z.string().url() })
|
|
124
137
|
.parse(result.envelope.data);
|
|
@@ -3,6 +3,7 @@ import type { BrowserMetadata, DesignContextKind, ServerUnavailableReason, Varia
|
|
|
3
3
|
import type { GuidanceErrorCode, GuidanceSelection } from '../types/guidance';
|
|
4
4
|
import type { MCPAuthMethod, MCPAuthState, MCPOnboardingCorrelation, MCPOAuthCallbackResult } from './MCPOnboardingTelemetry';
|
|
5
5
|
import { type MCPVariantsTelemetryMetadata } from './MCPVariantsTelemetry';
|
|
6
|
+
export type RequestRejectionReason = 'host_not_allowed' | 'origin_not_allowed' | 'editor_token_on_preview';
|
|
6
7
|
export type TelemetryOptions = {
|
|
7
8
|
enabled?: boolean;
|
|
8
9
|
source?: 'cli' | 'mcp' | 'core';
|
|
@@ -41,12 +42,14 @@ export declare class TelemetryService {
|
|
|
41
42
|
trackGuidanceOperation(data: GuidanceOperation): void;
|
|
42
43
|
trackProfileOperation(data: ProfileOperation): void;
|
|
43
44
|
trackLibraryOperation(data: LibraryOperation): void;
|
|
45
|
+
trackRequestRejected(reason: RequestRejectionReason): void;
|
|
44
46
|
private hashTelemetryValue;
|
|
45
47
|
private posthog;
|
|
46
48
|
private isEnabled;
|
|
47
49
|
private readonly defaultSource;
|
|
48
50
|
private readonly editor?;
|
|
49
51
|
private readonly identifiedAccounts;
|
|
52
|
+
private readonly reportedRequestRejections;
|
|
50
53
|
constructor(options?: boolean | TelemetryOptions);
|
|
51
54
|
private get distinctId();
|
|
52
55
|
identifyUser(identity?: AccountIdentity): void;
|
|
@@ -285,6 +288,7 @@ export declare class TelemetryService {
|
|
|
285
288
|
hasPort: boolean;
|
|
286
289
|
port?: number;
|
|
287
290
|
durationMs?: number | null;
|
|
291
|
+
staticEntrySource?: string;
|
|
288
292
|
}): void;
|
|
289
293
|
trackAgentVariantsPreviewFailed(data: {
|
|
290
294
|
sessionId: string;
|
|
@@ -298,6 +302,7 @@ export declare class TelemetryService {
|
|
|
298
302
|
exitCode?: number | null;
|
|
299
303
|
signal?: string | null;
|
|
300
304
|
missingDeps?: boolean;
|
|
305
|
+
staticEntrySource?: string;
|
|
301
306
|
error?: unknown;
|
|
302
307
|
}): void;
|
|
303
308
|
trackAgentVariantsPreviewSwitchStarted(data: {
|
|
@@ -11,10 +11,20 @@ const telemetryPolicy_1 = require("../config/telemetryPolicy");
|
|
|
11
11
|
const pluginMetrics_1 = require("../config/pluginMetrics");
|
|
12
12
|
const telemetryContract_1 = require("../config/telemetryContract");
|
|
13
13
|
const failureReason_1 = require("../utils/failureReason");
|
|
14
|
+
const posthog_1 = require("../config/posthog");
|
|
14
15
|
const proxy_1 = require("../config/proxy");
|
|
15
16
|
const MCPVariantsTelemetry_1 = require("./MCPVariantsTelemetry");
|
|
16
17
|
const errorMessage_1 = require("../utils/errorMessage");
|
|
18
|
+
const serverUnavailable_1 = require("../cli/serverUnavailable");
|
|
17
19
|
const log = (0, logger_1.createLogger)('TelemetryService');
|
|
20
|
+
const serverUnavailableReasonProperties = (error) => {
|
|
21
|
+
const reason = typeof error === 'object' && error !== null
|
|
22
|
+
? Reflect.get(error, 'serverUnavailableReason')
|
|
23
|
+
: undefined;
|
|
24
|
+
return (0, serverUnavailable_1.isServerUnavailableReason)(reason)
|
|
25
|
+
? { server_unavailable_reason: reason }
|
|
26
|
+
: {};
|
|
27
|
+
};
|
|
18
28
|
const KNOWN_MCP_EDITORS = new Set([
|
|
19
29
|
'cursor',
|
|
20
30
|
'codex',
|
|
@@ -32,7 +42,6 @@ const mcpEditorEventValue = (editor) => {
|
|
|
32
42
|
}
|
|
33
43
|
return 'other';
|
|
34
44
|
};
|
|
35
|
-
const POSTHOG_PUBLIC_API_KEY = 'phc_Ntj9tXHbS64XgYxlTfhglRmFivFsfm0AERph4ZlnNH';
|
|
36
45
|
const HASH_PREFIX_LENGTH = 12;
|
|
37
46
|
class TelemetryService {
|
|
38
47
|
trackGuidanceOperation(data) {
|
|
@@ -61,8 +70,15 @@ class TelemetryService {
|
|
|
61
70
|
this.track(`library_${data.operation}_${data.outcome}`, {
|
|
62
71
|
duration_ms: data.durationMs,
|
|
63
72
|
...(0, failureReason_1.failureReasonCodeProperties)(data.error),
|
|
73
|
+
...serverUnavailableReasonProperties(data.error),
|
|
64
74
|
});
|
|
65
75
|
}
|
|
76
|
+
trackRequestRejected(reason) {
|
|
77
|
+
if (this.reportedRequestRejections.has(reason))
|
|
78
|
+
return;
|
|
79
|
+
this.reportedRequestRejections.add(reason);
|
|
80
|
+
this.track('server_request_rejected', { reason });
|
|
81
|
+
}
|
|
66
82
|
hashTelemetryValue(value) {
|
|
67
83
|
return (0, crypto_1.createHash)('sha256')
|
|
68
84
|
.update(value)
|
|
@@ -74,6 +90,7 @@ class TelemetryService {
|
|
|
74
90
|
defaultSource;
|
|
75
91
|
editor;
|
|
76
92
|
identifiedAccounts = new Set();
|
|
93
|
+
reportedRequestRejections = new Set();
|
|
77
94
|
constructor(options = true) {
|
|
78
95
|
const opts = typeof options === 'boolean' ? { enabled: options } : options;
|
|
79
96
|
this.isEnabled = (opts.enabled ?? true) && (0, telemetryPolicy_1.getTelemetryMode)() !== 'off';
|
|
@@ -81,7 +98,7 @@ class TelemetryService {
|
|
|
81
98
|
this.editor = opts.editor;
|
|
82
99
|
if (this.isEnabled) {
|
|
83
100
|
try {
|
|
84
|
-
this.posthog = new posthog_node_1.PostHog(POSTHOG_PUBLIC_API_KEY, {
|
|
101
|
+
this.posthog = new posthog_node_1.PostHog(posthog_1.POSTHOG_PUBLIC_API_KEY, {
|
|
85
102
|
host: proxy_1.POSTHOG_HOST,
|
|
86
103
|
flushAt: 1,
|
|
87
104
|
flushInterval: 0,
|
|
@@ -682,6 +699,7 @@ class TelemetryService {
|
|
|
682
699
|
has_port: data.hasPort,
|
|
683
700
|
port: data.port,
|
|
684
701
|
duration_ms: data.durationMs,
|
|
702
|
+
static_entry_source: data.staticEntrySource,
|
|
685
703
|
source: 'mcp',
|
|
686
704
|
});
|
|
687
705
|
}
|
|
@@ -698,6 +716,7 @@ class TelemetryService {
|
|
|
698
716
|
exit_code: data.exitCode,
|
|
699
717
|
term_signal: data.signal,
|
|
700
718
|
missing_deps: data.missingDeps,
|
|
719
|
+
static_entry_source: data.staticEntrySource,
|
|
701
720
|
...(0, failureReason_1.failureReasonProperties)(data.error),
|
|
702
721
|
source: 'mcp',
|
|
703
722
|
});
|
|
@@ -3,6 +3,7 @@ import type { GuidanceDocument } from '../types/guidance';
|
|
|
3
3
|
import { type ReferenceImage } from './referenceImages';
|
|
4
4
|
import { type VariantReference } from '../types/variant-reference';
|
|
5
5
|
import type { VariantHistoryStatus, VariantHistoryKind, PersistVariantPreview, VariantServeSpec, VariantDesignSource, VariantDeployment, VariantCanvasDeployment, VariantHistoryManifest } from '../types/variant-history';
|
|
6
|
+
import type { DirectionRef } from '../types/direction-ref';
|
|
6
7
|
export type { VariantHistoryStatus, VariantHistoryKind, VariantHistoryPreview, PersistVariantPreview, VariantTreePointer, VariantBasePointer, DevServerRecipe, VariantServeSpec, VariantHistoryArtifact, VariantDesignSource, VariantDeployment, VariantCanvasDeployment, VariantHistoryManifest, VariantHistorySessionFile, } from '../types/variant-history';
|
|
7
8
|
import type { BundleMetadataStore } from '../storage/library/BundleMetadataStore';
|
|
8
9
|
import { TreeStore } from './TreeStore';
|
|
@@ -13,6 +14,7 @@ export interface PersistVariantArgs {
|
|
|
13
14
|
sessionId: string;
|
|
14
15
|
variantId: string;
|
|
15
16
|
requestId?: string;
|
|
17
|
+
directionRef?: DirectionRef;
|
|
16
18
|
label: string;
|
|
17
19
|
brief: string;
|
|
18
20
|
references?: VariantReference[];
|
|
@@ -116,6 +118,12 @@ export declare class VariantHistoryService {
|
|
|
116
118
|
label?: string;
|
|
117
119
|
runLabel?: string;
|
|
118
120
|
}): Promise<void>;
|
|
121
|
+
assignDirectionRef(args: {
|
|
122
|
+
projectPath: string;
|
|
123
|
+
sessionId: string;
|
|
124
|
+
variantId: string;
|
|
125
|
+
directionRef: DirectionRef;
|
|
126
|
+
}): Promise<void>;
|
|
119
127
|
renameRun(args: {
|
|
120
128
|
projectPath: string;
|
|
121
129
|
sessionId: string;
|
|
@@ -203,6 +203,7 @@ class VariantHistoryService {
|
|
|
203
203
|
let preservedDestinationPath;
|
|
204
204
|
let preservedCreatedAt;
|
|
205
205
|
let preservedRequestId;
|
|
206
|
+
let preservedDirectionRef;
|
|
206
207
|
let preservedReferences;
|
|
207
208
|
let preservedPreviewRoutes;
|
|
208
209
|
let preservedTree;
|
|
@@ -219,6 +220,7 @@ class VariantHistoryService {
|
|
|
219
220
|
});
|
|
220
221
|
preservedCreatedAt = prior.createdAt;
|
|
221
222
|
preservedRequestId = prior.requestId;
|
|
223
|
+
preservedDirectionRef = prior.directionRef;
|
|
222
224
|
preservedReferences = prior.references;
|
|
223
225
|
preservedPreviewRoutes = prior.previewRoutes;
|
|
224
226
|
preservedTree = prior.tree;
|
|
@@ -363,6 +365,9 @@ class VariantHistoryService {
|
|
|
363
365
|
...((args.requestId ?? preservedRequestId)
|
|
364
366
|
? { requestId: args.requestId ?? preservedRequestId }
|
|
365
367
|
: {}),
|
|
368
|
+
...((preservedDirectionRef ?? args.directionRef)
|
|
369
|
+
? { directionRef: preservedDirectionRef ?? args.directionRef }
|
|
370
|
+
: {}),
|
|
366
371
|
label: args.label,
|
|
367
372
|
brief: args.brief,
|
|
368
373
|
references: (0, variant_reference_1.mergeVariantReferences)(references),
|
|
@@ -527,6 +532,41 @@ class VariantHistoryService {
|
|
|
527
532
|
manifest,
|
|
528
533
|
});
|
|
529
534
|
}
|
|
535
|
+
async assignDirectionRef(args) {
|
|
536
|
+
assertSafeId(args.sessionId, 'sessionId');
|
|
537
|
+
assertSafeId(args.variantId, 'variantId');
|
|
538
|
+
const bundle = this.bundleFor(args.projectPath);
|
|
539
|
+
if (bundle) {
|
|
540
|
+
bundle.updateVariant({
|
|
541
|
+
...args,
|
|
542
|
+
update: (manifest) => {
|
|
543
|
+
manifest.directionRef ??= args.directionRef;
|
|
544
|
+
},
|
|
545
|
+
});
|
|
546
|
+
return;
|
|
547
|
+
}
|
|
548
|
+
const manifestPath = path_1.default.join(this.variantDir(args.projectPath, args.sessionId, args.variantId), MANIFEST_FILENAME);
|
|
549
|
+
let manifest;
|
|
550
|
+
try {
|
|
551
|
+
const raw = await promises_1.default.readFile(manifestPath, 'utf8');
|
|
552
|
+
manifest = JSON.parse(raw);
|
|
553
|
+
}
|
|
554
|
+
catch (err) {
|
|
555
|
+
const code = (0, errnoCode_1.errnoCode)(err);
|
|
556
|
+
if (code !== 'ENOENT') {
|
|
557
|
+
log.warn(`assignDirectionRef: manifest read failed at ${manifestPath} (session ${args.sessionId} variant ${args.variantId})`, err);
|
|
558
|
+
}
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
561
|
+
if (manifest.directionRef)
|
|
562
|
+
return;
|
|
563
|
+
manifest.directionRef = args.directionRef;
|
|
564
|
+
await writeManifestFile(manifestPath, manifest);
|
|
565
|
+
await this.projectManifestToIndex({
|
|
566
|
+
projectPath: args.projectPath,
|
|
567
|
+
manifest,
|
|
568
|
+
});
|
|
569
|
+
}
|
|
530
570
|
async renameRun(args) {
|
|
531
571
|
const entries = await this.listVariants({ projectPath: args.projectPath });
|
|
532
572
|
const targets = entries.filter((entry) => {
|
|
@@ -23,6 +23,7 @@ export declare class WorktreeManager {
|
|
|
23
23
|
createWorktrees(sessionId: string, count: number, instanceKeyPrefix?: string): Promise<string[]>;
|
|
24
24
|
forkWorktreesFrom(sourceWorktreePath: string, sessionId: string, count: number, instanceKeyPrefix?: string): Promise<string[]>;
|
|
25
25
|
getDiff(worktreePath: string): Promise<string>;
|
|
26
|
+
getChangedFiles(worktreePath: string): Promise<string[]>;
|
|
26
27
|
getFreePort(): Promise<number>;
|
|
27
28
|
findFreePortFrom(startPort: number, scanWindow?: number): Promise<number>;
|
|
28
29
|
releasePort(port: number): void;
|
|
@@ -276,6 +276,18 @@ class WorktreeManager {
|
|
|
276
276
|
await git.raw(['add', '--intent-to-add', '.']).catch(() => { });
|
|
277
277
|
return git.diff(['--binary', '--full-index', 'HEAD']);
|
|
278
278
|
}
|
|
279
|
+
async getChangedFiles(worktreePath) {
|
|
280
|
+
const git = (0, simple_git_1.simpleGit)(worktreePath, GIT_OPTS);
|
|
281
|
+
await git.raw(['add', '--intent-to-add', '.']).catch(() => { });
|
|
282
|
+
const names = await git.raw([
|
|
283
|
+
'diff',
|
|
284
|
+
'--name-only',
|
|
285
|
+
'--diff-filter=d',
|
|
286
|
+
'-z',
|
|
287
|
+
'HEAD',
|
|
288
|
+
]);
|
|
289
|
+
return names.split('\0').filter(Boolean);
|
|
290
|
+
}
|
|
279
291
|
getFreePort() {
|
|
280
292
|
return new Promise((resolve, reject) => {
|
|
281
293
|
const server = net_1.default.createServer();
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.createAgentVariantsOrchestrator = exports.withVariantsSessionReplayLinking = void 0;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
4
9
|
const index_core_1 = require("../index-core");
|
|
5
10
|
const agent_variants_1 = require("../agent-variants");
|
|
6
11
|
const devServerCommand_1 = require("../utils/devServerCommand");
|
|
@@ -69,11 +74,13 @@ const createAgentVariantsOrchestrator = (options) => {
|
|
|
69
74
|
targetPath: projectPath,
|
|
70
75
|
entryPath: options.staticEntry,
|
|
71
76
|
}).entryPath;
|
|
72
|
-
|
|
77
|
+
const hasEntry = options.staticEntry !== undefined ||
|
|
78
|
+
fs_1.default.existsSync(path_1.default.join(projectPath, entryPath));
|
|
79
|
+
log.info(`Resolved env for variants session ${sessionId}: static/${hasEntry ? entryPath : '(no entry page)'}`);
|
|
73
80
|
return {
|
|
74
81
|
projectPath,
|
|
75
82
|
framework,
|
|
76
|
-
entryPath,
|
|
83
|
+
...(hasEntry ? { entryPath } : {}),
|
|
77
84
|
};
|
|
78
85
|
}
|
|
79
86
|
const packageManager = await detection.detectPackageManager(projectPath);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { DirectionAddress, DirectionCandidate, DirectionRef, DirectionResolution, DirectionSearchAddress } from '../types/direction-ref';
|
|
2
|
+
import type { VariantHistoryManifest, VariantHistoryStatus } from '../types/variant-history';
|
|
3
|
+
export declare const isDirectionActive: (status: VariantHistoryStatus) => boolean;
|
|
4
|
+
type DirectionRefSource = {
|
|
5
|
+
manifest: Pick<VariantHistoryManifest, 'sessionId' | 'variantId' | 'label' | 'createdAt' | 'directionRef'>;
|
|
6
|
+
};
|
|
7
|
+
export declare const slugifyDirectionLabel: (label: string) => string;
|
|
8
|
+
export declare const nextDirectionRef: (args: {
|
|
9
|
+
label: string;
|
|
10
|
+
taken: ReadonlySet<string>;
|
|
11
|
+
}) => DirectionRef;
|
|
12
|
+
export declare const withDirectionRefs: <Entry extends DirectionRefSource>(entries: readonly Entry[]) => Array<Entry & {
|
|
13
|
+
directionRef: DirectionRef;
|
|
14
|
+
}>;
|
|
15
|
+
export declare const parseDirectionAddress: (raw: string) => DirectionAddress | null;
|
|
16
|
+
export declare const resolveDirectionAddress: (args: {
|
|
17
|
+
address: DirectionSearchAddress;
|
|
18
|
+
candidates: readonly DirectionCandidate[];
|
|
19
|
+
}) => DirectionResolution;
|
|
20
|
+
export {};
|
|
21
|
+
//# sourceMappingURL=directionRefs.d.ts.map
|