@adhdev/daemon-core 0.5.3
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 +2662 -0
- package/dist/index.js +11341 -0
- package/dist/index.js.map +1 -0
- package/package.json +48 -0
- package/providers/_builtin/.github/workflows/generate-registry.yml +57 -0
- package/providers/_builtin/COMPATIBILITY.md +217 -0
- package/providers/_builtin/CONTRIBUTING.md +200 -0
- package/providers/_builtin/README.md +119 -0
- package/providers/_builtin/_helpers/index.js +188 -0
- package/providers/_builtin/acp/agentpool/provider.json +54 -0
- package/providers/_builtin/acp/amp/provider.json +52 -0
- package/providers/_builtin/acp/auggie/provider.json +57 -0
- package/providers/_builtin/acp/autodev/provider.json +54 -0
- package/providers/_builtin/acp/autohand/provider.json +52 -0
- package/providers/_builtin/acp/blackbox-ai/provider.json +54 -0
- package/providers/_builtin/acp/claude-agent/provider.json +57 -0
- package/providers/_builtin/acp/cline-acp/provider.json +54 -0
- package/providers/_builtin/acp/codebuddy/provider.json +54 -0
- package/providers/_builtin/acp/codex-cli/provider.json +57 -0
- package/providers/_builtin/acp/corust-agent/provider.json +52 -0
- package/providers/_builtin/acp/crow-cli/provider.json +54 -0
- package/providers/_builtin/acp/cursor-acp/provider.json +54 -0
- package/providers/_builtin/acp/deepagents/provider.json +52 -0
- package/providers/_builtin/acp/dimcode/provider.json +54 -0
- package/providers/_builtin/acp/docker-cagent/provider.json +57 -0
- package/providers/_builtin/acp/factory-droid/provider.json +60 -0
- package/providers/_builtin/acp/fast-agent/provider.json +52 -0
- package/providers/_builtin/acp/gemini-cli/provider.json +114 -0
- package/providers/_builtin/acp/github-copilot/provider.json +54 -0
- package/providers/_builtin/acp/goose/provider.json +57 -0
- package/providers/_builtin/acp/junie/provider.json +52 -0
- package/providers/_builtin/acp/kilo/provider.json +54 -0
- package/providers/_builtin/acp/kimi-cli/provider.json +57 -0
- package/providers/_builtin/acp/minion-code/provider.json +52 -0
- package/providers/_builtin/acp/mistral-vibe/provider.json +57 -0
- package/providers/_builtin/acp/nova/provider.json +54 -0
- package/providers/_builtin/acp/openclaw/provider.json +54 -0
- package/providers/_builtin/acp/opencode/provider.json +52 -0
- package/providers/_builtin/acp/openhands/provider.json +54 -0
- package/providers/_builtin/acp/pi-acp/provider.json +52 -0
- package/providers/_builtin/acp/qoder/provider.json +54 -0
- package/providers/_builtin/acp/qwen-code/provider.json +60 -0
- package/providers/_builtin/acp/stakpak/provider.json +54 -0
- package/providers/_builtin/acp/vtcode/provider.json +54 -0
- package/providers/_builtin/cli/claude-cli/provider.json +100 -0
- package/providers/_builtin/cli/codex-cli/provider.json +89 -0
- package/providers/_builtin/cli/gemini-cli/provider.json +93 -0
- package/providers/_builtin/docs/CDP_SELECTOR_GUIDE.md +370 -0
- package/providers/_builtin/docs/PROVIDER_GUIDE.md +916 -0
- package/providers/_builtin/extension/cline/provider.json +35 -0
- package/providers/_builtin/extension/cline/scripts/focus_editor.js +48 -0
- package/providers/_builtin/extension/cline/scripts/list_chats.js +100 -0
- package/providers/_builtin/extension/cline/scripts/list_models.js +43 -0
- package/providers/_builtin/extension/cline/scripts/list_modes.js +35 -0
- package/providers/_builtin/extension/cline/scripts/new_session.js +85 -0
- package/providers/_builtin/extension/cline/scripts/open_panel.js +25 -0
- package/providers/_builtin/extension/cline/scripts/read_chat.js +257 -0
- package/providers/_builtin/extension/cline/scripts/resolve_action.js +83 -0
- package/providers/_builtin/extension/cline/scripts/send_message.js +95 -0
- package/providers/_builtin/extension/cline/scripts/set_mode.js +36 -0
- package/providers/_builtin/extension/cline/scripts/set_model.js +36 -0
- package/providers/_builtin/extension/cline/scripts/switch_session.js +206 -0
- package/providers/_builtin/extension/cline/scripts.js +73 -0
- package/providers/_builtin/extension/roo-code/provider.json +35 -0
- package/providers/_builtin/extension/roo-code/scripts.js +659 -0
- package/providers/_builtin/ide/antigravity/provider.json +68 -0
- package/providers/_builtin/ide/antigravity/scripts/1.106/focus_editor.js +20 -0
- package/providers/_builtin/ide/antigravity/scripts/1.106/list_chats.js +137 -0
- package/providers/_builtin/ide/antigravity/scripts/1.106/list_models.js +38 -0
- package/providers/_builtin/ide/antigravity/scripts/1.106/list_modes.js +48 -0
- package/providers/_builtin/ide/antigravity/scripts/1.106/new_session.js +75 -0
- package/providers/_builtin/ide/antigravity/scripts/1.106/read_chat.js +262 -0
- package/providers/_builtin/ide/antigravity/scripts/1.106/resolve_action.js +68 -0
- package/providers/_builtin/ide/antigravity/scripts/1.106/scripts.js +57 -0
- package/providers/_builtin/ide/antigravity/scripts/1.106/send_message.js +56 -0
- package/providers/_builtin/ide/antigravity/scripts/1.106/set_mode.js +34 -0
- package/providers/_builtin/ide/antigravity/scripts/1.106/set_model.js +47 -0
- package/providers/_builtin/ide/antigravity/scripts/1.106/switch_session.js +114 -0
- package/providers/_builtin/ide/antigravity/scripts/1.107/focus_editor.js +20 -0
- package/providers/_builtin/ide/antigravity/scripts/1.107/list_chats.js +137 -0
- package/providers/_builtin/ide/antigravity/scripts/1.107/list_models.js +61 -0
- package/providers/_builtin/ide/antigravity/scripts/1.107/list_modes.js +72 -0
- package/providers/_builtin/ide/antigravity/scripts/1.107/new_session.js +75 -0
- package/providers/_builtin/ide/antigravity/scripts/1.107/read_chat.js +262 -0
- package/providers/_builtin/ide/antigravity/scripts/1.107/resolve_action.js +68 -0
- package/providers/_builtin/ide/antigravity/scripts/1.107/scripts.js +67 -0
- package/providers/_builtin/ide/antigravity/scripts/1.107/send_message.js +56 -0
- package/providers/_builtin/ide/antigravity/scripts/1.107/set_mode.js +67 -0
- package/providers/_builtin/ide/antigravity/scripts/1.107/set_model.js +72 -0
- package/providers/_builtin/ide/antigravity/scripts/1.107/switch_session.js +114 -0
- package/providers/_builtin/ide/cursor/provider.json +70 -0
- package/providers/_builtin/ide/cursor/scripts/0.49/dismiss_notification.js +30 -0
- package/providers/_builtin/ide/cursor/scripts/0.49/focus_editor.js +13 -0
- package/providers/_builtin/ide/cursor/scripts/0.49/list_models.js +78 -0
- package/providers/_builtin/ide/cursor/scripts/0.49/list_modes.js +40 -0
- package/providers/_builtin/ide/cursor/scripts/0.49/list_notifications.js +23 -0
- package/providers/_builtin/ide/cursor/scripts/0.49/list_sessions.js +42 -0
- package/providers/_builtin/ide/cursor/scripts/0.49/new_session.js +20 -0
- package/providers/_builtin/ide/cursor/scripts/0.49/open_panel.js +23 -0
- package/providers/_builtin/ide/cursor/scripts/0.49/read_chat.js +75 -0
- package/providers/_builtin/ide/cursor/scripts/0.49/resolve_action.js +19 -0
- package/providers/_builtin/ide/cursor/scripts/0.49/scripts.js +78 -0
- package/providers/_builtin/ide/cursor/scripts/0.49/send_message.js +23 -0
- package/providers/_builtin/ide/cursor/scripts/0.49/set_mode.js +38 -0
- package/providers/_builtin/ide/cursor/scripts/0.49/set_model.js +81 -0
- package/providers/_builtin/ide/cursor/scripts/0.49/switch_session.js +28 -0
- package/providers/_builtin/ide/kiro/provider.json +67 -0
- package/providers/_builtin/ide/kiro/scripts/focus_editor.js +20 -0
- package/providers/_builtin/ide/kiro/scripts/open_panel.js +47 -0
- package/providers/_builtin/ide/kiro/scripts/resolve_action.js +54 -0
- package/providers/_builtin/ide/kiro/scripts/send_message.js +29 -0
- package/providers/_builtin/ide/kiro/scripts/webview_list_models.js +39 -0
- package/providers/_builtin/ide/kiro/scripts/webview_list_modes.js +39 -0
- package/providers/_builtin/ide/kiro/scripts/webview_list_sessions.js +21 -0
- package/providers/_builtin/ide/kiro/scripts/webview_new_session.js +34 -0
- package/providers/_builtin/ide/kiro/scripts/webview_read_chat.js +68 -0
- package/providers/_builtin/ide/kiro/scripts/webview_send_message.js +72 -0
- package/providers/_builtin/ide/kiro/scripts/webview_set_mode.js +15 -0
- package/providers/_builtin/ide/kiro/scripts/webview_set_model.js +15 -0
- package/providers/_builtin/ide/kiro/scripts/webview_switch_session.js +26 -0
- package/providers/_builtin/ide/kiro/scripts.js +62 -0
- package/providers/_builtin/ide/pearai/provider.json +67 -0
- package/providers/_builtin/ide/pearai/scripts/focus_editor.js +20 -0
- package/providers/_builtin/ide/pearai/scripts/list_sessions.js +38 -0
- package/providers/_builtin/ide/pearai/scripts/new_session.js +55 -0
- package/providers/_builtin/ide/pearai/scripts/open_panel.js +46 -0
- package/providers/_builtin/ide/pearai/scripts/resolve_action.js +54 -0
- package/providers/_builtin/ide/pearai/scripts/send_message.js +29 -0
- package/providers/_builtin/ide/pearai/scripts/webview_list_models.js +43 -0
- package/providers/_builtin/ide/pearai/scripts/webview_list_modes.js +35 -0
- package/providers/_builtin/ide/pearai/scripts/webview_list_sessions.js +62 -0
- package/providers/_builtin/ide/pearai/scripts/webview_new_session.js +49 -0
- package/providers/_builtin/ide/pearai/scripts/webview_read_chat.js +92 -0
- package/providers/_builtin/ide/pearai/scripts/webview_resolve_action.js +59 -0
- package/providers/_builtin/ide/pearai/scripts/webview_send_message.js +72 -0
- package/providers/_builtin/ide/pearai/scripts/webview_set_mode.js +36 -0
- package/providers/_builtin/ide/pearai/scripts/webview_set_model.js +36 -0
- package/providers/_builtin/ide/pearai/scripts/webview_switch_session.js +34 -0
- package/providers/_builtin/ide/pearai/scripts.js +74 -0
- package/providers/_builtin/ide/trae/provider.json +66 -0
- package/providers/_builtin/ide/trae/scripts/focus_editor.js +20 -0
- package/providers/_builtin/ide/trae/scripts/list_chats.js +24 -0
- package/providers/_builtin/ide/trae/scripts/list_models.js +39 -0
- package/providers/_builtin/ide/trae/scripts/list_modes.js +39 -0
- package/providers/_builtin/ide/trae/scripts/new_session.js +30 -0
- package/providers/_builtin/ide/trae/scripts/open_panel.js +44 -0
- package/providers/_builtin/ide/trae/scripts/read_chat.js +113 -0
- package/providers/_builtin/ide/trae/scripts/resolve_action.js +54 -0
- package/providers/_builtin/ide/trae/scripts/send_message.js +69 -0
- package/providers/_builtin/ide/trae/scripts/set_mode.js +15 -0
- package/providers/_builtin/ide/trae/scripts/set_model.js +15 -0
- package/providers/_builtin/ide/trae/scripts/switch_session.js +23 -0
- package/providers/_builtin/ide/trae/scripts.js +57 -0
- package/providers/_builtin/ide/vscode/provider.json +64 -0
- package/providers/_builtin/ide/vscode-insiders/provider.json +62 -0
- package/providers/_builtin/ide/vscodium/provider.json +63 -0
- package/providers/_builtin/ide/windsurf/provider.json +53 -0
- package/providers/_builtin/ide/windsurf/scripts/focus_editor.js +30 -0
- package/providers/_builtin/ide/windsurf/scripts/list_chats.js +117 -0
- package/providers/_builtin/ide/windsurf/scripts/list_models.js +39 -0
- package/providers/_builtin/ide/windsurf/scripts/list_modes.js +39 -0
- package/providers/_builtin/ide/windsurf/scripts/new_session.js +69 -0
- package/providers/_builtin/ide/windsurf/scripts/open_panel.js +58 -0
- package/providers/_builtin/ide/windsurf/scripts/read_chat.js +297 -0
- package/providers/_builtin/ide/windsurf/scripts/resolve_action.js +68 -0
- package/providers/_builtin/ide/windsurf/scripts/send_message.js +87 -0
- package/providers/_builtin/ide/windsurf/scripts/set_mode.js +15 -0
- package/providers/_builtin/ide/windsurf/scripts/set_model.js +15 -0
- package/providers/_builtin/ide/windsurf/scripts/switch_session.js +58 -0
- package/providers/_builtin/ide/windsurf/scripts.js +57 -0
- package/providers/_builtin/registry.json +266 -0
- package/providers/_builtin/validate.js +156 -0
- package/src/agent-stream/index.ts +6 -0
- package/src/agent-stream/manager.ts +286 -0
- package/src/agent-stream/poller.ts +154 -0
- package/src/agent-stream/provider-adapter.ts +138 -0
- package/src/agent-stream/types.ts +61 -0
- package/src/boot/daemon-lifecycle.ts +252 -0
- package/src/cdp/devtools.ts +335 -0
- package/src/cdp/initializer.ts +191 -0
- package/src/cdp/manager.ts +897 -0
- package/src/cdp/scanner.ts +185 -0
- package/src/cdp/setup.ts +150 -0
- package/src/cli-adapter-types.ts +25 -0
- package/src/cli-adapters/provider-cli-adapter.ts +448 -0
- package/src/commands/cdp-commands.ts +208 -0
- package/src/commands/chat-commands.ts +675 -0
- package/src/commands/cli-manager.ts +353 -0
- package/src/commands/handler.ts +328 -0
- package/src/commands/router.ts +258 -0
- package/src/commands/stream-commands.ts +325 -0
- package/src/config/chat-history.ts +211 -0
- package/src/config/config.ts +219 -0
- package/src/daemon/dev-server.ts +2378 -0
- package/src/daemon/scaffold-template.ts +394 -0
- package/src/daemon-core.ts +50 -0
- package/src/detection/cli-detector.ts +89 -0
- package/src/detection/ide-detector.ts +157 -0
- package/src/index.ts +103 -0
- package/src/installer.ts +263 -0
- package/src/ipc-protocol.ts +133 -0
- package/src/launch.ts +433 -0
- package/src/logging/command-log.ts +180 -0
- package/src/logging/logger.ts +316 -0
- package/src/providers/acp-provider-instance.ts +1140 -0
- package/src/providers/cli-provider-instance.ts +207 -0
- package/src/providers/contracts.ts +524 -0
- package/src/providers/extension-provider-instance.ts +156 -0
- package/src/providers/ide-provider-instance.ts +377 -0
- package/src/providers/index.ts +18 -0
- package/src/providers/provider-instance-manager.ts +182 -0
- package/src/providers/provider-instance.ts +112 -0
- package/src/providers/provider-loader.ts +1031 -0
- package/src/providers/status-monitor.ts +125 -0
- package/src/providers/version-archive.ts +266 -0
- package/src/status/reporter.ts +294 -0
- package/src/types.ts +206 -0
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider scaffold template generator
|
|
3
|
+
* Generates provider.json + scripts/ directory structure (Antigravity pattern).
|
|
4
|
+
*
|
|
5
|
+
* New pattern:
|
|
6
|
+
* - Scripts WITHOUT params: self-invoking IIFE — (() => { ... })()
|
|
7
|
+
* - Scripts WITH params: function expression — (params) => { ... }
|
|
8
|
+
* Router invokes: `(${script})(${JSON.stringify(params)})`
|
|
9
|
+
* - Each function is a separate .js file in scripts/<version>/
|
|
10
|
+
* - scripts.js router loads + invokes individual files
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
export interface ScaffoldOptions {
|
|
14
|
+
cdpPorts?: [number, number];
|
|
15
|
+
cli?: string;
|
|
16
|
+
processName?: string;
|
|
17
|
+
installPath?: string;
|
|
18
|
+
binary?: string;
|
|
19
|
+
extensionId?: string;
|
|
20
|
+
version?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface ScaffoldResult {
|
|
24
|
+
'provider.json': string;
|
|
25
|
+
files?: Record<string, string>;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function generateTemplate(type: string, name: string, category: string, opts: ScaffoldOptions = {}): string {
|
|
29
|
+
const result = generateFiles(type, name, category, opts);
|
|
30
|
+
return result['provider.json'];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Generate provider.json + per-function script files.
|
|
35
|
+
* Returns a map of relative paths -> file contents.
|
|
36
|
+
*/
|
|
37
|
+
export function generateFiles(type: string, name: string, category: string, opts: ScaffoldOptions = {}): ScaffoldResult {
|
|
38
|
+
const { cdpPorts, cli, processName, installPath, binary, extensionId, version = '0.1' } = opts;
|
|
39
|
+
|
|
40
|
+
// ─── CLI / ACP: provider.json only ───
|
|
41
|
+
if (category === 'cli' || category === 'acp') {
|
|
42
|
+
const bin = binary || type;
|
|
43
|
+
const meta: Record<string, any> = {
|
|
44
|
+
type,
|
|
45
|
+
name,
|
|
46
|
+
category,
|
|
47
|
+
icon: '💻',
|
|
48
|
+
binary: bin,
|
|
49
|
+
spawn: {
|
|
50
|
+
command: bin,
|
|
51
|
+
args: [],
|
|
52
|
+
shell: true,
|
|
53
|
+
},
|
|
54
|
+
patterns: {
|
|
55
|
+
prompt: ['^[>$#] '],
|
|
56
|
+
generating: ['\\.{3}$', 'thinking'],
|
|
57
|
+
approval: ['\\(y\\/n\\)', 'approve', 'allow'],
|
|
58
|
+
ready: ['ready'],
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
return { 'provider.json': JSON.stringify(meta, null, 2) + '\n' };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// ─── IDE / Extension: provider.json + scripts/ directory ───
|
|
65
|
+
const isExtension = category === 'extension';
|
|
66
|
+
const scriptDir = `scripts/${version}`;
|
|
67
|
+
|
|
68
|
+
const meta: Record<string, any> = {
|
|
69
|
+
type,
|
|
70
|
+
name,
|
|
71
|
+
category,
|
|
72
|
+
displayName: name,
|
|
73
|
+
icon: isExtension ? '🧩' : '💻',
|
|
74
|
+
};
|
|
75
|
+
if (cli) meta.cli = cli;
|
|
76
|
+
if (cdpPorts) meta.cdpPorts = cdpPorts;
|
|
77
|
+
else if (!isExtension) meta.cdpPorts = [9222, 9223];
|
|
78
|
+
if (processName) meta.processNames = { darwin: processName };
|
|
79
|
+
if (installPath) meta.paths = { darwin: [installPath] };
|
|
80
|
+
if (isExtension) {
|
|
81
|
+
meta.extensionId = extensionId || `publisher.${type}`;
|
|
82
|
+
meta.extensionIdPattern = `${extensionId || type}`;
|
|
83
|
+
} else {
|
|
84
|
+
meta.inputMethod = 'cdp-type-and-send';
|
|
85
|
+
meta.inputSelector = '[contenteditable="true"][role="textbox"]';
|
|
86
|
+
meta.providerVersion = '1.0.0';
|
|
87
|
+
meta.compatibility = [
|
|
88
|
+
{ ideVersion: `>=${version}.0`, scriptDir },
|
|
89
|
+
];
|
|
90
|
+
meta.defaultScriptDir = scriptDir;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// ─── Individual script files ───
|
|
94
|
+
const files: Record<string, string> = {};
|
|
95
|
+
|
|
96
|
+
// Router (scripts.js)
|
|
97
|
+
files[`${scriptDir}/scripts.js`] = `/**
|
|
98
|
+
* ${name} CDP Scripts — Router
|
|
99
|
+
*
|
|
100
|
+
* Loads individual .js files and invokes with params.
|
|
101
|
+
* Pattern:
|
|
102
|
+
* - No-params scripts: loaded as-is (IIFE)
|
|
103
|
+
* - With-params scripts: \`(\${script})(\${JSON.stringify(params)})\`
|
|
104
|
+
*/
|
|
105
|
+
|
|
106
|
+
'use strict';
|
|
107
|
+
|
|
108
|
+
const fs = require('fs');
|
|
109
|
+
const path = require('path');
|
|
110
|
+
|
|
111
|
+
function load(name) {
|
|
112
|
+
try { return fs.readFileSync(path.join(__dirname, name), 'utf-8'); }
|
|
113
|
+
catch { return null; }
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function withParams(name, params) {
|
|
117
|
+
const script = load(name);
|
|
118
|
+
if (!script) return null;
|
|
119
|
+
return \`(\${script})(\${JSON.stringify(params)})\`;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// ─── Core (no params — IIFE) ───
|
|
123
|
+
|
|
124
|
+
module.exports.readChat = () => load('read_chat.js');
|
|
125
|
+
module.exports.sendMessage = () => load('send_message.js');
|
|
126
|
+
module.exports.listSessions = () => load('list_sessions.js');
|
|
127
|
+
module.exports.newSession = () => load('new_session.js');
|
|
128
|
+
module.exports.focusEditor = () => load('focus_editor.js');
|
|
129
|
+
module.exports.openPanel = () => load('open_panel.js');
|
|
130
|
+
module.exports.listModels = () => load('list_models.js');
|
|
131
|
+
module.exports.listModes = () => load('list_modes.js');
|
|
132
|
+
|
|
133
|
+
// ─── With params (function expression) ───
|
|
134
|
+
|
|
135
|
+
module.exports.switchSession = (params) => {
|
|
136
|
+
const index = typeof params === 'number' ? params : params?.index ?? 0;
|
|
137
|
+
const title = typeof params === 'string' ? params : params?.title || null;
|
|
138
|
+
return withParams('switch_session.js', { index, title });
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
module.exports.resolveAction = (params) => {
|
|
142
|
+
const action = typeof params === 'string' ? params : params?.action || 'approve';
|
|
143
|
+
const buttonText = params?.button || params?.buttonText
|
|
144
|
+
|| (action === 'approve' ? 'Accept' : action === 'reject' ? 'Reject' : action);
|
|
145
|
+
return withParams('resolve_action.js', { buttonText });
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
module.exports.setModel = (params) => {
|
|
149
|
+
const model = typeof params === 'string' ? params : params?.model;
|
|
150
|
+
return withParams('set_model.js', { model });
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
module.exports.setMode = (params) => {
|
|
154
|
+
const mode = typeof params === 'string' ? params : params?.mode;
|
|
155
|
+
return withParams('set_mode.js', { mode });
|
|
156
|
+
};
|
|
157
|
+
`;
|
|
158
|
+
|
|
159
|
+
// read_chat.js — most complex, stub with detailed TODO
|
|
160
|
+
files[`${scriptDir}/read_chat.js`] = `/**
|
|
161
|
+
* ${name} — read_chat
|
|
162
|
+
*
|
|
163
|
+
* Extract chat messages, status, and approval state from DOM.
|
|
164
|
+
*
|
|
165
|
+
* TODO: Identify via CDP/DevConsole:
|
|
166
|
+
* 1. Chat container selector
|
|
167
|
+
* 2. User message selector + class pattern
|
|
168
|
+
* 3. Assistant message selector + class pattern
|
|
169
|
+
* 4. Status detection (generating/idle/waiting_approval)
|
|
170
|
+
* 5. Approval dialog detection (buttons, modal)
|
|
171
|
+
* 6. Input field selector
|
|
172
|
+
*
|
|
173
|
+
* → { id, status, title, messages[], inputContent, activeModal }
|
|
174
|
+
*/
|
|
175
|
+
(() => {
|
|
176
|
+
try {
|
|
177
|
+
const messages = [];
|
|
178
|
+
let status = 'idle';
|
|
179
|
+
let activeModal = null;
|
|
180
|
+
|
|
181
|
+
// TODO: Query chat container and extract messages
|
|
182
|
+
// Example:
|
|
183
|
+
// document.querySelectorAll('.chat-message').forEach(el => {
|
|
184
|
+
// const role = el.classList.contains('user') ? 'user' : 'assistant';
|
|
185
|
+
// messages.push({ role, content: el.innerText.trim(), index: messages.length });
|
|
186
|
+
// });
|
|
187
|
+
|
|
188
|
+
// TODO: Detect generating state
|
|
189
|
+
// TODO: Detect approval dialogs -> status = 'waiting_approval'
|
|
190
|
+
|
|
191
|
+
const inputEl = document.querySelector('[contenteditable="true"]');
|
|
192
|
+
const inputContent = inputEl?.innerText?.trim() || '';
|
|
193
|
+
|
|
194
|
+
return JSON.stringify({
|
|
195
|
+
id: 'active',
|
|
196
|
+
status,
|
|
197
|
+
title: document.title,
|
|
198
|
+
messages,
|
|
199
|
+
inputContent,
|
|
200
|
+
activeModal,
|
|
201
|
+
});
|
|
202
|
+
} catch(e) {
|
|
203
|
+
return JSON.stringify({ id: '', status: 'error', messages: [], error: e.message });
|
|
204
|
+
}
|
|
205
|
+
})()
|
|
206
|
+
`;
|
|
207
|
+
|
|
208
|
+
// send_message.js
|
|
209
|
+
files[`${scriptDir}/send_message.js`] = `/**
|
|
210
|
+
* ${name} — send_message
|
|
211
|
+
*
|
|
212
|
+
* For cdp-type-and-send IDEs: returns selector for daemon to type into.
|
|
213
|
+
* → { sent: false, needsTypeAndSend: true, selector }
|
|
214
|
+
*/
|
|
215
|
+
(() => {
|
|
216
|
+
try {
|
|
217
|
+
const input = document.querySelector('${meta.inputSelector || '[contenteditable="true"]'}');
|
|
218
|
+
if (!input) return JSON.stringify({ sent: false, error: 'Input not found' });
|
|
219
|
+
return JSON.stringify({
|
|
220
|
+
sent: false,
|
|
221
|
+
needsTypeAndSend: true,
|
|
222
|
+
selector: '${meta.inputSelector || '[contenteditable="true"]'}',
|
|
223
|
+
});
|
|
224
|
+
} catch(e) {
|
|
225
|
+
return JSON.stringify({ sent: false, error: e.message });
|
|
226
|
+
}
|
|
227
|
+
})()
|
|
228
|
+
`;
|
|
229
|
+
|
|
230
|
+
// list_sessions.js
|
|
231
|
+
files[`${scriptDir}/list_sessions.js`] = `/**
|
|
232
|
+
* ${name} — list_sessions
|
|
233
|
+
*
|
|
234
|
+
* TODO: Query session/chat list from sidebar.
|
|
235
|
+
* → { sessions: [{ id, title, active, index }] }
|
|
236
|
+
*/
|
|
237
|
+
(() => {
|
|
238
|
+
try {
|
|
239
|
+
const sessions = [];
|
|
240
|
+
// TODO: Find session list container and parse items
|
|
241
|
+
return JSON.stringify({ sessions });
|
|
242
|
+
} catch(e) {
|
|
243
|
+
return JSON.stringify({ sessions: [], error: e.message });
|
|
244
|
+
}
|
|
245
|
+
})()
|
|
246
|
+
`;
|
|
247
|
+
|
|
248
|
+
// switch_session.js
|
|
249
|
+
files[`${scriptDir}/switch_session.js`] = `/**
|
|
250
|
+
* ${name} — switch_session
|
|
251
|
+
*
|
|
252
|
+
* params.index: number, params.title: string|null
|
|
253
|
+
* TODO: Click on session in sidebar by title or index.
|
|
254
|
+
* → { switched: true/false }
|
|
255
|
+
*/
|
|
256
|
+
(params) => {
|
|
257
|
+
try {
|
|
258
|
+
// TODO: Find session list and click target
|
|
259
|
+
return JSON.stringify({ switched: false, error: 'Not implemented' });
|
|
260
|
+
} catch(e) {
|
|
261
|
+
return JSON.stringify({ switched: false, error: e.message });
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
`;
|
|
265
|
+
|
|
266
|
+
// new_session.js
|
|
267
|
+
files[`${scriptDir}/new_session.js`] = `/**
|
|
268
|
+
* ${name} — new_session
|
|
269
|
+
*
|
|
270
|
+
* TODO: Click "New Chat" button.
|
|
271
|
+
* → { created: true/false }
|
|
272
|
+
*/
|
|
273
|
+
(() => {
|
|
274
|
+
try {
|
|
275
|
+
const btn = document.querySelector('[aria-label*="New Chat"], [aria-label*="New Composer"]');
|
|
276
|
+
if (btn) { btn.click(); return JSON.stringify({ created: true }); }
|
|
277
|
+
return JSON.stringify({ created: false, error: 'New Chat button not found' });
|
|
278
|
+
} catch(e) {
|
|
279
|
+
return JSON.stringify({ created: false, error: e.message });
|
|
280
|
+
}
|
|
281
|
+
})()
|
|
282
|
+
`;
|
|
283
|
+
|
|
284
|
+
// focus_editor.js
|
|
285
|
+
files[`${scriptDir}/focus_editor.js`] = `/**
|
|
286
|
+
* ${name} — focus_editor
|
|
287
|
+
*/
|
|
288
|
+
(() => {
|
|
289
|
+
try {
|
|
290
|
+
const input = document.querySelector('${meta.inputSelector || '[contenteditable="true"]'}');
|
|
291
|
+
if (input) { input.focus(); return 'focused'; }
|
|
292
|
+
return 'not_found';
|
|
293
|
+
} catch(e) { return 'error'; }
|
|
294
|
+
})()
|
|
295
|
+
`;
|
|
296
|
+
|
|
297
|
+
// open_panel.js
|
|
298
|
+
files[`${scriptDir}/open_panel.js`] = `/**
|
|
299
|
+
* ${name} — open_panel
|
|
300
|
+
*
|
|
301
|
+
* TODO: Open chat/AI panel if not visible.
|
|
302
|
+
*/
|
|
303
|
+
(() => {
|
|
304
|
+
try {
|
|
305
|
+
// TODO: Check if panel visible, if not find toggle button
|
|
306
|
+
return 'not_found';
|
|
307
|
+
} catch(e) { return 'error'; }
|
|
308
|
+
})()
|
|
309
|
+
`;
|
|
310
|
+
|
|
311
|
+
// resolve_action.js
|
|
312
|
+
files[`${scriptDir}/resolve_action.js`] = `/**
|
|
313
|
+
* ${name} — resolve_action
|
|
314
|
+
*
|
|
315
|
+
* params.buttonText: string — button text to find and click.
|
|
316
|
+
* → { resolved: true/false, clicked? }
|
|
317
|
+
*/
|
|
318
|
+
(params) => {
|
|
319
|
+
try {
|
|
320
|
+
const btns = [...document.querySelectorAll('button, [role="button"]')].filter(b => b.offsetWidth > 0);
|
|
321
|
+
const searchText = (params.buttonText || '').toLowerCase();
|
|
322
|
+
const target = btns.find(b => (b.textContent||'').trim().toLowerCase().includes(searchText));
|
|
323
|
+
if (target) {
|
|
324
|
+
target.click();
|
|
325
|
+
return JSON.stringify({ resolved: true, clicked: target.textContent.trim() });
|
|
326
|
+
}
|
|
327
|
+
return JSON.stringify({ resolved: false, available: btns.map(b => b.textContent.trim()).filter(Boolean).slice(0, 10) });
|
|
328
|
+
} catch(e) { return JSON.stringify({ resolved: false, error: e.message }); }
|
|
329
|
+
}
|
|
330
|
+
`;
|
|
331
|
+
|
|
332
|
+
// list_models.js
|
|
333
|
+
files[`${scriptDir}/list_models.js`] = `/**
|
|
334
|
+
* ${name} — list_models
|
|
335
|
+
*
|
|
336
|
+
* TODO: Open model dropdown and extract model list.
|
|
337
|
+
* → { models[], current }
|
|
338
|
+
*/
|
|
339
|
+
(() => {
|
|
340
|
+
try {
|
|
341
|
+
return JSON.stringify({ models: [], current: '' });
|
|
342
|
+
} catch(e) { return JSON.stringify({ models: [], current: '', error: e.message }); }
|
|
343
|
+
})()
|
|
344
|
+
`;
|
|
345
|
+
|
|
346
|
+
// list_modes.js
|
|
347
|
+
files[`${scriptDir}/list_modes.js`] = `/**
|
|
348
|
+
* ${name} — list_modes
|
|
349
|
+
*
|
|
350
|
+
* TODO: Open mode dropdown and extract mode list.
|
|
351
|
+
* → { modes[], current }
|
|
352
|
+
*/
|
|
353
|
+
(() => {
|
|
354
|
+
try {
|
|
355
|
+
return JSON.stringify({ modes: [], current: '' });
|
|
356
|
+
} catch(e) { return JSON.stringify({ modes: [], current: '', error: e.message }); }
|
|
357
|
+
})()
|
|
358
|
+
`;
|
|
359
|
+
|
|
360
|
+
// set_model.js
|
|
361
|
+
files[`${scriptDir}/set_model.js`] = `/**
|
|
362
|
+
* ${name} — set_model
|
|
363
|
+
*
|
|
364
|
+
* params.model: string
|
|
365
|
+
* TODO: Open model dropdown and select target model.
|
|
366
|
+
* → { success: true/false }
|
|
367
|
+
*/
|
|
368
|
+
async (params) => {
|
|
369
|
+
try {
|
|
370
|
+
return JSON.stringify({ success: false, error: 'Not implemented' });
|
|
371
|
+
} catch(e) { return JSON.stringify({ success: false, error: e.message }); }
|
|
372
|
+
}
|
|
373
|
+
`;
|
|
374
|
+
|
|
375
|
+
// set_mode.js
|
|
376
|
+
files[`${scriptDir}/set_mode.js`] = `/**
|
|
377
|
+
* ${name} — set_mode
|
|
378
|
+
*
|
|
379
|
+
* params.mode: string
|
|
380
|
+
* TODO: Open mode dropdown and select target mode.
|
|
381
|
+
* → { success: true/false }
|
|
382
|
+
*/
|
|
383
|
+
async (params) => {
|
|
384
|
+
try {
|
|
385
|
+
return JSON.stringify({ success: false, error: 'Not implemented' });
|
|
386
|
+
} catch(e) { return JSON.stringify({ success: false, error: e.message }); }
|
|
387
|
+
}
|
|
388
|
+
`;
|
|
389
|
+
|
|
390
|
+
return {
|
|
391
|
+
'provider.json': JSON.stringify(meta, null, 2) + '\n',
|
|
392
|
+
files,
|
|
393
|
+
};
|
|
394
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DaemonCore — Core daemon orchestrator interface
|
|
3
|
+
*
|
|
4
|
+
* Both daemon-standalone and daemon-cloud use this interface via daemon-core.
|
|
5
|
+
* Actual implementation extracted from launcher and placed in this package.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { DaemonStatus, CommandResult, DaemonEvent, IdeEntry, CliEntry, AcpEntry } from './types.js';
|
|
9
|
+
|
|
10
|
+
export interface DaemonCoreOptions {
|
|
11
|
+
/** Data directory for config, logs */
|
|
12
|
+
dataDir?: string;
|
|
13
|
+
/** Custom provider directories */
|
|
14
|
+
providerDirs?: string[];
|
|
15
|
+
/** Enable/disable specific detectors */
|
|
16
|
+
enableIdeDetection?: boolean;
|
|
17
|
+
enableCliDetection?: boolean;
|
|
18
|
+
enableAcpDetection?: boolean;
|
|
19
|
+
/** Status report interval (ms) */
|
|
20
|
+
statusInterval?: number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface IDaemonCore {
|
|
24
|
+
/** Initialize and start the daemon core */
|
|
25
|
+
start(): Promise<void>;
|
|
26
|
+
|
|
27
|
+
/** Gracefully stop the daemon */
|
|
28
|
+
stop(): Promise<void>;
|
|
29
|
+
|
|
30
|
+
/** Get current daemon status snapshot */
|
|
31
|
+
getStatus(): DaemonStatus;
|
|
32
|
+
|
|
33
|
+
/** Subscribe to status changes. Returns unsubscribe function. */
|
|
34
|
+
onStatusChange(callback: (status: DaemonStatus) => void): () => void;
|
|
35
|
+
|
|
36
|
+
/** Subscribe to all daemon events. Returns unsubscribe function. */
|
|
37
|
+
onEvent(callback: (event: DaemonEvent) => void): () => void;
|
|
38
|
+
|
|
39
|
+
/** Execute a command (send_chat, new_session, etc.) */
|
|
40
|
+
executeCommand(type: string, payload: any, target?: string): Promise<CommandResult>;
|
|
41
|
+
|
|
42
|
+
/** Get currently detected/managed IDEs */
|
|
43
|
+
getManagedIdes(): IdeEntry[];
|
|
44
|
+
|
|
45
|
+
/** Get currently detected/managed CLIs */
|
|
46
|
+
getManagedClis(): CliEntry[];
|
|
47
|
+
|
|
48
|
+
/** Get currently detected/managed ACP agents */
|
|
49
|
+
getManagedAcps(): AcpEntry[];
|
|
50
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI AI Agent Detector
|
|
3
|
+
*
|
|
4
|
+
* Dynamic CLI detection based on Provider.
|
|
5
|
+
* Reads spawn.command from cli/acp categories via ProviderLoader to check installation.
|
|
6
|
+
*
|
|
7
|
+
* Uses parallel execution for fast detection across many providers.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { exec } from 'child_process';
|
|
11
|
+
import * as os from 'os';
|
|
12
|
+
import type { ProviderLoader } from '../providers/provider-loader.js';
|
|
13
|
+
|
|
14
|
+
export interface CLIInfo {
|
|
15
|
+
id: string;
|
|
16
|
+
displayName: string;
|
|
17
|
+
icon: string;
|
|
18
|
+
command: string;
|
|
19
|
+
installed: boolean;
|
|
20
|
+
version?: string;
|
|
21
|
+
path?: string;
|
|
22
|
+
category?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** Run a shell command with timeout, returning stdout or null on failure */
|
|
26
|
+
function execAsync(cmd: string, timeoutMs = 5000): Promise<string | null> {
|
|
27
|
+
return new Promise((resolve) => {
|
|
28
|
+
const child = exec(cmd, { encoding: 'utf-8', timeout: timeoutMs }, (err, stdout) => {
|
|
29
|
+
if (err || !stdout?.trim()) {
|
|
30
|
+
resolve(null);
|
|
31
|
+
} else {
|
|
32
|
+
resolve(stdout.trim());
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
// Safety: kill on timeout
|
|
36
|
+
child.on('error', () => resolve(null));
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Detect all CLI/ACP agents (parallel)
|
|
42
|
+
* @param providerLoader ProviderLoader instance (dynamic list creation)
|
|
43
|
+
*/
|
|
44
|
+
export async function detectCLIs(providerLoader?: ProviderLoader): Promise<CLIInfo[]> {
|
|
45
|
+
const platform = os.platform();
|
|
46
|
+
const whichCmd = platform === 'win32' ? 'where' : 'which';
|
|
47
|
+
|
|
48
|
+
// Provider-based dynamic list creation, fallback is empty array
|
|
49
|
+
const cliList = providerLoader
|
|
50
|
+
? providerLoader.getCliDetectionList()
|
|
51
|
+
: [];
|
|
52
|
+
|
|
53
|
+
// Run all `which` checks in parallel
|
|
54
|
+
const results = await Promise.all(
|
|
55
|
+
cliList.map(async (cli): Promise<CLIInfo> => {
|
|
56
|
+
try {
|
|
57
|
+
const pathResult = await execAsync(`${whichCmd} ${cli.command} 2>/dev/null`);
|
|
58
|
+
if (!pathResult) return { ...cli, installed: false };
|
|
59
|
+
|
|
60
|
+
const firstPath = pathResult.split('\n')[0];
|
|
61
|
+
|
|
62
|
+
// Get version (parallel with other checks)
|
|
63
|
+
let version: string | undefined;
|
|
64
|
+
try {
|
|
65
|
+
const versionResult = await execAsync(`${cli.command} --version 2>/dev/null`, 3000);
|
|
66
|
+
if (versionResult) {
|
|
67
|
+
// Extract version number (e.g. "gemini v1.2.3" → "1.2.3")
|
|
68
|
+
const match = versionResult.match(/(\d+\.\d+[\.\d]*)/);
|
|
69
|
+
version = match ? match[1] : versionResult.split('\n')[0].slice(0, 30);
|
|
70
|
+
}
|
|
71
|
+
} catch { }
|
|
72
|
+
|
|
73
|
+
return { ...cli, installed: true, version, path: firstPath };
|
|
74
|
+
} catch {
|
|
75
|
+
return { ...cli, installed: false };
|
|
76
|
+
}
|
|
77
|
+
})
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
return results;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** Detect specific CLI */
|
|
84
|
+
export async function detectCLI(cliId: string, providerLoader?: ProviderLoader): Promise<CLIInfo | null> {
|
|
85
|
+
// Resolve alias
|
|
86
|
+
const resolvedId = providerLoader ? providerLoader.resolveAlias(cliId) : cliId;
|
|
87
|
+
const all = await detectCLIs(providerLoader);
|
|
88
|
+
return all.find((c) => c.id === resolvedId && c.installed) || null;
|
|
89
|
+
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ADHDev — IDE Detector (canonical implementation)
|
|
3
|
+
*
|
|
4
|
+
* Detects installed IDEs on the user's local machine.
|
|
5
|
+
* Supports macOS, Windows, and Linux.
|
|
6
|
+
*
|
|
7
|
+
* Migrated from @adhdev/core — this is now the single source of truth.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { execSync } from 'child_process';
|
|
11
|
+
import { existsSync } from 'fs';
|
|
12
|
+
import { platform, homedir } from 'os';
|
|
13
|
+
|
|
14
|
+
// ─── Types ──────────────────────────────────────
|
|
15
|
+
|
|
16
|
+
export interface IDEInfo {
|
|
17
|
+
id: string;
|
|
18
|
+
name: string;
|
|
19
|
+
displayName: string;
|
|
20
|
+
installed: boolean;
|
|
21
|
+
path: string | null;
|
|
22
|
+
cliCommand: string | null;
|
|
23
|
+
version: string | null;
|
|
24
|
+
icon: string;
|
|
25
|
+
extensionSupport: 'full' | 'partial' | 'none';
|
|
26
|
+
notes?: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface IDEDefinition {
|
|
30
|
+
id: string;
|
|
31
|
+
name: string;
|
|
32
|
+
displayName: string;
|
|
33
|
+
icon: string;
|
|
34
|
+
extensionSupport: 'full' | 'partial' | 'none';
|
|
35
|
+
cli: string;
|
|
36
|
+
paths: {
|
|
37
|
+
darwin?: string[];
|
|
38
|
+
win32?: string[];
|
|
39
|
+
linux?: string[];
|
|
40
|
+
[key: string]: string[] | undefined;
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// No builtin IDE definitions — provider.js registered via registerToDetector() is the single source of truth
|
|
45
|
+
// To add new IDE: create providers/_builtin/ide/{name}/provider.js then define paths/cli
|
|
46
|
+
const BUILTIN_IDE_DEFINITIONS: IDEDefinition[] = [];
|
|
47
|
+
|
|
48
|
+
// ─── Runtime Registry ───────────────────────────
|
|
49
|
+
const registeredIDEs = new Map<string, IDEDefinition>();
|
|
50
|
+
|
|
51
|
+
export function registerIDEDefinition(def: IDEDefinition): void {
|
|
52
|
+
registeredIDEs.set(def.id, def);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function getMergedDefinitions(): IDEDefinition[] {
|
|
56
|
+
const merged = new Map<string, IDEDefinition>();
|
|
57
|
+
for (const def of BUILTIN_IDE_DEFINITIONS) {
|
|
58
|
+
merged.set(def.id, def);
|
|
59
|
+
}
|
|
60
|
+
for (const [id, def] of registeredIDEs) {
|
|
61
|
+
merged.set(id, def);
|
|
62
|
+
}
|
|
63
|
+
return [...merged.values()];
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function findCliCommand(command: string): string | null {
|
|
67
|
+
try {
|
|
68
|
+
const result = execSync(
|
|
69
|
+
platform() === 'win32' ? `where ${command}` : `which ${command}`,
|
|
70
|
+
{ encoding: 'utf-8', timeout: 5000, stdio: ['pipe', 'pipe', 'pipe'] }
|
|
71
|
+
).trim();
|
|
72
|
+
return result.split('\n')[0] || null;
|
|
73
|
+
} catch {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function getIdeVersion(cliCommand: string): string | null {
|
|
79
|
+
try {
|
|
80
|
+
const result = execSync(`"${cliCommand}" --version`, {
|
|
81
|
+
encoding: 'utf-8',
|
|
82
|
+
timeout: 10000,
|
|
83
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
84
|
+
}).trim();
|
|
85
|
+
return result.split('\n')[0] || null;
|
|
86
|
+
} catch {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function checkPathExists(paths: string[]): string | null {
|
|
92
|
+
for (const p of paths) {
|
|
93
|
+
if (p.includes('*')) {
|
|
94
|
+
const home = homedir();
|
|
95
|
+
const starIdx = p.indexOf('*');
|
|
96
|
+
const suffix = p.substring(starIdx + 1);
|
|
97
|
+
const homeNormalized = home.replace(/\//g, '\\\\');
|
|
98
|
+
const resolved = homeNormalized + suffix;
|
|
99
|
+
if (existsSync(resolved)) return resolved;
|
|
100
|
+
} else {
|
|
101
|
+
if (existsSync(p)) return p;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export async function detectIDEs(): Promise<IDEInfo[]> {
|
|
108
|
+
const os = platform() as 'darwin' | 'win32' | 'linux';
|
|
109
|
+
const results: IDEInfo[] = [];
|
|
110
|
+
|
|
111
|
+
for (const def of getMergedDefinitions()) {
|
|
112
|
+
const cliPath = findCliCommand(def.cli);
|
|
113
|
+
const appPath = checkPathExists(def.paths[os] || []);
|
|
114
|
+
const installed = !!(cliPath || appPath);
|
|
115
|
+
|
|
116
|
+
let resolvedCli = cliPath;
|
|
117
|
+
|
|
118
|
+
if (!resolvedCli && appPath && os === 'darwin') {
|
|
119
|
+
const bundledCli = `${appPath}/Contents/Resources/app/bin/${def.cli}`;
|
|
120
|
+
if (existsSync(bundledCli)) resolvedCli = bundledCli;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (!resolvedCli && appPath && os === 'win32') {
|
|
124
|
+
const { dirname } = await import('path');
|
|
125
|
+
const appDir = dirname(appPath);
|
|
126
|
+
const candidates = [
|
|
127
|
+
`${appDir}\\\\bin\\\\${def.cli}.cmd`,
|
|
128
|
+
`${appDir}\\\\bin\\\\${def.cli}`,
|
|
129
|
+
`${appDir}\\\\${def.cli}.cmd`,
|
|
130
|
+
`${appDir}\\\\${def.cli}.exe`,
|
|
131
|
+
`${appDir}\\\\resources\\\\app\\\\bin\\\\${def.cli}.cmd`,
|
|
132
|
+
];
|
|
133
|
+
for (const c of candidates) {
|
|
134
|
+
if (existsSync(c)) {
|
|
135
|
+
resolvedCli = c;
|
|
136
|
+
break;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const version = resolvedCli ? getIdeVersion(resolvedCli) : null;
|
|
142
|
+
|
|
143
|
+
results.push({
|
|
144
|
+
id: def.id,
|
|
145
|
+
name: def.name,
|
|
146
|
+
displayName: def.displayName,
|
|
147
|
+
installed,
|
|
148
|
+
path: appPath || cliPath,
|
|
149
|
+
cliCommand: resolvedCli || null,
|
|
150
|
+
version,
|
|
151
|
+
icon: def.icon,
|
|
152
|
+
extensionSupport: def.extensionSupport,
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return results;
|
|
157
|
+
}
|