apex-fast 0.0.2-next.1 → 0.0.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/Morph-Rules.md ADDED
@@ -0,0 +1,167 @@
1
+ # Morph Fast Apply - AI Agent Instructions
2
+
3
+ > **What is morph_edit / fastApply?** A tool that allows you to edit files using partial code snippets tagged with `// ... existing code ...` markers. Morph's AI merges your changes into the full file at 10,500+ tokens/sec with 98% accuracy.
4
+
5
+ ---
6
+
7
+ ## Choosing the Right Tool
8
+
9
+ | Situation | Tool | Reason |
10
+ | ----------------------------------- | ----------- | -------------------------------------------------------------------- |
11
+ | **Small, exact string replacement** | `edit` | **FASTEST.** No API call, immediate execution. |
12
+ | **Simple variable/function rename** | `edit` | Precise, no AI needed. |
13
+ | **Large file (300+ lines)** | `fastApply` | 10x faster, handles partial snippets without reading the whole file. |
14
+ | **Multiple scattered changes** | `fastApply` | Batch changes efficiently in one pass. |
15
+ | **Complex refactoring** | `fastApply` | AI understands context better than strict string matching. |
16
+ | **Whitespace-sensitive edits** | `fastApply` | Forgiving with formatting differences. |
17
+
18
+ ### ❌ Anti-Patterns (When NOT to use fastApply)
19
+
20
+ - **Do NOT** use for single-line changes (e.g., changing a port number). Use `edit`.
21
+ - **Do NOT** use for simple typo fixes. Use `edit`.
22
+ - **Do NOT** use for creating brand new files. Use `write`/`create`.
23
+
24
+ ---
25
+
26
+ ## Quick Reference
27
+
28
+ **IMPORTANT:** Use `fastApply` over `str_replace_editor` or full file writes. It works with partial code snippets—no need for full file content.
29
+
30
+ ---
31
+
32
+ ## CRITICAL: Omitting Markers Causes Deletions
33
+
34
+ **If you omit the `// ... existing code ...` markers, Morph will DELETE that code.**
35
+
36
+ ```javascript
37
+ // BAD - will DELETE everything before and after the function
38
+ function newFeature() {
39
+ return 'hello';
40
+ }
41
+
42
+ // GOOD - preserves existing code
43
+ // ... existing code ...
44
+ function newFeature() {
45
+ return 'hello';
46
+ }
47
+ // ... existing code ...
48
+ ```
49
+
50
+ **Always wrap your changes with markers at the start AND end** unless you intend to replace the entire file.
51
+
52
+ ### 🛡️ Pre-flight Validation
53
+
54
+ If you attempt a `fastApply` on a large file (>10 lines) and provide no `// ... existing code ...` markers, the plugin will **automatically reject the edit**. This failsafe prevents the AI from unintentionally wiping out entire files. Ensure your `codeEdit` param correctly utilizes markers.
55
+
56
+ ---
57
+
58
+ ## Instructions Parameter
59
+
60
+ **This is critical for accuracy.** Write a first-person description of your changes.
61
+
62
+ **Good:** "I am adding error handling for null users and removing the deprecated auth check"
63
+
64
+ **Bad:** "Update code" / "Fix bug" / "Add stuff"
65
+
66
+ ---
67
+
68
+ ## Examples
69
+
70
+ ### Adding a new function
71
+
72
+ ```javascript
73
+ // ... existing code ...
74
+ import { newDep } from './newDep';
75
+ // ... existing code ...
76
+
77
+ function newFeature() {
78
+ return newDep.process();
79
+ }
80
+ // ... existing code ...
81
+ ```
82
+
83
+ ### Modifying existing code
84
+
85
+ ```javascript
86
+ // ... existing code ...
87
+ function existingFunc(param) {
88
+ // Updated implementation
89
+ const result = param * 2; // Changed from * 1
90
+ return result;
91
+ }
92
+ // ... existing code ...
93
+ ```
94
+
95
+ ### Adding a timeout to fetch (From Morph docs)
96
+
97
+ ```javascript
98
+ // ... existing code ...
99
+ export async function fetchData(endpoint: string) {
100
+ // ... existing code ...
101
+ const response = await fetch(endpoint, {
102
+ headers,
103
+ timeout: 5000 // added timeout
104
+ });
105
+ // ... existing code ...
106
+ }
107
+ // ... existing code ...
108
+ ```
109
+
110
+ ### Deleting code (Show what remains)
111
+
112
+ ```javascript
113
+ // ... existing code ...
114
+ function keepThis() {
115
+ return 'stays';
116
+ }
117
+
118
+ // The function between these two was removed
119
+
120
+ function alsoKeepThis() {
121
+ return 'also stays';
122
+ }
123
+ // ... existing code ...
124
+ ```
125
+
126
+ ---
127
+
128
+ ## Providing Context for Disambiguation
129
+
130
+ When a file has similar code patterns, include enough unique context:
131
+
132
+ ```javascript
133
+ // BAD - "return result" could match many places
134
+ // ... existing code ...
135
+ return result;
136
+ }
137
+ // ... existing code ...
138
+
139
+ // GOOD - unique function signature anchors the location accurately
140
+ // ... existing code ...
141
+ function processUserData(userId) {
142
+ const result = await fetchUser(userId);
143
+ return result;
144
+ }
145
+ // ... existing code ...
146
+ ```
147
+
148
+ ---
149
+
150
+ ## Common Mistakes
151
+
152
+ | Mistake | Result | Fix |
153
+ | ----------------------- | ------------------------- | ------------------------------------------------------------ |
154
+ | No markers at start/end | Deletes code before/after | Always start and end snippet with `// ... existing code ...` |
155
+ | Too little context | Wrong location chosen | Add 1-2 unique lines around your change |
156
+ | Vague instructions | Ambiguous merge | Be specific: what, where, why |
157
+ | Using for tiny changes | Slower than `edit` | Use native `edit` for 1-2 line exact replacements |
158
+
159
+ ---
160
+
161
+ ## Fallback Behavior
162
+
163
+ If the Morph API fails (timeout, rate limit, etc.):
164
+
165
+ 1. An error message containing the specifics is returned
166
+ 2. Use the native `edit` tool as a fallback
167
+ 3. Note that the native `edit` tool requires exact string matching
package/README.md CHANGED
@@ -1,33 +1,208 @@
1
1
  # apex-fast
2
2
 
3
- Fast Apply is a tool that you give to your AI agent that allows it to edit code or files.
3
+ **apex-fast** is a plugin for [OpenCode AI](https://opencode.ai) that integrates [Morph Fast Apply](https://morphllm.com) — an AI model specialized for code editing boasting 10,500+ tokens/second speeds and 98% accuracy. This plugin overrides the built-in edit tool with `morph_edit`, which is significantly faster for large files and complex changes.
4
4
 
5
- > A Bun module created from the [bun-module](https://github.com/zenobi-us/bun-module) template
5
+ ---
6
6
 
7
- ## Usage
7
+ ## ✨ Features
8
8
 
9
- <!-- Example usage code goes here -->
9
+ - **10x Faster** Uses partial snippets, no need to read the entire file
10
+ - 🧠 **Smart Routing** — Automatically selects `morph-v3-fast` or `morph-v3-large` models based on instruction complexity
11
+ - 🔒 **Overrides `edit` Tool** — Blocks the built-in `edit` tool and directs the AI to use `fastApply` instead
12
+ - 🛡️ **Pre-flight Validation & Readonly Agents Protection** — Prevents catastrophic accidental deletions and disables edits in `plan` or `explore` modes.
13
+ - 🛠️ **MCP Server** — Can be run as a standalone MCP server (local via stdio or remote via SSE)
10
14
 
11
- ## Installation
15
+ ---
12
16
 
13
- <!-- Installation instructions go here -->
17
+ ## 🚀 Installation
14
18
 
15
- ## Development
19
+ ### Step 1: Get Morph API Key
16
20
 
17
- - `mise run build` - Build the module
18
- - `mise run test` - Run tests
19
- - `mise run lint` - Lint code
20
- - `mise run lint:fix` - Fix linting issues
21
- - `mise run format` - Format code with Prettier
21
+ Sign up and get your API key at **[morphllm.com](https://morphllm.com)**.
22
22
 
23
- ## Release
23
+ ---
24
24
 
25
- See the [RELEASE.md](RELEASE.md) file for instructions on how to release a new version of the module.
25
+ ### Step 2: Configure Plugin in OpenCode
26
26
 
27
- ## Contributing
27
+ Edit your `~/.config/opencode/opencode.json` file and add the plugin:
28
28
 
29
- Contributions are welcome! Please file issues or submit pull requests on the GitHub repository.
29
+ ```json
30
+ {
31
+ "plugin": ["apex-fast@latest"],
32
+ "instructions": ["Follow Instructions in `~/.config/opencode/Morph-Rules.md`"]
33
+ }
34
+ ```
30
35
 
31
- ## License
36
+ > **Note:** The `"instructions"` field tells the AI to read `Morph-Rules.md` as its guide on when to use `fastApply` vs other tools.
37
+
38
+ ---
39
+
40
+ ### Step 3: Install `Morph-Rules.md` _(REQUIRED)_
41
+
42
+ The `Morph-Rules.md` file acts as the primary behavioral guideline for the AI. You **must** copy it into your OpenCode config directory. Without it, the AI won't know how to use `morph_edit` properly.
43
+
44
+ ```bash
45
+ # Download Morph-Rules.md into your OpenCode config directory
46
+ curl -o ~/.config/opencode/Morph-Rules.md \
47
+ https://raw.githubusercontent.com/yunaamelia/apex-fast/main/Morph-Rules.md
48
+ ```
49
+
50
+ Alternatively, manually copy it from this repository.
51
+
52
+ ---
53
+
54
+ ### Step 4: Set Environment Variable
55
+
56
+ The plugin requires the `MORPH_API_KEY` to be available in your environment.
57
+
58
+ **Permanent approach (recommended):**
59
+
60
+ ```bash
61
+ # Add to ~/.bashrc or ~/.zshrc
62
+ echo 'export MORPH_API_KEY="sk-your-key-here"' >> ~/.bashrc
63
+ source ~/.bashrc
64
+ ```
65
+
66
+ **Or** add it directly to a `.env` file in your working directory:
67
+
68
+ ```env
69
+ MORPH_API_KEY=sk-your-key-here
70
+ ```
71
+
72
+ ---
73
+
74
+ ## 🛠️ Using the `fastApply` Tool
75
+
76
+ Once the plugin is active, your AI will have access to the `fastApply` tool. Use the syntax `// ... existing code ...` as a marker for unchanged code.
77
+
78
+ ### Parameters
79
+
80
+ | Parameter | Type | Required | Description |
81
+ | -------------- | -------- | -------- | ------------------------------------------------------------- |
82
+ | `filePath` | `string` | ✅ | Relative path to the file you want to edit |
83
+ | `instructions` | `string` | ✅ | Specific instructions detailing what to change |
84
+ | `codeEdit` | `string` | ❌ | Partial code snippet using `// ... existing code ...` markers |
85
+
86
+ ### Usage Examples
87
+
88
+ **Adding a new function:**
89
+
90
+ ```javascript
91
+ // ... existing code ...
92
+ import { newDep } from './newDep';
93
+ // ... existing code ...
94
+
95
+ function newFeature() {
96
+ return newDep.process();
97
+ }
98
+ // ... existing code ...
99
+ ```
100
+
101
+ **Modifying existing code:**
102
+
103
+ ```javascript
104
+ // ... existing code ...
105
+ function existingFunc(param) {
106
+ // Updated implementation
107
+ const result = param * 2; // Changed from * 1
108
+ return result;
109
+ }
110
+ // ... existing code ...
111
+ ```
112
+
113
+ > ⚠️ **IMPORTANT:** Always include `// ... existing code ...` at the beginning and end of your snippet. Otherwise, Morph will **delete** the code outside of the snippet.
114
+
115
+ ---
116
+
117
+ ## 📋 Tool Selection Guide
118
+
119
+ | Situation | Tool | Reason |
120
+ | -------------------------------- | ----------- | ----------------------------------------- |
121
+ | Small & exact string replacement | `edit` | Fastest, no API call |
122
+ | Simple variable/function rename | `edit` | Precise, no AI needed |
123
+ | **Large files (300+ lines)** | `fastApply` | 10x faster, partial snippets |
124
+ | **Multiple scattered changes** | `fastApply` | Batch changes in one pass |
125
+ | **Complex refactoring** | `fastApply` | AI parses context better |
126
+ | **Whitespace-sensitive edits** | `fastApply` | High tolerance for formatting differences |
127
+
128
+ ---
129
+
130
+ ## 🖥️ Running as an MCP Server (Optional)
131
+
132
+ This plugin can also run as a **standalone MCP Server** for use with other MCP clients (like Claude Desktop).
133
+
134
+ ### Stdio Mode (Default)
135
+
136
+ ```bash
137
+ MORPH_API_KEY=sk-your-key npx apex-fast-mcp
138
+ ```
139
+
140
+ ### SSE Mode (Remote/HTTP)
141
+
142
+ ```bash
143
+ MORPH_API_KEY=sk-your-key npx apex-fast-mcp sse 3000
144
+ ```
145
+
146
+ The server will run on:
147
+
148
+ - **SSE Endpoint:** `http://localhost:3000/sse`
149
+ - **Message Endpoint:** `http://localhost:3000/message`
150
+
151
+ ---
152
+
153
+ ## ⚠️ Troubleshooting
154
+
155
+ ### Error: `[ERROR] Missing MORPH_API_KEY`
156
+
157
+ The plugin cannot find the API key. Ensure:
158
+
159
+ - The `MORPH_API_KEY` environment variable is set
160
+ - If using `.env`, the file exists in the current working directory
161
+
162
+ ### Error: `[ERROR] Failed to read file`
163
+
164
+ The specific `filePath` cannot be read. Ensure:
165
+
166
+ - The path provided is **relative** to the current working directory
167
+ - The file actually exists
168
+
169
+ ### Pre-flight Validation Error
170
+
171
+ If you attempt to edit a large file (>10 lines) and omit the `// ... existing code ...` markers, the plugin will block the tool call to prevent catastrophic code loss. The AI should simply rewrite the `codeEdit` parameter correctly wrapped inside markers.
172
+
173
+ ### Fallback Behavior for Morph API Failure
174
+
175
+ If Morph API times out or rate limits:
176
+
177
+ 1. The plugin will return an error message containing the specifics
178
+ 2. The AI can fall back to using the built-in `edit` tool
179
+ 3. The built-in `edit` tool requires exact string matching
180
+
181
+ ---
182
+
183
+ ## 🔧 Development
184
+
185
+ ```bash
186
+ mise run build # Build the project
187
+ mise run test # Run the test suite
188
+ mise run lint # Lint the code
189
+ mise run lint:fix # Automatically fix linting issues
190
+ ```
191
+
192
+ ---
193
+
194
+ ## 📦 Release
195
+
196
+ See the [RELEASE.md](RELEASE.md) file for instructions on how to release a new version.
197
+
198
+ ---
199
+
200
+ ## 🤝 Contributing
201
+
202
+ Contributions are very welcome! Please open an issue or submit a pull request on the GitHub repository.
203
+
204
+ ---
205
+
206
+ ## 📄 License
32
207
 
33
208
  See the [LICENSE](LICENSE) file for details.
package/dist/index.js CHANGED
@@ -94,7 +94,7 @@ function isTextualFile(filePath, maxBytes = 2000000) {
94
94
  var init_chunk_YPKNMYD4 = () => {};
95
95
 
96
96
  // node_modules/@vscode/ripgrep/lib/index.js
97
- var __dirname = "/home/runner/work/apex-fast/apex-fast/node_modules/@vscode/ripgrep/lib", path2, $rgPath;
97
+ var __dirname = "/home/racoondev/my-module/node_modules/@vscode/ripgrep/lib", path2, $rgPath;
98
98
  var init_lib = __esm(() => {
99
99
  path2 = __require("path");
100
100
  $rgPath = path2.join(__dirname, `../bin/rg${process.platform === "win32" ? ".exe" : ""}`);
@@ -64705,6 +64705,11 @@ var FastApplyPlugin = async (ctx) => {
64705
64705
  codeEdit: tool.schema.string().optional().describe("The specific code snippet to edit (optional)")
64706
64706
  },
64707
64707
  execute: async (args, context) => {
64708
+ console.log(`[DEBUG] fastApply called for file: ${args.filePath}`);
64709
+ const READONLY_AGENTS = ["plan", "explore"];
64710
+ if (context && context.agent && READONLY_AGENTS.includes(context.agent)) {
64711
+ throw new Error(`[ERROR] fastApply is not available in ${context.agent} mode. Please switch to a build/code mode.`);
64712
+ }
64708
64713
  const directory = ctx?.directory || context?.directory || process.cwd();
64709
64714
  const absolutePath = path6.join(directory, args.filePath);
64710
64715
  let originalCode;
@@ -64718,6 +64723,15 @@ var FastApplyPlugin = async (ctx) => {
64718
64723
  }
64719
64724
  let result;
64720
64725
  try {
64726
+ if (args.codeEdit) {
64727
+ const lines = originalCode.split(`
64728
+ `);
64729
+ const isLargeFile = lines.length > 10;
64730
+ const hasMarkers = args.codeEdit.includes("... existing code ...");
64731
+ if (isLargeFile && !hasMarkers) {
64732
+ throw new Error("[ERROR] codeEdit missing '// ... existing code ...' markers for file >10 lines. This prevents catastrophic deletion. Please wrap partial edits with markers.");
64733
+ }
64734
+ }
64721
64735
  const { difficulty } = await morph.routers.raw.classify({
64722
64736
  input: args.instructions
64723
64737
  });
@@ -64749,6 +64763,18 @@ var FastApplyPlugin = async (ctx) => {
64749
64763
  }
64750
64764
  }
64751
64765
  })
64766
+ },
64767
+ "tool.execute.after": async (input, output) => {
64768
+ if (input.tool === "fastApply") {
64769
+ const fileMatch = output.output.match(/Successfully applied changes to (.+)/);
64770
+ if (fileMatch) {
64771
+ output.title = `Morph: applied changes to ${fileMatch[1]}`;
64772
+ }
64773
+ output.metadata = {
64774
+ ...output.metadata,
64775
+ provider: "morph"
64776
+ };
64777
+ }
64752
64778
  }
64753
64779
  };
64754
64780
  };