coding-agent-adapters 0.2.13 → 0.2.15

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.d.ts CHANGED
@@ -153,6 +153,12 @@ declare class GeminiAdapter extends BaseCodingAdapter {
153
153
  readonly adapterType = "gemini";
154
154
  readonly displayName = "Google Gemini";
155
155
  readonly installation: InstallationInfo;
156
+ /**
157
+ * Auto-response rules for Gemini CLI.
158
+ * Gemini uses Ink/React TUI with arrow-key radio menus.
159
+ * Source: FolderTrustDialog.tsx, MultiFolderTrustDialog.tsx, CloudFreePrivacyNotice.tsx
160
+ */
161
+ readonly autoResponseRules: AutoResponseRule[];
156
162
  getRecommendedModels(_credentials?: AgentCredentials): ModelRecommendations;
157
163
  getCommand(): string;
158
164
  getArgs(config: SpawnConfig): string[];
@@ -161,6 +167,15 @@ declare class GeminiAdapter extends BaseCodingAdapter {
161
167
  detectBlockingPrompt(output: string): BlockingPromptDetection;
162
168
  detectReady(output: string): boolean;
163
169
  parseOutput(output: string): ParsedOutput | null;
170
+ /**
171
+ * Detect exit conditions specific to Gemini CLI.
172
+ * Source: FolderTrustDialog.tsx:127, LogoutConfirmationDialog.tsx:64
173
+ */
174
+ detectExit(output: string): {
175
+ exited: boolean;
176
+ code?: number;
177
+ error?: string;
178
+ };
164
179
  getPromptPattern(): RegExp;
165
180
  getHealthCheckCommand(): string;
166
181
  }
@@ -177,7 +192,8 @@ declare class CodexAdapter extends BaseCodingAdapter {
177
192
  readonly installation: InstallationInfo;
178
193
  /**
179
194
  * Auto-response rules for OpenAI Codex CLI.
180
- * Codex uses TUI menus (Ink/React) rules use key sequences.
195
+ * Codex uses ratatui/crossterm full-screen TUI with arrow-key menus.
196
+ * Source: trust_directory.rs, update_prompt.rs, model_migration.rs, cwd_prompt.rs, chatwidget.rs, main.rs
181
197
  */
182
198
  readonly autoResponseRules: AutoResponseRule[];
183
199
  getRecommendedModels(_credentials?: AgentCredentials): ModelRecommendations;
@@ -186,11 +202,21 @@ declare class CodexAdapter extends BaseCodingAdapter {
186
202
  getEnv(config: SpawnConfig): Record<string, string>;
187
203
  detectLogin(output: string): LoginDetection;
188
204
  /**
189
- * Detect blocking prompts specific to OpenAI Codex CLI
205
+ * Detect blocking prompts specific to OpenAI Codex CLI.
206
+ * Source: approval_overlay.rs, chatwidget.rs, request_user_input/mod.rs
190
207
  */
191
208
  detectBlockingPrompt(output: string): BlockingPromptDetection;
192
209
  detectReady(output: string): boolean;
193
210
  parseOutput(output: string): ParsedOutput | null;
211
+ /**
212
+ * Detect exit conditions specific to Codex CLI.
213
+ * Source: main.rs:404, main.rs:414, main.rs:461
214
+ */
215
+ detectExit(output: string): {
216
+ exited: boolean;
217
+ code?: number;
218
+ error?: string;
219
+ };
194
220
  getPromptPattern(): RegExp;
195
221
  getHealthCheckCommand(): string;
196
222
  }
@@ -212,8 +238,10 @@ declare class AiderAdapter extends BaseCodingAdapter {
212
238
  readonly installation: InstallationInfo;
213
239
  /**
214
240
  * Auto-response rules for Aider CLI.
215
- * Aider uses plain text [y/n] prompts, NOT TUI menus.
216
- * Explicit responseType: 'text' prevents the usesTuiMenus default from kicking in.
241
+ * Aider uses plain text prompts via io.py:832 with (Y)es/(N)o format.
242
+ * All rules are responseType: 'text' Aider never uses TUI menus.
243
+ *
244
+ * Decline rules come first to override the generic accept patterns.
217
245
  */
218
246
  readonly autoResponseRules: AutoResponseRule[];
219
247
  getRecommendedModels(credentials?: AgentCredentials): ModelRecommendations;
@@ -221,9 +249,22 @@ declare class AiderAdapter extends BaseCodingAdapter {
221
249
  getArgs(config: SpawnConfig): string[];
222
250
  getEnv(config: SpawnConfig): Record<string, string>;
223
251
  detectLogin(output: string): LoginDetection;
252
+ /**
253
+ * Detect blocking prompts specific to Aider CLI.
254
+ * Source: io.py, onboarding.py, base_coder.py, report.py
255
+ */
224
256
  detectBlockingPrompt(output: string): BlockingPromptDetection;
225
257
  detectReady(output: string): boolean;
226
258
  parseOutput(output: string): ParsedOutput | null;
259
+ /**
260
+ * Detect exit conditions specific to Aider.
261
+ * Source: base_coder.py:994, base_coder.py:998, report.py:77, versioncheck.py:58
262
+ */
263
+ detectExit(output: string): {
264
+ exited: boolean;
265
+ code?: number;
266
+ error?: string;
267
+ };
227
268
  getPromptPattern(): RegExp;
228
269
  getHealthCheckCommand(): string;
229
270
  }
package/dist/index.js CHANGED
@@ -337,6 +337,43 @@ var GeminiAdapter = class extends BaseCodingAdapter {
337
337
  ],
338
338
  docsUrl: "https://github.com/anthropics/gemini-cli#installation"
339
339
  };
340
+ /**
341
+ * Auto-response rules for Gemini CLI.
342
+ * Gemini uses Ink/React TUI with arrow-key radio menus.
343
+ * Source: FolderTrustDialog.tsx, MultiFolderTrustDialog.tsx, CloudFreePrivacyNotice.tsx
344
+ */
345
+ autoResponseRules = [
346
+ {
347
+ pattern: /do.?you.?trust.?this.?folder|trust.?folder|trust.?parent.?folder/i,
348
+ type: "permission",
349
+ response: "",
350
+ responseType: "keys",
351
+ keys: ["enter"],
352
+ description: "Trust current folder (default selection in radio menu)",
353
+ safe: true,
354
+ once: true
355
+ },
356
+ {
357
+ pattern: /trust.?the.?following.?folders.*(added|workspace)/i,
358
+ type: "permission",
359
+ response: "",
360
+ responseType: "keys",
361
+ keys: ["enter"],
362
+ description: "Trust multiple folders being added to workspace",
363
+ safe: true,
364
+ once: true
365
+ },
366
+ {
367
+ pattern: /allow.?google.?to.?use.?this.?data/i,
368
+ type: "config",
369
+ response: "",
370
+ responseType: "keys",
371
+ keys: ["down", "enter"],
372
+ description: 'Decline Google data collection (select "No")',
373
+ safe: true,
374
+ once: true
375
+ }
376
+ ];
340
377
  getRecommendedModels(_credentials) {
341
378
  return {
342
379
  powerful: "gemini-3-pro",
@@ -381,6 +418,27 @@ var GeminiAdapter = class extends BaseCodingAdapter {
381
418
  instructions: "Set GOOGLE_API_KEY or GEMINI_API_KEY environment variable"
382
419
  };
383
420
  }
421
+ if (/enter.?gemini.?api.?key/i.test(stripped)) {
422
+ return {
423
+ required: true,
424
+ type: "api_key",
425
+ instructions: "Enter a Gemini API key or set GEMINI_API_KEY environment variable"
426
+ };
427
+ }
428
+ if (/how.?would.?you.?like.?to.?authenticate/i.test(stripped) || /get.?started/i.test(stripped) && /login.?with.?google|use.?gemini.?api.?key|vertex/i.test(stripped)) {
429
+ return {
430
+ required: true,
431
+ type: "oauth",
432
+ instructions: "Gemini CLI authentication required \u2014 select an auth method"
433
+ };
434
+ }
435
+ if (/waiting.?for.?auth/i.test(stripped)) {
436
+ return {
437
+ required: true,
438
+ type: "oauth",
439
+ instructions: "Waiting for browser authentication to complete"
440
+ };
441
+ }
384
442
  if (stripped.includes("Sign in with Google") || stripped.includes("OAuth") || stripped.includes("accounts.google.com")) {
385
443
  const urlMatch = stripped.match(/https?:\/\/[^\s]+/);
386
444
  return {
@@ -401,7 +459,7 @@ var GeminiAdapter = class extends BaseCodingAdapter {
401
459
  }
402
460
  detectBlockingPrompt(output) {
403
461
  const stripped = this.stripAnsi(output);
404
- if (/Apply this change\?/i.test(stripped) || /Waiting for user confirmation/i.test(stripped)) {
462
+ if (/apply.?this.?change\??/i.test(stripped) || /allow.?execution.?of/i.test(stripped) || /do.?you.?want.?to.?proceed\??/i.test(stripped) || /waiting.?for.?user.?confirmation/i.test(stripped)) {
405
463
  return {
406
464
  detected: true,
407
465
  type: "permission",
@@ -422,6 +480,15 @@ var GeminiAdapter = class extends BaseCodingAdapter {
422
480
  instructions: loginDetection.instructions
423
481
  };
424
482
  }
483
+ if (/further.?action.?is.?required/i.test(stripped) || /verify.?your.?account/i.test(stripped) || /waiting.?for.?verification/i.test(stripped)) {
484
+ return {
485
+ detected: true,
486
+ type: "config",
487
+ prompt: "Account verification required",
488
+ canAutoRespond: false,
489
+ instructions: "Your Gemini account requires verification before continuing"
490
+ };
491
+ }
425
492
  if (/select.*model|choose.*model|gemini-/i.test(stripped) && /\d+\)/i.test(stripped)) {
426
493
  return {
427
494
  detected: true,
@@ -453,7 +520,16 @@ var GeminiAdapter = class extends BaseCodingAdapter {
453
520
  }
454
521
  detectReady(output) {
455
522
  const stripped = this.stripAnsi(output);
456
- return stripped.includes("Ready") || stripped.includes("Type your message") || stripped.includes("How can I help") || stripped.includes("What would you like") || // Match "gemini> " prompt specifically, not bare ">"
523
+ if (/do.?you.?trust.?this.?folder/i.test(stripped) || /how.?would.?you.?like.?to.?authenticate/i.test(stripped) || /waiting.?for.?auth/i.test(stripped) || /allow.?google.?to.?use.?this.?data/i.test(stripped)) {
524
+ return false;
525
+ }
526
+ if (/type.?your.?message/i.test(stripped)) {
527
+ return true;
528
+ }
529
+ if (/^\s*[>!*]\s+/m.test(stripped) || /\(r:\)/.test(stripped)) {
530
+ return true;
531
+ }
532
+ return stripped.includes("How can I help") || stripped.includes("What would you like") || // Match "gemini> " prompt specifically, not bare ">"
457
533
  /gemini>\s*$/i.test(stripped);
458
534
  }
459
535
  parseOutput(output) {
@@ -475,6 +551,27 @@ var GeminiAdapter = class extends BaseCodingAdapter {
475
551
  }
476
552
  };
477
553
  }
554
+ /**
555
+ * Detect exit conditions specific to Gemini CLI.
556
+ * Source: FolderTrustDialog.tsx:127, LogoutConfirmationDialog.tsx:64
557
+ */
558
+ detectExit(output) {
559
+ const stripped = this.stripAnsi(output);
560
+ if (/folder.?trust.?level.?must.?be.?selected.*exiting/i.test(stripped)) {
561
+ return {
562
+ exited: true,
563
+ code: 1,
564
+ error: "Gemini CLI exited because no folder trust level was selected"
565
+ };
566
+ }
567
+ if (/you are now logged out/i.test(stripped)) {
568
+ return {
569
+ exited: true,
570
+ code: 0
571
+ };
572
+ }
573
+ return super.detectExit(output);
574
+ }
478
575
  getPromptPattern() {
479
576
  return /gemini>\s*$/i;
480
577
  }
@@ -496,11 +593,12 @@ var CodexAdapter = class extends BaseCodingAdapter {
496
593
  };
497
594
  /**
498
595
  * Auto-response rules for OpenAI Codex CLI.
499
- * Codex uses TUI menus (Ink/React) rules use key sequences.
596
+ * Codex uses ratatui/crossterm full-screen TUI with arrow-key menus.
597
+ * Source: trust_directory.rs, update_prompt.rs, model_migration.rs, cwd_prompt.rs, chatwidget.rs, main.rs
500
598
  */
501
599
  autoResponseRules = [
502
600
  {
503
- pattern: /Update (available|now)|Skip until next version/i,
601
+ pattern: /update.?available.*->|update.?now|skip.?until.?next.?version/i,
504
602
  type: "config",
505
603
  response: "",
506
604
  responseType: "keys",
@@ -509,14 +607,51 @@ var CodexAdapter = class extends BaseCodingAdapter {
509
607
  safe: true
510
608
  },
511
609
  {
512
- pattern: /trust.the.contents|trust.this.directory|do.you.trust/i,
610
+ pattern: /do.?you.?trust.?the.?contents|trust.?this.?directory|yes,?.?continue|prompt.?injection/i,
513
611
  type: "permission",
514
612
  response: "",
515
613
  responseType: "keys",
516
614
  keys: ["enter"],
517
- description: "Trust directory contents to allow Codex to operate",
615
+ description: 'Trust directory contents (default: "Yes, continue")',
518
616
  safe: true,
519
617
  once: true
618
+ },
619
+ {
620
+ pattern: /choose.?how.?you.?d.?like.?codex.?to.?proceed|try.?new.?model|use.?existing.?model/i,
621
+ type: "config",
622
+ response: "",
623
+ responseType: "keys",
624
+ keys: ["enter"],
625
+ description: 'Accept model migration (default: "Try new model")',
626
+ safe: true,
627
+ once: true
628
+ },
629
+ {
630
+ pattern: /choose.?working.?directory.?to.?(resume|fork)/i,
631
+ type: "config",
632
+ response: "",
633
+ responseType: "keys",
634
+ keys: ["enter"],
635
+ description: "Accept default working directory for session resume",
636
+ safe: true
637
+ },
638
+ {
639
+ pattern: /enable.?full.?access\??/i,
640
+ type: "permission",
641
+ response: "",
642
+ responseType: "keys",
643
+ keys: ["enter"],
644
+ description: 'Confirm full access mode (default: "Yes, continue anyway")',
645
+ safe: true,
646
+ once: true
647
+ },
648
+ {
649
+ pattern: /continue.?anyway\?\s*\[y\/N\]/i,
650
+ type: "config",
651
+ response: "y",
652
+ responseType: "text",
653
+ description: "Confirm dumb terminal continuation",
654
+ safe: true
520
655
  }
521
656
  ];
522
657
  getRecommendedModels(_credentials) {
@@ -561,6 +696,23 @@ var CodexAdapter = class extends BaseCodingAdapter {
561
696
  instructions: "Set OPENAI_API_KEY environment variable or provide credentials in adapterConfig"
562
697
  };
563
698
  }
699
+ if (/sign.?in.?with.?chatgpt/i.test(stripped) || /sign.?in.?with.?device.?code/i.test(stripped) && !/open.?this.?link/i.test(stripped) || /provide.?your.?own.?api.?key/i.test(stripped)) {
700
+ return {
701
+ required: true,
702
+ type: "oauth",
703
+ instructions: "Codex authentication required \u2014 select a sign-in method or provide an API key"
704
+ };
705
+ }
706
+ if (/preparing.?device.?code.?login/i.test(stripped) || /open.?this.?link.?in.?your.?browser/i.test(stripped) || /enter.?this.?one-time.?code/i.test(stripped)) {
707
+ const codeMatch = stripped.match(/code[:\s]+([A-Z0-9-]+)/i);
708
+ const urlMatch = stripped.match(/https?:\/\/[^\s]+/);
709
+ return {
710
+ required: true,
711
+ type: "device_code",
712
+ url: urlMatch ? urlMatch[0] : void 0,
713
+ instructions: codeMatch ? `Enter code ${codeMatch[1]} at the URL` : "Device code authentication in progress \u2014 complete in browser"
714
+ };
715
+ }
564
716
  if (stripped.includes("device code") || stripped.includes("Enter the code")) {
565
717
  const codeMatch = stripped.match(/code[:\s]+([A-Z0-9-]+)/i);
566
718
  const urlMatch = stripped.match(/https?:\/\/[^\s]+/);
@@ -574,10 +726,21 @@ var CodexAdapter = class extends BaseCodingAdapter {
574
726
  return { required: false };
575
727
  }
576
728
  /**
577
- * Detect blocking prompts specific to OpenAI Codex CLI
729
+ * Detect blocking prompts specific to OpenAI Codex CLI.
730
+ * Source: approval_overlay.rs, chatwidget.rs, request_user_input/mod.rs
578
731
  */
579
732
  detectBlockingPrompt(output) {
580
733
  const stripped = this.stripAnsi(output);
734
+ if (/would.?you.?like.?to.?run.?the.?following.?command/i.test(stripped) || /do.?you.?want.?to.?approve.?access/i.test(stripped) || /would.?you.?like.?to.?make.?the.?following.?edits/i.test(stripped) || /press.?enter.?to.?confirm/i.test(stripped) && /esc.?to.?cancel/i.test(stripped)) {
735
+ return {
736
+ detected: true,
737
+ type: "permission",
738
+ prompt: "Codex tool approval",
739
+ suggestedResponse: "keys:enter",
740
+ canAutoRespond: true,
741
+ instructions: "Codex is asking permission to execute a command, approve access, or apply edits"
742
+ };
743
+ }
581
744
  const loginDetection = this.detectLogin(output);
582
745
  if (loginDetection.required) {
583
746
  return {
@@ -589,6 +752,24 @@ var CodexAdapter = class extends BaseCodingAdapter {
589
752
  instructions: loginDetection.instructions
590
753
  };
591
754
  }
755
+ if (/set.?up.?default.?sandbox/i.test(stripped) || /use.?non-admin.?sandbox/i.test(stripped)) {
756
+ return {
757
+ detected: true,
758
+ type: "config",
759
+ prompt: "Windows sandbox setup",
760
+ canAutoRespond: false,
761
+ instructions: "Codex needs a sandbox configuration on Windows"
762
+ };
763
+ }
764
+ if (/type.?your.?answer/i.test(stripped) && /select.?an.?option/i.test(stripped)) {
765
+ return {
766
+ detected: true,
767
+ type: "unknown",
768
+ prompt: "Codex requesting structured user input",
769
+ canAutoRespond: false,
770
+ instructions: "Codex model is asking multi-step questions that require user input"
771
+ };
772
+ }
592
773
  if (/select.*model|choose.*model|gpt-4|gpt-3\.5/i.test(stripped) && /\d+\)/i.test(stripped)) {
593
774
  return {
594
775
  detected: true,
@@ -620,7 +801,16 @@ var CodexAdapter = class extends BaseCodingAdapter {
620
801
  }
621
802
  detectReady(output) {
622
803
  const stripped = this.stripAnsi(output);
623
- return stripped.includes("Codex") || stripped.includes("Ready") || stripped.includes("How can I help") || /(?:codex|>)\s*$/i.test(stripped);
804
+ 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)) {
805
+ return false;
806
+ }
807
+ if (/›\s+/m.test(stripped)) {
808
+ return true;
809
+ }
810
+ if (/explain this codebase|summarize recent commits|find and fix a bug/i.test(stripped)) {
811
+ return true;
812
+ }
813
+ return stripped.includes("How can I help") || /(?:codex|>)\s*$/i.test(stripped);
624
814
  }
625
815
  parseOutput(output) {
626
816
  const stripped = this.stripAnsi(output);
@@ -640,6 +830,24 @@ var CodexAdapter = class extends BaseCodingAdapter {
640
830
  }
641
831
  };
642
832
  }
833
+ /**
834
+ * Detect exit conditions specific to Codex CLI.
835
+ * Source: main.rs:404, main.rs:414, main.rs:461
836
+ */
837
+ detectExit(output) {
838
+ const stripped = this.stripAnsi(output);
839
+ if (/to.?continue.?this.?session,?.?run/i.test(stripped)) {
840
+ return { exited: true, code: 0 };
841
+ }
842
+ if (/update.?ran.?successfully.*restart.?codex/i.test(stripped)) {
843
+ return {
844
+ exited: true,
845
+ code: 0,
846
+ error: "Codex updated successfully \u2014 restart required"
847
+ };
848
+ }
849
+ return super.detectExit(output);
850
+ }
643
851
  getPromptPattern() {
644
852
  return /(?:codex|>)\s*$/i;
645
853
  }
@@ -667,12 +875,42 @@ var AiderAdapter = class extends BaseCodingAdapter {
667
875
  };
668
876
  /**
669
877
  * Auto-response rules for Aider CLI.
670
- * Aider uses plain text [y/n] prompts, NOT TUI menus.
671
- * Explicit responseType: 'text' prevents the usesTuiMenus default from kicking in.
878
+ * Aider uses plain text prompts via io.py:832 with (Y)es/(N)o format.
879
+ * All rules are responseType: 'text' Aider never uses TUI menus.
880
+ *
881
+ * Decline rules come first to override the generic accept patterns.
672
882
  */
673
883
  autoResponseRules = [
884
+ // ── Decline rules (specific, checked first) ────────────────────────
885
+ {
886
+ pattern: /allow collection of anonymous analytics/i,
887
+ type: "config",
888
+ response: "n",
889
+ responseType: "text",
890
+ description: "Decline Aider telemetry opt-in",
891
+ safe: true,
892
+ once: true
893
+ },
674
894
  {
675
- pattern: /Add .+ to the chat\?.*(\[y\/n\]|\[Yes\]|\(Y\)es)/i,
895
+ pattern: /would you like to see what.?s new in this version/i,
896
+ type: "config",
897
+ response: "n",
898
+ responseType: "text",
899
+ description: "Decline release notes offer",
900
+ safe: true,
901
+ once: true
902
+ },
903
+ {
904
+ pattern: /open a github issue pre-filled/i,
905
+ type: "config",
906
+ response: "n",
907
+ responseType: "text",
908
+ description: "Decline automatic bug report",
909
+ safe: true
910
+ },
911
+ // ── File / edit operations ──────────────────────────────────────────
912
+ {
913
+ pattern: /add .+ to the chat\?/i,
676
914
  type: "permission",
677
915
  response: "y",
678
916
  responseType: "text",
@@ -680,7 +918,15 @@ var AiderAdapter = class extends BaseCodingAdapter {
680
918
  safe: true
681
919
  },
682
920
  {
683
- pattern: /Create new file.*(\[y\/n\]|\[Yes\]|\(Y\)es)/i,
921
+ pattern: /add url to the chat\?/i,
922
+ type: "permission",
923
+ response: "y",
924
+ responseType: "text",
925
+ description: "Allow Aider to add URL content to chat",
926
+ safe: true
927
+ },
928
+ {
929
+ pattern: /create new file\?/i,
684
930
  type: "permission",
685
931
  response: "y",
686
932
  responseType: "text",
@@ -688,11 +934,96 @@ var AiderAdapter = class extends BaseCodingAdapter {
688
934
  safe: true
689
935
  },
690
936
  {
691
- pattern: /Apply.*changes.*(\[y\/n\]|\[Yes\]|\(Y\)es)/i,
937
+ pattern: /allow edits to file/i,
938
+ type: "permission",
939
+ response: "y",
940
+ responseType: "text",
941
+ description: "Allow edits to file not yet in chat",
942
+ safe: true
943
+ },
944
+ {
945
+ pattern: /edit the files\?/i,
692
946
  type: "permission",
693
947
  response: "y",
694
948
  responseType: "text",
695
- description: "Apply proposed changes",
949
+ description: "Accept architect mode edits",
950
+ safe: true
951
+ },
952
+ // ── Shell operations ────────────────────────────────────────────────
953
+ {
954
+ pattern: /run shell commands?\?/i,
955
+ type: "permission",
956
+ response: "y",
957
+ responseType: "text",
958
+ description: "Allow Aider to run shell commands",
959
+ safe: true
960
+ },
961
+ {
962
+ pattern: /add command output to the chat\?/i,
963
+ type: "permission",
964
+ response: "y",
965
+ responseType: "text",
966
+ description: "Add shell command output to chat context",
967
+ safe: true
968
+ },
969
+ {
970
+ pattern: /add \d+.*tokens of command output to the chat\?/i,
971
+ type: "permission",
972
+ response: "y",
973
+ responseType: "text",
974
+ description: "Add /run command output to chat context",
975
+ safe: true
976
+ },
977
+ // ── Setup / maintenance ─────────────────────────────────────────────
978
+ {
979
+ pattern: /no git repo found.*create one/i,
980
+ type: "config",
981
+ response: "y",
982
+ responseType: "text",
983
+ description: "Create git repo for change tracking",
984
+ safe: true,
985
+ once: true
986
+ },
987
+ {
988
+ pattern: /add .+ to \.gitignore/i,
989
+ type: "config",
990
+ response: "y",
991
+ responseType: "text",
992
+ description: "Update .gitignore with Aider patterns",
993
+ safe: true,
994
+ once: true
995
+ },
996
+ {
997
+ pattern: /run pip install\?/i,
998
+ type: "config",
999
+ response: "y",
1000
+ responseType: "text",
1001
+ description: "Install missing Python dependencies",
1002
+ safe: true
1003
+ },
1004
+ {
1005
+ pattern: /install playwright\?/i,
1006
+ type: "config",
1007
+ response: "y",
1008
+ responseType: "text",
1009
+ description: "Install Playwright for web scraping",
1010
+ safe: true
1011
+ },
1012
+ // ── Other safe confirmations ────────────────────────────────────────
1013
+ {
1014
+ pattern: /fix lint errors in/i,
1015
+ type: "permission",
1016
+ response: "y",
1017
+ responseType: "text",
1018
+ description: "Accept lint error fix suggestion",
1019
+ safe: true
1020
+ },
1021
+ {
1022
+ pattern: /try to proceed anyway\?/i,
1023
+ type: "config",
1024
+ response: "y",
1025
+ responseType: "text",
1026
+ description: "Continue despite context limit warning",
696
1027
  safe: true
697
1028
  }
698
1029
  ];
@@ -772,8 +1103,28 @@ var AiderAdapter = class extends BaseCodingAdapter {
772
1103
  instructions: "API key is invalid - please check your credentials"
773
1104
  };
774
1105
  }
1106
+ if (/login to openrouter or create a free account/i.test(stripped)) {
1107
+ return {
1108
+ required: true,
1109
+ type: "oauth",
1110
+ instructions: "Aider offering OpenRouter OAuth login \u2014 provide API keys to skip"
1111
+ };
1112
+ }
1113
+ if (/please open this url in your browser to connect aider with openrouter/i.test(stripped) || /waiting up to 5 minutes for you to finish in the browser/i.test(stripped)) {
1114
+ const urlMatch = stripped.match(/https?:\/\/[^\s]+/);
1115
+ return {
1116
+ required: true,
1117
+ type: "browser",
1118
+ url: urlMatch ? urlMatch[0] : void 0,
1119
+ instructions: "Complete OpenRouter authentication in browser"
1120
+ };
1121
+ }
775
1122
  return { required: false };
776
1123
  }
1124
+ /**
1125
+ * Detect blocking prompts specific to Aider CLI.
1126
+ * Source: io.py, onboarding.py, base_coder.py, report.py
1127
+ */
777
1128
  detectBlockingPrompt(output) {
778
1129
  const stripped = this.stripAnsi(output);
779
1130
  const loginDetection = this.detectLogin(output);
@@ -782,6 +1133,7 @@ var AiderAdapter = class extends BaseCodingAdapter {
782
1133
  detected: true,
783
1134
  type: "login",
784
1135
  prompt: loginDetection.instructions,
1136
+ url: loginDetection.url,
785
1137
  canAutoRespond: false,
786
1138
  instructions: loginDetection.instructions
787
1139
  };
@@ -795,16 +1147,16 @@ var AiderAdapter = class extends BaseCodingAdapter {
795
1147
  instructions: "Please select a model or set AIDER_MODEL env var"
796
1148
  };
797
1149
  }
798
- if (/not.*git.*repo|git.*not.*found|initialize.*git/i.test(stripped)) {
1150
+ if (/please answer with one of:/i.test(stripped)) {
799
1151
  return {
800
1152
  detected: true,
801
- type: "config",
802
- prompt: "Git repository required",
1153
+ type: "unknown",
1154
+ prompt: "Invalid confirmation input",
803
1155
  canAutoRespond: false,
804
- instructions: "Aider requires a git repository. Run git init or use --no-git"
1156
+ instructions: "Aider received an invalid response to a confirmation prompt"
805
1157
  };
806
1158
  }
807
- if (/delete|remove|overwrite/i.test(stripped) && /\[y\/n\]/i.test(stripped)) {
1159
+ if (/delete|remove|overwrite/i.test(stripped) && (/\[y\/n\]/i.test(stripped) || /\(Y\)es\/\(N\)o/i.test(stripped))) {
808
1160
  return {
809
1161
  detected: true,
810
1162
  type: "permission",
@@ -818,9 +1170,22 @@ var AiderAdapter = class extends BaseCodingAdapter {
818
1170
  }
819
1171
  detectReady(output) {
820
1172
  const stripped = this.stripAnsi(output);
821
- return stripped.includes("aider>") || stripped.includes("Aider") || /aider.*ready/i.test(stripped) || // Aider shows file list when ready
822
- /Added.*to the chat/i.test(stripped) || // Or the prompt
823
- />\s*$/.test(stripped);
1173
+ if (/login to openrouter/i.test(stripped) || /open this url in your browser/i.test(stripped) || /waiting up to 5 minutes/i.test(stripped)) {
1174
+ return false;
1175
+ }
1176
+ if (/(?:ask|code|architect|help)(?:\s+multi)?>\s*$/m.test(stripped) || /^multi>\s*$/m.test(stripped)) {
1177
+ return true;
1178
+ }
1179
+ if (/^Aider v\d+/m.test(stripped)) {
1180
+ return true;
1181
+ }
1182
+ if (/^(?:Readonly|Editable):/m.test(stripped)) {
1183
+ return true;
1184
+ }
1185
+ return (
1186
+ // Legacy prompt patterns
1187
+ stripped.includes("aider>") || /Added.*to the chat/i.test(stripped) || />\s*$/.test(stripped)
1188
+ );
824
1189
  }
825
1190
  parseOutput(output) {
826
1191
  const stripped = this.stripAnsi(output);
@@ -841,8 +1206,26 @@ var AiderAdapter = class extends BaseCodingAdapter {
841
1206
  }
842
1207
  };
843
1208
  }
1209
+ /**
1210
+ * Detect exit conditions specific to Aider.
1211
+ * Source: base_coder.py:994, base_coder.py:998, report.py:77, versioncheck.py:58
1212
+ */
1213
+ detectExit(output) {
1214
+ const stripped = this.stripAnsi(output);
1215
+ if (/\^C again to exit/i.test(stripped) || /\^C KeyboardInterrupt/i.test(stripped)) {
1216
+ return { exited: true, code: 130 };
1217
+ }
1218
+ if (/re-run aider to use new version/i.test(stripped)) {
1219
+ return {
1220
+ exited: true,
1221
+ code: 0,
1222
+ error: "Aider updated \u2014 restart required"
1223
+ };
1224
+ }
1225
+ return super.detectExit(output);
1226
+ }
844
1227
  getPromptPattern() {
845
- return /(?:aider>|>)\s*$/i;
1228
+ return /(?:ask|code|architect|help|aider|multi)(?:\s+multi)?>\s*$/i;
846
1229
  }
847
1230
  getHealthCheckCommand() {
848
1231
  return "aider --version";