coding-agent-adapters 0.2.17 → 0.2.19

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/README.md CHANGED
@@ -161,6 +161,62 @@ aider.getRecommendedModels({ googleKey: 'AIza...' });
161
161
  // { powerful: 'gemini/gemini-3-pro', fast: 'gemini/gemini-3-flash' }
162
162
  ```
163
163
 
164
+ ## Workspace Files & Memory
165
+
166
+ Each coding agent CLI has its own convention for project-level memory files (instructions the agent reads on startup) and config files. Adapters expose this knowledge so orchestration systems can write context to the correct files before spawning an agent.
167
+
168
+ ### Discovering Workspace Files
169
+
170
+ ```typescript
171
+ import { ClaudeAdapter, AiderAdapter } from 'coding-agent-adapters';
172
+
173
+ const claude = new ClaudeAdapter();
174
+ claude.getWorkspaceFiles();
175
+ // [
176
+ // { relativePath: 'CLAUDE.md', type: 'memory', autoLoaded: true, format: 'markdown', ... },
177
+ // { relativePath: '.claude/settings.json', type: 'config', autoLoaded: true, format: 'json', ... },
178
+ // { relativePath: '.claude/commands', type: 'config', autoLoaded: false, format: 'markdown', ... },
179
+ // ]
180
+
181
+ claude.memoryFilePath; // 'CLAUDE.md'
182
+
183
+ const aider = new AiderAdapter();
184
+ aider.memoryFilePath; // '.aider.conventions.md'
185
+ ```
186
+
187
+ ### Per-Adapter File Mappings
188
+
189
+ | Adapter | Memory File | Config | Other |
190
+ |---------|------------|--------|-------|
191
+ | Claude | `CLAUDE.md` | `.claude/settings.json` | `.claude/commands` |
192
+ | Gemini | `GEMINI.md` | `.gemini/settings.json` | `.gemini/styles` |
193
+ | Codex | `AGENTS.md` | `.codex/config.json` | `codex.md` |
194
+ | Aider | `.aider.conventions.md` | `.aider.conf.yml` | `.aiderignore` |
195
+
196
+ ### Writing Memory Files
197
+
198
+ Use `writeMemoryFile()` to write instructions into a workspace before spawning an agent. Parent directories are created automatically.
199
+
200
+ ```typescript
201
+ const adapter = new ClaudeAdapter();
202
+
203
+ // Write to the adapter's default memory file (CLAUDE.md)
204
+ await adapter.writeMemoryFile('/path/to/workspace', `# Project Context
205
+ This is a TypeScript monorepo using pnpm workspaces.
206
+ Always run tests before committing.
207
+ `);
208
+
209
+ // Append to an existing memory file
210
+ await adapter.writeMemoryFile('/path/to/workspace', '\n## Additional Rules\nUse snake_case.\n', {
211
+ append: true,
212
+ });
213
+
214
+ // Write to a custom file (e.g., template-specific context for sub-agents)
215
+ await adapter.writeMemoryFile('/path/to/workspace', '# Task-Specific Context\n...', {
216
+ fileName: 'TASK_CONTEXT.md',
217
+ });
218
+ ```
219
+
164
220
  ## Preflight Check
165
221
 
166
222
  Before spawning agents, check if the required CLIs are installed:
@@ -218,12 +274,18 @@ Extend `BaseCodingAdapter` to create adapters for other coding CLIs:
218
274
 
219
275
  ```typescript
220
276
  import { BaseCodingAdapter } from 'coding-agent-adapters';
277
+ import type { AgentFileDescriptor, InstallationInfo, ModelRecommendations } from 'coding-agent-adapters';
221
278
  import type { SpawnConfig, ParsedOutput, LoginDetection, AutoResponseRule } from 'pty-manager';
222
279
 
223
280
  export class CursorAdapter extends BaseCodingAdapter {
224
281
  readonly adapterType = 'cursor';
225
282
  readonly displayName = 'Cursor';
226
283
 
284
+ readonly installation: InstallationInfo = {
285
+ command: 'npm install -g cursor-cli',
286
+ docsUrl: 'https://cursor.sh/docs',
287
+ };
288
+
227
289
  // Set to false if the CLI uses text prompts instead of TUI menus
228
290
  override readonly usesTuiMenus = false;
229
291
 
@@ -231,6 +293,16 @@ export class CursorAdapter extends BaseCodingAdapter {
231
293
  { pattern: /accept terms/i, type: 'tos', response: 'y', responseType: 'text', description: 'Accept TOS', safe: true, once: true },
232
294
  ];
233
295
 
296
+ getWorkspaceFiles(): AgentFileDescriptor[] {
297
+ return [
298
+ { relativePath: '.cursor/rules', description: 'Project rules', autoLoaded: true, type: 'memory', format: 'markdown' },
299
+ ];
300
+ }
301
+
302
+ getRecommendedModels(): ModelRecommendations {
303
+ return { powerful: 'claude-sonnet-4', fast: 'gpt-4o-mini' };
304
+ }
305
+
234
306
  getCommand(): string { return 'cursor'; }
235
307
  getArgs(config: SpawnConfig): string[] { return ['--cli']; }
236
308
  getEnv(config: SpawnConfig): Record<string, string> { return {}; }
package/dist/index.cjs CHANGED
@@ -1,5 +1,7 @@
1
1
  'use strict';
2
2
 
3
+ var promises = require('fs/promises');
4
+ var path = require('path');
3
5
  var ptyManager = require('pty-manager');
4
6
 
5
7
  // src/base-coding-adapter.ts
@@ -8,6 +10,17 @@ var BaseCodingAdapter = class extends ptyManager.BaseCLIAdapter {
8
10
  * Coding agent CLIs use TUI menus that require arrow-key navigation.
9
11
  */
10
12
  usesTuiMenus = true;
13
+ /**
14
+ * The primary memory file for this CLI (the one it reads for project instructions).
15
+ * Returns the relativePath of the first 'memory' type file from getWorkspaceFiles().
16
+ */
17
+ get memoryFilePath() {
18
+ const memoryFile = this.getWorkspaceFiles().find((f) => f.type === "memory");
19
+ if (!memoryFile) {
20
+ throw new Error(`${this.displayName} adapter has no memory file defined`);
21
+ }
22
+ return memoryFile.relativePath;
23
+ }
11
24
  /**
12
25
  * Get credentials from config
13
26
  */
@@ -101,6 +114,26 @@ Docs: ${this.installation.docsUrl}`
101
114
  content = content.trim();
102
115
  return content;
103
116
  }
117
+ /**
118
+ * Write content to this agent's memory file in a workspace.
119
+ * Creates parent directories as needed.
120
+ *
121
+ * @param workspacePath - Absolute path to the workspace root
122
+ * @param content - The memory/instructions content to write
123
+ * @param options - Optional: custom fileName, append mode
124
+ * @returns The absolute path of the written file
125
+ */
126
+ async writeMemoryFile(workspacePath, content, options) {
127
+ const relativePath = options?.fileName ?? this.memoryFilePath;
128
+ const fullPath = path.join(workspacePath, relativePath);
129
+ await promises.mkdir(path.dirname(fullPath), { recursive: true });
130
+ if (options?.append) {
131
+ await promises.appendFile(fullPath, content, "utf-8");
132
+ } else {
133
+ await promises.writeFile(fullPath, content, "utf-8");
134
+ }
135
+ return fullPath;
136
+ }
104
137
  };
105
138
 
106
139
  // src/claude-adapter.ts
@@ -173,6 +206,31 @@ var ClaudeAdapter = class extends BaseCodingAdapter {
173
206
  safe: true
174
207
  }
175
208
  ];
209
+ getWorkspaceFiles() {
210
+ return [
211
+ {
212
+ relativePath: "CLAUDE.md",
213
+ description: "Project-level instructions read automatically on startup",
214
+ autoLoaded: true,
215
+ type: "memory",
216
+ format: "markdown"
217
+ },
218
+ {
219
+ relativePath: ".claude/settings.json",
220
+ description: "Project-scoped settings (allowed tools, permissions)",
221
+ autoLoaded: true,
222
+ type: "config",
223
+ format: "json"
224
+ },
225
+ {
226
+ relativePath: ".claude/commands",
227
+ description: "Custom slash commands directory",
228
+ autoLoaded: false,
229
+ type: "config",
230
+ format: "markdown"
231
+ }
232
+ ];
233
+ }
176
234
  getRecommendedModels(_credentials) {
177
235
  return {
178
236
  powerful: "claude-sonnet-4-20250514",
@@ -379,6 +437,31 @@ var GeminiAdapter = class extends BaseCodingAdapter {
379
437
  once: true
380
438
  }
381
439
  ];
440
+ getWorkspaceFiles() {
441
+ return [
442
+ {
443
+ relativePath: "GEMINI.md",
444
+ description: "Project-level instructions read automatically on startup",
445
+ autoLoaded: true,
446
+ type: "memory",
447
+ format: "markdown"
448
+ },
449
+ {
450
+ relativePath: ".gemini/settings.json",
451
+ description: "Project-scoped settings (tool permissions, sandbox config)",
452
+ autoLoaded: true,
453
+ type: "config",
454
+ format: "json"
455
+ },
456
+ {
457
+ relativePath: ".gemini/styles",
458
+ description: "Custom style/persona definitions directory",
459
+ autoLoaded: false,
460
+ type: "config",
461
+ format: "markdown"
462
+ }
463
+ ];
464
+ }
382
465
  getRecommendedModels(_credentials) {
383
466
  return {
384
467
  powerful: "gemini-3-pro",
@@ -659,6 +742,31 @@ var CodexAdapter = class extends BaseCodingAdapter {
659
742
  safe: true
660
743
  }
661
744
  ];
745
+ getWorkspaceFiles() {
746
+ return [
747
+ {
748
+ relativePath: "AGENTS.md",
749
+ description: "Project-level instructions read automatically on startup",
750
+ autoLoaded: true,
751
+ type: "memory",
752
+ format: "markdown"
753
+ },
754
+ {
755
+ relativePath: "codex.md",
756
+ description: "Additional project context file",
757
+ autoLoaded: true,
758
+ type: "memory",
759
+ format: "markdown"
760
+ },
761
+ {
762
+ relativePath: ".codex/config.json",
763
+ description: "Project-scoped Codex configuration",
764
+ autoLoaded: true,
765
+ type: "config",
766
+ format: "json"
767
+ }
768
+ ];
769
+ }
662
770
  getRecommendedModels(_credentials) {
663
771
  return {
664
772
  powerful: "o3",
@@ -1032,6 +1140,31 @@ var AiderAdapter = class extends BaseCodingAdapter {
1032
1140
  safe: true
1033
1141
  }
1034
1142
  ];
1143
+ getWorkspaceFiles() {
1144
+ return [
1145
+ {
1146
+ relativePath: ".aider.conventions.md",
1147
+ description: "Project conventions and instructions read on startup (--read flag)",
1148
+ autoLoaded: true,
1149
+ type: "memory",
1150
+ format: "markdown"
1151
+ },
1152
+ {
1153
+ relativePath: ".aider.conf.yml",
1154
+ description: "Project-scoped Aider configuration (model, flags, options)",
1155
+ autoLoaded: true,
1156
+ type: "config",
1157
+ format: "yaml"
1158
+ },
1159
+ {
1160
+ relativePath: ".aiderignore",
1161
+ description: "Gitignore-style file listing paths Aider should not edit",
1162
+ autoLoaded: true,
1163
+ type: "rules",
1164
+ format: "text"
1165
+ }
1166
+ ];
1167
+ }
1035
1168
  getRecommendedModels(credentials) {
1036
1169
  if (credentials?.anthropicKey) {
1037
1170
  return {