@letta-ai/letta-code 0.11.2-next.1 → 0.11.2-next.3

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/letta.js CHANGED
@@ -3237,7 +3237,7 @@ var package_default;
3237
3237
  var init_package = __esm(() => {
3238
3238
  package_default = {
3239
3239
  name: "@letta-ai/letta-code",
3240
- version: "0.11.2-next.1",
3240
+ version: "0.11.2-next.3",
3241
3241
  description: "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
3242
3242
  type: "module",
3243
3243
  bin: {
@@ -33383,6 +33383,17 @@ function getRipgrepBinDir() {
33383
33383
  return;
33384
33384
  }
33385
33385
  }
33386
+ function getPackageNodeModulesDir() {
33387
+ try {
33388
+ const __filename2 = fileURLToPath(import.meta.url);
33389
+ const require2 = createRequire2(__filename2);
33390
+ const clientPath = require2.resolve("@letta-ai/letta-client");
33391
+ const match = clientPath.match(/^(.+[/\\]node_modules)[/\\]/);
33392
+ return match ? match[1] : undefined;
33393
+ } catch {
33394
+ return;
33395
+ }
33396
+ }
33386
33397
  function getShellEnv() {
33387
33398
  const env3 = { ...process.env };
33388
33399
  const rgBinDir = getRipgrepBinDir();
@@ -33401,6 +33412,11 @@ function getShellEnv() {
33401
33412
  }
33402
33413
  } catch {}
33403
33414
  }
33415
+ const nodeModulesDir = getPackageNodeModulesDir();
33416
+ if (nodeModulesDir) {
33417
+ const currentNodePath = env3.NODE_PATH || "";
33418
+ env3.NODE_PATH = currentNodePath ? `${nodeModulesDir}${path3.delimiter}${currentNodePath}` : nodeModulesDir;
33419
+ }
33404
33420
  return env3;
33405
33421
  }
33406
33422
  var init_shellEnv = __esm(async () => {
@@ -77085,4 +77101,4 @@ Error during initialization: ${message}`);
77085
77101
  }
77086
77102
  main();
77087
77103
 
77088
- //# debugId=CC2D0370FEDF40B764756E2164756E21
77104
+ //# debugId=97EC206550CD703E64756E2164756E21
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@letta-ai/letta-code",
3
- "version": "0.11.2-next.1",
3
+ "version": "0.11.2-next.3",
4
4
  "description": "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -263,7 +263,7 @@ When creating a new skill from scratch, always run the `init-skill.ts` script. T
263
263
  Usage:
264
264
 
265
265
  ```bash
266
- npx ts-node scripts/init-skill.ts <skill-name> --path <output-directory>
266
+ npx tsx <SKILL_DIR>/scripts/init-skill.ts <skill-name> --path <output-directory>
267
267
  ```
268
268
 
269
269
  The script:
@@ -335,13 +335,13 @@ Write instructions for using the skill and its bundled resources.
335
335
  Once development of the skill is complete, it must be packaged into a distributable .skill file that gets shared with the user. The packaging process automatically validates the skill first to ensure it meets all requirements:
336
336
 
337
337
  ```bash
338
- npx ts-node scripts/package-skill.ts <path/to/skill-folder>
338
+ npx tsx <SKILL_DIR>/scripts/package-skill.ts <path/to/skill-folder>
339
339
  ```
340
340
 
341
341
  Optional output directory specification:
342
342
 
343
343
  ```bash
344
- npx ts-node scripts/package-skill.ts <path/to/skill-folder> ./dist
344
+ npx tsx <SKILL_DIR>/scripts/package-skill.ts <path/to/skill-folder> ./dist
345
345
  ```
346
346
 
347
347
  The packaging script will:
@@ -18,7 +18,7 @@ This skill helps you find other agents on the same Letta server.
18
18
  ## Script Usage
19
19
 
20
20
  ```bash
21
- npx ts-node scripts/find-agents.ts [options]
21
+ npx tsx <SKILL_DIR>/scripts/find-agents.ts [options]
22
22
  ```
23
23
 
24
24
  ### Options
@@ -39,7 +39,7 @@ npx ts-node scripts/find-agents.ts [options]
39
39
  Agents created by Letta Code are tagged with `origin:letta-code`. To find only Letta Code agents:
40
40
 
41
41
  ```bash
42
- npx ts-node scripts/find-agents.ts --tags "origin:letta-code"
42
+ npx tsx <SKILL_DIR>/scripts/find-agents.ts --tags "origin:letta-code"
43
43
  ```
44
44
 
45
45
  This is useful when the user is looking for agents they've worked with in Letta Code CLI sessions.
@@ -49,39 +49,39 @@ This is useful when the user is looking for agents they've worked with in Letta
49
49
  If the user has agents created outside Letta Code (via ADE, SDK, etc.), search without the tag filter:
50
50
 
51
51
  ```bash
52
- npx ts-node scripts/find-agents.ts
52
+ npx tsx <SKILL_DIR>/scripts/find-agents.ts
53
53
  ```
54
54
 
55
55
  ## Examples
56
56
 
57
57
  **List all agents (up to 20):**
58
58
  ```bash
59
- npx ts-node scripts/find-agents.ts
59
+ npx tsx <SKILL_DIR>/scripts/find-agents.ts
60
60
  ```
61
61
 
62
62
  **Find agent by exact name:**
63
63
  ```bash
64
- npx ts-node scripts/find-agents.ts --name "ProjectX-v1"
64
+ npx tsx <SKILL_DIR>/scripts/find-agents.ts --name "ProjectX-v1"
65
65
  ```
66
66
 
67
67
  **Search agents by name (fuzzy):**
68
68
  ```bash
69
- npx ts-node scripts/find-agents.ts --query "project"
69
+ npx tsx <SKILL_DIR>/scripts/find-agents.ts --query "project"
70
70
  ```
71
71
 
72
72
  **Find only Letta Code agents:**
73
73
  ```bash
74
- npx ts-node scripts/find-agents.ts --tags "origin:letta-code"
74
+ npx tsx <SKILL_DIR>/scripts/find-agents.ts --tags "origin:letta-code"
75
75
  ```
76
76
 
77
77
  **Find agents with multiple tags:**
78
78
  ```bash
79
- npx ts-node scripts/find-agents.ts --tags "frontend,production" --match-all-tags
79
+ npx tsx <SKILL_DIR>/scripts/find-agents.ts --tags "frontend,production" --match-all-tags
80
80
  ```
81
81
 
82
82
  **Include memory blocks in results:**
83
83
  ```bash
84
- npx ts-node scripts/find-agents.ts --query "project" --include-blocks
84
+ npx tsx <SKILL_DIR>/scripts/find-agents.ts --query "project" --include-blocks
85
85
  ```
86
86
 
87
87
  ## Output
@@ -1,9 +1,12 @@
1
- #!/usr/bin/env npx ts-node
1
+ #!/usr/bin/env npx tsx
2
2
  /**
3
3
  * Find Agents - Search for agents with various filters
4
4
  *
5
+ * This script is standalone and can be run outside the CLI process.
6
+ * It reads auth from LETTA_API_KEY env var or ~/.letta/settings.json.
7
+ *
5
8
  * Usage:
6
- * npx ts-node find-agents.ts [options]
9
+ * npx tsx find-agents.ts [options]
7
10
  *
8
11
  * Options:
9
12
  * --name <name> Exact name match
@@ -17,9 +20,17 @@
17
20
  * Raw API response from GET /v1/agents
18
21
  */
19
22
 
20
- import type Letta from "@letta-ai/letta-client";
21
- import { getClient } from "../../../../agent/client";
22
- import { settingsManager } from "../../../../settings-manager";
23
+ import { readFileSync } from "node:fs";
24
+ import { createRequire } from "node:module";
25
+ import { homedir } from "node:os";
26
+ import { join } from "node:path";
27
+
28
+ // Use createRequire for @letta-ai/letta-client so NODE_PATH is respected
29
+ // (ES module imports don't respect NODE_PATH, but require does)
30
+ const require = createRequire(import.meta.url);
31
+ const Letta = require("@letta-ai/letta-client")
32
+ .default as typeof import("@letta-ai/letta-client").default;
33
+ type LettaClient = InstanceType<typeof Letta>;
23
34
 
24
35
  interface FindAgentsOptions {
25
36
  name?: string;
@@ -30,6 +41,38 @@ interface FindAgentsOptions {
30
41
  limit?: number;
31
42
  }
32
43
 
44
+ /**
45
+ * Get API key from env var or settings file
46
+ */
47
+ function getApiKey(): string {
48
+ // First check env var (set by CLI's getShellEnv)
49
+ if (process.env.LETTA_API_KEY) {
50
+ return process.env.LETTA_API_KEY;
51
+ }
52
+
53
+ // Fall back to settings file
54
+ const settingsPath = join(homedir(), ".letta", "settings.json");
55
+ try {
56
+ const settings = JSON.parse(readFileSync(settingsPath, "utf-8"));
57
+ if (settings.env?.LETTA_API_KEY) {
58
+ return settings.env.LETTA_API_KEY;
59
+ }
60
+ } catch {
61
+ // Settings file doesn't exist or is invalid
62
+ }
63
+
64
+ throw new Error(
65
+ "No LETTA_API_KEY found. Set the env var or run the Letta CLI to authenticate.",
66
+ );
67
+ }
68
+
69
+ /**
70
+ * Create a Letta client with auth from env/settings
71
+ */
72
+ function createClient(): LettaClient {
73
+ return new Letta({ apiKey: getApiKey() });
74
+ }
75
+
33
76
  /**
34
77
  * Find agents matching the given criteria
35
78
  * @param client - Letta client instance
@@ -37,7 +80,7 @@ interface FindAgentsOptions {
37
80
  * @returns Array of agent objects from the API
38
81
  */
39
82
  export async function findAgents(
40
- client: Letta,
83
+ client: LettaClient,
41
84
  options: FindAgentsOptions = {},
42
85
  ): Promise<Awaited<ReturnType<typeof client.agents.list>>> {
43
86
  const params: Parameters<typeof client.agents.list>[0] = {
@@ -103,13 +146,13 @@ function parseArgs(args: string[]): FindAgentsOptions {
103
146
  return options;
104
147
  }
105
148
 
106
- // CLI entry point
107
- if (require.main === module) {
149
+ // CLI entry point - check if this file is being run directly
150
+ const isMainModule = import.meta.url === `file://${process.argv[1]}`;
151
+ if (isMainModule) {
108
152
  (async () => {
109
153
  try {
110
154
  const options = parseArgs(process.argv.slice(2));
111
- await settingsManager.initialize();
112
- const client = await getClient();
155
+ const client = createClient();
113
156
  const result = await findAgents(client, options);
114
157
  console.log(JSON.stringify(result, null, 2));
115
158
  } catch (error) {
@@ -118,7 +161,7 @@ if (require.main === module) {
118
161
  error instanceof Error ? error.message : String(error),
119
162
  );
120
163
  console.error(`
121
- Usage: npx ts-node find-agents.ts [options]
164
+ Usage: npx tsx find-agents.ts [options]
122
165
 
123
166
  Options:
124
167
  --name <name> Exact name match
@@ -60,7 +60,7 @@ Example: "What's the ID of the agent you want to migrate memory from?"
60
60
  Inspect what memory blocks the source agent has:
61
61
 
62
62
  ```bash
63
- npx ts-node scripts/get-agent-blocks.ts --agent-id <source-agent-id>
63
+ npx tsx <SKILL_DIR>/scripts/get-agent-blocks.ts --agent-id <source-agent-id>
64
64
  ```
65
65
 
66
66
  This shows each block's ID, label, description, and value.
@@ -71,14 +71,14 @@ For each block you want to migrate, choose copy or share:
71
71
 
72
72
  **To Copy (create independent block):**
73
73
  ```bash
74
- npx ts-node scripts/copy-block.ts --block-id <block-id> [--label <new-label>]
74
+ npx tsx <SKILL_DIR>/scripts/copy-block.ts --block-id <block-id> [--label <new-label>]
75
75
  ```
76
76
 
77
77
  Use `--label` if you already have a block with that label (e.g., `--label project-imported`).
78
78
 
79
79
  **To Share (attach existing block):**
80
80
  ```bash
81
- npx ts-node scripts/attach-block.ts --block-id <block-id>
81
+ npx tsx <SKILL_DIR>/scripts/attach-block.ts --block-id <block-id>
82
82
  ```
83
83
 
84
84
  Add `--read-only` flag to share to make this agent unable to modify the block.
@@ -113,20 +113,20 @@ Scenario: You're a new agent and want to inherit memory from an existing agent "
113
113
 
114
114
  2. **List its blocks:**
115
115
  ```bash
116
- npx ts-node scripts/get-agent-blocks.ts --agent-id agent-abc123
116
+ npx tsx <SKILL_DIR>/scripts/get-agent-blocks.ts --agent-id agent-abc123
117
117
  # Shows: project (block-def456), human (block-ghi789), persona (block-jkl012)
118
118
  ```
119
119
 
120
120
  3. **Copy project knowledge to yourself:**
121
121
  ```bash
122
122
  # If you don't have a 'project' block yet:
123
- npx ts-node scripts/copy-block.ts --block-id block-def456
123
+ npx tsx <SKILL_DIR>/scripts/copy-block.ts --block-id block-def456
124
124
 
125
125
  # If you already have 'project', use --label to rename:
126
- npx ts-node scripts/copy-block.ts --block-id block-def456 --label project-v1
126
+ npx tsx <SKILL_DIR>/scripts/copy-block.ts --block-id block-def456 --label project-v1
127
127
  ```
128
128
 
129
129
  4. **Optionally share human preferences (read-only):**
130
130
  ```bash
131
- npx ts-node scripts/attach-block.ts --block-id block-ghi789 --read-only
131
+ npx tsx <SKILL_DIR>/scripts/attach-block.ts --block-id block-ghi789 --read-only
132
132
  ```
@@ -1,24 +1,79 @@
1
- #!/usr/bin/env npx ts-node
1
+ #!/usr/bin/env npx tsx
2
2
  /**
3
3
  * Attach Block - Attaches an existing memory block to an agent (sharing)
4
4
  *
5
+ * This script is standalone and can be run outside the CLI process.
6
+ * It reads auth from LETTA_API_KEY env var or ~/.letta/settings.json.
7
+ * It reads agent ID from LETTA_AGENT_ID env var or --agent-id arg.
8
+ *
5
9
  * Usage:
6
- * npx ts-node attach-block.ts --block-id <block-id> --target-agent-id <agent-id> [--read-only]
10
+ * npx tsx attach-block.ts --block-id <block-id> [--agent-id <agent-id>] [--read-only]
7
11
  *
8
12
  * This attaches an existing block to another agent, making it shared.
9
13
  * Changes to the block will be visible to all agents that have it attached.
10
14
  *
11
15
  * Options:
12
- * --read-only Target agent can read but not modify the block
16
+ * --agent-id Target agent ID (overrides LETTA_AGENT_ID env var)
17
+ * --read-only Target agent can read but not modify the block
13
18
  *
14
19
  * Output:
15
20
  * Raw API response from the attach operation
16
21
  */
17
22
 
18
- import type Letta from "@letta-ai/letta-client";
19
- import { getClient } from "../../../../agent/client";
20
- import { getCurrentAgentId } from "../../../../agent/context";
21
- import { settingsManager } from "../../../../settings-manager";
23
+ import { readFileSync } from "node:fs";
24
+ import { createRequire } from "node:module";
25
+ import { homedir } from "node:os";
26
+ import { join } from "node:path";
27
+
28
+ // Use createRequire for @letta-ai/letta-client so NODE_PATH is respected
29
+ // (ES module imports don't respect NODE_PATH, but require does)
30
+ const require = createRequire(import.meta.url);
31
+ const Letta = require("@letta-ai/letta-client")
32
+ .default as typeof import("@letta-ai/letta-client").default;
33
+ type LettaClient = InstanceType<typeof Letta>;
34
+
35
+ /**
36
+ * Get API key from env var or settings file
37
+ */
38
+ function getApiKey(): string {
39
+ if (process.env.LETTA_API_KEY) {
40
+ return process.env.LETTA_API_KEY;
41
+ }
42
+
43
+ const settingsPath = join(homedir(), ".letta", "settings.json");
44
+ try {
45
+ const settings = JSON.parse(readFileSync(settingsPath, "utf-8"));
46
+ if (settings.env?.LETTA_API_KEY) {
47
+ return settings.env.LETTA_API_KEY;
48
+ }
49
+ } catch {
50
+ // Settings file doesn't exist or is invalid
51
+ }
52
+
53
+ throw new Error(
54
+ "No LETTA_API_KEY found. Set the env var or run the Letta CLI to authenticate.",
55
+ );
56
+ }
57
+
58
+ /**
59
+ * Get agent ID from CLI arg, env var, or throw
60
+ */
61
+ function getAgentId(cliArg?: string): string {
62
+ if (cliArg) return cliArg;
63
+ if (process.env.LETTA_AGENT_ID) {
64
+ return process.env.LETTA_AGENT_ID;
65
+ }
66
+ throw new Error(
67
+ "No agent ID provided. Use --agent-id or ensure LETTA_AGENT_ID env var is set.",
68
+ );
69
+ }
70
+
71
+ /**
72
+ * Create a Letta client with auth from env/settings
73
+ */
74
+ function createClient(): LettaClient {
75
+ return new Letta({ apiKey: getApiKey() });
76
+ }
22
77
 
23
78
  /**
24
79
  * Attach an existing block to the current agent (sharing it)
@@ -29,13 +84,13 @@ import { settingsManager } from "../../../../settings-manager";
29
84
  * @returns API response from the attach operation
30
85
  */
31
86
  export async function attachBlock(
32
- client: Letta,
87
+ client: LettaClient,
33
88
  blockId: string,
34
89
  readOnly = false,
35
90
  targetAgentId?: string,
36
91
  ): Promise<Awaited<ReturnType<typeof client.agents.blocks.attach>>> {
37
92
  // Get current agent ID (the agent calling this script) or use provided ID
38
- const currentAgentId = targetAgentId ?? getCurrentAgentId();
93
+ const currentAgentId = getAgentId(targetAgentId);
39
94
 
40
95
  const result = await client.agents.blocks.attach(blockId, {
41
96
  agent_id: currentAgentId,
@@ -58,8 +113,10 @@ export async function attachBlock(
58
113
  function parseArgs(args: string[]): {
59
114
  blockId: string;
60
115
  readOnly: boolean;
116
+ agentId?: string;
61
117
  } {
62
118
  const blockIdIndex = args.indexOf("--block-id");
119
+ const agentIdIndex = args.indexOf("--agent-id");
63
120
  const readOnly = args.includes("--read-only");
64
121
 
65
122
  if (blockIdIndex === -1 || blockIdIndex + 1 >= args.length) {
@@ -69,17 +126,21 @@ function parseArgs(args: string[]): {
69
126
  return {
70
127
  blockId: args[blockIdIndex + 1] as string,
71
128
  readOnly,
129
+ agentId:
130
+ agentIdIndex !== -1 && agentIdIndex + 1 < args.length
131
+ ? (args[agentIdIndex + 1] as string)
132
+ : undefined,
72
133
  };
73
134
  }
74
135
 
75
- // CLI entry point
76
- if (require.main === module) {
136
+ // CLI entry point - check if this file is being run directly
137
+ const isMainModule = import.meta.url === `file://${process.argv[1]}`;
138
+ if (isMainModule) {
77
139
  (async () => {
78
140
  try {
79
- const { blockId, readOnly } = parseArgs(process.argv.slice(2));
80
- await settingsManager.initialize();
81
- const client = await getClient();
82
- const result = await attachBlock(client, blockId, readOnly);
141
+ const { blockId, readOnly, agentId } = parseArgs(process.argv.slice(2));
142
+ const client = createClient();
143
+ const result = await attachBlock(client, blockId, readOnly, agentId);
83
144
  console.log(JSON.stringify(result, null, 2));
84
145
  } catch (error) {
85
146
  console.error(
@@ -91,7 +152,7 @@ if (require.main === module) {
91
152
  error.message.includes("Missing required argument")
92
153
  ) {
93
154
  console.error(
94
- "\nUsage: npx ts-node attach-block.ts --block-id <block-id> [--read-only]",
155
+ "\nUsage: npx tsx attach-block.ts --block-id <block-id> [--agent-id <agent-id>] [--read-only]",
95
156
  );
96
157
  }
97
158
  process.exit(1);
@@ -1,12 +1,17 @@
1
- #!/usr/bin/env npx ts-node
1
+ #!/usr/bin/env npx tsx
2
2
  /**
3
3
  * Copy Block - Copies a memory block to create a new independent block for the current agent
4
4
  *
5
+ * This script is standalone and can be run outside the CLI process.
6
+ * It reads auth from LETTA_API_KEY env var or ~/.letta/settings.json.
7
+ * It reads agent ID from LETTA_AGENT_ID env var or --agent-id arg.
8
+ *
5
9
  * Usage:
6
- * npx ts-node copy-block.ts --block-id <block-id> [--label <new-label>]
10
+ * npx tsx copy-block.ts --block-id <block-id> [--label <new-label>] [--agent-id <agent-id>]
7
11
  *
8
12
  * Options:
9
- * --label Override the block label (required if you already have a block with that label)
13
+ * --label Override the block label (required if you already have a block with that label)
14
+ * --agent-id Target agent ID (overrides LETTA_AGENT_ID env var)
10
15
  *
11
16
  * This creates a new block with the same content as the source block,
12
17
  * then attaches it to the current agent. Changes to the new block
@@ -16,17 +21,65 @@
16
21
  * Raw API response from each step (retrieve, create, attach)
17
22
  */
18
23
 
19
- import type Letta from "@letta-ai/letta-client";
20
- import { getClient } from "../../../../agent/client";
21
- import { getCurrentAgentId } from "../../../../agent/context";
22
- import { settingsManager } from "../../../../settings-manager";
24
+ import { readFileSync } from "node:fs";
25
+ import { createRequire } from "node:module";
26
+ import { homedir } from "node:os";
27
+ import { join } from "node:path";
28
+
29
+ // Use createRequire for @letta-ai/letta-client so NODE_PATH is respected
30
+ // (ES module imports don't respect NODE_PATH, but require does)
31
+ const require = createRequire(import.meta.url);
32
+ const Letta = require("@letta-ai/letta-client")
33
+ .default as typeof import("@letta-ai/letta-client").default;
34
+ type LettaClient = InstanceType<typeof Letta>;
23
35
 
24
36
  interface CopyBlockResult {
25
- sourceBlock: Awaited<ReturnType<typeof Letta.prototype.blocks.retrieve>>;
26
- newBlock: Awaited<ReturnType<typeof Letta.prototype.blocks.create>>;
27
- attachResult: Awaited<
28
- ReturnType<typeof Letta.prototype.agents.blocks.attach>
29
- >;
37
+ sourceBlock: Awaited<ReturnType<LettaClient["blocks"]["retrieve"]>>;
38
+ newBlock: Awaited<ReturnType<LettaClient["blocks"]["create"]>>;
39
+ attachResult: Awaited<ReturnType<LettaClient["agents"]["blocks"]["attach"]>>;
40
+ }
41
+
42
+ /**
43
+ * Get API key from env var or settings file
44
+ */
45
+ function getApiKey(): string {
46
+ if (process.env.LETTA_API_KEY) {
47
+ return process.env.LETTA_API_KEY;
48
+ }
49
+
50
+ const settingsPath = join(homedir(), ".letta", "settings.json");
51
+ try {
52
+ const settings = JSON.parse(readFileSync(settingsPath, "utf-8"));
53
+ if (settings.env?.LETTA_API_KEY) {
54
+ return settings.env.LETTA_API_KEY;
55
+ }
56
+ } catch {
57
+ // Settings file doesn't exist or is invalid
58
+ }
59
+
60
+ throw new Error(
61
+ "No LETTA_API_KEY found. Set the env var or run the Letta CLI to authenticate.",
62
+ );
63
+ }
64
+
65
+ /**
66
+ * Get agent ID from CLI arg, env var, or throw
67
+ */
68
+ function getAgentId(cliArg?: string): string {
69
+ if (cliArg) return cliArg;
70
+ if (process.env.LETTA_AGENT_ID) {
71
+ return process.env.LETTA_AGENT_ID;
72
+ }
73
+ throw new Error(
74
+ "No agent ID provided. Use --agent-id or ensure LETTA_AGENT_ID env var is set.",
75
+ );
76
+ }
77
+
78
+ /**
79
+ * Create a Letta client with auth from env/settings
80
+ */
81
+ function createClient(): LettaClient {
82
+ return new Letta({ apiKey: getApiKey() });
30
83
  }
31
84
 
32
85
  /**
@@ -37,12 +90,12 @@ interface CopyBlockResult {
37
90
  * @returns Object containing source block, new block, and attach result
38
91
  */
39
92
  export async function copyBlock(
40
- client: Letta,
93
+ client: LettaClient,
41
94
  blockId: string,
42
95
  options?: { labelOverride?: string; targetAgentId?: string },
43
96
  ): Promise<CopyBlockResult> {
44
97
  // Get current agent ID (the agent calling this script) or use provided ID
45
- const currentAgentId = options?.targetAgentId ?? getCurrentAgentId();
98
+ const currentAgentId = getAgentId(options?.targetAgentId);
46
99
 
47
100
  // 1. Get source block details
48
101
  const sourceBlock = await client.blocks.retrieve(blockId);
@@ -63,9 +116,14 @@ export async function copyBlock(
63
116
  return { sourceBlock, newBlock, attachResult };
64
117
  }
65
118
 
66
- function parseArgs(args: string[]): { blockId: string; label?: string } {
119
+ function parseArgs(args: string[]): {
120
+ blockId: string;
121
+ label?: string;
122
+ agentId?: string;
123
+ } {
67
124
  const blockIdIndex = args.indexOf("--block-id");
68
125
  const labelIndex = args.indexOf("--label");
126
+ const agentIdIndex = args.indexOf("--agent-id");
69
127
 
70
128
  if (blockIdIndex === -1 || blockIdIndex + 1 >= args.length) {
71
129
  throw new Error("Missing required argument: --block-id <block-id>");
@@ -77,17 +135,24 @@ function parseArgs(args: string[]): { blockId: string; label?: string } {
77
135
  labelIndex !== -1 && labelIndex + 1 < args.length
78
136
  ? (args[labelIndex + 1] as string)
79
137
  : undefined,
138
+ agentId:
139
+ agentIdIndex !== -1 && agentIdIndex + 1 < args.length
140
+ ? (args[agentIdIndex + 1] as string)
141
+ : undefined,
80
142
  };
81
143
  }
82
144
 
83
- // CLI entry point
84
- if (require.main === module) {
145
+ // CLI entry point - check if this file is being run directly
146
+ const isMainModule = import.meta.url === `file://${process.argv[1]}`;
147
+ if (isMainModule) {
85
148
  (async () => {
86
149
  try {
87
- const { blockId, label } = parseArgs(process.argv.slice(2));
88
- await settingsManager.initialize();
89
- const client = await getClient();
90
- const result = await copyBlock(client, blockId, { labelOverride: label });
150
+ const { blockId, label, agentId } = parseArgs(process.argv.slice(2));
151
+ const client = createClient();
152
+ const result = await copyBlock(client, blockId, {
153
+ labelOverride: label,
154
+ targetAgentId: agentId,
155
+ });
91
156
  console.log(JSON.stringify(result, null, 2));
92
157
  } catch (error) {
93
158
  console.error(
@@ -99,7 +164,7 @@ if (require.main === module) {
99
164
  error.message.includes("Missing required argument")
100
165
  ) {
101
166
  console.error(
102
- "\nUsage: npx ts-node copy-block.ts --block-id <block-id> [--label <new-label>]",
167
+ "\nUsage: npx tsx copy-block.ts --block-id <block-id> [--label <new-label>] [--agent-id <agent-id>]",
103
168
  );
104
169
  }
105
170
  process.exit(1);
@@ -1,17 +1,58 @@
1
- #!/usr/bin/env npx ts-node
1
+ #!/usr/bin/env npx tsx
2
2
  /**
3
3
  * Get Agent Blocks - Retrieves memory blocks from a specific agent
4
4
  *
5
+ * This script is standalone and can be run outside the CLI process.
6
+ * It reads auth from LETTA_API_KEY env var or ~/.letta/settings.json.
7
+ *
5
8
  * Usage:
6
- * npx ts-node get-agent-blocks.ts --agent-id <agent-id>
9
+ * npx tsx get-agent-blocks.ts --agent-id <agent-id>
7
10
  *
8
11
  * Output:
9
12
  * Raw API response from GET /v1/agents/{id}/core-memory/blocks
10
13
  */
11
14
 
12
- import type Letta from "@letta-ai/letta-client";
13
- import { getClient } from "../../../../agent/client";
14
- import { settingsManager } from "../../../../settings-manager";
15
+ import { readFileSync } from "node:fs";
16
+ import { createRequire } from "node:module";
17
+ import { homedir } from "node:os";
18
+ import { join } from "node:path";
19
+
20
+ // Use createRequire for @letta-ai/letta-client so NODE_PATH is respected
21
+ // (ES module imports don't respect NODE_PATH, but require does)
22
+ const require = createRequire(import.meta.url);
23
+ const Letta = require("@letta-ai/letta-client")
24
+ .default as typeof import("@letta-ai/letta-client").default;
25
+ type LettaClient = InstanceType<typeof Letta>;
26
+
27
+ /**
28
+ * Get API key from env var or settings file
29
+ */
30
+ function getApiKey(): string {
31
+ if (process.env.LETTA_API_KEY) {
32
+ return process.env.LETTA_API_KEY;
33
+ }
34
+
35
+ const settingsPath = join(homedir(), ".letta", "settings.json");
36
+ try {
37
+ const settings = JSON.parse(readFileSync(settingsPath, "utf-8"));
38
+ if (settings.env?.LETTA_API_KEY) {
39
+ return settings.env.LETTA_API_KEY;
40
+ }
41
+ } catch {
42
+ // Settings file doesn't exist or is invalid
43
+ }
44
+
45
+ throw new Error(
46
+ "No LETTA_API_KEY found. Set the env var or run the Letta CLI to authenticate.",
47
+ );
48
+ }
49
+
50
+ /**
51
+ * Create a Letta client with auth from env/settings
52
+ */
53
+ function createClient(): LettaClient {
54
+ return new Letta({ apiKey: getApiKey() });
55
+ }
15
56
 
16
57
  /**
17
58
  * Get memory blocks for a specific agent
@@ -20,7 +61,7 @@ import { settingsManager } from "../../../../settings-manager";
20
61
  * @returns Array of block objects from the API
21
62
  */
22
63
  export async function getAgentBlocks(
23
- client: Letta,
64
+ client: LettaClient,
24
65
  agentId: string,
25
66
  ): Promise<Awaited<ReturnType<typeof client.agents.blocks.list>>> {
26
67
  return await client.agents.blocks.list(agentId);
@@ -34,13 +75,13 @@ function parseArgs(args: string[]): { agentId: string } {
34
75
  return { agentId: args[agentIdIndex + 1] as string };
35
76
  }
36
77
 
37
- // CLI entry point
38
- if (require.main === module) {
78
+ // CLI entry point - check if this file is being run directly
79
+ const isMainModule = import.meta.url === `file://${process.argv[1]}`;
80
+ if (isMainModule) {
39
81
  (async () => {
40
82
  try {
41
83
  const { agentId } = parseArgs(process.argv.slice(2));
42
- await settingsManager.initialize();
43
- const client = await getClient();
84
+ const client = createClient();
44
85
  const result = await getAgentBlocks(client, agentId);
45
86
  console.log(JSON.stringify(result, null, 2));
46
87
  } catch (error) {
@@ -53,7 +94,7 @@ if (require.main === module) {
53
94
  error.message.includes("Missing required argument")
54
95
  ) {
55
96
  console.error(
56
- "\nUsage: npx ts-node get-agent-blocks.ts --agent-id <agent-id>",
97
+ "\nUsage: npx tsx get-agent-blocks.ts --agent-id <agent-id>",
57
98
  );
58
99
  }
59
100
  process.exit(1);
@@ -26,9 +26,16 @@
26
26
  */
27
27
 
28
28
  import { readFileSync } from "node:fs";
29
+ import { createRequire } from "node:module";
29
30
  import { homedir } from "node:os";
30
31
  import { join } from "node:path";
31
- import Letta from "@letta-ai/letta-client";
32
+
33
+ // Use createRequire for @letta-ai/letta-client so NODE_PATH is respected
34
+ // (ES module imports don't respect NODE_PATH, but require does)
35
+ const require = createRequire(import.meta.url);
36
+ const Letta = require("@letta-ai/letta-client")
37
+ .default as typeof import("@letta-ai/letta-client").default;
38
+ type LettaClient = InstanceType<typeof Letta>;
32
39
 
33
40
  interface GetMessagesOptions {
34
41
  startDate?: string;
@@ -85,7 +92,7 @@ function getAgentId(cliArg?: string): string {
85
92
  /**
86
93
  * Create a Letta client with auth from env/settings
87
94
  */
88
- function createClient(): Letta {
95
+ function createClient(): LettaClient {
89
96
  return new Letta({ apiKey: getApiKey() });
90
97
  }
91
98
 
@@ -96,7 +103,7 @@ function createClient(): Letta {
96
103
  * @returns Array of messages in chronological order
97
104
  */
98
105
  export async function getMessages(
99
- client: Letta,
106
+ client: LettaClient,
100
107
  options: GetMessagesOptions = {},
101
108
  ): Promise<unknown[]> {
102
109
  const agentId = getAgentId(options.agentId);
@@ -24,9 +24,16 @@
24
24
  */
25
25
 
26
26
  import { readFileSync } from "node:fs";
27
+ import { createRequire } from "node:module";
27
28
  import { homedir } from "node:os";
28
29
  import { join } from "node:path";
29
- import Letta from "@letta-ai/letta-client";
30
+
31
+ // Use createRequire for @letta-ai/letta-client so NODE_PATH is respected
32
+ // (ES module imports don't respect NODE_PATH, but require does)
33
+ const require = createRequire(import.meta.url);
34
+ const Letta = require("@letta-ai/letta-client")
35
+ .default as typeof import("@letta-ai/letta-client").default;
36
+ type LettaClient = InstanceType<typeof Letta>;
30
37
 
31
38
  interface SearchMessagesOptions {
32
39
  query: string;
@@ -83,7 +90,7 @@ function getAgentId(cliArg?: string): string {
83
90
  /**
84
91
  * Create a Letta client with auth from env/settings
85
92
  */
86
- function createClient(): Letta {
93
+ function createClient(): LettaClient {
87
94
  return new Letta({ apiKey: getApiKey() });
88
95
  }
89
96
 
@@ -94,7 +101,7 @@ function createClient(): Letta {
94
101
  * @returns Array of search results with scores
95
102
  */
96
103
  export async function searchMessages(
97
- client: Letta,
104
+ client: LettaClient,
98
105
  options: SearchMessagesOptions,
99
106
  ): Promise<Awaited<ReturnType<typeof client.messages.search>>> {
100
107
  // Default to current agent unless --all-agents is specified