coding-agent-adapters 0.3.0 → 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/README.md +26 -0
- package/dist/index.cjs +96 -0
- 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 +96 -0
- 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 | `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,6 +749,29 @@ 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 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
|
+
}
|
|
750
775
|
detectReady(output) {
|
|
751
776
|
const stripped = this.stripAnsi(output);
|
|
752
777
|
if (/trust.*directory|do you want to|needs? your permission/i.test(stripped)) {
|
|
@@ -1004,6 +1029,26 @@ var GeminiAdapter = class extends BaseCodingAdapter {
|
|
|
1004
1029
|
}
|
|
1005
1030
|
return super.detectBlockingPrompt(output);
|
|
1006
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
|
+
}
|
|
1007
1052
|
detectReady(output) {
|
|
1008
1053
|
const stripped = this.stripAnsi(output);
|
|
1009
1054
|
if (/type.?your.?message/i.test(stripped)) {
|
|
@@ -1314,6 +1359,32 @@ var CodexAdapter = class extends BaseCodingAdapter {
|
|
|
1314
1359
|
}
|
|
1315
1360
|
return super.detectBlockingPrompt(output);
|
|
1316
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
|
+
}
|
|
1317
1388
|
detectReady(output) {
|
|
1318
1389
|
const stripped = this.stripAnsi(output);
|
|
1319
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)) {
|
|
@@ -1718,6 +1789,31 @@ var AiderAdapter = class extends BaseCodingAdapter {
|
|
|
1718
1789
|
}
|
|
1719
1790
|
return super.detectBlockingPrompt(output);
|
|
1720
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
|
+
}
|
|
1721
1817
|
detectReady(output) {
|
|
1722
1818
|
const stripped = this.stripAnsi(output);
|
|
1723
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)) {
|