coding-agent-adapters 0.2.12 → 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.js CHANGED
@@ -121,13 +121,14 @@ var ClaudeAdapter = class extends BaseCodingAdapter {
121
121
  */
122
122
  autoResponseRules = [
123
123
  {
124
- pattern: /trust.*folder|safety check/i,
124
+ pattern: /trust.*folder|safety.?check|project.you.created/i,
125
125
  type: "permission",
126
126
  response: "",
127
127
  responseType: "keys",
128
128
  keys: ["enter"],
129
129
  description: "Accept trust prompt for working directory",
130
- safe: true
130
+ safe: true,
131
+ once: true
131
132
  },
132
133
  {
133
134
  pattern: /update available.*\[y\/n\]/i,
@@ -336,6 +337,43 @@ var GeminiAdapter = class extends BaseCodingAdapter {
336
337
  ],
337
338
  docsUrl: "https://github.com/anthropics/gemini-cli#installation"
338
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
+ ];
339
377
  getRecommendedModels(_credentials) {
340
378
  return {
341
379
  powerful: "gemini-3-pro",
@@ -380,6 +418,27 @@ var GeminiAdapter = class extends BaseCodingAdapter {
380
418
  instructions: "Set GOOGLE_API_KEY or GEMINI_API_KEY environment variable"
381
419
  };
382
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
+ }
383
442
  if (stripped.includes("Sign in with Google") || stripped.includes("OAuth") || stripped.includes("accounts.google.com")) {
384
443
  const urlMatch = stripped.match(/https?:\/\/[^\s]+/);
385
444
  return {
@@ -400,7 +459,7 @@ var GeminiAdapter = class extends BaseCodingAdapter {
400
459
  }
401
460
  detectBlockingPrompt(output) {
402
461
  const stripped = this.stripAnsi(output);
403
- 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)) {
404
463
  return {
405
464
  detected: true,
406
465
  type: "permission",
@@ -421,6 +480,15 @@ var GeminiAdapter = class extends BaseCodingAdapter {
421
480
  instructions: loginDetection.instructions
422
481
  };
423
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
+ }
424
492
  if (/select.*model|choose.*model|gemini-/i.test(stripped) && /\d+\)/i.test(stripped)) {
425
493
  return {
426
494
  detected: true,
@@ -452,7 +520,16 @@ var GeminiAdapter = class extends BaseCodingAdapter {
452
520
  }
453
521
  detectReady(output) {
454
522
  const stripped = this.stripAnsi(output);
455
- 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 ">"
456
533
  /gemini>\s*$/i.test(stripped);
457
534
  }
458
535
  parseOutput(output) {
@@ -474,6 +551,27 @@ var GeminiAdapter = class extends BaseCodingAdapter {
474
551
  }
475
552
  };
476
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
+ }
477
575
  getPromptPattern() {
478
576
  return /gemini>\s*$/i;
479
577
  }
@@ -495,11 +593,12 @@ var CodexAdapter = class extends BaseCodingAdapter {
495
593
  };
496
594
  /**
497
595
  * Auto-response rules for OpenAI Codex CLI.
498
- * 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
499
598
  */
500
599
  autoResponseRules = [
501
600
  {
502
- pattern: /Update (available|now)|Skip until next version/i,
601
+ pattern: /update.?available.*->|update.?now|skip.?until.?next.?version/i,
503
602
  type: "config",
504
603
  response: "",
505
604
  responseType: "keys",
@@ -508,12 +607,50 @@ var CodexAdapter = class extends BaseCodingAdapter {
508
607
  safe: true
509
608
  },
510
609
  {
511
- pattern: /trust the contents of this directory/i,
610
+ pattern: /do.?you.?trust.?the.?contents|trust.?this.?directory|yes,?.?continue|prompt.?injection/i,
512
611
  type: "permission",
513
612
  response: "",
514
613
  responseType: "keys",
515
614
  keys: ["enter"],
516
- description: "Trust directory contents to allow Codex to operate",
615
+ description: 'Trust directory contents (default: "Yes, continue")',
616
+ safe: true,
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",
517
654
  safe: true
518
655
  }
519
656
  ];
@@ -559,6 +696,23 @@ var CodexAdapter = class extends BaseCodingAdapter {
559
696
  instructions: "Set OPENAI_API_KEY environment variable or provide credentials in adapterConfig"
560
697
  };
561
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
+ }
562
716
  if (stripped.includes("device code") || stripped.includes("Enter the code")) {
563
717
  const codeMatch = stripped.match(/code[:\s]+([A-Z0-9-]+)/i);
564
718
  const urlMatch = stripped.match(/https?:\/\/[^\s]+/);
@@ -572,10 +726,21 @@ var CodexAdapter = class extends BaseCodingAdapter {
572
726
  return { required: false };
573
727
  }
574
728
  /**
575
- * 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
576
731
  */
577
732
  detectBlockingPrompt(output) {
578
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
+ }
579
744
  const loginDetection = this.detectLogin(output);
580
745
  if (loginDetection.required) {
581
746
  return {
@@ -587,6 +752,24 @@ var CodexAdapter = class extends BaseCodingAdapter {
587
752
  instructions: loginDetection.instructions
588
753
  };
589
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
+ }
590
773
  if (/select.*model|choose.*model|gpt-4|gpt-3\.5/i.test(stripped) && /\d+\)/i.test(stripped)) {
591
774
  return {
592
775
  detected: true,
@@ -618,7 +801,16 @@ var CodexAdapter = class extends BaseCodingAdapter {
618
801
  }
619
802
  detectReady(output) {
620
803
  const stripped = this.stripAnsi(output);
621
- 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);
622
814
  }
623
815
  parseOutput(output) {
624
816
  const stripped = this.stripAnsi(output);
@@ -638,6 +830,24 @@ var CodexAdapter = class extends BaseCodingAdapter {
638
830
  }
639
831
  };
640
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
+ }
641
851
  getPromptPattern() {
642
852
  return /(?:codex|>)\s*$/i;
643
853
  }
@@ -665,12 +875,42 @@ var AiderAdapter = class extends BaseCodingAdapter {
665
875
  };
666
876
  /**
667
877
  * Auto-response rules for Aider CLI.
668
- * Aider uses plain text [y/n] prompts, NOT TUI menus.
669
- * 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.
670
882
  */
671
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
+ },
672
894
  {
673
- pattern: /Add .+ to the chat\?.*\[y\/n\]/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,
674
914
  type: "permission",
675
915
  response: "y",
676
916
  responseType: "text",
@@ -678,7 +918,15 @@ var AiderAdapter = class extends BaseCodingAdapter {
678
918
  safe: true
679
919
  },
680
920
  {
681
- pattern: /Create new file.*\[y\/n\]/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,
682
930
  type: "permission",
683
931
  response: "y",
684
932
  responseType: "text",
@@ -686,11 +934,96 @@ var AiderAdapter = class extends BaseCodingAdapter {
686
934
  safe: true
687
935
  },
688
936
  {
689
- pattern: /Apply.*changes.*\[y\/n\]/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,
946
+ type: "permission",
947
+ response: "y",
948
+ responseType: "text",
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,
690
1015
  type: "permission",
691
1016
  response: "y",
692
1017
  responseType: "text",
693
- description: "Apply proposed changes",
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",
694
1027
  safe: true
695
1028
  }
696
1029
  ];
@@ -770,8 +1103,28 @@ var AiderAdapter = class extends BaseCodingAdapter {
770
1103
  instructions: "API key is invalid - please check your credentials"
771
1104
  };
772
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
+ }
773
1122
  return { required: false };
774
1123
  }
1124
+ /**
1125
+ * Detect blocking prompts specific to Aider CLI.
1126
+ * Source: io.py, onboarding.py, base_coder.py, report.py
1127
+ */
775
1128
  detectBlockingPrompt(output) {
776
1129
  const stripped = this.stripAnsi(output);
777
1130
  const loginDetection = this.detectLogin(output);
@@ -780,6 +1133,7 @@ var AiderAdapter = class extends BaseCodingAdapter {
780
1133
  detected: true,
781
1134
  type: "login",
782
1135
  prompt: loginDetection.instructions,
1136
+ url: loginDetection.url,
783
1137
  canAutoRespond: false,
784
1138
  instructions: loginDetection.instructions
785
1139
  };
@@ -793,16 +1147,16 @@ var AiderAdapter = class extends BaseCodingAdapter {
793
1147
  instructions: "Please select a model or set AIDER_MODEL env var"
794
1148
  };
795
1149
  }
796
- if (/not.*git.*repo|git.*not.*found|initialize.*git/i.test(stripped)) {
1150
+ if (/please answer with one of:/i.test(stripped)) {
797
1151
  return {
798
1152
  detected: true,
799
- type: "config",
800
- prompt: "Git repository required",
1153
+ type: "unknown",
1154
+ prompt: "Invalid confirmation input",
801
1155
  canAutoRespond: false,
802
- instructions: "Aider requires a git repository. Run git init or use --no-git"
1156
+ instructions: "Aider received an invalid response to a confirmation prompt"
803
1157
  };
804
1158
  }
805
- 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))) {
806
1160
  return {
807
1161
  detected: true,
808
1162
  type: "permission",
@@ -816,9 +1170,22 @@ var AiderAdapter = class extends BaseCodingAdapter {
816
1170
  }
817
1171
  detectReady(output) {
818
1172
  const stripped = this.stripAnsi(output);
819
- return stripped.includes("aider>") || stripped.includes("Aider") || /aider.*ready/i.test(stripped) || // Aider shows file list when ready
820
- /Added.*to the chat/i.test(stripped) || // Or the prompt
821
- />\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
+ );
822
1189
  }
823
1190
  parseOutput(output) {
824
1191
  const stripped = this.stripAnsi(output);
@@ -839,8 +1206,26 @@ var AiderAdapter = class extends BaseCodingAdapter {
839
1206
  }
840
1207
  };
841
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
+ }
842
1227
  getPromptPattern() {
843
- return /(?:aider>|>)\s*$/i;
1228
+ return /(?:ask|code|architect|help|aider|multi)(?:\s+multi)?>\s*$/i;
844
1229
  }
845
1230
  getHealthCheckCommand() {
846
1231
  return "aider --version";