framer-dalton 0.0.10 → 0.0.11

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/cli.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import fs2 from 'fs';
3
- import path3 from 'path';
2
+ import fs3 from 'fs';
3
+ import path4 from 'path';
4
4
  import { Command } from 'commander';
5
5
  import crypto from 'crypto';
6
6
  import http from 'http';
@@ -10,7 +10,7 @@ import { z } from 'zod';
10
10
  import { fileURLToPath } from 'url';
11
11
  import { createTRPCClient, httpLink } from '@trpc/client';
12
12
 
13
- /* @framer/ai CLI v0.0.10 */
13
+ /* @framer/ai CLI v0.0.11 */
14
14
  var __defProp = Object.defineProperty;
15
15
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
16
16
  function openUrl(url) {
@@ -36,20 +36,20 @@ function openUrl(url) {
36
36
  __name(openUrl, "openUrl");
37
37
  function getConfigDir() {
38
38
  if (process.env.XDG_CONFIG_HOME) {
39
- return path3.join(process.env.XDG_CONFIG_HOME, "framer");
39
+ return path4.join(process.env.XDG_CONFIG_HOME, "framer");
40
40
  }
41
41
  if (process.platform === "win32") {
42
- return path3.join(process.env.APPDATA || os.homedir(), "framer");
42
+ return path4.join(process.env.APPDATA || os.homedir(), "framer");
43
43
  }
44
- return path3.join(os.homedir(), ".config", "framer");
44
+ return path4.join(os.homedir(), ".config", "framer");
45
45
  }
46
46
  __name(getConfigDir, "getConfigDir");
47
47
  function getProjectsConfigPath() {
48
- return path3.join(getConfigDir(), "projects.json");
48
+ return path4.join(getConfigDir(), "projects.json");
49
49
  }
50
50
  __name(getProjectsConfigPath, "getProjectsConfigPath");
51
51
  function getLegacyCredentialsPath() {
52
- return path3.join(getConfigDir(), "credentials.json");
52
+ return path4.join(getConfigDir(), "credentials.json");
53
53
  }
54
54
  __name(getLegacyCredentialsPath, "getLegacyCredentialsPath");
55
55
  var ProjectsConfigSchema = z.object({
@@ -65,11 +65,11 @@ var ProjectsConfigSchema = z.object({
65
65
  });
66
66
  var LegacyCredentialsSchema = z.record(z.string(), z.string());
67
67
  function readJsonFile(filePath) {
68
- if (!fs2.existsSync(filePath)) {
68
+ if (!fs3.existsSync(filePath)) {
69
69
  return null;
70
70
  }
71
71
  try {
72
- return JSON.parse(fs2.readFileSync(filePath, "utf-8"));
72
+ return JSON.parse(fs3.readFileSync(filePath, "utf-8"));
73
73
  } catch (_error) {
74
74
  return null;
75
75
  }
@@ -77,14 +77,14 @@ function readJsonFile(filePath) {
77
77
  __name(readJsonFile, "readJsonFile");
78
78
  function ensureConfigDir() {
79
79
  const configDir = getConfigDir();
80
- if (!fs2.existsSync(configDir)) {
81
- fs2.mkdirSync(configDir, { recursive: true, mode: 448 });
80
+ if (!fs3.existsSync(configDir)) {
81
+ fs3.mkdirSync(configDir, { recursive: true, mode: 448 });
82
82
  }
83
83
  }
84
84
  __name(ensureConfigDir, "ensureConfigDir");
85
85
  function writeProjectsConfig(config) {
86
86
  ensureConfigDir();
87
- fs2.writeFileSync(
87
+ fs3.writeFileSync(
88
88
  getProjectsConfigPath(),
89
89
  JSON.stringify(config, null, " "),
90
90
  {
@@ -111,7 +111,7 @@ function migrateLegacyCredentials() {
111
111
  }
112
112
  const config = { version: 2, projects };
113
113
  writeProjectsConfig(config);
114
- fs2.rmSync(getLegacyCredentialsPath(), { force: true });
114
+ fs3.rmSync(getLegacyCredentialsPath(), { force: true });
115
115
  return config;
116
116
  }
117
117
  __name(migrateLegacyCredentials, "migrateLegacyCredentials");
@@ -124,7 +124,7 @@ function readProjectsConfig() {
124
124
  return result.data;
125
125
  }
126
126
  }
127
- if (fs2.existsSync(getLegacyCredentialsPath())) {
127
+ if (fs3.existsSync(getLegacyCredentialsPath())) {
128
128
  return migrateLegacyCredentials();
129
129
  }
130
130
  return { version: 2, projects: {} };
@@ -14909,8 +14909,8 @@ ${typeDef}`);
14909
14909
  }
14910
14910
  __name(renderDocs, "renderDocs");
14911
14911
  var __filename$1 = fileURLToPath(import.meta.url);
14912
- var __dirname$1 = path3.dirname(__filename$1);
14913
- var VERSION = "0.0.10" ;
14912
+ var __dirname$1 = path4.dirname(__filename$1);
14913
+ var VERSION = "0.0.11" ;
14914
14914
  var RELAY_PORT = Number(process.env.FRAMER_CLI_PORT) || 19988;
14915
14915
  var client = createTRPCClient({
14916
14916
  links: [
@@ -14972,7 +14972,7 @@ async function ensureRelayServerRunning(options = {}) {
14972
14972
  logger?.log("Relay server not running, starting it...");
14973
14973
  }
14974
14974
  const isRunningFromSource = __filename$1.endsWith(".ts");
14975
- const scriptPath = isRunningFromSource ? path3.resolve(__dirname$1, "./start-relay-server.ts") : path3.resolve(__dirname$1, "./start-relay-server.js");
14975
+ const scriptPath = isRunningFromSource ? path4.resolve(__dirname$1, "./start-relay-server.ts") : path4.resolve(__dirname$1, "./start-relay-server.js");
14976
14976
  const serverProcess = spawn(
14977
14977
  isRunningFromSource ? "tsx" : process.execPath,
14978
14978
  [scriptPath],
@@ -14994,16 +14994,37 @@ async function ensureRelayServerRunning(options = {}) {
14994
14994
  throw new Error("Failed to start relay server after 5 seconds");
14995
14995
  }
14996
14996
  __name(ensureRelayServerRunning, "ensureRelayServerRunning");
14997
+ var FRAMER_TEMPORARY_DIR = path4.join(os.tmpdir(), "framer");
14998
+ function ensureTemporaryDir() {
14999
+ fs3.mkdirSync(FRAMER_TEMPORARY_DIR, { recursive: true });
15000
+ }
15001
+ __name(ensureTemporaryDir, "ensureTemporaryDir");
15002
+ function isTemporaryFile(filePath) {
15003
+ const absolutePath = path4.resolve(filePath);
15004
+ const isInTemporaryDir = absolutePath.startsWith(
15005
+ FRAMER_TEMPORARY_DIR + path4.sep
15006
+ );
15007
+ const isFile = fs3.statSync(absolutePath, { throwIfNoEntry: false })?.isFile() ?? false;
15008
+ return isInTemporaryDir && isFile;
15009
+ }
15010
+ __name(isTemporaryFile, "isTemporaryFile");
15011
+ function removeTemporaryFile(filePath) {
15012
+ fs3.unlinkSync(filePath);
15013
+ }
15014
+ __name(removeTemporaryFile, "removeTemporaryFile");
15015
+
15016
+ // src/skills.ts
14997
15017
  var META_SKILL_NAME = "framer";
14998
15018
  var CODE_COMPONENTS_SKILL_NAME = "framer-code-components";
14999
- var __dirname2 = path3.dirname(fileURLToPath(import.meta.url));
15000
- var skillsDocsDir = path3.join(__dirname2, "..", "docs", "skills");
15019
+ var __dirname2 = path4.dirname(fileURLToPath(import.meta.url));
15020
+ var skillsDocsDir = path4.join(__dirname2, "..", "docs", "skills");
15001
15021
  function readSkillDoc(name) {
15002
- return fs2.readFileSync(path3.join(skillsDocsDir, name), "utf-8").trimEnd();
15022
+ return fs3.readFileSync(path4.join(skillsDocsDir, name), "utf-8").trimEnd();
15003
15023
  }
15004
15024
  __name(readSkillDoc, "readSkillDoc");
15005
15025
  function buildMetaSkill() {
15006
- return `${readSkillDoc("framer.md")}
15026
+ const template = readSkillDoc("framer.md");
15027
+ return `${renderTemplate(template, { FRAMER_TEMPORARY_DIR })}
15007
15028
  `;
15008
15029
  }
15009
15030
  __name(buildMetaSkill, "buildMetaSkill");
@@ -15033,36 +15054,37 @@ function buildProjectCanvasSkill(projectId, agentContext, canvasPrompt) {
15033
15054
  PROJECT_ID: projectId,
15034
15055
  GENERATED_AT: (/* @__PURE__ */ new Date()).toISOString(),
15035
15056
  CANVAS_PROMPT: canvasPrompt.trimEnd(),
15036
- AGENT_CONTEXT: agentContext.trimEnd()
15057
+ AGENT_CONTEXT: agentContext.trimEnd(),
15058
+ FRAMER_TEMPORARY_DIR
15037
15059
  })}
15038
15060
  `;
15039
15061
  return { skillName, content };
15040
15062
  }
15041
15063
  __name(buildProjectCanvasSkill, "buildProjectCanvasSkill");
15042
15064
  function writeSkill(root, skillName, content) {
15043
- fs2.mkdirSync(root, { recursive: true });
15044
- const rootStat = fs2.statSync(root);
15065
+ fs3.mkdirSync(root, { recursive: true });
15066
+ const rootStat = fs3.statSync(root);
15045
15067
  if (!rootStat.isDirectory()) {
15046
15068
  throw new Error(`Skill root is not a directory: ${root}`);
15047
15069
  }
15048
- const skillDir = path3.join(root, skillName);
15049
- const filePath = path3.join(skillDir, "SKILL.md");
15050
- if (fs2.existsSync(skillDir)) {
15051
- const current = fs2.lstatSync(skillDir);
15070
+ const skillDir = path4.join(root, skillName);
15071
+ const filePath = path4.join(skillDir, "SKILL.md");
15072
+ if (fs3.existsSync(skillDir)) {
15073
+ const current = fs3.lstatSync(skillDir);
15052
15074
  if (current.isSymbolicLink() || !current.isDirectory()) {
15053
- fs2.rmSync(skillDir, { recursive: true, force: true });
15075
+ fs3.rmSync(skillDir, { recursive: true, force: true });
15054
15076
  }
15055
15077
  }
15056
- fs2.mkdirSync(skillDir, { recursive: true });
15057
- fs2.writeFileSync(filePath, content, "utf-8");
15078
+ fs3.mkdirSync(skillDir, { recursive: true });
15079
+ fs3.writeFileSync(filePath, content, "utf-8");
15058
15080
  return filePath;
15059
15081
  }
15060
15082
  __name(writeSkill, "writeSkill");
15061
15083
  function getDefaultSkillRoots() {
15062
15084
  const home = os.homedir();
15063
15085
  return [
15064
- path3.join(home, ".agents", "skills"),
15065
- path3.join(home, ".claude", "skills")
15086
+ path4.join(home, ".agents", "skills"),
15087
+ path4.join(home, ".claude", "skills")
15066
15088
  ];
15067
15089
  }
15068
15090
  __name(getDefaultSkillRoots, "getDefaultSkillRoots");
@@ -15111,8 +15133,8 @@ function printSetupSummary(results) {
15111
15133
  const installLocations = /* @__PURE__ */ new Set();
15112
15134
  for (const result of results) {
15113
15135
  for (const filePath of result.paths) {
15114
- const skillDir = path3.dirname(filePath);
15115
- const root = path3.dirname(skillDir);
15136
+ const skillDir = path4.dirname(filePath);
15137
+ const root = path4.dirname(skillDir);
15116
15138
  installLocations.add(root);
15117
15139
  }
15118
15140
  }
@@ -15216,14 +15238,18 @@ async function ensureRelayForCli() {
15216
15238
  __name(ensureRelayForCli, "ensureRelayForCli");
15217
15239
  program.option("-s, --session <id>", "Session ID (required for code execution)").option("-e, --eval <code>", "Code to execute (or pipe via stdin)").option("-f, --file <path>", "File containing code to execute").action(async (options) => {
15218
15240
  const { session: sessionId, eval: evalCode, file: filePath } = options;
15241
+ ensureTemporaryDir();
15219
15242
  let code = evalCode;
15220
15243
  if (!code && filePath) {
15221
15244
  try {
15222
- code = fs2.readFileSync(filePath, "utf-8");
15245
+ code = fs3.readFileSync(filePath, "utf-8");
15223
15246
  } catch (err) {
15224
15247
  printError(`Failed to read file: ${formatError(err)}`);
15225
15248
  process.exit(1);
15226
15249
  }
15250
+ if (isTemporaryFile(filePath)) {
15251
+ removeTemporaryFile(filePath);
15252
+ }
15227
15253
  }
15228
15254
  if (!code && !process.stdin.isTTY) {
15229
15255
  code = await readStdin();
@@ -13,7 +13,7 @@ import { createRequire } from 'module';
13
13
  import * as vm from 'vm';
14
14
  import { connect } from 'framer-api';
15
15
 
16
- /* @framer/ai relay server v0.0.10 */
16
+ /* @framer/ai relay server v0.0.11 */
17
17
  var __defProp = Object.defineProperty;
18
18
  var __knownSymbol = (name, symbol) => (symbol = Symbol[name]) ? symbol : /* @__PURE__ */ Symbol.for("Symbol." + name);
19
19
  var __typeError = (msg) => {
@@ -91,7 +91,7 @@ function log(message) {
91
91
  __name(log, "log");
92
92
  var __filename$1 = fileURLToPath(import.meta.url);
93
93
  path.dirname(__filename$1);
94
- var VERSION = "0.0.10" ;
94
+ var VERSION = "0.0.11" ;
95
95
  var RELAY_PORT = Number(process.env.FRAMER_CLI_PORT) || 19988;
96
96
  createTRPCClient({
97
97
  links: [
@@ -456,25 +456,24 @@ async function execute(session, framer, code, options = {}) {
456
456
  }
457
457
  }
458
458
  __name(execute, "execute");
459
- async function executeWithReconnect(session, framer, code, options, reconnect) {
459
+ async function executeWithReconnect(session, framer, code, options, reconnect, execId) {
460
460
  const result = await tryExecute(session, framer, code, options);
461
461
  if (!result.error || !isConnectionError(result.error)) {
462
462
  return result;
463
463
  }
464
- log(
465
- `reconnect session=${session.id} project=${session.projectId} reason="${result.error}"`
466
- );
464
+ const reqId = framer.requestId;
465
+ const tag = `exec=${execId} session=${session.id}${reqId ? ` req=${reqId}` : ""}`;
466
+ log(`reconnect ${tag} project=${session.projectId} reason="${result.error}"`);
467
467
  const newFramer = await reconnect();
468
468
  if (!newFramer) {
469
- log(
470
- `reconnect.failed session=${session.id} error="no connection returned"`
471
- );
469
+ log(`reconnect.failed ${tag} error="no connection returned"`);
472
470
  return {
473
471
  output: [],
474
472
  error: "Connection lost and failed to reconnect"
475
473
  };
476
474
  }
477
- log(`reconnect.success session=${session.id}`);
475
+ const newReqId = newFramer.requestId;
476
+ log(`reconnect.success ${tag}${newReqId ? ` new_req=${newReqId}` : ""}`);
478
477
  return tryExecute(session, newFramer, code, options);
479
478
  }
480
479
  __name(executeWithReconnect, "executeWithReconnect");
@@ -522,6 +521,10 @@ var ConnectionPool = class {
522
521
  const entry = this.pool.get(projectId);
523
522
  if (entry) {
524
523
  entry.sessions.add(session);
524
+ if (!entry.connected) {
525
+ await entry.connection.reconnect();
526
+ entry.connected = true;
527
+ }
525
528
  return entry.connection;
526
529
  }
527
530
  const connection = await connect(projectId, apiKey);
@@ -645,6 +648,9 @@ var SessionManager = class {
645
648
  getFramer(session) {
646
649
  return connectionPool.getConnection(session.projectId);
647
650
  }
651
+ isConnected(session) {
652
+ return connectionPool.isConnected(session.projectId);
653
+ }
648
654
  async reconnect(session) {
649
655
  return connectionPool.reconnect(session.projectId);
650
656
  }
@@ -696,13 +702,23 @@ var SessionManager = class {
696
702
  }
697
703
  async reapIdleSessions() {
698
704
  const now = Date.now();
699
- const disconnects = [];
705
+ const projectSessions = /* @__PURE__ */ new Map();
700
706
  for (const session of this.sessions.values()) {
701
- if (session.inflight > 0) continue;
702
- if (now - session.lastActivityAt < SESSION_IDLE_TIMEOUT_MS) continue;
703
- if (!connectionPool.isConnected(session.projectId)) continue;
704
- const { projectId } = session;
705
- log(`idle disconnect project=${projectId}`);
707
+ const existing = projectSessions.get(session.projectId);
708
+ if (existing) existing.push(session);
709
+ else projectSessions.set(session.projectId, [session]);
710
+ }
711
+ const disconnects = [];
712
+ for (const [projectId, sessions] of projectSessions) {
713
+ if (!connectionPool.isConnected(projectId)) continue;
714
+ const allIdle = sessions.every(
715
+ (s) => s.inflight === 0 && now - s.lastActivityAt >= SESSION_IDLE_TIMEOUT_MS
716
+ );
717
+ if (!allIdle) continue;
718
+ const reqId = connectionPool.getConnection(projectId)?.requestId;
719
+ log(
720
+ `idle disconnect project=${projectId}${reqId ? ` req=${reqId}` : ""}`
721
+ );
706
722
  disconnects.push(connectionPool.disconnect(projectId));
707
723
  }
708
724
  const results = await Promise.allSettled(disconnects);
@@ -719,6 +735,7 @@ var sessionManager = new SessionManager();
719
735
 
720
736
  // src/router.ts
721
737
  var t = initTRPC.create();
738
+ var nextExecId = 0;
722
739
  var appRouter = t.router({
723
740
  version: t.procedure.query(() => {
724
741
  return { version: VERSION };
@@ -761,11 +778,19 @@ var appRouter = t.router({
761
778
  });
762
779
  }
763
780
  const _guard = __using(_stack, sessionManager.exec(sessionId));
764
- log(
765
- `exec session=${sessionId} code=${JSON.stringify(code).slice(0, 100)}`
766
- );
767
- const framer = sessionManager.getFramer(session);
781
+ const execId = nextExecId++;
782
+ let framer = sessionManager.getFramer(session);
783
+ if (framer && !sessionManager.isConnected(session)) {
784
+ log(
785
+ `exec.reconnect exec=${execId} session=${sessionId} reason="idle disconnected"`
786
+ );
787
+ framer = await sessionManager.reconnect(session);
788
+ }
789
+ const reqId = framer?.requestId;
790
+ const tag = `exec=${execId} session=${sessionId}${reqId ? ` req=${reqId}` : ""}`;
791
+ log(`exec ${tag} code=${JSON.stringify(code).slice(0, 100)}`);
768
792
  if (!framer) {
793
+ log(`exec.error ${tag} error="no connection"`);
769
794
  return {
770
795
  output: [],
771
796
  error: "Failed to get connection for session"
@@ -776,10 +801,11 @@ var appRouter = t.router({
776
801
  framer,
777
802
  code,
778
803
  { cwd },
779
- () => sessionManager.reconnect(session)
804
+ () => sessionManager.reconnect(session),
805
+ execId
780
806
  );
781
807
  if (result.error) {
782
- log(`exec.error session=${sessionId} error="${result.error}"`);
808
+ log(`exec.error ${tag} error="${result.error}"`);
783
809
  }
784
810
  return result;
785
811
  } catch (_) {
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: {{SKILL_NAME}}
3
3
  description: "Project-scoped Framer canvas editing skill for project {{PROJECT_ID}}. Very important: never load this skill without having already read the `framer` skill and without having already run `session new`, which will dynamically update this skill."
4
- allowed-tools: ["Bash(npx framer-dalton:*)", "Bash(npx framer-dalton@latest:*)", "Write(/tmp/framer-*)"]
4
+ allowed-tools: ["Bash(npx framer-dalton:*)", "Bash(npx framer-dalton@latest:*)", "Write({{FRAMER_TEMPORARY_DIR}}/*)"]
5
5
  ---
6
6
 
7
7
  ## Project Scope
@@ -27,26 +27,26 @@ allowed-tools: ["Bash(npx framer-dalton:*)", "Bash(npx framer-dalton@latest:*)",
27
27
  ## Workflow Loop
28
28
 
29
29
  ```bash
30
- # 1) Read page structure first — write code to /tmp/framer-<sessionId>.js, then execute with -f
31
- # /tmp/framer-<sessionId>.js:
30
+ # 1) Read page structure first — write code to a unique file, then execute with -f
31
+ # {{FRAMER_TEMPORARY_DIR}}/<sessionId>-read-page.js:
32
32
  # const { results } = await framer.readProjectForAgent(
33
33
  # [{ type: "page", path: "/" }],
34
34
  # { pagePath: "/" }
35
35
  # );
36
36
  # console.log(results);
37
37
 
38
- framer -s <sessionId> -f /tmp/framer-<sessionId>.js
38
+ framer -s <sessionId> -f {{FRAMER_TEMPORARY_DIR}}/<sessionId>-read-page.js
39
39
 
40
40
  # 2) Request additional targeted queries only if needed
41
41
 
42
42
  # 3) Apply changes in a later call, once `dsl` has been prepared
43
- # /tmp/framer-<sessionId>.js:
43
+ # {{FRAMER_TEMPORARY_DIR}}/<sessionId>-apply-changes.js:
44
44
  # const dsl = `
45
45
  # ...your canvas DSL...
46
46
  # `;
47
47
  # await framer.applyAgentChanges(dsl, { pagePath: "/" });
48
48
 
49
- framer -s <sessionId> -f /tmp/framer-<sessionId>.js
49
+ framer -s <sessionId> -f {{FRAMER_TEMPORARY_DIR}}/<sessionId>-apply-changes.js
50
50
  ```
51
51
 
52
52
  ## Live Agent System Prompt
@@ -3,7 +3,7 @@ name: framer
3
3
  description: >
4
4
  Use when the user wants to design, edit, or publish a website or web page — creating layouts, editing sections, updating text or images, managing CMS collections and content, syncing external data, creating or modifying code components, managing color and text styles, handling localization, or publishing deployments. Trigger when the user mentions Framer, references their website or web pages, asks to edit designs, update site content, or work with any Framer project — even if they don't explicitly say 'Framer'.
5
5
  **Mandatory precondition**: run `npx framer-dalton@latest setup` and let it complete **BEFORE** loading this skill.
6
- allowed-tools: ["Bash(npx framer-dalton:*)", "Bash(npx framer-dalton@latest:*)", "Write(/tmp/framer-*)"]
6
+ allowed-tools: ["Bash(npx framer-dalton:*)", "Bash(npx framer-dalton@latest:*)", "Write({{FRAMER_TEMPORARY_DIR}}/*)"]
7
7
  ---
8
8
 
9
9
  If you didn't run this command before loading the skill, run it now:
@@ -59,14 +59,12 @@ npx framer-dalton docs Collection.getItems # What are the parameters and return
59
59
 
60
60
  #### 3. Execute code
61
61
 
62
- Only after checking docs, write your code to a `framer-<sessionId>.js` file in the OS temp directory and execute with `-f`. Use the session ID in the filename to avoid collisions between parallel sessions:
62
+ Only after checking docs, write your code to a unique file under `{{FRAMER_TEMPORARY_DIR}}/` and execute with `-f`. Name each file `<sessionId>-<short-summary>.js` where `<short-summary>` is a brief kebab-case description (e.g., `1-read-collections.js`, `1-add-team-member.js`). Files are automatically deleted after execution.
63
63
 
64
64
  ```bash
65
- npx framer-dalton -s 1 -f /tmp/framer-1.js
65
+ npx framer-dalton -s 1 -f {{FRAMER_TEMPORARY_DIR}}/1-read-collections.js
66
66
  ```
67
67
 
68
- On Windows, use the equivalent temp directory (e.g. `%TEMP%\framer-1.js`).
69
-
70
68
  #### 4. Store results in `state`
71
69
 
72
70
  Always save results you'll need again. Don't repeat API calls.
@@ -93,22 +91,22 @@ Always save results you'll need again. Don't repeat API calls.
93
91
  **Always store results in `state` when you'll need them again.** API calls are slow - don't repeat them.
94
92
 
95
93
  ```js
96
- // /tmp/framer-1.js
94
+ // {{FRAMER_TEMPORARY_DIR}}/1-get-collections.js
97
95
  state.collections = await framer.getCollections();
98
96
  ```
99
97
 
100
98
  ```bash
101
- npx framer-dalton -s 1 -f /tmp/framer-1.js
99
+ npx framer-dalton -s 1 -f {{FRAMER_TEMPORARY_DIR}}/1-get-collections.js
102
100
  ```
103
101
 
104
102
  ```js
105
- // /tmp/framer-1.js — reuse from state
103
+ // {{FRAMER_TEMPORARY_DIR}}/1-get-team-items.js — reuse from state
106
104
  state.teamItems = await state.collections.find(c => c.name === 'Team').getItems();
107
105
  console.log(state.teamItems.length);
108
106
  ```
109
107
 
110
108
  ```bash
111
- npx framer-dalton -s 1 -f /tmp/framer-1.js
109
+ npx framer-dalton -s 1 -f {{FRAMER_TEMPORARY_DIR}}/1-get-team-items.js
112
110
  ```
113
111
 
114
112
  Store anything you'll reference again.
@@ -144,10 +142,10 @@ After session creation, load the dynamically created project-scoped skill `frame
144
142
 
145
143
  ## Execute Code
146
144
 
147
- Write your code to `framer-<sessionId>.js` in the OS temp directory and execute with `-f`:
145
+ Write your code to a unique file under `{{FRAMER_TEMPORARY_DIR}}/` and execute with `-f`:
148
146
 
149
147
  ```bash
150
- npx framer-dalton -s <sessionId> -f /tmp/framer-<sessionId>.js
148
+ npx framer-dalton -s <sessionId> -f {{FRAMER_TEMPORARY_DIR}}/<sessionId>-<short-summary>.js
151
149
  ```
152
150
 
153
151
  ## API Documentation
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "framer-dalton",
3
- "version": "0.0.10",
3
+ "version": "0.0.11",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "framer-dalton": "./dist/cli.js"