coding-agent-adapters 0.3.0 → 0.4.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.
- package/README.md +26 -0
- package/dist/index.cjs +100 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +54 -0
- package/dist/index.d.ts +54 -0
- package/dist/index.js +100 -2
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -94,6 +94,27 @@ Adapters detect prompts that block the session and require user action:
|
|
|
94
94
|
| Codex | Directory trust, tool approval, update available, model migration, CWD selection |
|
|
95
95
|
| Aider | File operations, shell commands, git init, pip install, destructive operations |
|
|
96
96
|
|
|
97
|
+
### Task Completion Detection
|
|
98
|
+
|
|
99
|
+
Each adapter implements `detectTaskComplete(output)` to recognize when the CLI has finished a task and returned to its idle prompt. This is more specific than `detectReady()` — it matches high-confidence completion indicators (duration summaries, explicit done messages) that short-circuit the LLM stall classifier in pty-manager.
|
|
100
|
+
|
|
101
|
+
| Adapter | Completion Indicators | Source Patterns |
|
|
102
|
+
|---------|----------------------|----------------|
|
|
103
|
+
| Claude | Turn duration (`Cooked for 3m 12s`, custom verb) + `❯` prompt (tolerates trailing status bar) | `claude_completed_turn_duration` |
|
|
104
|
+
| Gemini | `◇ Ready` window title, `Type your message` composer | `gemini_ready_title` |
|
|
105
|
+
| Codex | `Worked for 1m 05s` separator + `›` prompt | `codex_completed_worked_for_separator`, `codex_ready_prompt` |
|
|
106
|
+
| Aider | `Aider is waiting for your input`, mode prompts with edit/cost markers | `aider_completed_llm_response_ready` |
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
const claude = new ClaudeAdapter();
|
|
110
|
+
claude.detectTaskComplete('Cooked for 3m 12s\n❯ '); // true
|
|
111
|
+
claude.detectTaskComplete('Reading 5 files…'); // false
|
|
112
|
+
|
|
113
|
+
const aider = new AiderAdapter();
|
|
114
|
+
aider.detectTaskComplete('Applied edit to main.ts\nTokens: 1234\ncode> '); // true
|
|
115
|
+
aider.detectTaskComplete('Waiting for claude-sonnet-4-20250514'); // false
|
|
116
|
+
```
|
|
117
|
+
|
|
97
118
|
### Exit Detection
|
|
98
119
|
|
|
99
120
|
Adapters detect when a CLI session has ended:
|
|
@@ -390,6 +411,11 @@ export class CursorAdapter extends BaseCodingAdapter {
|
|
|
390
411
|
return /cursor>\s*$/m.test(output);
|
|
391
412
|
}
|
|
392
413
|
|
|
414
|
+
detectTaskComplete(output: string): boolean {
|
|
415
|
+
// High-confidence: task summary + idle prompt
|
|
416
|
+
return /completed in \d+s/.test(output) && /cursor>\s*$/m.test(output);
|
|
417
|
+
}
|
|
418
|
+
|
|
393
419
|
parseOutput(output: string): ParsedOutput | null {
|
|
394
420
|
return { type: 'response', content: output.trim(), isComplete: true, isQuestion: output.includes('?') };
|
|
395
421
|
}
|
package/dist/index.cjs
CHANGED
|
@@ -56,6 +56,8 @@ var CLAUDE_TOOL_CATEGORIES = {
|
|
|
56
56
|
// file_write
|
|
57
57
|
Write: "file_write",
|
|
58
58
|
Edit: "file_write",
|
|
59
|
+
MultiEdit: "file_write",
|
|
60
|
+
NotebookEdit: "file_write",
|
|
59
61
|
// shell
|
|
60
62
|
Bash: "shell",
|
|
61
63
|
BashOutput: "shell",
|
|
@@ -747,15 +749,40 @@ var ClaudeAdapter = class extends BaseCodingAdapter {
|
|
|
747
749
|
}
|
|
748
750
|
return super.detectBlockingPrompt(output);
|
|
749
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 tail = stripped.slice(-300);
|
|
767
|
+
const hasIdlePrompt = /❯/.test(tail);
|
|
768
|
+
if (hasDuration && hasIdlePrompt) {
|
|
769
|
+
return true;
|
|
770
|
+
}
|
|
771
|
+
if (hasIdlePrompt && stripped.includes("for shortcuts")) {
|
|
772
|
+
return true;
|
|
773
|
+
}
|
|
774
|
+
return false;
|
|
775
|
+
}
|
|
750
776
|
detectReady(output) {
|
|
751
777
|
const stripped = this.stripAnsi(output);
|
|
752
778
|
if (/trust.*directory|do you want to|needs? your permission/i.test(stripped)) {
|
|
753
779
|
return false;
|
|
754
780
|
}
|
|
781
|
+
const tail = stripped.slice(-300);
|
|
755
782
|
return stripped.includes("How can I help") || stripped.includes("What would you like") || // v2.1+ shows "for shortcuts" hint when ready
|
|
756
783
|
stripped.includes("for shortcuts") || // Match "claude> " or similar specific prompts, not bare ">"
|
|
757
|
-
/claude
|
|
758
|
-
|
|
784
|
+
/claude>/i.test(tail) || // v2.1+ uses ❯ as the input prompt
|
|
785
|
+
/❯/.test(tail);
|
|
759
786
|
}
|
|
760
787
|
parseOutput(output) {
|
|
761
788
|
const stripped = this.stripAnsi(output);
|
|
@@ -1004,6 +1031,26 @@ var GeminiAdapter = class extends BaseCodingAdapter {
|
|
|
1004
1031
|
}
|
|
1005
1032
|
return super.detectBlockingPrompt(output);
|
|
1006
1033
|
}
|
|
1034
|
+
/**
|
|
1035
|
+
* Detect task completion for Gemini CLI.
|
|
1036
|
+
*
|
|
1037
|
+
* High-confidence patterns:
|
|
1038
|
+
* - "◇ Ready" window title signal (OSC sequence, may survive ANSI stripping)
|
|
1039
|
+
* - "Type your message" composer placeholder after agent output
|
|
1040
|
+
*
|
|
1041
|
+
* Patterns from: AGENT_LOADING_STATUS_PATTERNS.json
|
|
1042
|
+
* - gemini_ready_title
|
|
1043
|
+
*/
|
|
1044
|
+
detectTaskComplete(output) {
|
|
1045
|
+
const stripped = this.stripAnsi(output);
|
|
1046
|
+
if (/◇\s+Ready/.test(stripped)) {
|
|
1047
|
+
return true;
|
|
1048
|
+
}
|
|
1049
|
+
if (/type.?your.?message/i.test(stripped)) {
|
|
1050
|
+
return true;
|
|
1051
|
+
}
|
|
1052
|
+
return false;
|
|
1053
|
+
}
|
|
1007
1054
|
detectReady(output) {
|
|
1008
1055
|
const stripped = this.stripAnsi(output);
|
|
1009
1056
|
if (/type.?your.?message/i.test(stripped)) {
|
|
@@ -1314,6 +1361,32 @@ var CodexAdapter = class extends BaseCodingAdapter {
|
|
|
1314
1361
|
}
|
|
1315
1362
|
return super.detectBlockingPrompt(output);
|
|
1316
1363
|
}
|
|
1364
|
+
/**
|
|
1365
|
+
* Detect task completion for Codex CLI.
|
|
1366
|
+
*
|
|
1367
|
+
* High-confidence patterns:
|
|
1368
|
+
* - "Worked for Xm Ys" separator after work-heavy turns
|
|
1369
|
+
* - "› Ask Codex to do anything" ready prompt
|
|
1370
|
+
*
|
|
1371
|
+
* Patterns from: AGENT_LOADING_STATUS_PATTERNS.json
|
|
1372
|
+
* - codex_completed_worked_for_separator
|
|
1373
|
+
* - codex_ready_prompt
|
|
1374
|
+
*/
|
|
1375
|
+
detectTaskComplete(output) {
|
|
1376
|
+
const stripped = this.stripAnsi(output);
|
|
1377
|
+
const hasWorkedFor = /Worked\s+for\s+\d+(?:h\s+\d{2}m\s+\d{2}s|m\s+\d{2}s|s)/.test(stripped);
|
|
1378
|
+
const hasReadyPrompt = /›\s+Ask\s+Codex\s+to\s+do\s+anything/.test(stripped);
|
|
1379
|
+
if (hasWorkedFor && hasReadyPrompt) {
|
|
1380
|
+
return true;
|
|
1381
|
+
}
|
|
1382
|
+
if (hasReadyPrompt) {
|
|
1383
|
+
return true;
|
|
1384
|
+
}
|
|
1385
|
+
if (hasWorkedFor && /›\s+/m.test(stripped)) {
|
|
1386
|
+
return true;
|
|
1387
|
+
}
|
|
1388
|
+
return false;
|
|
1389
|
+
}
|
|
1317
1390
|
detectReady(output) {
|
|
1318
1391
|
const stripped = this.stripAnsi(output);
|
|
1319
1392
|
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)) {
|
|
@@ -1718,6 +1791,31 @@ var AiderAdapter = class extends BaseCodingAdapter {
|
|
|
1718
1791
|
}
|
|
1719
1792
|
return super.detectBlockingPrompt(output);
|
|
1720
1793
|
}
|
|
1794
|
+
/**
|
|
1795
|
+
* Detect task completion for Aider.
|
|
1796
|
+
*
|
|
1797
|
+
* High-confidence patterns:
|
|
1798
|
+
* - "Aider is waiting for your input" notification (bell message)
|
|
1799
|
+
* - Edit-format mode prompts (ask>, code>, architect>) after output
|
|
1800
|
+
*
|
|
1801
|
+
* Patterns from: AGENT_LOADING_STATUS_PATTERNS.json
|
|
1802
|
+
* - aider_completed_llm_response_ready
|
|
1803
|
+
*/
|
|
1804
|
+
detectTaskComplete(output) {
|
|
1805
|
+
const stripped = this.stripAnsi(output);
|
|
1806
|
+
if (/Aider\s+is\s+waiting\s+for\s+your\s+input/.test(stripped)) {
|
|
1807
|
+
return true;
|
|
1808
|
+
}
|
|
1809
|
+
const hasPrompt = /(?:ask|code|architect)(?:\s+multi)?>\s*$/m.test(stripped);
|
|
1810
|
+
if (hasPrompt) {
|
|
1811
|
+
const hasEditMarkers = /Applied edit to|Commit [a-f0-9]+|wrote to|Updated/i.test(stripped);
|
|
1812
|
+
const hasTokenUsage = /Tokens:|Cost:/i.test(stripped);
|
|
1813
|
+
if (hasEditMarkers || hasTokenUsage) {
|
|
1814
|
+
return true;
|
|
1815
|
+
}
|
|
1816
|
+
}
|
|
1817
|
+
return false;
|
|
1818
|
+
}
|
|
1721
1819
|
detectReady(output) {
|
|
1722
1820
|
const stripped = this.stripAnsi(output);
|
|
1723
1821
|
if (/login to openrouter/i.test(stripped) || /open this url in your browser/i.test(stripped) || /waiting up to 5 minutes/i.test(stripped)) {
|