@adhdev/daemon-core 0.6.56 → 0.6.58
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 +23 -0
- package/dist/index.js +423 -95
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/providers/_builtin/cli/aider-cli/scripts/1.0/parse_output.js +51 -3
- package/providers/_builtin/cli/claude-cli/provider.json +18 -6
- package/providers/_builtin/cli/claude-cli/scripts/1.0/detect_status.js +68 -16
- package/providers/_builtin/cli/claude-cli/scripts/1.0/parse_approval.js +81 -22
- package/providers/_builtin/cli/claude-cli/scripts/1.0/parse_output.js +347 -94
- package/providers/_builtin/cli/codex-cli/provider.json +2 -0
- package/providers/_builtin/cli/codex-cli/scripts/1.0/detect_status.js +44 -10
- package/providers/_builtin/cli/codex-cli/scripts/1.0/parse_approval.js +83 -7
- package/providers/_builtin/cli/codex-cli/scripts/1.0/parse_output.js +501 -47
- package/providers/_builtin/cli/cursor-cli/scripts/1.0/parse_output.js +1 -1
- package/providers/_builtin/cli/github-copilot-cli/scripts/1.0/parse_output.js +1 -1
- package/providers/_builtin/cli/goose-cli/scripts/1.0/parse_output.js +1 -1
- package/providers/_builtin/cli/opencode-cli/scripts/1.0/parse_output.js +1 -1
- package/providers/_builtin/ide/vscode/provider.json +5 -1
- package/providers/_builtin/ide/vscode/scripts/1.0/focus_editor.js +1 -0
- package/providers/_builtin/ide/vscode/scripts/1.0/list_models.js +1 -0
- package/providers/_builtin/ide/vscode/scripts/1.0/list_sessions.js +1 -0
- package/providers/_builtin/ide/vscode/scripts/1.0/new_session.js +1 -0
- package/providers/_builtin/ide/vscode/scripts/1.0/open_panel.js +1 -0
- package/providers/_builtin/ide/vscode/scripts/1.0/read_chat.js +1 -0
- package/providers/_builtin/ide/vscode/scripts/1.0/resolve_action.js +1 -0
- package/providers/_builtin/ide/vscode/scripts/1.0/scripts.js +25 -0
- package/providers/_builtin/ide/vscode/scripts/1.0/send_message.js +1 -0
- package/providers/_builtin/ide/vscode/scripts/1.0/set_model.js +1 -0
- package/providers/_builtin/ide/vscode/scripts/1.0/switch_session.js +1 -0
- package/providers/_builtin/registry.json +1 -1
- package/src/cli-adapters/provider-cli-adapter.ts +410 -65
- package/src/commands/chat-commands.ts +7 -1
- package/src/config/chat-history.ts +53 -1
- package/src/daemon/dev-server.ts +7 -9
- package/src/providers/cli-provider-instance.ts +10 -23
- package/src/providers/provider-instance.ts +1 -0
- package/src/providers/version-archive.ts +4 -1
package/package.json
CHANGED
|
@@ -35,13 +35,61 @@ function splitTurns(buffer) {
|
|
|
35
35
|
return messages.length > 50 ? messages.slice(-50) : messages;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
function mergeMessages(priorMessages, parsedMessages, status) {
|
|
39
|
+
const base = Array.isArray(priorMessages)
|
|
40
|
+
? priorMessages
|
|
41
|
+
.filter(message => message && (message.role === 'user' || message.role === 'assistant'))
|
|
42
|
+
.map(message => ({
|
|
43
|
+
role: message.role,
|
|
44
|
+
content: typeof message.content === 'string' ? message.content : String(message.content || ''),
|
|
45
|
+
timestamp: message.timestamp,
|
|
46
|
+
}))
|
|
47
|
+
: [];
|
|
48
|
+
if (!parsedMessages.length) return base.map((message, index) => ({
|
|
49
|
+
id: `msg_${index}`,
|
|
50
|
+
role: message.role,
|
|
51
|
+
content: message.content,
|
|
52
|
+
index,
|
|
53
|
+
kind: 'standard',
|
|
54
|
+
}));
|
|
55
|
+
|
|
56
|
+
const latestAssistant = [...parsedMessages].reverse().find(message => message.role === 'assistant' && message.content);
|
|
57
|
+
if (!latestAssistant) {
|
|
58
|
+
return base.map((message, index) => ({
|
|
59
|
+
id: `msg_${index}`,
|
|
60
|
+
role: message.role,
|
|
61
|
+
content: message.content,
|
|
62
|
+
index,
|
|
63
|
+
kind: 'standard',
|
|
64
|
+
}));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const last = base[base.length - 1];
|
|
68
|
+
if (last && last.role === 'assistant') {
|
|
69
|
+
last.content = latestAssistant.content;
|
|
70
|
+
} else {
|
|
71
|
+
base.push({ role: 'assistant', content: latestAssistant.content });
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return base.slice(-50).map((message, index, slice) => ({
|
|
75
|
+
id: `msg_${index}`,
|
|
76
|
+
role: message.role,
|
|
77
|
+
content: typeof message.content === 'string' ? message.content.slice(0, 6000) : '',
|
|
78
|
+
index,
|
|
79
|
+
kind: 'standard',
|
|
80
|
+
...(status === 'generating' && index === slice.length - 1 && message.role === 'assistant'
|
|
81
|
+
? { meta: { streaming: true } }
|
|
82
|
+
: {}),
|
|
83
|
+
}));
|
|
84
|
+
}
|
|
85
|
+
|
|
38
86
|
module.exports = function parseOutput(input) {
|
|
39
|
-
const { buffer, recentBuffer, partialResponse, screenText } = input;
|
|
40
|
-
const transcript =
|
|
87
|
+
const { buffer, recentBuffer, partialResponse, screenText, messages: priorMessages } = input;
|
|
88
|
+
const transcript = buffer || screenText;
|
|
41
89
|
const tail = recentBuffer || (transcript || '').slice(-500);
|
|
42
90
|
const status = detectStatus({ tail });
|
|
43
91
|
const activeModal = status === 'waiting_approval' ? parseApproval({ buffer: transcript, tail }) : null;
|
|
44
|
-
const messages = splitTurns(transcript);
|
|
92
|
+
const messages = mergeMessages(priorMessages, splitTurns(transcript), status);
|
|
45
93
|
if (status === 'generating' && partialResponse && partialResponse.trim().length > 2) {
|
|
46
94
|
messages.push({ id: 'msg_partial', role: 'assistant', content: partialResponse.trim().slice(0, 6000), index: messages.length, kind: 'standard', meta: { streaming: true } });
|
|
47
95
|
}
|
|
@@ -58,9 +58,14 @@
|
|
|
58
58
|
}
|
|
59
59
|
},
|
|
60
60
|
"binary": "claude",
|
|
61
|
+
"sendDelayMs": 700,
|
|
62
|
+
"submitStrategy": "immediate",
|
|
61
63
|
"spawn": {
|
|
62
64
|
"command": "claude",
|
|
63
|
-
"args": [
|
|
65
|
+
"args": [
|
|
66
|
+
"--permission-mode",
|
|
67
|
+
"acceptEdits"
|
|
68
|
+
],
|
|
64
69
|
"shell": true,
|
|
65
70
|
"env": {}
|
|
66
71
|
},
|
|
@@ -69,14 +74,21 @@
|
|
|
69
74
|
{ "source": "Type your message", "flags": "i" },
|
|
70
75
|
{ "source": "for\\s*shortcuts", "flags": "i" },
|
|
71
76
|
{ "source": "\\?\\s*for\\s*help", "flags": "i" },
|
|
72
|
-
{ "source": "Press enter", "flags": "i" }
|
|
77
|
+
{ "source": "Press enter", "flags": "i" },
|
|
78
|
+
{ "source": "[›❯]\\s*$", "flags": "m" },
|
|
79
|
+
{ "source": "medium\\s+·\\s+/effort", "flags": "i" }
|
|
73
80
|
],
|
|
74
81
|
"generating": [
|
|
75
82
|
{ "source": "[\\u2800-\\u28ff]", "flags": "" },
|
|
76
83
|
{ "source": "esc to (cancel|interrupt|stop)", "flags": "i" },
|
|
77
84
|
{ "source": "generating\\.\\.\\.", "flags": "i" },
|
|
78
85
|
{ "source": "Claude is (?:thinking|processing|working)", "flags": "i" },
|
|
79
|
-
{ "source": "Flummoxing", "flags": "i" }
|
|
86
|
+
{ "source": "Flummoxing", "flags": "i" },
|
|
87
|
+
{ "source": "Finagling", "flags": "i" },
|
|
88
|
+
{ "source": "Scurrying", "flags": "i" },
|
|
89
|
+
{ "source": "Bloviating", "flags": "i" },
|
|
90
|
+
{ "source": "Whatchamacallit(?:ing)?", "flags": "i" },
|
|
91
|
+
{ "source": "(Thinking|Processing|Working|Analyzing|Planning|Drafting|Synthesizing|Inspecting|Reading|Searching)…?", "flags": "i" }
|
|
80
92
|
],
|
|
81
93
|
"approval": [
|
|
82
94
|
{ "source": "Allow\\s*once", "flags": "i" },
|
|
@@ -95,9 +107,9 @@
|
|
|
95
107
|
]
|
|
96
108
|
},
|
|
97
109
|
"approvalKeys": {
|
|
98
|
-
"0": "
|
|
99
|
-
"1": "
|
|
100
|
-
"2": "
|
|
110
|
+
"0": "\r",
|
|
111
|
+
"1": "\u001b[B\r",
|
|
112
|
+
"2": "\u001b[B\u001b[B\r"
|
|
101
113
|
},
|
|
102
114
|
"compatibility": [
|
|
103
115
|
{
|
|
@@ -1,31 +1,83 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Claude Code — detect_status
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* Output: 'idle' | 'generating' | 'waiting_approval'
|
|
4
|
+
* Uses the current visible PTY screen when available.
|
|
5
|
+
* `tail` is still used as a fallback for older runtimes.
|
|
7
6
|
*/
|
|
8
7
|
|
|
9
8
|
'use strict';
|
|
10
9
|
|
|
10
|
+
function splitLines(text) {
|
|
11
|
+
return String(text || '')
|
|
12
|
+
.replace(/\u0007/g, '')
|
|
13
|
+
.split(/\r\n|\n|\r/g)
|
|
14
|
+
.map(line => line.replace(/\s+$/, ''));
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function normalize(line) {
|
|
18
|
+
return String(line || '')
|
|
19
|
+
.replace(/\u0007/g, '')
|
|
20
|
+
.replace(/^\d+;/, '')
|
|
21
|
+
.trim();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function isVisiblePrompt(line) {
|
|
25
|
+
return /^❯\s*$/.test(normalize(line));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function isVisibleApproval(line) {
|
|
29
|
+
const trimmed = normalize(line);
|
|
30
|
+
return /Allow\s*once/i.test(trimmed)
|
|
31
|
+
|| /Always\s*allow/i.test(trimmed)
|
|
32
|
+
|| /This command requires approval/i.test(trimmed)
|
|
33
|
+
|| /Do you want to (?:proceed|allow|run)/i.test(trimmed)
|
|
34
|
+
|| /Deny|Reject|Cancel/i.test(trimmed)
|
|
35
|
+
|| /\(y\/n\)/i.test(trimmed)
|
|
36
|
+
|| /\[Y\/n\]/i.test(trimmed)
|
|
37
|
+
|| /^([❯›>]\s*)?\d+[.)]\s+/.test(trimmed);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function isVisibleSpinner(line) {
|
|
41
|
+
const trimmed = normalize(line);
|
|
42
|
+
if (!trimmed) return false;
|
|
43
|
+
if (/^[✻✶✳✢✽⠂⠐⠒⠓⠦⠴⠶⠷⠿]+$/.test(trimmed)) return true;
|
|
44
|
+
if (/esc to (cancel|interrupt|stop)/i.test(trimmed)) return true;
|
|
45
|
+
if (/Running(?:\u2026|\.{3})?$/i.test(trimmed)) return true;
|
|
46
|
+
if (/(?:Finagling|Scurrying|Bloviating|Whatchamacallit(?:ing)?|Hatching|Thinking|Processing|Working|Analyzing|Planning|Drafting|Synthesizing|Inspecting|Reading|Searching|Tinkering|Canoodling|Whirring|Infusing|Accomplishing|Deliberating)\u2026?$/i.test(trimmed)) return true;
|
|
47
|
+
if (/^[A-Z][a-z]+ing\u2026?$/.test(trimmed)) return true;
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
|
|
11
51
|
module.exports = function detectStatus(input) {
|
|
12
|
-
const
|
|
13
|
-
|
|
52
|
+
const tail = String(input?.tail || '');
|
|
53
|
+
const screenText = String(input?.screenText || '');
|
|
54
|
+
const visibleLines = splitLines(screenText);
|
|
55
|
+
const visibleText = visibleLines.map(normalize).filter(Boolean).join('\n');
|
|
56
|
+
if (visibleText) {
|
|
57
|
+
if (visibleLines.some(isVisibleApproval)) return 'waiting_approval';
|
|
58
|
+
} else if (tail) {
|
|
59
|
+
const hasApproval = /Allow\s*once/i.test(tail)
|
|
60
|
+
|| /Always\s*allow/i.test(tail)
|
|
61
|
+
|| /This command requires approval/i.test(tail)
|
|
62
|
+
|| /Do you want to (?:proceed|allow|run)/i.test(tail)
|
|
63
|
+
|| /\(y\/n\)|\[Y\/n\]/i.test(tail)
|
|
64
|
+
|| /^([❯›>]\s*)?\d+[.)]\s+/m.test(tail);
|
|
65
|
+
if (hasApproval) return 'waiting_approval';
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (visibleLines.length > 0) {
|
|
69
|
+
const hasSpinner = visibleLines.some(isVisibleSpinner);
|
|
70
|
+
if (hasSpinner) return 'generating';
|
|
14
71
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
if (/\(y\/n\)/i.test(tail) || /\[Y\/n\]/i.test(tail)) return 'waiting_approval';
|
|
72
|
+
const hasPrompt = visibleLines.some(isVisiblePrompt);
|
|
73
|
+
if (hasPrompt) return 'idle';
|
|
74
|
+
}
|
|
19
75
|
|
|
20
|
-
// ─── generating ───
|
|
21
|
-
// Braille spinner characters (universal TUI spinner)
|
|
22
76
|
if (/[\u2800-\u28ff]/.test(tail)) return 'generating';
|
|
23
|
-
// Status line indicators
|
|
24
77
|
if (/esc to (cancel|interrupt|stop)/i.test(tail)) return 'generating';
|
|
25
|
-
if (/
|
|
26
|
-
if (/
|
|
27
|
-
if (
|
|
78
|
+
if (/Running(?:\u2026|\.{3})?$/im.test(tail)) return 'generating';
|
|
79
|
+
if (/(?:Finagling|Scurrying|Bloviating|Whatchamacallit(?:ing)?|Hatching|Thinking|Processing|Working|Analyzing|Planning|Drafting|Synthesizing|Inspecting|Reading|Searching|Tinkering|Canoodling|Whirring|Infusing|Accomplishing|Deliberating)\u2026?$/i.test(tail)) return 'generating';
|
|
80
|
+
if (/^[A-Z][a-z]+ing\u2026?$/m.test(tail)) return 'generating';
|
|
28
81
|
|
|
29
|
-
// ─── idle ───
|
|
30
82
|
return 'idle';
|
|
31
83
|
};
|
|
@@ -1,38 +1,97 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Claude Code — parse_approval
|
|
3
|
-
*
|
|
4
|
-
* Extract approval modal info from PTY output.
|
|
5
|
-
* Input: { buffer: string, tail: string }
|
|
6
|
-
* Output: { message: string, buttons: string[] } | null
|
|
7
3
|
*/
|
|
8
4
|
|
|
9
5
|
'use strict';
|
|
10
6
|
|
|
7
|
+
function splitLines(text) {
|
|
8
|
+
return String(text || '')
|
|
9
|
+
.replace(/\u0007/g, '')
|
|
10
|
+
.split(/\r\n|\n|\r/g)
|
|
11
|
+
.map(line => line.replace(/\s+$/, ''));
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function normalize(line) {
|
|
15
|
+
return String(line || '')
|
|
16
|
+
.replace(/\u0007/g, '')
|
|
17
|
+
.replace(/^\d+;/, '')
|
|
18
|
+
.trim();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function isNoise(line) {
|
|
22
|
+
const trimmed = normalize(line);
|
|
23
|
+
if (!trimmed) return true;
|
|
24
|
+
if (/^[─═╭╮╰╯│┌┐└┘├┤┬┴┼]+$/.test(trimmed)) return true;
|
|
25
|
+
if (/^❯\s*$/.test(trimmed)) return true;
|
|
26
|
+
if (/^➜\s+\S+/.test(trimmed)) return true;
|
|
27
|
+
if (/^Update available!/i.test(trimmed)) return true;
|
|
28
|
+
if (/^Claude Code v\d/i.test(trimmed)) return true;
|
|
29
|
+
if (/^(Sonnet|Opus|Haiku)\b/i.test(trimmed)) return true;
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function normalizeButtonLabel(line) {
|
|
34
|
+
return normalize(line)
|
|
35
|
+
.replace(/^[❯›>]\s*/, '')
|
|
36
|
+
.replace(/^[([{]?\d+[)\].:\]-]?\s*/, '')
|
|
37
|
+
.replace(/\s+/g, ' ')
|
|
38
|
+
.trim();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function isButtonLine(line) {
|
|
42
|
+
const raw = normalize(line);
|
|
43
|
+
const trimmed = normalizeButtonLabel(line);
|
|
44
|
+
if (/^Esc to cancel/i.test(raw)) return false;
|
|
45
|
+
return /^([❯›>]\s*)?\d+[.)]\s+/.test(raw)
|
|
46
|
+
|| /^(Allow\s*once|Always\s*allow.*|Deny|Reject|Yes|No)$/i.test(trimmed);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function stripContextPrefix(line) {
|
|
50
|
+
return normalize(line)
|
|
51
|
+
.replace(/^[⏺•]\s+/, '')
|
|
52
|
+
.replace(/\s+/g, ' ')
|
|
53
|
+
.trim();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function findLastIndex(lines, predicate) {
|
|
57
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
58
|
+
if (predicate(lines[i])) return i;
|
|
59
|
+
}
|
|
60
|
+
return -1;
|
|
61
|
+
}
|
|
62
|
+
|
|
11
63
|
module.exports = function parseApproval(input) {
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
|
|
64
|
+
const primary = String(input?.buffer || '');
|
|
65
|
+
const fallback = String(input?.tail || '');
|
|
66
|
+
const lines = splitLines(primary || fallback);
|
|
67
|
+
if (lines.length === 0) return null;
|
|
15
68
|
|
|
16
|
-
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
69
|
+
const buttons = [];
|
|
70
|
+
for (const line of lines.slice(-40)) {
|
|
71
|
+
if (!isButtonLine(line)) continue;
|
|
72
|
+
const label = normalizeButtonLabel(line);
|
|
73
|
+
if (label && !buttons.includes(label)) buttons.push(label);
|
|
74
|
+
}
|
|
22
75
|
|
|
76
|
+
const hasApproval = buttons.length > 0
|
|
77
|
+
|| /Allow\s*once|Always\s*allow|\(y\/n\)|\[Y\/n\]/i.test(primary || fallback);
|
|
23
78
|
if (!hasApproval) return null;
|
|
24
79
|
|
|
25
|
-
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
80
|
+
const questionIndex = findLastIndex(lines, line => /Do you want to (?:proceed|make this edit|run this command|allow)/i.test(normalize(line)));
|
|
81
|
+
const actionIndex = findLastIndex(lines, line => /^(?:[⏺•]\s+)?(?:Bash|Write|Edit|MultiEdit|Read|Task|Glob|Grep|LS|NotebookEdit)\(/.test(stripContextPrefix(line)));
|
|
82
|
+
const startIndex = Math.max(0, (actionIndex >= 0 ? actionIndex : questionIndex >= 0 ? questionIndex - 4 : lines.length - 8));
|
|
83
|
+
const endIndex = questionIndex >= 0 ? questionIndex + 1 : lines.length;
|
|
29
84
|
|
|
30
|
-
const
|
|
85
|
+
const context = [];
|
|
86
|
+
for (const line of lines.slice(startIndex, endIndex)) {
|
|
87
|
+
if (isNoise(line) || isButtonLine(line)) continue;
|
|
88
|
+
const trimmed = stripContextPrefix(line);
|
|
89
|
+
if (!trimmed) continue;
|
|
90
|
+
if (context[context.length - 1] !== trimmed) context.push(trimmed);
|
|
91
|
+
}
|
|
31
92
|
|
|
32
|
-
// Claude Code-specific button labels
|
|
33
|
-
// These map to approvalKeys in provider.json: { "0": "1", "1": "2", "2": "3" }
|
|
34
93
|
return {
|
|
35
|
-
message,
|
|
36
|
-
buttons: ['
|
|
94
|
+
message: context.slice(-3).join(' ').slice(0, 240) || 'Claude Code approval required',
|
|
95
|
+
buttons: buttons.length > 0 ? buttons : ['Allow once', 'Always allow', 'Deny'],
|
|
37
96
|
};
|
|
38
97
|
};
|