framer-dalton 0.0.24 → 0.0.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -5
- package/dist/cli.js +347 -36
- package/dist/start-relay-server.js +112 -27
- package/docs/skills/framer-code-components.md +1 -1
- package/docs/skills/framer-project.md +439 -0
- package/docs/skills/framer.md +6 -383
- package/package.json +8 -7
- package/docs/skills/framer-canvas-editing-project.md +0 -49
|
@@ -2,6 +2,7 @@ import fs4 from 'fs';
|
|
|
2
2
|
import os from 'os';
|
|
3
3
|
import path from 'path';
|
|
4
4
|
import 'child_process';
|
|
5
|
+
import 'net';
|
|
5
6
|
import { fileURLToPath } from 'url';
|
|
6
7
|
import { createTRPCClient, httpLink } from '@trpc/client';
|
|
7
8
|
import crypto, { randomUUID, timingSafeEqual } from 'crypto';
|
|
@@ -13,7 +14,7 @@ import { z } from 'zod';
|
|
|
13
14
|
import { createRequire } from 'module';
|
|
14
15
|
import * as vm from 'vm';
|
|
15
16
|
|
|
16
|
-
/* @framer/ai relay server v0.0.
|
|
17
|
+
/* @framer/ai relay server v0.0.26 */
|
|
17
18
|
var __defProp = Object.defineProperty;
|
|
18
19
|
var __knownSymbol = (name2, symbol) => (symbol = Symbol[name2]) ? symbol : /* @__PURE__ */ Symbol.for("Symbol." + name2);
|
|
19
20
|
var __typeError = (msg) => {
|
|
@@ -159,7 +160,7 @@ __name(debug, "debug");
|
|
|
159
160
|
// src/version.ts
|
|
160
161
|
var VERSION = (
|
|
161
162
|
// typeof is used to ensure this can be used just via tsx or node etc. without build
|
|
162
|
-
"0.0.
|
|
163
|
+
"0.0.26"
|
|
163
164
|
);
|
|
164
165
|
|
|
165
166
|
// src/relay-client.ts
|
|
@@ -181,6 +182,35 @@ createTRPCClient({
|
|
|
181
182
|
]
|
|
182
183
|
});
|
|
183
184
|
|
|
185
|
+
// src/agent-thread-context.ts
|
|
186
|
+
var MAX_AGENT_THREAD_ID_LENGTH = 256;
|
|
187
|
+
var MAX_AGENT_PROVIDER_LENGTH = 64;
|
|
188
|
+
var SAFE_VALUE_PATTERN = /^[A-Za-z0-9._:-]+$/;
|
|
189
|
+
function normalizeValue(value, maxLength) {
|
|
190
|
+
const trimmed = value?.trim();
|
|
191
|
+
if (!trimmed) return void 0;
|
|
192
|
+
if (trimmed.length > maxLength) return void 0;
|
|
193
|
+
if (!SAFE_VALUE_PATTERN.test(trimmed)) return void 0;
|
|
194
|
+
return trimmed;
|
|
195
|
+
}
|
|
196
|
+
__name(normalizeValue, "normalizeValue");
|
|
197
|
+
function normalizeAgentThreadContext(input) {
|
|
198
|
+
const agentThreadId = normalizeValue(
|
|
199
|
+
input.agentThreadId,
|
|
200
|
+
MAX_AGENT_THREAD_ID_LENGTH
|
|
201
|
+
);
|
|
202
|
+
if (!agentThreadId) return {};
|
|
203
|
+
const agentProvider = normalizeValue(
|
|
204
|
+
input.agentProvider,
|
|
205
|
+
MAX_AGENT_PROVIDER_LENGTH
|
|
206
|
+
);
|
|
207
|
+
return {
|
|
208
|
+
agentThreadId,
|
|
209
|
+
...agentProvider ? { agentProvider } : {}
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
__name(normalizeAgentThreadContext, "normalizeAgentThreadContext");
|
|
213
|
+
|
|
184
214
|
// src/connection-errors.ts
|
|
185
215
|
var CONNECTION_ERROR_PATTERNS = [
|
|
186
216
|
"Connection closed",
|
|
@@ -197,8 +227,15 @@ var CONNECTION_ERROR_PATTERNS = [
|
|
|
197
227
|
// Our own check in executor.ts
|
|
198
228
|
"Execution timed out after",
|
|
199
229
|
// Likely dead connection
|
|
200
|
-
"Session expired"
|
|
230
|
+
"Session expired",
|
|
201
231
|
// Server-side session expiry
|
|
232
|
+
// Typed page-death (PROJECT_CLOSED) for the string fallback; isRetryableError is the primary path.
|
|
233
|
+
"Project session crashed",
|
|
234
|
+
// PageCrashedError (renderer crash / OOM)
|
|
235
|
+
"Project was closed",
|
|
236
|
+
// StaleSessionError (page closed/reaped)
|
|
237
|
+
"Session was recycled"
|
|
238
|
+
// SessionRecycledError (destroy->respawn reconnect race)
|
|
202
239
|
];
|
|
203
240
|
function isConnectionError(errorMessage) {
|
|
204
241
|
return CONNECTION_ERROR_PATTERNS.some(
|
|
@@ -206,6 +243,18 @@ function isConnectionError(errorMessage) {
|
|
|
206
243
|
);
|
|
207
244
|
}
|
|
208
245
|
__name(isConnectionError, "isConnectionError");
|
|
246
|
+
function isRetryableError(err) {
|
|
247
|
+
if (err && typeof err === "object") {
|
|
248
|
+
const e = err;
|
|
249
|
+
if (e.retryable === true) return true;
|
|
250
|
+
if (e.code === "PROJECT_CLOSED") return true;
|
|
251
|
+
if (typeof e.message === "string" && isConnectionError(e.message))
|
|
252
|
+
return true;
|
|
253
|
+
return false;
|
|
254
|
+
}
|
|
255
|
+
return typeof err === "string" && isConnectionError(err);
|
|
256
|
+
}
|
|
257
|
+
__name(isRetryableError, "isRetryableError");
|
|
209
258
|
var AUTH_ERROR_PATTERNS = ["does not have access", "UNAUTHORIZED"];
|
|
210
259
|
function isAuthError(errorMessage) {
|
|
211
260
|
return AUTH_ERROR_PATTERNS.some((p) => errorMessage.includes(p));
|
|
@@ -540,20 +589,37 @@ async function execute(session, code, options = {}) {
|
|
|
540
589
|
return { output };
|
|
541
590
|
} catch (err) {
|
|
542
591
|
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
543
|
-
|
|
592
|
+
const retryable = isRetryableError(err);
|
|
593
|
+
if (retryable || isConnectionError(errorMessage)) {
|
|
544
594
|
session.connection.markDisconnected();
|
|
545
595
|
}
|
|
546
596
|
const errorRef = getErrorRef(err);
|
|
547
597
|
return {
|
|
548
598
|
output,
|
|
549
599
|
error: errorMessage,
|
|
550
|
-
...errorRef ? { errorRef } : {}
|
|
600
|
+
...errorRef ? { errorRef } : {},
|
|
601
|
+
...retryable ? { retryable: true } : {}
|
|
551
602
|
};
|
|
552
603
|
} finally {
|
|
553
604
|
if (timeoutId) clearTimeout(timeoutId);
|
|
554
605
|
}
|
|
555
606
|
}
|
|
556
607
|
__name(execute, "execute");
|
|
608
|
+
function isReconnectable(err) {
|
|
609
|
+
return isRetryableError(err) || isConnectionError(err instanceof Error ? err.message : String(err));
|
|
610
|
+
}
|
|
611
|
+
__name(isReconnectable, "isReconnectable");
|
|
612
|
+
function connectionFailureResult(prefix, err) {
|
|
613
|
+
const inner = err instanceof Error ? err.message : String(err);
|
|
614
|
+
const errorRef = getErrorRef(err);
|
|
615
|
+
return {
|
|
616
|
+
output: [],
|
|
617
|
+
error: `${prefix}: ${inner}`,
|
|
618
|
+
...errorRef ? { errorRef } : {},
|
|
619
|
+
...isRetryableError(err) ? { retryable: true } : {}
|
|
620
|
+
};
|
|
621
|
+
}
|
|
622
|
+
__name(connectionFailureResult, "connectionFailureResult");
|
|
557
623
|
async function executeWithReconnect(session, code, options, execId) {
|
|
558
624
|
if (!session.connection.isConnected()) {
|
|
559
625
|
log(
|
|
@@ -562,17 +628,27 @@ async function executeWithReconnect(session, code, options, execId) {
|
|
|
562
628
|
try {
|
|
563
629
|
await session.connection.reconnect();
|
|
564
630
|
} catch (err) {
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
631
|
+
if (!isReconnectable(err)) {
|
|
632
|
+
return connectionFailureResult(
|
|
633
|
+
"Failed to get connection for session",
|
|
634
|
+
err
|
|
635
|
+
);
|
|
636
|
+
}
|
|
637
|
+
log(
|
|
638
|
+
`exec.reconnect.retry exec=${execId} session=${session.id} reason="${err instanceof Error ? err.message : String(err)}"`
|
|
639
|
+
);
|
|
640
|
+
try {
|
|
641
|
+
await session.connection.reconnect();
|
|
642
|
+
} catch (err2) {
|
|
643
|
+
return connectionFailureResult(
|
|
644
|
+
"Failed to get connection for session",
|
|
645
|
+
err2
|
|
646
|
+
);
|
|
647
|
+
}
|
|
572
648
|
}
|
|
573
649
|
}
|
|
574
650
|
const result = await execute(session, code, options);
|
|
575
|
-
if (!result.error || !isConnectionError(result.error)) {
|
|
651
|
+
if (!result.error || !(result.retryable || isConnectionError(result.error))) {
|
|
576
652
|
return result;
|
|
577
653
|
}
|
|
578
654
|
log(
|
|
@@ -581,16 +657,13 @@ async function executeWithReconnect(session, code, options, execId) {
|
|
|
581
657
|
try {
|
|
582
658
|
await session.connection.reconnect();
|
|
583
659
|
} catch (err) {
|
|
584
|
-
const inner = err instanceof Error ? err.message : String(err);
|
|
585
|
-
const errorRef = getErrorRef(err);
|
|
586
660
|
log(
|
|
587
|
-
`reconnect.failed exec=${execId} session=${session.id} req=${session.connection.framer.requestId} error="${
|
|
661
|
+
`reconnect.failed exec=${execId} session=${session.id} req=${session.connection.framer.requestId} error="${err instanceof Error ? err.message : String(err)}"`
|
|
662
|
+
);
|
|
663
|
+
return connectionFailureResult(
|
|
664
|
+
"Connection lost and failed to reconnect",
|
|
665
|
+
err
|
|
588
666
|
);
|
|
589
|
-
return {
|
|
590
|
-
output: [],
|
|
591
|
-
error: `Connection lost and failed to reconnect: ${inner}`,
|
|
592
|
-
...errorRef ? { errorRef } : {}
|
|
593
|
-
};
|
|
594
667
|
}
|
|
595
668
|
log(
|
|
596
669
|
`reconnect.success exec=${execId} session=${session.id} req=${session.connection.framer.requestId}`
|
|
@@ -896,10 +969,11 @@ var Connection = class _Connection {
|
|
|
896
969
|
headlessServerUrl: this.headlessServerUrl
|
|
897
970
|
}));
|
|
898
971
|
}
|
|
899
|
-
createSession(id) {
|
|
972
|
+
createSession(id, agentThreadContext) {
|
|
900
973
|
const session = {
|
|
901
974
|
id,
|
|
902
975
|
state: {},
|
|
976
|
+
agentThreadContext,
|
|
903
977
|
lastActivityAt: Date.now(),
|
|
904
978
|
inflight: 0,
|
|
905
979
|
connection: this
|
|
@@ -970,14 +1044,17 @@ var SessionManager = class {
|
|
|
970
1044
|
}
|
|
971
1045
|
connections = [];
|
|
972
1046
|
idleCheck = null;
|
|
973
|
-
async create(projectId, userId, apiKey, headlessServerUrl) {
|
|
1047
|
+
async create(projectId, userId, apiKey, headlessServerUrl, agentThreadContext = {}) {
|
|
974
1048
|
const connection = await this.findOrCreateConnection(
|
|
975
1049
|
projectId,
|
|
976
1050
|
userId,
|
|
977
1051
|
apiKey,
|
|
978
1052
|
headlessServerUrl
|
|
979
1053
|
);
|
|
980
|
-
const session = connection.createSession(
|
|
1054
|
+
const session = connection.createSession(
|
|
1055
|
+
this.getNextSessionId(),
|
|
1056
|
+
agentThreadContext
|
|
1057
|
+
);
|
|
981
1058
|
this.startIdleCheck();
|
|
982
1059
|
return session;
|
|
983
1060
|
}
|
|
@@ -1007,6 +1084,7 @@ var SessionManager = class {
|
|
|
1007
1084
|
projectId: session.connection.projectId,
|
|
1008
1085
|
userId: session.connection.userId,
|
|
1009
1086
|
sessionId: session.connection.getServerSessionId(),
|
|
1087
|
+
...session.agentThreadContext,
|
|
1010
1088
|
durationMs,
|
|
1011
1089
|
hasError: result.error !== void 0,
|
|
1012
1090
|
...result.error ? { errorMessage: result.error } : {}
|
|
@@ -1047,7 +1125,8 @@ var SessionManager = class {
|
|
|
1047
1125
|
trackSessionDestroy({
|
|
1048
1126
|
projectId: session.connection.projectId,
|
|
1049
1127
|
userId: session.connection.userId,
|
|
1050
|
-
sessionId: session.connection.getServerSessionId()
|
|
1128
|
+
sessionId: session.connection.getServerSessionId(),
|
|
1129
|
+
...session.agentThreadContext
|
|
1051
1130
|
});
|
|
1052
1131
|
session.connection.removeSession(id);
|
|
1053
1132
|
if (!session.connection.hasSessions()) {
|
|
@@ -1201,16 +1280,20 @@ var appRouter = t.router({
|
|
|
1201
1280
|
projectId: z.string(),
|
|
1202
1281
|
apiKey: z.string(),
|
|
1203
1282
|
userId: z.string().optional(),
|
|
1204
|
-
headlessServerUrl: z.string()
|
|
1283
|
+
headlessServerUrl: z.string(),
|
|
1284
|
+
agentThreadId: z.string().optional(),
|
|
1285
|
+
agentProvider: z.string().optional()
|
|
1205
1286
|
})
|
|
1206
1287
|
).mutation(async ({ input }) => {
|
|
1207
1288
|
const start = performance.now();
|
|
1289
|
+
const agentThreadContext = normalizeAgentThreadContext(input);
|
|
1208
1290
|
try {
|
|
1209
1291
|
const session = await sessionManager.create(
|
|
1210
1292
|
input.projectId,
|
|
1211
1293
|
input.userId,
|
|
1212
1294
|
input.apiKey,
|
|
1213
|
-
input.headlessServerUrl
|
|
1295
|
+
input.headlessServerUrl,
|
|
1296
|
+
agentThreadContext
|
|
1214
1297
|
);
|
|
1215
1298
|
log(
|
|
1216
1299
|
`session.new id=${session.id} project=${input.projectId} headlessServerUrl=${input.headlessServerUrl}`
|
|
@@ -1219,6 +1302,7 @@ var appRouter = t.router({
|
|
|
1219
1302
|
projectId: input.projectId,
|
|
1220
1303
|
userId: session.connection.userId,
|
|
1221
1304
|
sessionId: session.connection.getServerSessionId(),
|
|
1305
|
+
...session.agentThreadContext,
|
|
1222
1306
|
durationMs: Math.round(performance.now() - start)
|
|
1223
1307
|
});
|
|
1224
1308
|
return { id: session.id };
|
|
@@ -1228,6 +1312,7 @@ var appRouter = t.router({
|
|
|
1228
1312
|
errorType: "session_create_error",
|
|
1229
1313
|
projectId: input.projectId,
|
|
1230
1314
|
userId: input.userId,
|
|
1315
|
+
...agentThreadContext,
|
|
1231
1316
|
errorMessage: message
|
|
1232
1317
|
});
|
|
1233
1318
|
throw new TRPCError({
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: framer-code-components
|
|
3
|
-
description: "Framer code component implementation guidance, platform constraints, layout annotations, property controls, and authoring best practices. Use only after loading the framer skill first in the same task; never load this skill directly as the entry point."
|
|
3
|
+
description: "Framer code component implementation guidance, platform constraints, layout annotations, property controls, and authoring best practices. Use only after loading the framer skill and the generated framer-project-<projectId> skill first in the same task; never load this skill directly as the entry point."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Framer Code Components
|