coding-agent-adapters 0.2.19 → 0.4.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/dist/index.cjs CHANGED
@@ -4,6 +4,364 @@ var promises = require('fs/promises');
4
4
  var path = require('path');
5
5
  var ptyManager = require('pty-manager');
6
6
 
7
+ // src/base-coding-adapter.ts
8
+
9
+ // src/approval-presets.ts
10
+ var TOOL_CATEGORIES = [
11
+ { category: "file_read", risk: "low", description: "Read files, search, list directories" },
12
+ { category: "file_write", risk: "medium", description: "Write, edit, and create files" },
13
+ { category: "shell", risk: "high", description: "Execute shell commands" },
14
+ { category: "web", risk: "medium", description: "Web search and fetch" },
15
+ { category: "agent", risk: "medium", description: "Spawn sub-agents, skills, MCP tools" },
16
+ { category: "planning", risk: "low", description: "Task planning and todo management" },
17
+ { category: "user_interaction", risk: "low", description: "Ask user questions" }
18
+ ];
19
+ var PRESET_DEFINITIONS = [
20
+ {
21
+ preset: "readonly",
22
+ description: "Read-only. Safe for auditing.",
23
+ autoApprove: ["file_read", "planning", "user_interaction"],
24
+ requireApproval: [],
25
+ blocked: ["file_write", "shell", "web", "agent"]
26
+ },
27
+ {
28
+ preset: "standard",
29
+ description: "Standard dev. Reads + web auto, writes/shell prompt.",
30
+ autoApprove: ["file_read", "planning", "user_interaction", "web"],
31
+ requireApproval: ["file_write", "shell", "agent"],
32
+ blocked: []
33
+ },
34
+ {
35
+ preset: "permissive",
36
+ description: "File ops auto-approved, shell still prompts.",
37
+ autoApprove: ["file_read", "file_write", "planning", "user_interaction", "web", "agent"],
38
+ requireApproval: ["shell"],
39
+ blocked: []
40
+ },
41
+ {
42
+ preset: "autonomous",
43
+ description: "Everything auto-approved. Use with sandbox.",
44
+ autoApprove: ["file_read", "file_write", "shell", "web", "agent", "planning", "user_interaction"],
45
+ requireApproval: [],
46
+ blocked: []
47
+ }
48
+ ];
49
+ var CLAUDE_TOOL_CATEGORIES = {
50
+ // file_read
51
+ Read: "file_read",
52
+ Grep: "file_read",
53
+ Glob: "file_read",
54
+ LS: "file_read",
55
+ NotebookRead: "file_read",
56
+ // file_write
57
+ Write: "file_write",
58
+ Edit: "file_write",
59
+ MultiEdit: "file_write",
60
+ NotebookEdit: "file_write",
61
+ // shell
62
+ Bash: "shell",
63
+ BashOutput: "shell",
64
+ KillShell: "shell",
65
+ // web
66
+ WebSearch: "web",
67
+ WebFetch: "web",
68
+ // agent
69
+ Task: "agent",
70
+ Skill: "agent",
71
+ // planning
72
+ TodoWrite: "planning",
73
+ // user_interaction
74
+ AskUserQuestion: "user_interaction"
75
+ };
76
+ var GEMINI_TOOL_CATEGORIES = {
77
+ // file_read
78
+ read_file: "file_read",
79
+ read_many_files: "file_read",
80
+ list_directory: "file_read",
81
+ glob: "file_read",
82
+ search_file_content: "file_read",
83
+ // file_write
84
+ write_file: "file_write",
85
+ replace: "file_write",
86
+ // shell
87
+ run_shell_command: "shell",
88
+ // web
89
+ web_fetch: "web",
90
+ google_web_search: "web",
91
+ // agent
92
+ activate_skill: "agent",
93
+ get_internal_docs: "agent",
94
+ // planning
95
+ save_memory: "planning",
96
+ write_todos: "planning",
97
+ // user_interaction
98
+ ask_user: "user_interaction"
99
+ };
100
+ var CODEX_TOOL_CATEGORIES = {
101
+ // shell (codex uses shell for most operations)
102
+ exec_command: "shell",
103
+ write_stdin: "shell",
104
+ shell_command: "shell",
105
+ // file_write
106
+ apply_patch: "file_write",
107
+ // file_read
108
+ grep_files: "file_read",
109
+ read_file: "file_read",
110
+ list_dir: "file_read",
111
+ // web
112
+ web_search: "web",
113
+ view_image: "web",
114
+ // agent
115
+ spawn_agent: "agent",
116
+ send_input: "agent",
117
+ resume_agent: "agent",
118
+ wait: "agent",
119
+ close_agent: "agent",
120
+ // planning
121
+ update_plan: "planning",
122
+ // user_interaction
123
+ request_user_input: "user_interaction"
124
+ };
125
+ var AIDER_COMMAND_CATEGORIES = {
126
+ // file_read
127
+ "/read-only": "file_read",
128
+ "/ls": "file_read",
129
+ "/map": "file_read",
130
+ "/map-refresh": "file_read",
131
+ "/tokens": "file_read",
132
+ "/diff": "file_read",
133
+ "/context": "file_read",
134
+ // file_write
135
+ "/add": "file_write",
136
+ "/drop": "file_write",
137
+ "/edit": "file_write",
138
+ "/code": "file_write",
139
+ "/architect": "file_write",
140
+ "/undo": "file_write",
141
+ // shell
142
+ "/run": "shell",
143
+ "/test": "shell",
144
+ "/lint": "shell",
145
+ "/git": "shell",
146
+ // web
147
+ "/web": "web",
148
+ // planning
149
+ "/ask": "planning",
150
+ // user_interaction
151
+ "/voice": "user_interaction",
152
+ "/help": "user_interaction",
153
+ // config/other
154
+ "/model": "planning",
155
+ "/settings": "planning",
156
+ "/commit": "file_write",
157
+ "/clear": "planning",
158
+ "/reset": "planning"
159
+ };
160
+ function getToolsForCategories(mapping, categories) {
161
+ return Object.entries(mapping).filter(([, cat]) => categories.includes(cat)).map(([tool]) => tool);
162
+ }
163
+ function generateClaudeApprovalConfig(preset) {
164
+ const def = getPresetDefinition(preset);
165
+ const allowTools = getToolsForCategories(CLAUDE_TOOL_CATEGORIES, def.autoApprove);
166
+ const denyTools = getToolsForCategories(CLAUDE_TOOL_CATEGORIES, def.blocked);
167
+ const settings = {
168
+ permissions: {}
169
+ };
170
+ const permissions = settings.permissions;
171
+ if (allowTools.length > 0) {
172
+ permissions.allow = allowTools;
173
+ }
174
+ if (denyTools.length > 0) {
175
+ permissions.deny = denyTools;
176
+ }
177
+ if (preset === "autonomous") {
178
+ settings.sandbox = {
179
+ enabled: true,
180
+ autoAllowBashIfSandboxed: true
181
+ };
182
+ }
183
+ const cliFlags = [];
184
+ if (preset === "autonomous") {
185
+ const allTools = Object.keys(CLAUDE_TOOL_CATEGORIES);
186
+ cliFlags.push("--tools", allTools.join(","));
187
+ }
188
+ return {
189
+ preset,
190
+ cliFlags,
191
+ workspaceFiles: [
192
+ {
193
+ relativePath: ".claude/settings.json",
194
+ content: JSON.stringify(settings, null, 2),
195
+ format: "json"
196
+ }
197
+ ],
198
+ envVars: {},
199
+ summary: `Claude Code: ${def.description}`
200
+ };
201
+ }
202
+ function generateGeminiApprovalConfig(preset) {
203
+ const def = getPresetDefinition(preset);
204
+ const cliFlags = [];
205
+ const allowedTools = getToolsForCategories(GEMINI_TOOL_CATEGORIES, def.autoApprove);
206
+ const excludeTools = getToolsForCategories(GEMINI_TOOL_CATEGORIES, def.blocked);
207
+ let approvalMode;
208
+ switch (preset) {
209
+ case "readonly":
210
+ approvalMode = "plan";
211
+ cliFlags.push("--approval-mode", "plan");
212
+ break;
213
+ case "standard":
214
+ approvalMode = "default";
215
+ break;
216
+ case "permissive":
217
+ approvalMode = "auto_edit";
218
+ cliFlags.push("--approval-mode", "auto_edit");
219
+ break;
220
+ case "autonomous":
221
+ approvalMode = "auto_edit";
222
+ cliFlags.push("-y");
223
+ break;
224
+ }
225
+ const settings = {
226
+ general: {
227
+ defaultApprovalMode: approvalMode
228
+ },
229
+ tools: {}
230
+ };
231
+ const tools = settings.tools;
232
+ if (allowedTools.length > 0) {
233
+ tools.allowed = allowedTools;
234
+ }
235
+ if (excludeTools.length > 0) {
236
+ tools.exclude = excludeTools;
237
+ }
238
+ return {
239
+ preset,
240
+ cliFlags,
241
+ workspaceFiles: [
242
+ {
243
+ relativePath: ".gemini/settings.json",
244
+ content: JSON.stringify(settings, null, 2),
245
+ format: "json"
246
+ }
247
+ ],
248
+ envVars: {},
249
+ summary: `Gemini CLI: ${def.description}`
250
+ };
251
+ }
252
+ function generateCodexApprovalConfig(preset) {
253
+ const cliFlags = [];
254
+ let approvalPolicy;
255
+ let sandboxMode;
256
+ let webSearch;
257
+ switch (preset) {
258
+ case "readonly":
259
+ approvalPolicy = "untrusted";
260
+ sandboxMode = "workspace-read";
261
+ webSearch = false;
262
+ cliFlags.push("--sandbox", "workspace-read", "-a", "untrusted");
263
+ break;
264
+ case "standard":
265
+ approvalPolicy = "on-failure";
266
+ sandboxMode = "workspace-write";
267
+ webSearch = true;
268
+ cliFlags.push("--sandbox", "workspace-write");
269
+ break;
270
+ case "permissive":
271
+ approvalPolicy = "on-request";
272
+ sandboxMode = "workspace-write";
273
+ webSearch = true;
274
+ cliFlags.push("-a", "on-request");
275
+ break;
276
+ case "autonomous":
277
+ approvalPolicy = "never";
278
+ sandboxMode = "workspace-write";
279
+ webSearch = true;
280
+ cliFlags.push("--full-auto");
281
+ break;
282
+ }
283
+ const config = {
284
+ approval_policy: approvalPolicy,
285
+ sandbox_mode: sandboxMode,
286
+ tools: {
287
+ web_search: webSearch
288
+ }
289
+ };
290
+ return {
291
+ preset,
292
+ cliFlags,
293
+ workspaceFiles: [
294
+ {
295
+ relativePath: ".codex/config.json",
296
+ content: JSON.stringify(config, null, 2),
297
+ format: "json"
298
+ }
299
+ ],
300
+ envVars: {},
301
+ summary: `Codex: ${getPresetDefinition(preset).description}`
302
+ };
303
+ }
304
+ function generateAiderApprovalConfig(preset) {
305
+ const def = getPresetDefinition(preset);
306
+ const cliFlags = [];
307
+ const lines = [];
308
+ switch (preset) {
309
+ case "readonly":
310
+ lines.push("yes-always: false");
311
+ lines.push("no-auto-commits: true");
312
+ cliFlags.push("--no-auto-commits");
313
+ break;
314
+ case "standard":
315
+ lines.push("yes-always: false");
316
+ break;
317
+ case "permissive":
318
+ lines.push("yes-always: true");
319
+ cliFlags.push("--yes-always");
320
+ break;
321
+ case "autonomous":
322
+ lines.push("yes-always: true");
323
+ cliFlags.push("--yes-always");
324
+ break;
325
+ }
326
+ return {
327
+ preset,
328
+ cliFlags,
329
+ workspaceFiles: [
330
+ {
331
+ relativePath: ".aider.conf.yml",
332
+ content: lines.join("\n") + "\n",
333
+ format: "yaml"
334
+ }
335
+ ],
336
+ envVars: {},
337
+ summary: `Aider: ${def.description}`
338
+ };
339
+ }
340
+ function generateApprovalConfig(adapterType, preset) {
341
+ switch (adapterType) {
342
+ case "claude":
343
+ return generateClaudeApprovalConfig(preset);
344
+ case "gemini":
345
+ return generateGeminiApprovalConfig(preset);
346
+ case "codex":
347
+ return generateCodexApprovalConfig(preset);
348
+ case "aider":
349
+ return generateAiderApprovalConfig(preset);
350
+ default:
351
+ throw new Error(`Unknown adapter type: ${adapterType}`);
352
+ }
353
+ }
354
+ function listPresets() {
355
+ return [...PRESET_DEFINITIONS];
356
+ }
357
+ function getPresetDefinition(preset) {
358
+ const def = PRESET_DEFINITIONS.find((d) => d.preset === preset);
359
+ if (!def) {
360
+ throw new Error(`Unknown preset: ${preset}`);
361
+ }
362
+ return def;
363
+ }
364
+
7
365
  // src/base-coding-adapter.ts
8
366
  var BaseCodingAdapter = class extends ptyManager.BaseCLIAdapter {
9
367
  /**
@@ -114,6 +472,40 @@ Docs: ${this.installation.docsUrl}`
114
472
  content = content.trim();
115
473
  return content;
116
474
  }
475
+ // ─────────────────────────────────────────────────────────────────────────────
476
+ // Approval Presets
477
+ // ─────────────────────────────────────────────────────────────────────────────
478
+ /**
479
+ * Extract the approval preset from a spawn config, if set.
480
+ */
481
+ getApprovalPreset(config) {
482
+ const adapterConfig = config.adapterConfig;
483
+ return adapterConfig?.approvalPreset;
484
+ }
485
+ /**
486
+ * Generate the approval config for this adapter, if a preset is set.
487
+ */
488
+ getApprovalConfig(config) {
489
+ const preset = this.getApprovalPreset(config);
490
+ if (!preset) return null;
491
+ return generateApprovalConfig(this.adapterType, preset);
492
+ }
493
+ /**
494
+ * Write approval config files to a workspace directory.
495
+ * Returns the list of files written (absolute paths).
496
+ */
497
+ async writeApprovalConfig(workspacePath, config) {
498
+ const approvalConfig = this.getApprovalConfig(config);
499
+ if (!approvalConfig) return [];
500
+ const written = [];
501
+ for (const file of approvalConfig.workspaceFiles) {
502
+ const fullPath = path.join(workspacePath, file.relativePath);
503
+ await promises.mkdir(path.dirname(fullPath), { recursive: true });
504
+ await promises.writeFile(fullPath, file.content, "utf-8");
505
+ written.push(fullPath);
506
+ }
507
+ return written;
508
+ }
117
509
  /**
118
510
  * Write content to this agent's memory file in a workspace.
119
511
  * Creates parent directories as needed.
@@ -248,6 +640,10 @@ var ClaudeAdapter = class extends BaseCodingAdapter {
248
640
  args.push("--cwd", config.workdir);
249
641
  }
250
642
  }
643
+ const approvalConfig = this.getApprovalConfig(config);
644
+ if (approvalConfig) {
645
+ args.push(...approvalConfig.cliFlags);
646
+ }
251
647
  return args;
252
648
  }
253
649
  getEnv(config) {
@@ -353,6 +749,29 @@ var ClaudeAdapter = class extends BaseCodingAdapter {
353
749
  }
354
750
  return super.detectBlockingPrompt(output);
355
751
  }
752
+ /**
753
+ * Detect task completion for Claude Code.
754
+ *
755
+ * High-confidence pattern: turn duration summary + idle prompt.
756
+ * Claude Code shows "<Verb> for Xm Ys" (e.g. "Cooked for 3m 12s")
757
+ * when a turn completes, followed by the ❯ input prompt.
758
+ *
759
+ * Patterns from: AGENT_LOADING_STATUS_PATTERNS.json
760
+ * - claude_completed_turn_duration
761
+ * - claude_completed_turn_duration_custom_verb
762
+ */
763
+ detectTaskComplete(output) {
764
+ const stripped = this.stripAnsi(output);
765
+ const hasDuration = /[A-Z][A-Za-z' -]{2,40}\s+for\s+\d+(?:h\s+\d{1,2}m\s+\d{1,2}s|m\s+\d{1,2}s|s)/.test(stripped);
766
+ const hasIdlePrompt = /❯\s*$/.test(stripped);
767
+ if (hasDuration && hasIdlePrompt) {
768
+ return true;
769
+ }
770
+ if (hasIdlePrompt && stripped.includes("for shortcuts")) {
771
+ return true;
772
+ }
773
+ return false;
774
+ }
356
775
  detectReady(output) {
357
776
  const stripped = this.stripAnsi(output);
358
777
  if (/trust.*directory|do you want to|needs? your permission/i.test(stripped)) {
@@ -480,6 +899,10 @@ var GeminiAdapter = class extends BaseCodingAdapter {
480
899
  args.push("--cwd", config.workdir);
481
900
  }
482
901
  }
902
+ const approvalConfig = this.getApprovalConfig(config);
903
+ if (approvalConfig) {
904
+ args.push(...approvalConfig.cliFlags);
905
+ }
483
906
  return args;
484
907
  }
485
908
  getEnv(config) {
@@ -606,6 +1029,26 @@ var GeminiAdapter = class extends BaseCodingAdapter {
606
1029
  }
607
1030
  return super.detectBlockingPrompt(output);
608
1031
  }
1032
+ /**
1033
+ * Detect task completion for Gemini CLI.
1034
+ *
1035
+ * High-confidence patterns:
1036
+ * - "◇ Ready" window title signal (OSC sequence, may survive ANSI stripping)
1037
+ * - "Type your message" composer placeholder after agent output
1038
+ *
1039
+ * Patterns from: AGENT_LOADING_STATUS_PATTERNS.json
1040
+ * - gemini_ready_title
1041
+ */
1042
+ detectTaskComplete(output) {
1043
+ const stripped = this.stripAnsi(output);
1044
+ if (/◇\s+Ready/.test(stripped)) {
1045
+ return true;
1046
+ }
1047
+ if (/type.?your.?message/i.test(stripped)) {
1048
+ return true;
1049
+ }
1050
+ return false;
1051
+ }
609
1052
  detectReady(output) {
610
1053
  const stripped = this.stripAnsi(output);
611
1054
  if (/type.?your.?message/i.test(stripped)) {
@@ -784,6 +1227,10 @@ var CodexAdapter = class extends BaseCodingAdapter {
784
1227
  args.push("--cwd", config.workdir);
785
1228
  }
786
1229
  }
1230
+ const approvalConfig = this.getApprovalConfig(config);
1231
+ if (approvalConfig) {
1232
+ args.push(...approvalConfig.cliFlags);
1233
+ }
787
1234
  return args;
788
1235
  }
789
1236
  getEnv(config) {
@@ -912,6 +1359,32 @@ var CodexAdapter = class extends BaseCodingAdapter {
912
1359
  }
913
1360
  return super.detectBlockingPrompt(output);
914
1361
  }
1362
+ /**
1363
+ * Detect task completion for Codex CLI.
1364
+ *
1365
+ * High-confidence patterns:
1366
+ * - "Worked for Xm Ys" separator after work-heavy turns
1367
+ * - "› Ask Codex to do anything" ready prompt
1368
+ *
1369
+ * Patterns from: AGENT_LOADING_STATUS_PATTERNS.json
1370
+ * - codex_completed_worked_for_separator
1371
+ * - codex_ready_prompt
1372
+ */
1373
+ detectTaskComplete(output) {
1374
+ const stripped = this.stripAnsi(output);
1375
+ const hasWorkedFor = /Worked\s+for\s+\d+(?:h\s+\d{2}m\s+\d{2}s|m\s+\d{2}s|s)/.test(stripped);
1376
+ const hasReadyPrompt = /›\s+Ask\s+Codex\s+to\s+do\s+anything/.test(stripped);
1377
+ if (hasWorkedFor && hasReadyPrompt) {
1378
+ return true;
1379
+ }
1380
+ if (hasReadyPrompt) {
1381
+ return true;
1382
+ }
1383
+ if (hasWorkedFor && /›\s+/m.test(stripped)) {
1384
+ return true;
1385
+ }
1386
+ return false;
1387
+ }
915
1388
  detectReady(output) {
916
1389
  const stripped = this.stripAnsi(output);
917
1390
  if (/do.?you.?trust.?the.?contents/i.test(stripped) || /sign.?in.?with.?chatgpt/i.test(stripped) || /update.?available/i.test(stripped) || /enable.?full.?access/i.test(stripped) || /choose.?working.?directory/i.test(stripped)) {
@@ -1219,6 +1692,10 @@ var AiderAdapter = class extends BaseCodingAdapter {
1219
1692
  if (credentials.anthropicKey) args.push("--api-key", `anthropic=${credentials.anthropicKey}`);
1220
1693
  if (credentials.openaiKey) args.push("--api-key", `openai=${credentials.openaiKey}`);
1221
1694
  if (credentials.googleKey) args.push("--api-key", `gemini=${credentials.googleKey}`);
1695
+ const approvalConfig = this.getApprovalConfig(config);
1696
+ if (approvalConfig) {
1697
+ args.push(...approvalConfig.cliFlags);
1698
+ }
1222
1699
  return args;
1223
1700
  }
1224
1701
  getEnv(config) {
@@ -1312,6 +1789,31 @@ var AiderAdapter = class extends BaseCodingAdapter {
1312
1789
  }
1313
1790
  return super.detectBlockingPrompt(output);
1314
1791
  }
1792
+ /**
1793
+ * Detect task completion for Aider.
1794
+ *
1795
+ * High-confidence patterns:
1796
+ * - "Aider is waiting for your input" notification (bell message)
1797
+ * - Edit-format mode prompts (ask>, code>, architect>) after output
1798
+ *
1799
+ * Patterns from: AGENT_LOADING_STATUS_PATTERNS.json
1800
+ * - aider_completed_llm_response_ready
1801
+ */
1802
+ detectTaskComplete(output) {
1803
+ const stripped = this.stripAnsi(output);
1804
+ if (/Aider\s+is\s+waiting\s+for\s+your\s+input/.test(stripped)) {
1805
+ return true;
1806
+ }
1807
+ const hasPrompt = /(?:ask|code|architect)(?:\s+multi)?>\s*$/m.test(stripped);
1808
+ if (hasPrompt) {
1809
+ const hasEditMarkers = /Applied edit to|Commit [a-f0-9]+|wrote to|Updated/i.test(stripped);
1810
+ const hasTokenUsage = /Tokens:|Cost:/i.test(stripped);
1811
+ if (hasEditMarkers || hasTokenUsage) {
1812
+ return true;
1813
+ }
1814
+ }
1815
+ return false;
1816
+ }
1315
1817
  detectReady(output) {
1316
1818
  const stripped = this.stripAnsi(output);
1317
1819
  if (/login to openrouter/i.test(stripped) || /open this url in your browser/i.test(stripped) || /waiting up to 5 minutes/i.test(stripped)) {
@@ -1575,18 +2077,31 @@ async function printMissingAdapters(types) {
1575
2077
  }
1576
2078
 
1577
2079
  exports.ADAPTER_TYPES = ADAPTER_TYPES;
2080
+ exports.AIDER_COMMAND_CATEGORIES = AIDER_COMMAND_CATEGORIES;
1578
2081
  exports.AiderAdapter = AiderAdapter;
1579
2082
  exports.BaseCodingAdapter = BaseCodingAdapter;
2083
+ exports.CLAUDE_TOOL_CATEGORIES = CLAUDE_TOOL_CATEGORIES;
2084
+ exports.CODEX_TOOL_CATEGORIES = CODEX_TOOL_CATEGORIES;
1580
2085
  exports.ClaudeAdapter = ClaudeAdapter;
1581
2086
  exports.CodexAdapter = CodexAdapter;
2087
+ exports.GEMINI_TOOL_CATEGORIES = GEMINI_TOOL_CATEGORIES;
1582
2088
  exports.GeminiAdapter = GeminiAdapter;
2089
+ exports.PRESET_DEFINITIONS = PRESET_DEFINITIONS;
2090
+ exports.TOOL_CATEGORIES = TOOL_CATEGORIES;
1583
2091
  exports.checkAdapters = checkAdapters;
1584
2092
  exports.checkAllAdapters = checkAllAdapters;
1585
2093
  exports.clearPatternCache = clearPatternCache;
1586
2094
  exports.createAdapter = createAdapter;
1587
2095
  exports.createAllAdapters = createAllAdapters;
2096
+ exports.generateAiderApprovalConfig = generateAiderApprovalConfig;
2097
+ exports.generateApprovalConfig = generateApprovalConfig;
2098
+ exports.generateClaudeApprovalConfig = generateClaudeApprovalConfig;
2099
+ exports.generateCodexApprovalConfig = generateCodexApprovalConfig;
2100
+ exports.generateGeminiApprovalConfig = generateGeminiApprovalConfig;
1588
2101
  exports.getBaselinePatterns = getBaselinePatterns;
2102
+ exports.getPresetDefinition = getPresetDefinition;
1589
2103
  exports.hasDynamicPatterns = hasDynamicPatterns;
2104
+ exports.listPresets = listPresets;
1590
2105
  exports.loadPatterns = loadPatterns;
1591
2106
  exports.loadPatternsSync = loadPatternsSync;
1592
2107
  exports.preloadAllPatterns = preloadAllPatterns;