opencodekit 0.12.7 → 0.13.1

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.
Files changed (32) hide show
  1. package/README.md +2 -2
  2. package/dist/index.js +2753 -508
  3. package/dist/template/.opencode/AGENTS.md +35 -128
  4. package/dist/template/.opencode/README.md +4 -3
  5. package/dist/template/.opencode/command/design.md +1 -0
  6. package/dist/template/.opencode/command/fix.md +28 -1
  7. package/dist/template/.opencode/command/implement.md +195 -39
  8. package/dist/template/.opencode/command/new-feature.md +229 -188
  9. package/dist/template/.opencode/command/plan.md +354 -82
  10. package/dist/template/.opencode/command/research.md +29 -6
  11. package/dist/template/.opencode/command/start.md +227 -0
  12. package/dist/template/.opencode/command/triage.md +66 -12
  13. package/dist/template/.opencode/memory/project/beads-workflow.md +510 -0
  14. package/dist/template/.opencode/memory/session-context.md +40 -0
  15. package/dist/template/.opencode/opencode.json +20 -5
  16. package/dist/template/.opencode/package.json +1 -1
  17. package/dist/template/.opencode/plugin/compaction.ts +62 -18
  18. package/dist/template/.opencode/plugin/lib/notify.ts +2 -3
  19. package/dist/template/.opencode/plugin/sessions.ts +1 -1
  20. package/dist/template/.opencode/plugin/skill-mcp.ts +11 -12
  21. package/dist/template/.opencode/skill/beads/SKILL.md +44 -0
  22. package/dist/template/.opencode/skill/source-code-research/SKILL.md +537 -0
  23. package/dist/template/.opencode/tool/ast-grep.ts +3 -3
  24. package/dist/template/.opencode/tool/bd-inbox.ts +7 -6
  25. package/dist/template/.opencode/tool/bd-msg.ts +3 -3
  26. package/dist/template/.opencode/tool/bd-release.ts +2 -2
  27. package/dist/template/.opencode/tool/bd-reserve.ts +5 -4
  28. package/dist/template/.opencode/tool/memory-read.ts +2 -2
  29. package/dist/template/.opencode/tool/memory-search.ts +2 -2
  30. package/dist/template/.opencode/tool/memory-update.ts +11 -12
  31. package/dist/template/.opencode/tool/observation.ts +6 -6
  32. package/package.json +5 -2
@@ -0,0 +1,537 @@
1
+ ---
2
+ name: source-code-research
3
+ description: >
4
+ Use when researching library implementation details beyond API docs. Fetches package source code
5
+ using opensrc to understand internals, edge cases, and implementation patterns. Complements
6
+ documentation-based research with actual code inspection.
7
+ version: "1.0.0"
8
+ license: MIT
9
+ ---
10
+
11
+ # Source Code Research - Deep Library Investigation
12
+
13
+ Fetch and analyze package source code when documentation is insufficient.
14
+
15
+ ## When to Use This Skill
16
+
17
+ Use source code research when:
18
+
19
+ - **Documentation gaps**: API docs don't explain behavior clearly
20
+ - **Edge cases**: Need to understand how library handles corner cases
21
+ - **Implementation details**: Need to see actual code, not just interfaces
22
+ - **Debugging**: Library behaving unexpectedly, need to trace internals
23
+ - **Evaluation**: Deciding if library fits requirements, need to assess quality
24
+ - **Type definitions**: TypeScript types exist but implementation unclear
25
+
26
+ **Don't use when:**
27
+
28
+ - Official docs answer your question (check Context7 first)
29
+ - You only need API syntax (codesearch is faster)
30
+ - Library is too large to analyze in session (>50k LOC)
31
+
32
+ ## Prerequisites
33
+
34
+ OpenSrc must be available:
35
+
36
+ ```bash
37
+ npx opensrc --help
38
+ ```
39
+
40
+ If not installed, it will be fetched via npx automatically.
41
+
42
+ ## Workflow
43
+
44
+ ### Step 1: Identify What to Fetch
45
+
46
+ Determine the minimal package/repo needed:
47
+
48
+ ```typescript
49
+ // If researching a specific npm package
50
+ const target = "zod"; // Just the package name
51
+
52
+ // If researching Python library
53
+ const target = "pypi:requests";
54
+
55
+ // If researching Rust crate
56
+ const target = "crates:serde";
57
+
58
+ // If researching GitHub repo directly
59
+ const target = "vercel/ai"; // or "github:vercel/ai@v3.0.0"
60
+ ```
61
+
62
+ ### Step 2: Fetch Source Code
63
+
64
+ Run opensrc to clone the repository:
65
+
66
+ ```bash
67
+ npx opensrc <package>
68
+ ```
69
+
70
+ **Examples:**
71
+
72
+ ```bash
73
+ npx opensrc zod # Fetch latest zod from npm
74
+ npx opensrc zod@3.22.0 # Fetch specific version
75
+ npx opensrc pypi:requests # Fetch Python package
76
+ npx opensrc vercel/ai # Fetch GitHub repo
77
+ npx opensrc vercel/ai@v3.0.0 # Fetch specific tag
78
+ ```
79
+
80
+ **What happens:**
81
+
82
+ - Clones source to `opensrc/repos/<host>/<owner>/<repo>/`
83
+ - Auto-detects version from lockfiles if no version specified
84
+ - Updates `opensrc/sources.json` with metadata
85
+ - Adds `opensrc/` to `.gitignore` automatically (asks once)
86
+
87
+ ### Step 3: Locate Relevant Code
88
+
89
+ Use search tools to find the code you need:
90
+
91
+ ```typescript
92
+ // Find all TypeScript source files
93
+ glob({ pattern: "opensrc/**/src/**/*.ts" });
94
+
95
+ // Search for specific function/class
96
+ grep({
97
+ pattern: "class ValidationError",
98
+ path: "opensrc/",
99
+ include: "*.ts",
100
+ });
101
+
102
+ // Use AST search for precise patterns
103
+ ast_grep({
104
+ pattern: "export function parse($$$) { $$$ }",
105
+ path: "opensrc/",
106
+ });
107
+ ```
108
+
109
+ ### Step 4: Read and Analyze
110
+
111
+ Read the implementation:
112
+
113
+ ```typescript
114
+ // Read the file
115
+ read({ filePath: "opensrc/repos/github.com/colinhacks/zod/src/types.ts" });
116
+
117
+ // Use LSP for navigation (if available)
118
+ lsp_lsp_goto_definition({
119
+ filePath: "opensrc/.../file.ts",
120
+ line: 42,
121
+ character: 10,
122
+ });
123
+
124
+ // Find all references
125
+ lsp_lsp_find_references({
126
+ filePath: "opensrc/.../file.ts",
127
+ line: 42,
128
+ character: 10,
129
+ });
130
+ ```
131
+
132
+ ### Step 5: Document Findings
133
+
134
+ Write research findings to bead artifact:
135
+
136
+ ````markdown
137
+ # Research: [Library Name] Implementation
138
+
139
+ **Package:** [name@version]
140
+ **Source:** opensrc/repos/[path]
141
+ **Focus:** [What you were investigating]
142
+
143
+ ## Key Findings
144
+
145
+ ### [Topic 1]: [Function/Pattern Name]
146
+
147
+ **Location:** `opensrc/repos/.../file.ts:42`
148
+
149
+ **Implementation:**
150
+
151
+ ```typescript
152
+ // Paste relevant code snippet
153
+ ```
154
+ ````
155
+
156
+ **Insights:**
157
+
158
+ - [What you learned]
159
+ - [Edge cases discovered]
160
+ - [Performance implications]
161
+
162
+ **Confidence:** High (direct source code)
163
+
164
+ ---
165
+
166
+ ### [Topic 2]: [Another Discovery]
167
+
168
+ [Same structure]
169
+
170
+ ## Answers to Original Questions
171
+
172
+ 1. **Q:** [Original question]
173
+ **A:** [Answer based on source code]
174
+ **Evidence:** `file.ts:123-145`
175
+
176
+ 2. **Q:** [Another question]
177
+ **A:** [Answer]
178
+
179
+ ## Recommendations
180
+
181
+ Based on source analysis:
182
+
183
+ - [Recommendation 1]
184
+ - [Recommendation 2]
185
+
186
+ ## Caveats
187
+
188
+ - Version analyzed: [version]
189
+ - Code may have changed in newer versions
190
+ - Private APIs discovered may change without notice
191
+
192
+ ````
193
+
194
+ ## Common Patterns
195
+
196
+ ### Pattern 1: Understanding Error Handling
197
+
198
+ ```typescript
199
+ // 1. Fetch package
200
+ // bash: npx opensrc zod
201
+
202
+ // 2. Find error classes
203
+ grep({ pattern: "class.*Error", path: "opensrc/", include: "*.ts" });
204
+
205
+ // 3. Read error implementation
206
+ read({ filePath: "opensrc/repos/.../errors.ts" });
207
+
208
+ // 4. Find where errors are thrown
209
+ grep({ pattern: "throw new", path: "opensrc/", include: "*.ts" });
210
+ ````
211
+
212
+ ### Pattern 2: Tracing Function Behavior
213
+
214
+ ```typescript
215
+ // 1. Fetch source
216
+ // bash: npx opensrc react-hook-form
217
+
218
+ // 2. Find function definition
219
+ ast_grep({
220
+ pattern: "export function useForm($$$) { $$$ }",
221
+ path: "opensrc/",
222
+ });
223
+
224
+ // 3. Read implementation
225
+ read({ filePath: "opensrc/.../useForm.ts" });
226
+
227
+ // 4. Find dependencies
228
+ grep({ pattern: "import.*from", path: "opensrc/.../useForm.ts" });
229
+ ```
230
+
231
+ ### Pattern 3: Evaluating Library Quality
232
+
233
+ ```typescript
234
+ // 1. Fetch source
235
+ // bash: npx opensrc candidate-library
236
+
237
+ // 2. Check test coverage
238
+ glob({ pattern: "opensrc/**/*.test.ts" });
239
+ glob({ pattern: "opensrc/**/*.spec.ts" });
240
+
241
+ // 3. Read tests for usage patterns
242
+ read({ filePath: "opensrc/.../feature.test.ts" });
243
+
244
+ // 4. Check for TypeScript usage
245
+ glob({ pattern: "opensrc/**/tsconfig.json" });
246
+
247
+ // 5. Review package.json for dependencies
248
+ read({ filePath: "opensrc/.../package.json" });
249
+ ```
250
+
251
+ ## Source Structure Guide
252
+
253
+ ### npm Packages
254
+
255
+ ```
256
+ opensrc/
257
+ └── repos/
258
+ └── github.com/ # npm packages resolve to GitHub
259
+ └── owner/
260
+ └── repo/
261
+ ├── src/ # Source code (usually)
262
+ ├── dist/ # Built output (ignore)
263
+ ├── test/ # Tests (useful for examples)
264
+ ├── package.json # Dependencies, scripts
265
+ └── README.md # Often has examples
266
+ ```
267
+
268
+ ### Python Packages (PyPI)
269
+
270
+ ```
271
+ opensrc/
272
+ └── repos/
273
+ └── github.com/ # Most PyPI packages on GitHub
274
+ └── owner/
275
+ └── repo/
276
+ ├── src/ # or package_name/
277
+ ├── tests/ # Python tests
278
+ ├── setup.py # Package config
279
+ └── pyproject.toml
280
+ ```
281
+
282
+ ### Rust Crates
283
+
284
+ ```
285
+ opensrc/
286
+ └── repos/
287
+ └── github.com/
288
+ └── owner/
289
+ └── repo/
290
+ ├── src/
291
+ │ └── lib.rs # Main library file
292
+ ├── tests/
293
+ ├── Cargo.toml # Dependencies
294
+ └── examples/ # Usage examples
295
+ ```
296
+
297
+ ## Tips for Efficient Analysis
298
+
299
+ ### 1. Start with Tests
300
+
301
+ Tests often show real-world usage better than docs:
302
+
303
+ ```typescript
304
+ glob({ pattern: "opensrc/**/*.test.{ts,js}" });
305
+ read({ filePath: "opensrc/.../feature.test.ts" });
306
+ ```
307
+
308
+ ### 2. Check Examples Directory
309
+
310
+ Many repos have `examples/` or `samples/`:
311
+
312
+ ```typescript
313
+ glob({ pattern: "opensrc/**/examples/**/*" });
314
+ ```
315
+
316
+ ### 3. Read CHANGELOG for Context
317
+
318
+ Understand recent changes:
319
+
320
+ ```typescript
321
+ read({ filePath: "opensrc/.../CHANGELOG.md" });
322
+ ```
323
+
324
+ ### 4. Check TypeScript Definitions
325
+
326
+ Often more accurate than docs:
327
+
328
+ ```typescript
329
+ glob({ pattern: "opensrc/**/*.d.ts" });
330
+ read({ filePath: "opensrc/.../index.d.ts" });
331
+ ```
332
+
333
+ ### 5. Use Blame for History (if needed)
334
+
335
+ ```bash
336
+ cd opensrc/repos/github.com/owner/repo
337
+ git log --oneline -- src/file.ts
338
+ git show <commit>:src/file.ts
339
+ ```
340
+
341
+ ## Limitations
342
+
343
+ ### When Source Code Won't Help
344
+
345
+ - **Build-time transforms**: Source may differ from runtime (Babel, webpack)
346
+ - **Native modules**: C/C++ code requires different analysis
347
+ - **Minified code**: Some packages don't publish source
348
+ - **Monorepos**: May need to navigate complex structure
349
+
350
+ ### Alternatives
351
+
352
+ If opensrc doesn't work:
353
+
354
+ 1. **GitHub web interface**: Browse online at github.com/owner/repo
355
+ 2. **npm unpacked**: `npm pack <package>` then extract
356
+ 3. **node_modules**: If already installed, check `node_modules/<package>/`
357
+ 4. **Source maps**: If debugging, browser DevTools may show original source
358
+
359
+ ## Integration with Other Research Methods
360
+
361
+ Source code research complements other tools:
362
+
363
+ | Method | Best For | Source Code Adds |
364
+ | -------------- | -------------------------- | ------------------------------ |
365
+ | **Context7** | API docs, official guides | Implementation details |
366
+ | **codesearch** | Usage patterns in the wild | Canonical implementation |
367
+ | **gh_grep** | Real-world examples | How library itself works |
368
+ | **Web search** | Tutorials, blog posts | Ground truth from source |
369
+ | **Codebase** | Project-specific patterns | How dependencies actually work |
370
+
371
+ **Recommended flow:**
372
+
373
+ 1. Context7 - Check official docs
374
+ 2. Codebase - Check existing usage
375
+ 3. **Source code** - If still unclear, fetch source
376
+ 4. codesearch/gh_grep - See how others use it
377
+ 5. Web search - Last resort for context
378
+
379
+ ## Cleanup
380
+
381
+ After research is complete:
382
+
383
+ ```bash
384
+ # Remove specific package
385
+ npx opensrc remove <package>
386
+
387
+ # Remove all sources
388
+ npx opensrc clean
389
+
390
+ # Remove just npm packages
391
+ npx opensrc clean --npm
392
+
393
+ # Keep sources for documentation
394
+ # (opensrc/ is gitignored, won't be committed)
395
+ ```
396
+
397
+ ## Example: Complete Workflow
398
+
399
+ **Scenario:** Need to understand how zod handles async refinements.
400
+
401
+ ```bash
402
+ # 1. Fetch source
403
+ npx opensrc zod
404
+ ```
405
+
406
+ ```typescript
407
+ // 2. Find refinement code
408
+ grep({
409
+ pattern: "refine.*async",
410
+ path: "opensrc/",
411
+ include: "*.ts",
412
+ });
413
+
414
+ // 3. Locate implementation
415
+ ast_grep({
416
+ pattern: "refine($$$) { $$$ }",
417
+ path: "opensrc/repos/github.com/colinhacks/zod/",
418
+ });
419
+
420
+ // 4. Read the implementation
421
+ read({
422
+ filePath: "opensrc/repos/github.com/colinhacks/zod/src/types.ts",
423
+ offset: 500,
424
+ limit: 100,
425
+ });
426
+
427
+ // 5. Check tests for usage examples
428
+ glob({
429
+ pattern: "opensrc/**/zod/**/*.test.ts",
430
+ });
431
+
432
+ read({
433
+ filePath: "opensrc/repos/.../async.test.ts",
434
+ });
435
+
436
+ // 6. Document findings
437
+ write({
438
+ filePath: ".beads/artifacts/bd-xxx/research.md",
439
+ content: `# Zod Async Refinements
440
+
441
+ **Finding:** Async refinements use \`parseAsync()\` not \`parse()\`
442
+
443
+ **Evidence:** \`src/types.ts:842-856\`
444
+
445
+ Async refinements return Promise<Output> and require:
446
+ - Use \`.parseAsync()\` method
447
+ - Refinement function must return Promise<boolean>
448
+ - Errors handled via Promise rejection
449
+
450
+ **Code snippet:**
451
+ [paste relevant code]
452
+
453
+ **Recommendation:** Use \`.refine(async (val) => {...})\` with \`.parseAsync()\`
454
+ `,
455
+ });
456
+ ```
457
+
458
+ ## Success Criteria
459
+
460
+ You've successfully used this skill when:
461
+
462
+ - [ ] Fetched correct package/version source
463
+ - [ ] Located relevant implementation code
464
+ - [ ] Understood behavior from reading source
465
+ - [ ] Documented findings with file:line references
466
+ - [ ] Answered original research question with high confidence
467
+ - [ ] Provided code evidence for claims
468
+
469
+ ## Anti-Patterns
470
+
471
+ ### ❌ Don't: Fetch Entire Ecosystem
472
+
473
+ ```bash
474
+ # Bad: Fetching everything
475
+ npx opensrc react
476
+ npx opensrc react-dom
477
+ npx opensrc react-router
478
+ npx opensrc react-query
479
+ # ... (too much code)
480
+ ```
481
+
482
+ **Do:** Fetch only what you need to answer specific question.
483
+
484
+ ### ❌ Don't: Read Random Files
485
+
486
+ ```typescript
487
+ // Bad: Reading without purpose
488
+ read({ filePath: "opensrc/.../index.ts" });
489
+ read({ filePath: "opensrc/.../utils.ts" });
490
+ read({ filePath: "opensrc/.../helpers.ts" });
491
+ // ... (unfocused exploration)
492
+ ```
493
+
494
+ **Do:** Use grep/ast-grep to find relevant code first, then read.
495
+
496
+ ### ❌ Don't: Ignore Version Mismatch
497
+
498
+ ```bash
499
+ # Bad: Fetching latest when project uses old version
500
+ npx opensrc zod # Fetches 3.23.x
501
+ # But project uses zod@3.20.0 (different behavior)
502
+ ```
503
+
504
+ **Do:** Specify version matching your lockfile, or let opensrc auto-detect.
505
+
506
+ ## Quick Reference
507
+
508
+ ```bash
509
+ # Fetch package source
510
+ npx opensrc <package> # npm (auto-detect version)
511
+ npx opensrc <package>@<version> # npm (specific version)
512
+ npx opensrc pypi:<package> # Python
513
+ npx opensrc crates:<package> # Rust
514
+ npx opensrc <owner>/<repo> # GitHub
515
+ npx opensrc <owner>/<repo>@<tag> # GitHub (specific tag)
516
+
517
+ # List fetched sources
518
+ npx opensrc list
519
+ npx opensrc list --json
520
+
521
+ # Remove sources
522
+ npx opensrc remove <package>
523
+ npx opensrc clean
524
+ npx opensrc clean --npm --pypi --crates
525
+
526
+ # Source location
527
+ opensrc/repos/<host>/<owner>/<repo>/
528
+
529
+ # Metadata
530
+ opensrc/sources.json
531
+ ```
532
+
533
+ ## Further Reading
534
+
535
+ - OpenSrc Docs: https://github.com/vercel-labs/opensrc
536
+ - When to read source vs docs: https://danluu.com/read-code/
537
+ - Code reading techniques: https://www.codeproject.com/Articles/10/Code-Reading
@@ -6,8 +6,8 @@
6
6
  * Requires: npm install -g @ast-grep/cli (or brew install ast-grep)
7
7
  */
8
8
 
9
- import { exec } from "child_process";
10
- import { promisify } from "util";
9
+ import { exec } from "node:child_process";
10
+ import { promisify } from "node:util";
11
11
  import { tool } from "@opencode-ai/plugin";
12
12
 
13
13
  const execAsync = promisify(exec);
@@ -224,7 +224,7 @@ Install via:
224
224
  preview += `... and ${count - 10} more matches\n`;
225
225
  }
226
226
 
227
- preview += `\n**To apply:** Run again with dryRun: false`;
227
+ preview += "\n**To apply:** Run again with dryRun: false";
228
228
  return preview;
229
229
  } catch {
230
230
  return `Dry run preview:\n${stdout}`;
@@ -1,6 +1,6 @@
1
- import path from "path";
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
2
3
  import { tool } from "@opencode-ai/plugin";
3
- import fs from "fs/promises";
4
4
 
5
5
  const RESERVATIONS_DIR = ".reservations";
6
6
  const MESSAGES_FILE = "messages.jsonl";
@@ -84,7 +84,7 @@ export default tool({
84
84
  }
85
85
  await fs.writeFile(
86
86
  messagesPath,
87
- allMsgs.map((m) => JSON.stringify(m)).join("\n") + "\n",
87
+ `${allMsgs.map((m) => JSON.stringify(m)).join("\n")}\n`,
88
88
  "utf-8",
89
89
  );
90
90
  }
@@ -99,11 +99,12 @@ export default tool({
99
99
  messages = messages.slice(-limit).reverse();
100
100
 
101
101
  return JSON.stringify({ msgs: messages, count: messages.length });
102
- } catch (e: any) {
103
- if (e.code === "ENOENT") {
102
+ } catch (e) {
103
+ const err = e as NodeJS.ErrnoException;
104
+ if (err.code === "ENOENT") {
104
105
  return JSON.stringify({ msgs: [], count: 0 });
105
106
  }
106
- return JSON.stringify({ error: e.message });
107
+ return JSON.stringify({ error: (e as Error).message });
107
108
  }
108
109
  },
109
110
  });
@@ -1,6 +1,6 @@
1
- import path from "path";
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
2
3
  import { tool } from "@opencode-ai/plugin";
3
- import fs from "fs/promises";
4
4
 
5
5
  const RESERVATIONS_DIR = ".reservations";
6
6
  const MESSAGES_FILE = "messages.jsonl";
@@ -56,7 +56,7 @@ export default tool({
56
56
  read: false,
57
57
  };
58
58
 
59
- await fs.appendFile(messagesPath, JSON.stringify(msg) + "\n", "utf-8");
59
+ await fs.appendFile(messagesPath, `${JSON.stringify(msg)}\n`, "utf-8");
60
60
  return JSON.stringify({ ok: 1, id: msg.id });
61
61
  },
62
62
  });
@@ -1,6 +1,6 @@
1
- import path from "path";
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
2
3
  import { tool } from "@opencode-ai/plugin";
3
- import fs from "fs/promises";
4
4
 
5
5
  const RESERVATIONS_DIR = ".reservations";
6
6
 
@@ -1,6 +1,6 @@
1
- import path from "path";
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
2
3
  import { tool } from "@opencode-ai/plugin";
3
- import fs from "fs/promises";
4
4
 
5
5
  const RESERVATIONS_DIR = ".reservations";
6
6
 
@@ -69,8 +69,9 @@ export default tool({
69
69
  };
70
70
  await fs.writeFile(metaPath, JSON.stringify(lockData), "utf-8");
71
71
  granted.push(filePath);
72
- } catch (e: any) {
73
- if (e.code === "EEXIST") {
72
+ } catch (e) {
73
+ const err = e as NodeJS.ErrnoException;
74
+ if (err.code === "EEXIST") {
74
75
  // Lock exists - check if expired or ours
75
76
  try {
76
77
  const content = await fs.readFile(metaPath, "utf-8");
@@ -1,6 +1,6 @@
1
- import path from "path";
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
2
3
  import { tool } from "@opencode-ai/plugin";
3
- import fs from "fs/promises";
4
4
 
5
5
  export default tool({
6
6
  description:
@@ -1,6 +1,6 @@
1
- import path from "path";
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
2
3
  import { tool } from "@opencode-ai/plugin";
3
- import fs from "fs/promises";
4
4
 
5
5
  interface SearchResult {
6
6
  file: string;
@@ -1,6 +1,6 @@
1
- import path from "path";
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
2
3
  import { tool } from "@opencode-ai/plugin";
3
- import fs from "fs/promises";
4
4
 
5
5
  export default tool({
6
6
  description:
@@ -41,21 +41,20 @@ export default tool({
41
41
  const appendContent = `\n\n---\n**Updated:** ${timestamp}\n\n${args.content}`;
42
42
  await fs.appendFile(filePath, appendContent, "utf-8");
43
43
  return `Successfully appended to ${normalizedFile}.md\n[Written to: ${filePath}]`;
44
- } else {
45
- // Replace mode - update timestamp
46
- const timestamp = new Date().toISOString();
47
- const updatedContent = args.content.replace(
48
- /\*\*Last Updated:\*\* \[Timestamp\]/,
49
- `**Last Updated:** ${timestamp}`,
50
- );
51
- await fs.writeFile(filePath, updatedContent, "utf-8");
52
- return `Successfully updated ${normalizedFile}.md\n[Written to: ${filePath}]`;
53
44
  }
45
+ // Replace mode - update timestamp
46
+ const timestamp = new Date().toISOString();
47
+ const updatedContent = args.content.replace(
48
+ /\*\*Last Updated:\*\* \[Timestamp\]/,
49
+ `**Last Updated:** ${timestamp}`,
50
+ );
51
+ await fs.writeFile(filePath, updatedContent, "utf-8");
52
+ return `Successfully updated ${normalizedFile}.md\n[Written to: ${filePath}]`;
54
53
  } catch (error) {
55
54
  if (error instanceof Error) {
56
55
  return `Error updating memory: ${error.message}`;
57
56
  }
58
- return `Unknown error updating memory file`;
57
+ return "Unknown error updating memory file";
59
58
  }
60
59
  },
61
60
  });