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

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@letta-ai/letta-code",
3
- "version": "0.11.2-next.3",
3
+ "version": "0.12.0",
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": {
@@ -0,0 +1,126 @@
1
+ ---
2
+ name: acquiring-skills
3
+ description: Guide for safely discovering and installing skills from external repositories. Use when a user asks for something where a specialized skill likely exists (browser testing, PDF processing, document generation, etc.) and you want to bootstrap your understanding rather than starting from scratch.
4
+ ---
5
+
6
+ # Acquiring New Skills
7
+
8
+ This skill teaches you how to safely discover and install skills from external sources.
9
+
10
+ ## SAFETY - READ THIS FIRST
11
+
12
+ Skills can contain:
13
+ - **Markdown files** (.md) - Risk: prompt injection, misleading instructions
14
+ - **Scripts** (Python, TypeScript, Bash) - Risk: malicious code execution
15
+
16
+ ### Trusted Sources (no user approval needed for download)
17
+ - `https://github.com/letta-ai/skills` - Letta's community skills
18
+ - `https://github.com/anthropics/skills` - Anthropic's official skills
19
+
20
+ ### Untrusted Sources (ALWAYS verify with user)
21
+ For ANY source other than letta-ai or anthropics:
22
+ 1. Ask the user before downloading
23
+ 2. Explain where the skill comes from
24
+ 3. Get explicit approval
25
+
26
+ ### Script Safety
27
+ Even for skills from trusted sources, ALWAYS:
28
+ 1. Read and inspect any scripts before executing them
29
+ 2. Understand what the script does
30
+ 3. Be wary of network calls, file operations, or system commands
31
+
32
+ ## When to Use This Skill
33
+
34
+ **DO use** when:
35
+ - User asks for something where a skill likely exists (e.g., "help me test this webapp", "generate a PDF report")
36
+ - You think "there's probably a skill that would bootstrap my understanding"
37
+ - User explicitly asks about available skills or extending capabilities
38
+
39
+ **DON'T use** for:
40
+ - General coding tasks you can already handle
41
+ - Simple bug fixes or feature implementations
42
+ - Tasks where you have sufficient knowledge
43
+
44
+ ## Ask Before Searching (Interactive Mode)
45
+
46
+ If you recognize a task that might have an associated skill, **ask the user first**:
47
+
48
+ > "This sounds like something where a community skill might help (e.g., webapp testing with Playwright). Would you like me to look for available skills in the Letta or Anthropic repositories? This might take a minute, or I can start coding right away if you prefer."
49
+
50
+ The user may prefer to start immediately rather than wait for skill discovery.
51
+
52
+ Only proceed with skill acquisition if the user agrees.
53
+
54
+ ## Skill Repositories
55
+
56
+ | Repository | Description |
57
+ |------------|-------------|
58
+ | https://github.com/letta-ai/skills | Community skills for Letta agents |
59
+ | https://github.com/anthropics/skills | Anthropic's official Agent Skills |
60
+
61
+ Browse these repositories to discover available skills. Check the README for skill listings.
62
+
63
+ ## Installation Locations
64
+
65
+ | Location | Path | When to Use |
66
+ |----------|------|-------------|
67
+ | **Global** | `~/.letta/skills/<skill>/` | General-purpose skills useful across projects |
68
+ | **Project** | `.skills/<skill>/` | Project-specific skills |
69
+
70
+ **Rule**: If useful across multiple projects, install globally. If project-specific, install in `.skills/`.
71
+
72
+ ## How to Download Skills
73
+
74
+ Skills are directories containing SKILL.md and optionally scripts/, references/, examples/.
75
+
76
+ ### Method: Clone to /tmp, then copy
77
+
78
+ ```bash
79
+ # 1. Clone the repo (shallow)
80
+ git clone --depth 1 https://github.com/anthropics/skills /tmp/skills-temp
81
+
82
+ # 2. Copy the skill to your skills directory
83
+ # For global:
84
+ cp -r /tmp/skills-temp/skills/webapp-testing ~/.letta/skills/
85
+ # For project:
86
+ cp -r /tmp/skills-temp/skills/webapp-testing .skills/
87
+
88
+ # 3. Cleanup
89
+ rm -rf /tmp/skills-temp
90
+ ```
91
+
92
+ ### Alternative: rsync (preserves permissions)
93
+
94
+ ```bash
95
+ git clone --depth 1 https://github.com/anthropics/skills /tmp/skills-temp
96
+ rsync -av /tmp/skills-temp/skills/webapp-testing/ ~/.letta/skills/webapp-testing/
97
+ rm -rf /tmp/skills-temp
98
+ ```
99
+
100
+ ## Registering New Skills
101
+
102
+ After downloading, refresh the skills list:
103
+
104
+ ```
105
+ Skill(command: "refresh")
106
+ ```
107
+
108
+ This scans `~/.letta/skills/` and `.skills/` and updates your `skills` memory block.
109
+
110
+ ## Complete Example
111
+
112
+ User asks: "Can you help me test my React app's UI?"
113
+
114
+ 1. **Recognize opportunity**: Browser/webapp testing - likely has a skill
115
+ 2. **Ask user**: "Would you like me to look for webapp testing skills, or start coding right away?"
116
+ 3. **If user agrees, find skill**: Check anthropics/skills for webapp-testing
117
+ 4. **Download** (trusted source):
118
+ ```bash
119
+ git clone --depth 1 https://github.com/anthropics/skills /tmp/skills-temp
120
+ cp -r /tmp/skills-temp/skills/webapp-testing ~/.letta/skills/
121
+ rm -rf /tmp/skills-temp
122
+ ```
123
+ 5. **Refresh**: `Skill(command: "refresh")`
124
+ 6. **Inspect scripts**: Read any .py or .ts files before using them
125
+ 7. **Load**: `Skill(command: "load", skills: ["webapp-testing"])`
126
+ 8. **Use**: Follow the skill's instructions for the user's task
@@ -29,7 +29,6 @@ Best for: Extracting sections, cleaning up messy content, selective migration.
29
29
 
30
30
  Creates new blocks with the same content using `copy-block.ts`. After copying:
31
31
  - You own the copy - changes don't sync
32
- - Use `--label` flag if you already have a block with that label
33
32
  - Best for: One-time migration, forking an agent
34
33
 
35
34
  ### 3. Share (Linked Blocks)
@@ -40,7 +39,31 @@ Attaches the same block to multiple agents using `attach-block.ts`. After sharin
40
39
  - Can be read-only (target can read but not modify)
41
40
  - Best for: Shared knowledge bases, synchronized state
42
41
 
43
- **Note:** You cannot have two blocks with the same label. When copying, use `--label` to rename if needed.
42
+ ## Handling Duplicate Label Errors
43
+
44
+ **You cannot have two blocks with the same label.** If you try to copy/attach a block and you already have one with that label, you'll get a `duplicate key value violates unique constraint` error.
45
+
46
+ **Solutions:**
47
+
48
+ 1. **Use `--label` (copy only):** Rename the block when copying:
49
+ ```bash
50
+ npx tsx <SKILL_DIR>/scripts/copy-block.ts --block-id <id> --label project-imported
51
+ ```
52
+
53
+ 2. **Use `--override` (copy or attach):** Automatically detach your existing block first:
54
+ ```bash
55
+ npx tsx <SKILL_DIR>/scripts/copy-block.ts --block-id <id> --override
56
+ npx tsx <SKILL_DIR>/scripts/attach-block.ts --block-id <id> --override
57
+ ```
58
+ If the operation fails, the original block is automatically reattached.
59
+
60
+ 3. **Manual detach first:** Use the `memory` tool to detach your existing block:
61
+ ```
62
+ memory(agent_state, "delete", path="/memories/<label>")
63
+ ```
64
+ Then run the copy/attach script.
65
+
66
+ **Note:** `attach-block.ts` does NOT support `--label` because attached blocks keep their original label (they're shared, not copied).
44
67
 
45
68
  ## Workflow
46
69
 
@@ -92,8 +115,8 @@ All scripts are located in the `scripts/` directory and output raw API responses
92
115
  | Script | Purpose | Args |
93
116
  |--------|---------|------|
94
117
  | `get-agent-blocks.ts` | Get blocks from an agent | `--agent-id` |
95
- | `copy-block.ts` | Copy block to current agent | `--block-id`, optional `--label` |
96
- | `attach-block.ts` | Attach existing block to current agent | `--block-id`, optional `--read-only` |
118
+ | `copy-block.ts` | Copy block to current agent | `--block-id`, optional `--label`, `--override` |
119
+ | `attach-block.ts` | Attach existing block to current agent | `--block-id`, optional `--read-only`, `--override` |
97
120
 
98
121
  ## Authentication
99
122
 
@@ -7,7 +7,7 @@
7
7
  * It reads agent ID from LETTA_AGENT_ID env var or --agent-id arg.
8
8
  *
9
9
  * Usage:
10
- * npx tsx attach-block.ts --block-id <block-id> [--agent-id <agent-id>] [--read-only]
10
+ * npx tsx attach-block.ts --block-id <block-id> [--agent-id <agent-id>] [--read-only] [--override]
11
11
  *
12
12
  * This attaches an existing block to another agent, making it shared.
13
13
  * Changes to the block will be visible to all agents that have it attached.
@@ -15,6 +15,8 @@
15
15
  * Options:
16
16
  * --agent-id Target agent ID (overrides LETTA_AGENT_ID env var)
17
17
  * --read-only Target agent can read but not modify the block
18
+ * --override If you already have a block with the same label, detach it first
19
+ * (on error, the original block is reattached)
18
20
  *
19
21
  * Output:
20
22
  * Raw API response from the attach operation
@@ -75,49 +77,109 @@ function createClient(): LettaClient {
75
77
  return new Letta({ apiKey: getApiKey() });
76
78
  }
77
79
 
80
+ interface AttachBlockResult {
81
+ attachResult: Awaited<ReturnType<LettaClient["agents"]["blocks"]["attach"]>>;
82
+ detachedBlock?: Awaited<ReturnType<LettaClient["blocks"]["retrieve"]>>;
83
+ }
84
+
78
85
  /**
79
86
  * Attach an existing block to the current agent (sharing it)
80
87
  * @param client - Letta client instance
81
88
  * @param blockId - The block ID to attach
82
- * @param readOnly - Whether this agent should have read-only access
83
- * @param targetAgentId - Optional target agent ID (defaults to current agent)
89
+ * @param options - readOnly, targetAgentId, override (detach existing block with same label)
84
90
  * @returns API response from the attach operation
85
91
  */
86
92
  export async function attachBlock(
87
93
  client: LettaClient,
88
94
  blockId: string,
89
- readOnly = false,
90
- targetAgentId?: string,
91
- ): Promise<Awaited<ReturnType<typeof client.agents.blocks.attach>>> {
92
- // Get current agent ID (the agent calling this script) or use provided ID
93
- const currentAgentId = getAgentId(targetAgentId);
94
-
95
- const result = await client.agents.blocks.attach(blockId, {
96
- agent_id: currentAgentId,
97
- });
98
-
99
- // If read-only is requested, update the block's read_only flag for this agent
100
- // Note: This may require a separate API call depending on how read_only works
101
- if (readOnly) {
102
- // The read_only flag is per-block, not per-agent attachment
103
- // For now, we'll note this in the output
95
+ options?: { readOnly?: boolean; targetAgentId?: string; override?: boolean },
96
+ ): Promise<AttachBlockResult> {
97
+ const currentAgentId = getAgentId(options?.targetAgentId);
98
+ let detachedBlock:
99
+ | Awaited<ReturnType<LettaClient["blocks"]["retrieve"]>>
100
+ | undefined;
101
+
102
+ // If override is requested, check for existing block with same label and detach it
103
+ if (options?.override) {
104
+ // Get the block we're trying to attach to find its label
105
+ const sourceBlock = await client.blocks.retrieve(blockId);
106
+ const sourceLabel = sourceBlock.label;
107
+
108
+ // Get current agent's blocks to check for label conflict
109
+ const currentBlocksResponse =
110
+ await client.agents.blocks.list(currentAgentId);
111
+ // The response may be paginated or an array depending on SDK version
112
+ const currentBlocks = Array.isArray(currentBlocksResponse)
113
+ ? currentBlocksResponse
114
+ : (currentBlocksResponse as { items?: unknown[] }).items || [];
115
+ const conflictingBlock = currentBlocks.find(
116
+ (b: { label?: string }) => b.label === sourceLabel,
117
+ );
118
+
119
+ if (conflictingBlock) {
120
+ console.error(
121
+ `Detaching existing block with label "${sourceLabel}" (${conflictingBlock.id})...`,
122
+ );
123
+ detachedBlock = conflictingBlock;
124
+ try {
125
+ await client.agents.blocks.detach(conflictingBlock.id, {
126
+ agent_id: currentAgentId,
127
+ });
128
+ } catch (detachError) {
129
+ throw new Error(
130
+ `Failed to detach existing block "${sourceLabel}": ${detachError instanceof Error ? detachError.message : String(detachError)}`,
131
+ );
132
+ }
133
+ }
134
+ }
135
+
136
+ // Attempt to attach the new block
137
+ let attachResult: Awaited<ReturnType<typeof client.agents.blocks.attach>>;
138
+ try {
139
+ attachResult = await client.agents.blocks.attach(blockId, {
140
+ agent_id: currentAgentId,
141
+ });
142
+ } catch (attachError) {
143
+ // If attach failed and we detached a block, try to reattach it
144
+ if (detachedBlock) {
145
+ console.error(
146
+ `Attach failed, reattaching original block "${detachedBlock.label}"...`,
147
+ );
148
+ try {
149
+ await client.agents.blocks.attach(detachedBlock.id, {
150
+ agent_id: currentAgentId,
151
+ });
152
+ console.error("Original block reattached successfully.");
153
+ } catch {
154
+ console.error(
155
+ `WARNING: Failed to reattach original block! Block ID: ${detachedBlock.id}`,
156
+ );
157
+ }
158
+ }
159
+ throw attachError;
160
+ }
161
+
162
+ // If read-only is requested, note the limitation
163
+ if (options?.readOnly) {
104
164
  console.warn(
105
165
  "Note: read_only flag is set on the block itself, not per-agent. " +
106
166
  "Use the block update API to set read_only if needed.",
107
167
  );
108
168
  }
109
169
 
110
- return result;
170
+ return { attachResult, detachedBlock };
111
171
  }
112
172
 
113
173
  function parseArgs(args: string[]): {
114
174
  blockId: string;
115
175
  readOnly: boolean;
176
+ override: boolean;
116
177
  agentId?: string;
117
178
  } {
118
179
  const blockIdIndex = args.indexOf("--block-id");
119
180
  const agentIdIndex = args.indexOf("--agent-id");
120
181
  const readOnly = args.includes("--read-only");
182
+ const override = args.includes("--override");
121
183
 
122
184
  if (blockIdIndex === -1 || blockIdIndex + 1 >= args.length) {
123
185
  throw new Error("Missing required argument: --block-id <block-id>");
@@ -126,6 +188,7 @@ function parseArgs(args: string[]): {
126
188
  return {
127
189
  blockId: args[blockIdIndex + 1] as string,
128
190
  readOnly,
191
+ override,
129
192
  agentId:
130
193
  agentIdIndex !== -1 && agentIdIndex + 1 < args.length
131
194
  ? (args[agentIdIndex + 1] as string)
@@ -138,9 +201,15 @@ const isMainModule = import.meta.url === `file://${process.argv[1]}`;
138
201
  if (isMainModule) {
139
202
  (async () => {
140
203
  try {
141
- const { blockId, readOnly, agentId } = parseArgs(process.argv.slice(2));
204
+ const { blockId, readOnly, override, agentId } = parseArgs(
205
+ process.argv.slice(2),
206
+ );
142
207
  const client = createClient();
143
- const result = await attachBlock(client, blockId, readOnly, agentId);
208
+ const result = await attachBlock(client, blockId, {
209
+ readOnly,
210
+ override,
211
+ targetAgentId: agentId,
212
+ });
144
213
  console.log(JSON.stringify(result, null, 2));
145
214
  } catch (error) {
146
215
  console.error(
@@ -152,7 +221,7 @@ if (isMainModule) {
152
221
  error.message.includes("Missing required argument")
153
222
  ) {
154
223
  console.error(
155
- "\nUsage: npx tsx attach-block.ts --block-id <block-id> [--agent-id <agent-id>] [--read-only]",
224
+ "\nUsage: npx tsx attach-block.ts --block-id <block-id> [--agent-id <agent-id>] [--read-only] [--override]",
156
225
  );
157
226
  }
158
227
  process.exit(1);
@@ -7,11 +7,13 @@
7
7
  * It reads agent ID from LETTA_AGENT_ID env var or --agent-id arg.
8
8
  *
9
9
  * Usage:
10
- * npx tsx copy-block.ts --block-id <block-id> [--label <new-label>] [--agent-id <agent-id>]
10
+ * npx tsx copy-block.ts --block-id <block-id> [--label <new-label>] [--agent-id <agent-id>] [--override]
11
11
  *
12
12
  * Options:
13
- * --label Override the block label (required if you already have a block with that label)
13
+ * --label Override the block label (useful to avoid duplicate label errors)
14
14
  * --agent-id Target agent ID (overrides LETTA_AGENT_ID env var)
15
+ * --override If you already have a block with the same label, detach it first
16
+ * (on error, the original block is reattached)
15
17
  *
16
18
  * This creates a new block with the same content as the source block,
17
19
  * then attaches it to the current agent. Changes to the new block
@@ -37,6 +39,7 @@ interface CopyBlockResult {
37
39
  sourceBlock: Awaited<ReturnType<LettaClient["blocks"]["retrieve"]>>;
38
40
  newBlock: Awaited<ReturnType<LettaClient["blocks"]["create"]>>;
39
41
  attachResult: Awaited<ReturnType<LettaClient["agents"]["blocks"]["attach"]>>;
42
+ detachedBlock?: Awaited<ReturnType<LettaClient["blocks"]["retrieve"]>>;
40
43
  }
41
44
 
42
45
  /**
@@ -86,44 +89,125 @@ function createClient(): LettaClient {
86
89
  * Copy a block's content to a new block and attach to the current agent
87
90
  * @param client - Letta client instance
88
91
  * @param blockId - The source block ID to copy from
89
- * @param options - Optional settings: labelOverride, targetAgentId
92
+ * @param options - Optional settings: labelOverride, targetAgentId, override
90
93
  * @returns Object containing source block, new block, and attach result
91
94
  */
92
95
  export async function copyBlock(
93
96
  client: LettaClient,
94
97
  blockId: string,
95
- options?: { labelOverride?: string; targetAgentId?: string },
98
+ options?: {
99
+ labelOverride?: string;
100
+ targetAgentId?: string;
101
+ override?: boolean;
102
+ },
96
103
  ): Promise<CopyBlockResult> {
97
- // Get current agent ID (the agent calling this script) or use provided ID
98
104
  const currentAgentId = getAgentId(options?.targetAgentId);
105
+ let detachedBlock:
106
+ | Awaited<ReturnType<LettaClient["blocks"]["retrieve"]>>
107
+ | undefined;
99
108
 
100
109
  // 1. Get source block details
101
110
  const sourceBlock = await client.blocks.retrieve(blockId);
111
+ const targetLabel =
112
+ options?.labelOverride || sourceBlock.label || "migrated-block";
102
113
 
103
- // 2. Create new block with same content (optionally override label)
104
- const newBlock = await client.blocks.create({
105
- label: options?.labelOverride || sourceBlock.label || "migrated-block",
106
- value: sourceBlock.value,
107
- description: sourceBlock.description || undefined,
108
- limit: sourceBlock.limit,
109
- });
114
+ // 2. If override is requested, check for existing block with same label and detach it
115
+ if (options?.override) {
116
+ const currentBlocksResponse =
117
+ await client.agents.blocks.list(currentAgentId);
118
+ // The response may be paginated or an array depending on SDK version
119
+ const currentBlocks = Array.isArray(currentBlocksResponse)
120
+ ? currentBlocksResponse
121
+ : (currentBlocksResponse as { items?: unknown[] }).items || [];
122
+ const conflictingBlock = currentBlocks.find(
123
+ (b: { label?: string }) => b.label === targetLabel,
124
+ );
110
125
 
111
- // 3. Attach new block to current agent
112
- const attachResult = await client.agents.blocks.attach(newBlock.id, {
113
- agent_id: currentAgentId,
114
- });
126
+ if (conflictingBlock) {
127
+ console.error(
128
+ `Detaching existing block with label "${targetLabel}" (${conflictingBlock.id})...`,
129
+ );
130
+ detachedBlock = conflictingBlock;
131
+ try {
132
+ await client.agents.blocks.detach(conflictingBlock.id, {
133
+ agent_id: currentAgentId,
134
+ });
135
+ } catch (detachError) {
136
+ throw new Error(
137
+ `Failed to detach existing block "${targetLabel}": ${detachError instanceof Error ? detachError.message : String(detachError)}`,
138
+ );
139
+ }
140
+ }
141
+ }
115
142
 
116
- return { sourceBlock, newBlock, attachResult };
143
+ // 3. Create new block with same content
144
+ let newBlock: Awaited<ReturnType<LettaClient["blocks"]["create"]>>;
145
+ try {
146
+ newBlock = await client.blocks.create({
147
+ label: targetLabel,
148
+ value: sourceBlock.value,
149
+ description: sourceBlock.description || undefined,
150
+ limit: sourceBlock.limit,
151
+ });
152
+ } catch (createError) {
153
+ // If create failed and we detached a block, try to reattach it
154
+ if (detachedBlock) {
155
+ console.error(
156
+ `Create failed, reattaching original block "${detachedBlock.label}"...`,
157
+ );
158
+ try {
159
+ await client.agents.blocks.attach(detachedBlock.id, {
160
+ agent_id: currentAgentId,
161
+ });
162
+ console.error("Original block reattached successfully.");
163
+ } catch {
164
+ console.error(
165
+ `WARNING: Failed to reattach original block! Block ID: ${detachedBlock.id}`,
166
+ );
167
+ }
168
+ }
169
+ throw createError;
170
+ }
171
+
172
+ // 4. Attach new block to current agent
173
+ let attachResult: Awaited<ReturnType<typeof client.agents.blocks.attach>>;
174
+ try {
175
+ attachResult = await client.agents.blocks.attach(newBlock.id, {
176
+ agent_id: currentAgentId,
177
+ });
178
+ } catch (attachError) {
179
+ // If attach failed and we detached a block, try to reattach it
180
+ if (detachedBlock) {
181
+ console.error(
182
+ `Attach failed, reattaching original block "${detachedBlock.label}"...`,
183
+ );
184
+ try {
185
+ await client.agents.blocks.attach(detachedBlock.id, {
186
+ agent_id: currentAgentId,
187
+ });
188
+ console.error("Original block reattached successfully.");
189
+ } catch {
190
+ console.error(
191
+ `WARNING: Failed to reattach original block! Block ID: ${detachedBlock.id}`,
192
+ );
193
+ }
194
+ }
195
+ throw attachError;
196
+ }
197
+
198
+ return { sourceBlock, newBlock, attachResult, detachedBlock };
117
199
  }
118
200
 
119
201
  function parseArgs(args: string[]): {
120
202
  blockId: string;
121
203
  label?: string;
122
204
  agentId?: string;
205
+ override: boolean;
123
206
  } {
124
207
  const blockIdIndex = args.indexOf("--block-id");
125
208
  const labelIndex = args.indexOf("--label");
126
209
  const agentIdIndex = args.indexOf("--agent-id");
210
+ const override = args.includes("--override");
127
211
 
128
212
  if (blockIdIndex === -1 || blockIdIndex + 1 >= args.length) {
129
213
  throw new Error("Missing required argument: --block-id <block-id>");
@@ -139,6 +223,7 @@ function parseArgs(args: string[]): {
139
223
  agentIdIndex !== -1 && agentIdIndex + 1 < args.length
140
224
  ? (args[agentIdIndex + 1] as string)
141
225
  : undefined,
226
+ override,
142
227
  };
143
228
  }
144
229
 
@@ -147,11 +232,14 @@ const isMainModule = import.meta.url === `file://${process.argv[1]}`;
147
232
  if (isMainModule) {
148
233
  (async () => {
149
234
  try {
150
- const { blockId, label, agentId } = parseArgs(process.argv.slice(2));
235
+ const { blockId, label, agentId, override } = parseArgs(
236
+ process.argv.slice(2),
237
+ );
151
238
  const client = createClient();
152
239
  const result = await copyBlock(client, blockId, {
153
240
  labelOverride: label,
154
241
  targetAgentId: agentId,
242
+ override,
155
243
  });
156
244
  console.log(JSON.stringify(result, null, 2));
157
245
  } catch (error) {
@@ -164,7 +252,7 @@ if (isMainModule) {
164
252
  error.message.includes("Missing required argument")
165
253
  ) {
166
254
  console.error(
167
- "\nUsage: npx tsx copy-block.ts --block-id <block-id> [--label <new-label>] [--agent-id <agent-id>]",
255
+ "\nUsage: npx tsx copy-block.ts --block-id <block-id> [--label <new-label>] [--agent-id <agent-id>] [--override]",
168
256
  );
169
257
  }
170
258
  process.exit(1);