rivet-design 0.27.0 → 0.27.1
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/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 +4 -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/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/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 +19 -0
- 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/skills/cli-guidance.js +4 -3
- package/dist/utils/subprocessEnvironment.d.ts +1 -1
- package/dist/utils/subprocessEnvironment.js +0 -1
- package/package.json +3 -3
- package/src/ui/dist/assets/LibraryEntry-BZ5EdFgA.js +37 -0
- package/src/ui/dist/assets/main-MepMmTwb.css +1 -0
- package/src/ui/dist/assets/main-RriU35pI.js +497 -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/fonts/Goldman-Bold.woff2 +0 -0
- package/src/ui/dist/fonts/Goldman-Regular.woff2 +0 -0
|
@@ -50,6 +50,7 @@ const handoff_1 = require("../handoff");
|
|
|
50
50
|
const callerModel_1 = require("../callerModel");
|
|
51
51
|
const shared_1 = require("./shared");
|
|
52
52
|
const elementSelector_1 = require("./elementSelector");
|
|
53
|
+
const directionTarget_1 = require("./directionTarget");
|
|
53
54
|
const hostWorkNextAction_1 = require("../hostWorkNextAction");
|
|
54
55
|
const runLabel_1 = require("../../agent-variants/runLabel");
|
|
55
56
|
const contracts_1 = require("../../agent-variants/contracts");
|
|
@@ -116,44 +117,22 @@ const LIST_FLAG_SPEC = {
|
|
|
116
117
|
const GET_FLAG_SPEC = {
|
|
117
118
|
detail: { takesValue: false },
|
|
118
119
|
};
|
|
119
|
-
const
|
|
120
|
-
|
|
120
|
+
const START_TARGET_USAGE = 'Usage: --target <directionRef>|<sessionId>:<variantId> (example: --target warm-editorial-green)';
|
|
121
|
+
const GET_USAGE = 'Usage: rivet variants get <directionRef>|last|[<projectId>/]<sessionId>:<variantId> [--detail] [--project <path>]';
|
|
122
|
+
const resolveStartTarget = async (args) => {
|
|
123
|
+
if (args.raw === undefined)
|
|
121
124
|
return { ok: true };
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
const sessionId =
|
|
131
|
-
const variantId = raw.slice(separatorIndex + 1).trim();
|
|
132
|
-
if (!sessionId || !variantId) {
|
|
133
|
-
return {
|
|
134
|
-
ok: false,
|
|
135
|
-
message: 'Usage: --target <sessionId>:<variantId> (example: --target abc:def)',
|
|
136
|
-
};
|
|
137
|
-
}
|
|
125
|
+
const resolved = await (0, directionTarget_1.resolveDirectionTarget)({
|
|
126
|
+
command: START_COMMAND,
|
|
127
|
+
projectPath: args.projectPath,
|
|
128
|
+
input: args.raw,
|
|
129
|
+
usage: START_TARGET_USAGE,
|
|
130
|
+
});
|
|
131
|
+
if (!resolved.ok)
|
|
132
|
+
return resolved;
|
|
133
|
+
const { sessionId, variantId } = resolved.target;
|
|
138
134
|
return { ok: true, target: { kind: 'variant', sessionId, variantId } };
|
|
139
135
|
};
|
|
140
|
-
const variantReferenceFromString = (raw) => {
|
|
141
|
-
if (!raw)
|
|
142
|
-
return null;
|
|
143
|
-
const projectSeparator = raw.indexOf('/');
|
|
144
|
-
const projectId = projectSeparator === -1 ? undefined : raw.slice(0, projectSeparator);
|
|
145
|
-
const direction = projectSeparator === -1 ? raw : raw.slice(projectSeparator + 1);
|
|
146
|
-
if (projectSeparator !== -1 && (!projectId || direction.includes('/')))
|
|
147
|
-
return null;
|
|
148
|
-
const variantSeparator = direction.indexOf(':');
|
|
149
|
-
if (variantSeparator <= 0 || variantSeparator === direction.length - 1)
|
|
150
|
-
return null;
|
|
151
|
-
if (direction.indexOf(':', variantSeparator + 1) !== -1)
|
|
152
|
-
return null;
|
|
153
|
-
const sessionId = direction.slice(0, variantSeparator).trim();
|
|
154
|
-
const variantId = direction.slice(variantSeparator + 1).trim();
|
|
155
|
-
return sessionId && variantId ? { projectId, sessionId, variantId } : null;
|
|
156
|
-
};
|
|
157
136
|
const parseJsonFlag = (command, name, raw) => {
|
|
158
137
|
if (raw === undefined) {
|
|
159
138
|
return { ok: true };
|
|
@@ -437,7 +416,7 @@ const handleVariantsStart = async (args, options) => {
|
|
|
437
416
|
}
|
|
438
417
|
const instruction = (0, flags_1.stringFlag)(context.flags, 'instruction');
|
|
439
418
|
if (!instruction?.trim()) {
|
|
440
|
-
return (0, envelope_1.errorResult)(START_COMMAND, 'USAGE_ERROR', 'Usage: rivet variants start --instruction <text> [--run-label <text>] [--briefs <json>] [--count N] [--fidelity low|medium|high] [--element <selector>] [--files <json>] [--fresh] [--context-images <json>] [--context-assets <json>] [--reference-pages <json>] [--reference-videos <json>] [--target <sessionId>:<variantId>]');
|
|
419
|
+
return (0, envelope_1.errorResult)(START_COMMAND, 'USAGE_ERROR', 'Usage: rivet variants start --instruction <text> [--run-label <text>] [--briefs <json>] [--count N] [--fidelity low|medium|high] [--element <selector>] [--files <json>] [--fresh] [--context-images <json>] [--context-assets <json>] [--reference-pages <json>] [--reference-videos <json>] [--target <directionRef>|<sessionId>:<variantId>]');
|
|
441
420
|
}
|
|
442
421
|
if (context.flags.errors.length > 0) {
|
|
443
422
|
return (0, envelope_1.errorResult)(START_COMMAND, 'USAGE_ERROR', context.flags.errors.join('; '));
|
|
@@ -508,10 +487,12 @@ const handleVariantsStart = async (args, options) => {
|
|
|
508
487
|
return (0, envelope_1.errorResult)(START_COMMAND, 'USAGE_ERROR', '--count must match --briefs length when both are provided.');
|
|
509
488
|
}
|
|
510
489
|
const isFresh = isFreshStart;
|
|
511
|
-
const parsedTarget =
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
}
|
|
490
|
+
const parsedTarget = await resolveStartTarget({
|
|
491
|
+
projectPath: context.projectPath,
|
|
492
|
+
raw: (0, flags_1.stringFlag)(context.flags, 'target'),
|
|
493
|
+
});
|
|
494
|
+
if (!parsedTarget.ok)
|
|
495
|
+
return parsedTarget.result;
|
|
515
496
|
if (isFresh && parsedTarget.target) {
|
|
516
497
|
return (0, envelope_1.errorResult)(START_COMMAND, 'USAGE_ERROR', '--fresh cannot be combined with --target; start fresh generation from the base project.');
|
|
517
498
|
}
|
|
@@ -782,6 +763,7 @@ const handleSavedVariantGet = async (args) => {
|
|
|
782
763
|
return (0, envelope_1.errorResult)(GET_COMMAND, 'WORK_ITEM_NOT_FOUND', 'No saved variant exists for this project and reference.');
|
|
783
764
|
const saved = 'detail' in found ? found.detail : found.summary;
|
|
784
765
|
const { manifest, variantDir } = saved;
|
|
766
|
+
const directionRef = args.directionRef ?? manifest.directionRef;
|
|
785
767
|
const kind = manifest.artifact.kind === 'diff' ? 'diff' : 'project-created';
|
|
786
768
|
const artifactPath = path.join(variantDir, manifest.artifact.kind === 'diff'
|
|
787
769
|
? manifest.artifact.diffPath
|
|
@@ -789,6 +771,7 @@ const handleSavedVariantGet = async (args) => {
|
|
|
789
771
|
const variant = args.isDetailed && 'detail' in found
|
|
790
772
|
? {
|
|
791
773
|
...manifest,
|
|
774
|
+
directionRef,
|
|
792
775
|
kind,
|
|
793
776
|
artifactPath,
|
|
794
777
|
diff: found.detail.diff,
|
|
@@ -796,6 +779,7 @@ const handleSavedVariantGet = async (args) => {
|
|
|
796
779
|
designMarkdown: found.detail.designMarkdown,
|
|
797
780
|
}
|
|
798
781
|
: {
|
|
782
|
+
directionRef,
|
|
799
783
|
sessionId: manifest.sessionId,
|
|
800
784
|
variantId: manifest.variantId,
|
|
801
785
|
status: manifest.status,
|
|
@@ -825,12 +809,21 @@ const handleVariantsGet = async (args) => {
|
|
|
825
809
|
if ((0, shared_1.isCommandResult)(context)) {
|
|
826
810
|
return context;
|
|
827
811
|
}
|
|
828
|
-
const
|
|
829
|
-
if (
|
|
812
|
+
const input = context.flags.positionals[0];
|
|
813
|
+
if (input === undefined ||
|
|
830
814
|
context.flags.positionals.length !== 1 ||
|
|
831
815
|
context.flags.errors.length > 0) {
|
|
832
|
-
return (0, envelope_1.errorResult)(GET_COMMAND, 'USAGE_ERROR',
|
|
816
|
+
return (0, envelope_1.errorResult)(GET_COMMAND, 'USAGE_ERROR', GET_USAGE);
|
|
833
817
|
}
|
|
818
|
+
const resolved = await (0, directionTarget_1.resolveDirectionTarget)({
|
|
819
|
+
command: GET_COMMAND,
|
|
820
|
+
projectPath: context.projectPath,
|
|
821
|
+
input,
|
|
822
|
+
usage: GET_USAGE,
|
|
823
|
+
});
|
|
824
|
+
if (!resolved.ok)
|
|
825
|
+
return resolved.result;
|
|
826
|
+
const reference = resolved.target;
|
|
834
827
|
if (reference.projectId)
|
|
835
828
|
return handleSavedVariantGet({
|
|
836
829
|
...reference,
|
package/dist/cli/envelope.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ export declare const CLI_EXIT_CODES: {
|
|
|
8
8
|
readonly waitTimeout: 5;
|
|
9
9
|
};
|
|
10
10
|
export type CliExitCode = (typeof CLI_EXIT_CODES)[keyof typeof CLI_EXIT_CODES];
|
|
11
|
-
export type CliErrorCode = 'OPERATION_FAILED' | 'USAGE_ERROR' | 'AUTH_REQUIRED' | 'SERVER_UNAVAILABLE' | 'WAIT_TIMEOUT' | 'SESSION_NOT_FOUND' | 'WORK_ITEM_NOT_FOUND' | 'MCP_REMOVED';
|
|
11
|
+
export type CliErrorCode = 'OPERATION_FAILED' | 'USAGE_ERROR' | 'AUTH_REQUIRED' | 'SERVER_UNAVAILABLE' | 'WAIT_TIMEOUT' | 'SESSION_NOT_FOUND' | 'WORK_ITEM_NOT_FOUND' | 'DIRECTION_AMBIGUOUS' | 'MCP_REMOVED';
|
|
12
12
|
export type CliLoginAction = {
|
|
13
13
|
action: 'login';
|
|
14
14
|
command: 'rivet login';
|
package/dist/cli/envelope.js
CHANGED
|
@@ -24,6 +24,7 @@ const ERROR_EXIT_CODES = {
|
|
|
24
24
|
WAIT_TIMEOUT: exports.CLI_EXIT_CODES.waitTimeout,
|
|
25
25
|
SESSION_NOT_FOUND: exports.CLI_EXIT_CODES.operationFailed,
|
|
26
26
|
WORK_ITEM_NOT_FOUND: exports.CLI_EXIT_CODES.operationFailed,
|
|
27
|
+
DIRECTION_AMBIGUOUS: exports.CLI_EXIT_CODES.usageError,
|
|
27
28
|
MCP_REMOVED: exports.CLI_EXIT_CODES.usageError,
|
|
28
29
|
};
|
|
29
30
|
const loginRecovery = (authUrl) => ({
|
|
@@ -12,6 +12,17 @@ type RuntimeUpgradeOutcome = {
|
|
|
12
12
|
restartArgs?: string[];
|
|
13
13
|
interruptedWork?: RuntimeInterruption;
|
|
14
14
|
};
|
|
15
|
+
type RuntimeRetirement = {
|
|
16
|
+
outcome: 'retired';
|
|
17
|
+
restartArgs?: string[];
|
|
18
|
+
} | {
|
|
19
|
+
outcome: 'kept';
|
|
20
|
+
};
|
|
21
|
+
export declare const retireUnavailablePreview: ({ attached, clientVersion, shutdownTimeoutMs, }: {
|
|
22
|
+
attached: AttachedServer;
|
|
23
|
+
clientVersion: string;
|
|
24
|
+
shutdownTimeoutMs: number;
|
|
25
|
+
}) => Promise<RuntimeRetirement>;
|
|
15
26
|
export declare const prepareRuntimeUpgrade: ({ attached, io, shutdownTimeoutMs, }: {
|
|
16
27
|
attached: AttachedServer;
|
|
17
28
|
io: CliIO;
|
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.prepareRuntimeUpgrade = void 0;
|
|
6
|
+
exports.prepareRuntimeUpgrade = exports.retireUnavailablePreview = void 0;
|
|
7
7
|
const zod_1 = require("zod");
|
|
8
8
|
const fs_1 = __importDefault(require("fs"));
|
|
9
9
|
const client_1 = require("./client");
|
|
@@ -34,6 +34,43 @@ const INTERRUPTIBLE_REASONS = new Set([
|
|
|
34
34
|
'active_work',
|
|
35
35
|
'unknown_execution_state',
|
|
36
36
|
]);
|
|
37
|
+
const awaitOwnedRuntimeShutdown = async ({ attached, processIdentity, shutdownTimeoutMs, }) => {
|
|
38
|
+
if (await (0, serverShutdown_1.waitForServerShutdown)(attached, shutdownTimeoutMs))
|
|
39
|
+
return;
|
|
40
|
+
await (0, stopRuntimeProcess_1.stopRuntimeProcess)({
|
|
41
|
+
pid: attached.handshake.pid,
|
|
42
|
+
timeoutMs: shutdownTimeoutMs,
|
|
43
|
+
isOwned: async () => {
|
|
44
|
+
return (processIdentity !== null &&
|
|
45
|
+
(0, stopRuntimeProcess_1.runtimeProcessIdentity)(attached.handshake.pid) === processIdentity);
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
};
|
|
49
|
+
const retireUnavailablePreview = async ({ attached, clientVersion, shutdownTimeoutMs, }) => {
|
|
50
|
+
const serverVersion = attached.handshake.rivetVersion;
|
|
51
|
+
if (!serverVersion || (0, serverVersion_1.isNewerVersion)(serverVersion, clientVersion))
|
|
52
|
+
return { outcome: 'kept' };
|
|
53
|
+
try {
|
|
54
|
+
const processIdentity = (0, stopRuntimeProcess_1.runtimeProcessIdentity)(attached.handshake.pid);
|
|
55
|
+
const upgrade = await (0, client_1.requestServer)(attached, '/api/cli/upgrade', {
|
|
56
|
+
method: 'POST',
|
|
57
|
+
body: { clientVersion, requireIdle: true },
|
|
58
|
+
});
|
|
59
|
+
const parsed = upgradeSchema.parse(upgrade.body);
|
|
60
|
+
if (upgrade.status !== 200 || parsed.stopping !== true)
|
|
61
|
+
return { outcome: 'kept' };
|
|
62
|
+
await awaitOwnedRuntimeShutdown({
|
|
63
|
+
attached,
|
|
64
|
+
processIdentity,
|
|
65
|
+
shutdownTimeoutMs,
|
|
66
|
+
});
|
|
67
|
+
return { outcome: 'retired', restartArgs: parsed.restartArgs };
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return { outcome: 'kept' };
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
exports.retireUnavailablePreview = retireUnavailablePreview;
|
|
37
74
|
const prepareRuntimeUpgrade = async ({ attached, io, shutdownTimeoutMs, }) => {
|
|
38
75
|
const info = (0, serverVersion_1.serverVersionInfo)(attached.handshake);
|
|
39
76
|
if (!info.staleServer)
|
|
@@ -92,16 +129,11 @@ const prepareRuntimeUpgrade = async ({ attached, io, shutdownTimeoutMs, }) => {
|
|
|
92
129
|
: undefined;
|
|
93
130
|
if (interruptedWork)
|
|
94
131
|
io.writeProgress(`${interruptedWork.message} Recovery details: ${interruptedWork.receiptPath}`);
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
return (processIdentity !== null &&
|
|
101
|
-
(0, stopRuntimeProcess_1.runtimeProcessIdentity)(attached.handshake.pid) === processIdentity);
|
|
102
|
-
},
|
|
103
|
-
});
|
|
104
|
-
}
|
|
132
|
+
await awaitOwnedRuntimeShutdown({
|
|
133
|
+
attached,
|
|
134
|
+
processIdentity,
|
|
135
|
+
shutdownTimeoutMs,
|
|
136
|
+
});
|
|
105
137
|
io.writeProgress(`Upgrading project server to rivet v${info.cliVersion}…`);
|
|
106
138
|
return {
|
|
107
139
|
outcome: 'spawn',
|
|
@@ -120,6 +120,7 @@ const metricProperties = zod_1.z.object({
|
|
|
120
120
|
'WAIT_TIMEOUT',
|
|
121
121
|
'SESSION_NOT_FOUND',
|
|
122
122
|
'WORK_ITEM_NOT_FOUND',
|
|
123
|
+
'DIRECTION_AMBIGUOUS',
|
|
123
124
|
'MCP_REMOVED',
|
|
124
125
|
'STATIC_PREVIEW_FAILED',
|
|
125
126
|
'DEV_SERVER_FAILED',
|
|
@@ -164,6 +165,7 @@ const metricProperties = zod_1.z.object({
|
|
|
164
165
|
'usage_error',
|
|
165
166
|
'wait_timeout',
|
|
166
167
|
'session_not_found',
|
|
168
|
+
'direction_ambiguous',
|
|
167
169
|
'mcp_removed',
|
|
168
170
|
'server_start_timeout',
|
|
169
171
|
'handshake_missing',
|
|
@@ -117,7 +117,7 @@ exports.explorationShape = {
|
|
|
117
117
|
baseDirectionId: v3_1.z
|
|
118
118
|
.string()
|
|
119
119
|
.optional()
|
|
120
|
-
.describe('start: sessionId:variantId — refine an existing variant in place'),
|
|
120
|
+
.describe('start: direction ref (e.g. warm-editorial-green), sessionId:variantId, or projectId/sessionId:variantId — refine an existing variant in place'),
|
|
121
121
|
project: v3_1.z.string().trim().min(1).describe('Absolute project root path'),
|
|
122
122
|
};
|
|
123
123
|
//# sourceMappingURL=explorationSchema.js.map
|
|
@@ -17,6 +17,8 @@ const ConfigManager_1 = require("../services/ConfigManager");
|
|
|
17
17
|
const ProjectLibrary_1 = require("../services/ProjectLibrary");
|
|
18
18
|
const VariantHistoryService_1 = require("../services/VariantHistoryService");
|
|
19
19
|
const historyRoots_1 = require("../services/historyRoots");
|
|
20
|
+
const directionRefs_1 = require("../services/directionRefs");
|
|
21
|
+
const projectDirections_1 = require("../services/projectDirections");
|
|
20
22
|
const profileAccess_1 = require("./profileAccess");
|
|
21
23
|
const getExploration = async (input) => {
|
|
22
24
|
const command = 'rivet_get_exploration';
|
|
@@ -68,12 +70,16 @@ const getExploration = async (input) => {
|
|
|
68
70
|
? registered.library.registry.historyRoots(registered.owner.id)
|
|
69
71
|
: [project, ...(0, historyRoots_1.nestedFreshSessionWorkdirs)(project)];
|
|
70
72
|
if (!hasLiveServer || input.includeHistory || input.sessionId) {
|
|
73
|
+
const directions = await (0, projectDirections_1.listProjectDirections)(registered
|
|
74
|
+
? {
|
|
75
|
+
kind: 'library',
|
|
76
|
+
library: registered.library,
|
|
77
|
+
projectId: registered.owner.id,
|
|
78
|
+
}
|
|
79
|
+
: { kind: 'history', history, projectPath: project });
|
|
71
80
|
const entries = registered
|
|
72
|
-
?
|
|
73
|
-
:
|
|
74
|
-
...entry,
|
|
75
|
-
projectPath,
|
|
76
|
-
}))))).flat();
|
|
81
|
+
? directions.filter((entry) => (0, directionRefs_1.isDirectionActive)(entry.manifest.status))
|
|
82
|
+
: directions;
|
|
77
83
|
data.history = entries.filter((entry) => (!input.sessionId || entry.manifest.sessionId === input.sessionId) &&
|
|
78
84
|
(!input.variantId || entry.manifest.variantId === input.variantId));
|
|
79
85
|
if (input.variantId && input.sessionId) {
|
|
@@ -13,6 +13,10 @@ const TARGET_ADDRESSED_PREVIEW_PREFIX = '/__rivet/preview';
|
|
|
13
13
|
const TARGET_ADDRESSED_PREVIEW_KIND_BASE = 'base';
|
|
14
14
|
const TARGET_ADDRESSED_PREVIEW_KIND_HISTORY = 'history';
|
|
15
15
|
const TARGET_ADDRESSED_PREVIEW_KIND_VARIANT = 'variant';
|
|
16
|
+
const CACHE_VALIDATOR_REQUEST_HEADERS = [
|
|
17
|
+
'if-none-match',
|
|
18
|
+
'if-modified-since',
|
|
19
|
+
];
|
|
16
20
|
const hasValidUserDevPort = (userPort) => Number.isInteger(userPort) && userPort > 0;
|
|
17
21
|
const resolveTargetAddressedPreview = (args) => {
|
|
18
22
|
const parsed = new URL(args.rawUrl ?? '/', 'http://rivet.local');
|
|
@@ -152,6 +156,9 @@ const createUserDevServerProxy = (userPort, userHost = 'localhost', options = {}
|
|
|
152
156
|
requestTargets.set(req, target);
|
|
153
157
|
if (target.isTargetAddressed) {
|
|
154
158
|
req.url = target.path;
|
|
159
|
+
for (const header of CACHE_VALIDATOR_REQUEST_HEADERS) {
|
|
160
|
+
delete req.headers[header];
|
|
161
|
+
}
|
|
155
162
|
}
|
|
156
163
|
};
|
|
157
164
|
const getRouterTargetForLibrary = (req) => {
|
|
@@ -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();
|
|
@@ -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: {
|