๐Ÿ“ commands/copy/ ยท 01_command_definition_strategy.md

Chapter 1: Command Definition Strategy

๐Ÿ“„ commands/copy/01_command_definition_strategy.md

Chapter 1: Command Definition Strategy

Welcome to the first chapter of our journey building the copy command!

Why do we need a "Strategy"?

Imagine you walk into a restaurant and sit down. You pick up the menu. You see the names of dishes: "Burger", "Salad", "Pasta".

Now, imagine if the kitchen started cooking every single dish on the menu the moment you sat down, just in case you ordered one. That would be chaotic, slow, and wasteful!

Instead, the restaurant uses a strategy:

  1. The Menu (Metadata): Light, easy to read, just names and descriptions.
  2. The Kitchen (Implementation): Heavy work, starts cooking only after you place an order.

The Command Definition Strategy does exactly this for our software.

The Use Case

Our CLI tool might have dozens of commands. When a user starts the tool, we want it to feel instant.


How it Works

Let's look at how we define the copy command. We create a small object that acts as the "Menu Item."

1. Setting up the Definition

First, we define the basic identity of our command. This file is lightweight and loads instantly.

// index.ts
import type { Command } from '../../commands.js'

// This is our lightweight "Menu Item"
const copy = {
  type: 'local-jsx', // Tells the CLI this uses UI components
  name: 'copy',      // The command the user types
  description: "Copy Claude's last response to clipboard",
  // ... logic comes next
}

Explanation:

2. The "Lazy" Load

This is the magic part. We use a function to load the heavy code only when the command is actually triggered.

// index.ts (continued)

const copy = {
  // ... previous properties (name, type)
  
  // The kitchen starts cooking ONLY when this function is called
  load: () => import('./copy.js'),
} satisfies Command

export default copy

Explanation:


Under the Hood: The Sequence

What happens when the application starts?

  1. The CLI loads our Command Definition (the menu).
  2. It reads the name and description.
  3. It waits.
  4. Only when the user types copy does it run the load() function.

Here is a diagram showing this flow:

sequenceDiagram participant User participant CLI as CLI Core participant Def as Command Definition participant Heavy as Heavy Logic (copy.tsx) User->>CLI: Starts Application CLI->>Def: Read Name & Description Def-->>CLI: "I am 'copy'" Note over CLI: CLI is ready (Fast startup!) User->>CLI: Types "copy" CLI->>Def: Run load() function Def->>Heavy: Import the heavy code... Heavy-->>CLI: Return the Logic CLI->>User: Execute Command

Deep Dive: The Implementation

The code we looked at earlier is located in index.ts. It acts as the "Gatekeeper."

It separates the Interface (what the command looks like) from the Implementation (what the command does).

/**
 * Copy command - minimal metadata only.
 * Implementation is lazy-loaded from copy.tsx to reduce startup time.
 */
import type { Command } from '../../commands.js'

const copy = {
  type: 'local-jsx',
  name: 'copy',
  description:
    "Copy Claude's last response to clipboard (or /copy N for the Nth-latest)",
  load: () => import('./copy.js'),
} satisfies Command

export default copy

By using export default copy, we make this definition available to the main application. The main app collects these lightweight objects from all commands to build its help menu.

Now that the CLI knows how to load our command, it needs to know what to load. The load function points to ./copy.js. This is where the real work happens.

In that file, the first thing we need to do is go back in time and find what Claude said previously so we can copy it.

Conclusion

In this chapter, we learned the Command Definition Strategy.

Now that the command is defined and the application knows how to load it, we need to build the actual logic. The first step of the copy logic is finding the text we want to copy.

Next: Message History Retrieval


Generated by Code IQ