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.
@@ -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.24 */
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.24"
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
- if (isConnectionError(errorMessage)) {
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
- const inner = err instanceof Error ? err.message : String(err);
566
- const errorRef = getErrorRef(err);
567
- return {
568
- output: [],
569
- error: `Failed to get connection for session: ${inner}`,
570
- ...errorRef ? { errorRef } : {}
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="${inner}"`
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(this.getNextSessionId());
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