adhdev 0.6.12 → 0.6.13

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/cli/index.js CHANGED
@@ -22808,9 +22808,9 @@ var require_dist = __commonJS({
22808
22808
  const pkgName = isStandalone ? "@adhdev/daemon-standalone" : "adhdev";
22809
22809
  const latest = execSync7(`npm view ${pkgName} version`, { encoding: "utf-8", timeout: 1e4 }).trim();
22810
22810
  LOG5.info("Upgrade", `Latest ${pkgName}: v${latest}`);
22811
- execSync7(`npm install -g ${pkgName}@latest`, {
22811
+ execSync7(`npm install -g ${pkgName}@latest --force`, {
22812
22812
  encoding: "utf-8",
22813
- timeout: 6e4,
22813
+ timeout: 12e4,
22814
22814
  stdio: ["pipe", "pipe", "pipe"]
22815
22815
  });
22816
22816
  LOG5.info("Upgrade", `\u2705 Upgraded to v${latest}`);
@@ -26065,8 +26065,10 @@ ${installInfo}`
26065
26065
  if (cli) meta3.cli = cli;
26066
26066
  if (cdpPorts) meta3.cdpPorts = cdpPorts;
26067
26067
  else if (!isExtension) meta3.cdpPorts = [9222, 9223];
26068
- if (processName) meta3.processNames = { darwin: processName };
26069
- if (installPath) meta3.paths = { darwin: [installPath] };
26068
+ if (opts.processNames) meta3.processNames = opts.processNames;
26069
+ else if (processName) meta3.processNames = { darwin: processName };
26070
+ if (opts.osPaths) meta3.paths = opts.osPaths;
26071
+ else if (installPath) meta3.paths = { darwin: [installPath] };
26070
26072
  if (isExtension) {
26071
26073
  meta3.extensionId = extensionId || `publisher.${type}`;
26072
26074
  meta3.extensionIdPattern = `${extensionId || type}`;
@@ -27332,7 +27334,9 @@ async (params) => {
27332
27334
  installPath,
27333
27335
  binary,
27334
27336
  extensionId,
27335
- version: version2
27337
+ version: version2,
27338
+ osPaths,
27339
+ processNames
27336
27340
  } = body;
27337
27341
  if (!type || !name) {
27338
27342
  this.json(res, 400, { error: "type and name required" });
@@ -27351,7 +27355,7 @@ async (params) => {
27351
27355
  return;
27352
27356
  }
27353
27357
  try {
27354
- const result = generateFiles(type, name, category, { cdpPorts, cli, processName, installPath, binary, extensionId, version: version2 });
27358
+ const result = generateFiles(type, name, category, { cdpPorts, cli, processName, installPath, binary, extensionId, version: version2, osPaths, processNames });
27355
27359
  fs9.mkdirSync(targetDir, { recursive: true });
27356
27360
  fs9.writeFileSync(jsonPath, result["provider.json"], "utf-8");
27357
27361
  const createdFiles = ["provider.json"];
@@ -28148,50 +28152,8 @@ async (params) => {
28148
28152
  return;
28149
28153
  }
28150
28154
  try {
28151
- this.sendAutoImplSSE({ event: "progress", data: { function: "_init", status: "analyzing", message: "DOM \uAD6C\uC870 \uC218\uC9D1 \uC911..." } });
28152
- let domContext = null;
28153
- const cdp = this.getCdp(type);
28154
- if (cdp) {
28155
- try {
28156
- const domScript = `(() => {
28157
- function fp(el) {
28158
- if (!el || el === document.body) return 'body';
28159
- const parts = [];
28160
- let c = el;
28161
- while (c && c !== document.documentElement) {
28162
- let s = c.tagName.toLowerCase();
28163
- if (c.id) s = '#' + c.id;
28164
- else if (c.className && typeof c.className === 'string') {
28165
- const cls = c.className.trim().split(/\\s+/).filter(x => x && !x.startsWith('_')).slice(0, 2);
28166
- if (cls.length) s += '.' + cls.join('.');
28167
- }
28168
- parts.unshift(s);
28169
- c = c.parentElement;
28170
- }
28171
- return parts.join(' > ');
28172
- }
28173
- const r = {};
28174
- // Content editables
28175
- r.editables = [...document.querySelectorAll('[contenteditable], textarea, input')].filter(e => e.offsetWidth > 0).slice(0, 10).map(e => ({
28176
- selector: fp(e), tag: e.tagName.toLowerCase(), ce: e.getAttribute('contenteditable'), role: e.getAttribute('role'), ph: e.getAttribute('placeholder')
28177
- }));
28178
- // Scroll containers
28179
- r.scrollContainers = [...document.querySelectorAll('div, section')].filter(e => {
28180
- const s = getComputedStyle(e); const b = e.getBoundingClientRect();
28181
- return (s.overflowY === 'auto' || s.overflowY === 'scroll') && b.height > 200 && e.children.length > 2;
28182
- }).slice(0, 5).map(e => ({ selector: fp(e), children: e.children.length, h: Math.round(e.getBoundingClientRect().height) }));
28183
- // Buttons
28184
- r.buttons = [...document.querySelectorAll('button, [role="button"]')].filter(e => e.offsetWidth > 0).slice(0, 20).map(e => ({
28185
- text: (e.textContent||'').trim().substring(0, 60), selector: fp(e), label: e.getAttribute('aria-label')
28186
- }));
28187
- return JSON.stringify(r);
28188
- })()`;
28189
- const raw = await cdp.evaluate(domScript, 1e4);
28190
- domContext = typeof raw === "string" ? JSON.parse(raw) : raw;
28191
- } catch (e) {
28192
- this.log(`DOM context collection failed (non-fatal): ${e.message}`);
28193
- }
28194
- }
28155
+ this.sendAutoImplSSE({ event: "progress", data: { function: "_init", status: "analyzing", message: "\uC5D0\uC774\uC804\uD2B8 \uCD08\uAE30\uD654 (DOM \uD0D0\uC0C9 \uAD8C\uD55C \uBD80\uC5EC)..." } });
28156
+ const domContext = null;
28195
28157
  this.sendAutoImplSSE({ event: "progress", data: { function: "_init", status: "loading_reference", message: `\uB808\uD37C\uB7F0\uC2A4 \uC2A4\uD06C\uB9BD\uD2B8 \uB85C\uB4DC \uC911 (${reference})...` } });
28196
28158
  let referenceScripts = {};
28197
28159
  const builtinDir = this.providerLoader.builtinDir || path12.resolve(__dirname, "../providers/_builtin");
@@ -28386,22 +28348,11 @@ async (params) => {
28386
28348
  } else {
28387
28349
  args = [...baseArgs];
28388
28350
  }
28389
- const { execSync: execSync7 } = await import("child_process");
28390
- try {
28391
- execSync7(`which ${command}`, { stdio: "pipe" });
28392
- } catch {
28393
- try {
28394
- fs9.unlinkSync(promptFile);
28395
- } catch {
28396
- }
28397
- this.json(res, 400, { error: `Agent binary '${command}' not found on PATH. Install it first: ${agentProvider?.install || "check provider docs"}` });
28398
- return;
28399
- }
28400
28351
  this.sendAutoImplSSE({ event: "progress", data: { function: "_init", status: "spawning", message: `\uC5D0\uC774\uC804\uD2B8 \uC2E4\uD589 \uC911: ${command} ${args.join(" ")} (prompt: ${prompt.length} chars)` } });
28401
28352
  this.autoImplStatus = { running: true, type, progress: [] };
28402
28353
  const { spawn: spawnFn } = await import("child_process");
28403
28354
  const escapedArgs = args.map((a) => `'${a.replace(/'/g, "'\\''")}'`).join(" ");
28404
- const shellCmd = `cat '${promptFile}' | ${command} ${escapedArgs}`;
28355
+ const shellCmd = `${command} ${escapedArgs} -p "$(cat '${promptFile}')"`;
28405
28356
  this.log(`Auto-implement spawn: ${shellCmd}`);
28406
28357
  const child = spawnFn("sh", ["-c", shellCmd], {
28407
28358
  cwd: providerDir,
@@ -28560,6 +28511,7 @@ async (params) => {
28560
28511
  lines.push("4. Always wrap in try-catch, return `JSON.stringify(result)`");
28561
28512
  lines.push("5. Do NOT modify `scripts.js` router \u2014 only edit individual `*.js` files");
28562
28513
  lines.push("6. All scripts run in the browser (CDP evaluate) \u2014 use DOM APIs only");
28514
+ lines.push('7. **Cross-Platform Compatibility**: If you use ARIA labels that contain keyboard shortcuts (e.g., `Cascade (\u2318L)`), you MUST use substring matches (`aria-label*="Cascade"`) or handle both macOS (`\u2318`, `Cmd`) and Windows (`Ctrl`) so the script does not break on other operating systems.');
28563
28515
  lines.push("");
28564
28516
  lines.push("## Required Return Format");
28565
28517
  lines.push("| Function | Return JSON |");
@@ -28582,42 +28534,40 @@ async (params) => {
28582
28534
  lines.push("2. After editing, TEST each function using the DevConsole API (see below)");
28583
28535
  lines.push("3. If a test fails, fix the implementation and re-test");
28584
28536
  lines.push("");
28585
- lines.push("## DevConsole API (for testing)");
28586
- lines.push(`The DevConsole is running at \`http://127.0.0.1:${DEV_SERVER_PORT}\`. Use these HTTP APIs to test your implementations.`);
28587
- lines.push("");
28588
- lines.push("### Run a script against the live IDE");
28589
- lines.push("```bash");
28590
- lines.push(`curl -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/providers/${type}/scripts/run \\`);
28591
- lines.push(` -H "Content-Type: application/json" \\`);
28592
- lines.push(` -d '{"script": "readChat"}'`);
28593
- lines.push("```");
28594
- lines.push('Replace `"readChat"` with any function name. For functions with params:');
28595
- lines.push("```bash");
28596
- lines.push(`curl -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/providers/${type}/scripts/run \\`);
28597
- lines.push(` -H "Content-Type: application/json" \\`);
28598
- lines.push(` -d '{"script": "sendMessage", "params": {"text": "hello"}}'`);
28599
- lines.push("```");
28537
+ lines.push("## YOU MUST EXPLORE THE DOM YOURSELF!");
28538
+ lines.push("I have NOT provided you with the DOM snapshot. You MUST use your command-line tools to discover the IDE structure dynamically!");
28600
28539
  lines.push("");
28601
- lines.push("### Evaluate raw JS in the IDE (CDP)");
28540
+ lines.push("### 1. Evaluate JS to explore IDE DOM");
28541
+ lines.push("Use cURL to run JavaScript inside the IDE:");
28602
28542
  lines.push("```bash");
28603
- lines.push(`curl -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cdp/evaluate \\`);
28543
+ lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cdp/evaluate \\`);
28604
28544
  lines.push(` -H "Content-Type: application/json" \\`);
28605
- lines.push(` -d '{"expression": "document.title", "ideType": "${type}"}'`);
28545
+ lines.push(` -d '{"expression": "document.body.innerHTML.substring(0, 1000)", "ideType": "${type}"}'`);
28606
28546
  lines.push("```");
28607
28547
  lines.push("");
28608
- lines.push("### Reload provider (after editing files)");
28548
+ lines.push("### 2. Test your generated function");
28549
+ lines.push("Once you save the file, test it by running:");
28609
28550
  lines.push("```bash");
28610
28551
  lines.push(`curl -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/providers/reload`);
28552
+ lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/providers/${type}/scripts/run -H "Content-Type: application/json" -d '{"script": "readChat"}'`);
28611
28553
  lines.push("```");
28612
- lines.push("**IMPORTANT**: After editing script files, you MUST call reload before running scripts.");
28613
28554
  lines.push("");
28614
- lines.push("### Workflow: Edit \u2192 Reload \u2192 Test \u2192 Fix");
28615
- lines.push("1. Edit the `.js` file");
28616
- lines.push("2. `curl POST /api/providers/reload`");
28617
- lines.push(`3. \`curl POST /api/providers/${type}/scripts/run -d '{"script":"readChat"}'\``);
28618
- lines.push("4. Check the response \u2014 if error, fix and repeat from step 1");
28555
+ lines.push("### Task Workflow");
28556
+ lines.push("1. Write bash scripts to `curl` the CDP evaluate API above to find exactly where `.chat-message`, etc., are located.");
28557
+ lines.push("2. Iteratively explore until you are confident in your selectors.");
28558
+ lines.push("3. Edit the `.js` files using the selectors you discovered.");
28559
+ lines.push("4. Reload providers and TEST your script via the API.");
28619
28560
  lines.push("");
28620
- lines.push("Start NOW. Edit files, then test each one.");
28561
+ lines.push("### \u{1F525} Advanced UI Parsing (CRUCIAL for `readChat`)");
28562
+ lines.push("Your `readChat` must flawlessly parse complex UI elements (tables, code blocks, tool calls, and AI thoughts). The quality must match the `antigravity` reference.");
28563
+ lines.push("To achieve this, you MUST generate a live test scenario:");
28564
+ lines.push("1. Early in your process, send a rich prompt to the IDE using the API:");
28565
+ lines.push(' `curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/providers/${type}/scripts/run -H "Content-Type: application/json" -d \'{"script": "sendMessage", "params": {"text": "Write a python script, draw a markdown table, use a tool, and show your reasoning/thought process"}}\'`');
28566
+ lines.push("2. Wait a few seconds for the IDE AI to generate these elements in the UI.");
28567
+ lines.push("3. Use CDP evaluate to deeply inspect the DOM structure of the newly generated tables, code blocks, thought blocks, and tool calls.");
28568
+ lines.push("4. Ensure `readChat` extracts `content` with precise markdown formatting (especially for tables/code) and assigns correct `kind` tags (`thought`, `tool`, `terminal`).");
28569
+ lines.push("");
28570
+ lines.push("Start NOW. Do not ask for permission. Explore the DOM -> Code -> Test.");
28621
28571
  return lines.join("\n");
28622
28572
  }
28623
28573
  handleAutoImplSSE(type, req, res) {
@@ -29611,7 +29561,21 @@ var init_daemon_p2p = __esm({
29611
29561
  this.nodeDatachannel = esmRequire("node-datachannel");
29612
29562
  const keys = Object.keys(this.nodeDatachannel).join(",");
29613
29563
  log(`node-datachannel loaded \u2705 (keys: ${keys.substring(0, 100)})`);
29614
- return;
29564
+ try {
29565
+ const Ctor = this.nodeDatachannel.PeerConnection || this.nodeDatachannel.default?.PeerConnection;
29566
+ if (Ctor) {
29567
+ const testPc = new Ctor("smoke-test", { iceServers: ["stun:stun.cloudflare.com:3478"] });
29568
+ testPc.close();
29569
+ log("PeerConnection smoke test passed \u2705");
29570
+ } else {
29571
+ log("PeerConnection constructor not found \u2014 P2P disabled");
29572
+ this.nodeDatachannel = null;
29573
+ }
29574
+ } catch (smokeErr) {
29575
+ log(`PeerConnection smoke test FAILED: ${smokeErr?.message} \u2014 P2P disabled`);
29576
+ this.nodeDatachannel = null;
29577
+ }
29578
+ if (this.nodeDatachannel) return;
29615
29579
  } catch (e) {
29616
29580
  log(`node-datachannel not found: ${e?.message}
29617
29581
  ${e?.stack || ""}`);
@@ -29798,7 +29762,9 @@ ${e?.stack || ""}`);
29798
29762
  }
29799
29763
  let iceServers = [
29800
29764
  "stun:stun.cloudflare.com:3478",
29801
- "stun:stun.l.google.com:19302"
29765
+ "stun:stun.l.google.com:19302",
29766
+ "stun:stun1.l.google.com:19302",
29767
+ "stun:stun2.l.google.com:19302"
29802
29768
  ];
29803
29769
  const serverIceServers = this.serverConn.getIceServers();
29804
29770
  if (serverIceServers?.length) {
@@ -30540,7 +30506,7 @@ var init_adhdev_daemon = __esm({
30540
30506
  fs2 = __toESM(require("fs"));
30541
30507
  path2 = __toESM(require("path"));
30542
30508
  import_chalk = __toESM(require("chalk"));
30543
- pkgVersion = "0.6.12";
30509
+ pkgVersion = "0.6.13";
30544
30510
  if (pkgVersion === "unknown") {
30545
30511
  try {
30546
30512
  const possiblePaths = [
@@ -30590,6 +30556,13 @@ var init_adhdev_daemon = __esm({
30590
30556
  installGlobalInterceptor();
30591
30557
  } catch {
30592
30558
  }
30559
+ process.on("uncaughtException", (err) => {
30560
+ import_daemon_core4.LOG.error("Daemon", `Uncaught exception: ${err?.message}
30561
+ ${err?.stack || ""}`);
30562
+ });
30563
+ process.on("unhandledRejection", (reason) => {
30564
+ import_daemon_core4.LOG.error("Daemon", `Unhandled rejection: ${reason?.message || reason}`);
30565
+ });
30593
30566
  this.localPort = options.localPort || import_daemon_core4.DEFAULT_DAEMON_PORT;
30594
30567
  const workingDir = options.workingDir || process.cwd();
30595
30568
  if (isDaemonRunning()) {
@@ -31964,14 +31937,102 @@ function registerProviderCommands(program2) {
31964
31937
  }
31965
31938
  }
31966
31939
  });
31967
- provider.command("create <type>").description("Scaffold a new provider.js from template").option("-n, --name <name>", "Display name").option("-c, --category <cat>", "Category: ide, extension, cli", "ide").option("--builtin", "Create in builtin directory (default: ~/.adhdev/providers/)").action(async (type, options) => {
31940
+ provider;
31941
+ provider.command("create [type]").description("Interactive wizard to scaffold a new provider").option("-n, --name <name>", "Display name").option("-c, --category <cat>", "Category: ide, extension, cli, acp").option("-p, --port <port>", "Starting CDP port").option("--builtin", "Create in builtin directory").action(async (cliType, options) => {
31968
31942
  try {
31969
- const name = options.name || type.split("-").map((s) => s[0].toUpperCase() + s.slice(1)).join(" ");
31970
- const category = options.category;
31943
+ const readline = await import("readline/promises");
31944
+ const net = await import("net");
31945
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
31946
+ let type = cliType;
31947
+ if (!type) {
31948
+ console.log(import_chalk5.default.bold("\n\u2728 ADHDev Provider Wizard\n"));
31949
+ type = await rl.question("Provider ID (e.g. cursor, my-cli, pearai): ");
31950
+ if (!type) {
31951
+ console.log("Cancelled.");
31952
+ process.exit(0);
31953
+ }
31954
+ }
31955
+ const defaultName = type.split("-").map((s) => s[0].toUpperCase() + s.slice(1)).join(" ");
31956
+ const name = options.name || await rl.question(`Display Name [${defaultName}]: `) || defaultName;
31957
+ let category = options.category;
31958
+ if (!category) {
31959
+ while (true) {
31960
+ const ans = (await rl.question("Category (ide | extension | cli | acp) [ide]: ")).trim() || "ide";
31961
+ if (["ide", "extension", "cli", "acp"].includes(ans)) {
31962
+ category = ans;
31963
+ break;
31964
+ }
31965
+ console.log(import_chalk5.default.yellow("Invalid category."));
31966
+ }
31967
+ }
31968
+ let cdpPorts = [9222, 9223];
31969
+ let osPaths = {};
31970
+ let processNames = {};
31971
+ if (category === "ide") {
31972
+ const fs3 = await import("fs");
31973
+ const path3 = await import("path");
31974
+ const os3 = await import("os");
31975
+ if (os3.platform() === "darwin") {
31976
+ while (true) {
31977
+ const p = (await rl.question(`macOS Application Path (e.g. /Applications/${defaultName}.app): `)).trim() || `/Applications/${defaultName}.app`;
31978
+ if (p === "skip") break;
31979
+ if (!fs3.existsSync(p)) {
31980
+ console.log(import_chalk5.default.red(` \u2717 Path not found: ${p}`));
31981
+ console.log(import_chalk5.default.gray(` (Please provide the exact absolute path to the .app or binary, or type 'skip')`));
31982
+ continue;
31983
+ }
31984
+ console.log(import_chalk5.default.green(` \u2713 Path verified: ${p}`));
31985
+ osPaths["darwin"] = [p];
31986
+ processNames["darwin"] = path3.basename(p, ".app");
31987
+ break;
31988
+ }
31989
+ } else if (os3.platform() === "win32") {
31990
+ while (true) {
31991
+ const p = (await rl.question(`Windows Executable Path (e.g. C:\\Program Files\\${defaultName}\\${defaultName}.exe): `)).trim();
31992
+ if (!p || p === "skip") break;
31993
+ if (!fs3.existsSync(p)) {
31994
+ console.log(import_chalk5.default.red(` \u2717 Path not found: ${p}`));
31995
+ console.log(import_chalk5.default.gray(` (Please provide the exact absolute path, or type 'skip')`));
31996
+ continue;
31997
+ }
31998
+ console.log(import_chalk5.default.green(` \u2713 Path verified: ${p}`));
31999
+ osPaths["win32"] = [p];
32000
+ processNames["win32"] = path3.basename(p, ".exe");
32001
+ break;
32002
+ }
32003
+ }
32004
+ if (options.port) {
32005
+ cdpPorts = [parseInt(options.port), parseInt(options.port) + 1];
32006
+ } else {
32007
+ while (true) {
32008
+ const portStr = (await rl.question("Primary CDP Port [9222]: ")).trim() || "9222";
32009
+ const port = parseInt(portStr);
32010
+ if (isNaN(port) || port < 1024 || port > 65535) {
32011
+ console.log(import_chalk5.default.yellow("Invalid port number."));
32012
+ continue;
32013
+ }
32014
+ const isFree = await new Promise((resolve) => {
32015
+ const server = net.createServer();
32016
+ server.unref();
32017
+ server.on("error", () => resolve(false));
32018
+ server.listen(port, "127.0.0.1", () => {
32019
+ server.close(() => resolve(true));
32020
+ });
32021
+ });
32022
+ if (!isFree) {
32023
+ console.log(import_chalk5.default.red(`Port ${port} is currently in use. Please pick another one.`));
32024
+ continue;
32025
+ }
32026
+ cdpPorts = [port, port + 1];
32027
+ break;
32028
+ }
32029
+ }
32030
+ }
32031
+ rl.close();
31971
32032
  const location = options.builtin ? "builtin" : "user";
31972
32033
  const http = await import("http");
31973
32034
  const result = await new Promise((resolve, reject) => {
31974
- const postData = JSON.stringify({ type, name, category, location });
32035
+ const postData = JSON.stringify({ type, name, category, location, cdpPorts, osPaths, processNames });
31975
32036
  const req = http.request({
31976
32037
  hostname: "127.0.0.1",
31977
32038
  port: 19280,
@@ -31989,53 +32050,45 @@ function registerProviderCommands(program2) {
31989
32050
  }
31990
32051
  });
31991
32052
  });
31992
- req.on("error", () => {
31993
- reject(new Error("DevServer not reachable"));
31994
- });
32053
+ req.on("error", () => reject(new Error("DevServer not reachable")));
31995
32054
  req.write(postData);
31996
32055
  req.end();
31997
32056
  }).catch(async () => {
31998
32057
  const pathMod = await import("path");
31999
32058
  const fsMod = await import("fs");
32000
32059
  const osMod = await import("os");
32001
- let targetDir;
32002
- if (location === "builtin") {
32003
- targetDir = pathMod.resolve(__dirname, "../../providers/_builtin", category, type);
32004
- } else {
32005
- targetDir = pathMod.join(osMod.homedir(), ".adhdev", "providers", type);
32006
- }
32007
- const targetFile = pathMod.join(targetDir, "provider.js");
32008
- if (fsMod.existsSync(targetFile)) {
32009
- return { error: `Provider already exists at ${targetFile}`, path: targetFile };
32010
- }
32011
- const isExtension = category === "extension";
32012
- const template = `/**
32013
- * ${name} \u2014 Provider
32014
- */
32015
- module.exports = {
32016
- type: '${type}',
32017
- name: '${name}',
32018
- category: '${category}',
32019
- ${isExtension ? ` extensionId: 'publisher.${type}',
32020
- extensionIdPattern: /extensionId=publisher\\\\.${type}/i,` : ` inputMethod: 'cdp-type-and-send',
32021
- inputSelector: '[contenteditable="true"]',`}
32022
-
32023
- scripts: {
32024
- readChat() { return \`(() => { return JSON.stringify({ messages: [], status: 'idle', title: document.title }); })()\`; },
32025
- sendMessage(text) { return \`(async () => { return JSON.stringify({ sent: false, needsTypeAndSend: true }); })()\`; },
32026
- listSessions() { return \`(async () => { return JSON.stringify([]); })()\`; },
32027
- },
32028
- };
32029
- `;
32060
+ let targetDir = location === "builtin" ? pathMod.resolve(__dirname, "../../providers/_builtin", category, type) : pathMod.join(osMod.homedir(), ".adhdev", "providers", type);
32061
+ if (fsMod.existsSync(targetDir)) return { error: `Provider already exists at ${targetDir}` };
32062
+ const isExt = category === "extension";
32063
+ const isIde = category === "ide";
32064
+ const pJson = {
32065
+ type,
32066
+ name,
32067
+ category,
32068
+ ...isIde ? { cdpPorts, paths: osPaths, processNames } : {},
32069
+ ...isExt ? { extensionId: `publisher.${type}` } : {},
32070
+ ...!isExt ? { inputMethod: "cdp-type-and-send" } : {}
32071
+ };
32030
32072
  fsMod.mkdirSync(targetDir, { recursive: true });
32031
- fsMod.writeFileSync(targetFile, template, "utf-8");
32073
+ const targetFile = pathMod.join(targetDir, "provider.json");
32074
+ fsMod.writeFileSync(targetFile, JSON.stringify(pJson, null, 2), "utf-8");
32075
+ const scriptsDir = pathMod.join(targetDir, "scripts", "0.1");
32076
+ fsMod.mkdirSync(scriptsDir, { recursive: true });
32077
+ const stubNames = ["open_panel", "send_message", "read_chat", "new_session", "list_sessions", "switch_session", "resolve_action", "list_models", "set_model", "list_modes", "set_mode", "focus_editor"];
32078
+ for (const s of stubNames) {
32079
+ fsMod.writeFileSync(pathMod.join(scriptsDir, `${s}.js`), `/**
32080
+ * ${name} \u2014 ${s}
32081
+ */
32082
+ (() => {
32083
+ return JSON.stringify({ error: 'stub' });
32084
+ })()
32085
+ `, "utf-8");
32086
+ }
32032
32087
  return { created: true, path: targetFile, type, name, category };
32033
32088
  });
32034
32089
  if (result.error) {
32035
32090
  console.log(import_chalk5.default.red(`
32036
32091
  \u2717 ${result.error}
32037
- `));
32038
- if (result.path) console.log(import_chalk5.default.gray(` Path: ${result.path}
32039
32092
  `));
32040
32093
  process.exit(1);
32041
32094
  }
@@ -32043,16 +32096,186 @@ ${isExtension ? ` extensionId: 'publisher.${type}',
32043
32096
  \u2713 Provider scaffolded!
32044
32097
  `));
32045
32098
  console.log(` ${import_chalk5.default.bold("Type:")} ${result.type}`);
32046
- console.log(` ${import_chalk5.default.bold("Name:")} ${result.name}`);
32047
- console.log(` ${import_chalk5.default.bold("Category:")} ${result.category}`);
32048
32099
  console.log(` ${import_chalk5.default.bold("Path:")} ${import_chalk5.default.cyan(result.path)}`);
32049
- console.log();
32050
- console.log(import_chalk5.default.gray(" Next steps:"));
32051
- console.log(import_chalk5.default.gray(` 1. Edit ${result.path}`));
32052
- console.log(import_chalk5.default.gray(" 2. Run: adhdev provider reload"));
32053
- console.log(import_chalk5.default.gray(` 3. Test: adhdev provider test ${type}`));
32054
- console.log(import_chalk5.default.gray(" 4. Open DevConsole: http://127.0.0.1:19280"));
32055
- console.log();
32100
+ console.log(import_chalk5.default.gray(" Next steps: 1. adhdev provider fix " + result.type + "\n"));
32101
+ } catch (e) {
32102
+ console.error(import_chalk5.default.red(`
32103
+ \u2717 ${e.message}
32104
+ `));
32105
+ process.exit(1);
32106
+ }
32107
+ });
32108
+ provider.command("fix <type>").description("Auto-implement provider scripts using AI reading the target IDE DOM").action(async (type) => {
32109
+ try {
32110
+ const http = await import("http");
32111
+ console.log(import_chalk5.default.bold(`
32112
+ \u{1F916} Starting Auto-Implement Agent for [${import_chalk5.default.cyan(type)}]...
32113
+ `));
32114
+ const functionsToFix = [
32115
+ "openPanel",
32116
+ "sendMessage",
32117
+ "readChat",
32118
+ "newSession",
32119
+ "listSessions",
32120
+ "switchSession",
32121
+ "resolveAction",
32122
+ "listModels",
32123
+ "setModel",
32124
+ "listModes",
32125
+ "setMode",
32126
+ "focusEditor"
32127
+ ];
32128
+ let consecutiveFailures = 0;
32129
+ for (let i = 0; i < functionsToFix.length; i++) {
32130
+ const fn = functionsToFix[i];
32131
+ console.log(import_chalk5.default.bold(`
32132
+ \u25B6\uFE0F Generating [${import_chalk5.default.cyan(fn)}] for ${type}...`));
32133
+ try {
32134
+ const postData = JSON.stringify({ functions: [fn] });
32135
+ const startResult = await new Promise((resolve, reject) => {
32136
+ const req = http.request({
32137
+ hostname: "127.0.0.1",
32138
+ port: 19280,
32139
+ path: `/api/providers/${type}/auto-implement`,
32140
+ method: "POST",
32141
+ headers: { "Content-Type": "application/json", "Content-Length": Buffer.byteLength(postData) }
32142
+ }, (res) => {
32143
+ let data = "";
32144
+ res.on("data", (c) => data += c);
32145
+ res.on("end", () => {
32146
+ try {
32147
+ resolve(JSON.parse(data));
32148
+ } catch {
32149
+ resolve({ raw: data });
32150
+ }
32151
+ });
32152
+ });
32153
+ req.on("error", () => reject(new Error("DevServer not reachable. Please run adhdev daemon --dev")));
32154
+ req.write(postData);
32155
+ req.end();
32156
+ });
32157
+ if (startResult.error) {
32158
+ if (startResult.error.includes("already in progress")) {
32159
+ throw new Error(`DevServer is busy. Cancel existing Auto-Impl task in DevConsole first.`);
32160
+ } else {
32161
+ throw new Error(`Auto-Impl Failed for ${fn}: ${startResult.error}`);
32162
+ }
32163
+ }
32164
+ if (!startResult.started || !startResult.sseUrl) {
32165
+ throw new Error(`Unexpected response: ${JSON.stringify(startResult)}`);
32166
+ }
32167
+ const pathMod = await import("path");
32168
+ const osPaths = await import("os");
32169
+ const targetDir = pathMod.join(osPaths.homedir(), ".adhdev", "providers", type);
32170
+ const fsMock = await import("fs");
32171
+ const logFile2 = pathMod.join(targetDir, `auto-impl-${fn}.log`);
32172
+ fsMock.writeFileSync(logFile2, `=== Auto-Impl Started for ${fn} ===
32173
+ `);
32174
+ console.log(import_chalk5.default.gray(` Agent logs: ${logFile2}`));
32175
+ await new Promise((resolve, reject) => {
32176
+ http.get(`http://127.0.0.1:19280${startResult.sseUrl}`, (res) => {
32177
+ let buffer = "";
32178
+ res.on("data", (chunk) => {
32179
+ const rawStr = chunk.toString();
32180
+ buffer += rawStr;
32181
+ fsMock.appendFileSync(logFile2, rawStr);
32182
+ const parts = buffer.split("\n\n");
32183
+ buffer = parts.pop() || "";
32184
+ for (const part of parts) {
32185
+ const lines = part.split("\n");
32186
+ let currentEvent = "message";
32187
+ let currentData = null;
32188
+ for (const line of lines) {
32189
+ if (line.startsWith("event: ")) {
32190
+ currentEvent = line.substring(7).trim();
32191
+ } else if (line.startsWith("data: ")) {
32192
+ try {
32193
+ const payload = line.substring(6).trim();
32194
+ if (payload !== "") currentData = JSON.parse(payload);
32195
+ } catch (err) {
32196
+ console.error(import_chalk5.default.red(`
32197
+ [Debug SSE] Parse Error: ` + err.message));
32198
+ }
32199
+ }
32200
+ }
32201
+ if (currentData) {
32202
+ if (currentEvent === "output" && currentData.chunk) {
32203
+ const txt = currentData.chunk;
32204
+ process.stdout.write(currentData.stream === "stderr" ? import_chalk5.default.yellow(txt) : import_chalk5.default.cyan(txt));
32205
+ } else if (currentEvent === "complete") {
32206
+ fsMock.appendFileSync(logFile2, `
32207
+ === COMPLETED with exitCode: ${currentData.exitCode} ===
32208
+ `);
32209
+ if (currentData.success === false) {
32210
+ reject(new Error(`Agent failed to implement ${fn} properly (exit: ${currentData.exitCode})`));
32211
+ } else {
32212
+ resolve();
32213
+ }
32214
+ } else if (currentEvent === "error") {
32215
+ fsMock.appendFileSync(logFile2, `
32216
+ === ERROR: ${currentData.message} ===
32217
+ `);
32218
+ reject(new Error(currentData.message || "Unknown stream error"));
32219
+ }
32220
+ }
32221
+ }
32222
+ });
32223
+ res.on("end", resolve);
32224
+ }).on("error", reject);
32225
+ });
32226
+ console.log(import_chalk5.default.green(` \u2713 ${fn} implementation generated. Check log at auto-impl-${fn}.log`));
32227
+ consecutiveFailures = 0;
32228
+ } catch (err) {
32229
+ consecutiveFailures++;
32230
+ console.error(import_chalk5.default.red(` \u2717 Auto-Implement error on ${fn}: ${err.message}`));
32231
+ if (consecutiveFailures >= 3) {
32232
+ console.error(import_chalk5.default.red.bold(`
32233
+ \u26D4 Reached 3 consecutive failures. Aborting pipeline to prevent runaway API usage/bans.
32234
+ `));
32235
+ process.exit(1);
32236
+ } else {
32237
+ console.log(import_chalk5.default.yellow(` \u26A0\uFE0F Retrying... (${consecutiveFailures}/3 attempts failed)
32238
+ `));
32239
+ i--;
32240
+ }
32241
+ }
32242
+ }
32243
+ console.log(import_chalk5.default.green(`
32244
+
32245
+ \u{1F389} Auto-Implement sequence completed for ${type}!`));
32246
+ console.log(import_chalk5.default.gray(` Please run: adhdev provider verify ${type}
32247
+ `));
32248
+ } catch (e) {
32249
+ console.error(import_chalk5.default.red(`
32250
+ \u2717 ${e.message}
32251
+ `));
32252
+ process.exit(1);
32253
+ }
32254
+ });
32255
+ provider.command("launch [type]").description("Launch an IDE provider with CDP remote debugging enabled").action(async (type) => {
32256
+ try {
32257
+ const { launchWithCdp, getAvailableIdeIds } = await Promise.resolve().then(() => __toESM(require_dist()));
32258
+ if (!type) {
32259
+ const ids = getAvailableIdeIds();
32260
+ console.log(import_chalk5.default.bold("\n\u{1F680} Available IDE Providers to launch:\n"));
32261
+ console.log(" " + import_chalk5.default.cyan(ids.join(", ")));
32262
+ console.log(import_chalk5.default.gray("\nRun: adhdev provider launch <type>\n"));
32263
+ return;
32264
+ }
32265
+ console.log(import_chalk5.default.bold(`
32266
+ \u{1F680} Launching ${import_chalk5.default.cyan(type)} with CDP...`));
32267
+ const res = await launchWithCdp({ ideId: type });
32268
+ if (res.success) {
32269
+ const icon = res.action === "reused" ? "\u267B\uFE0F" : res.action === "restarted" ? "\u{1F504}" : "\u2728";
32270
+ console.log(import_chalk5.default.green(`
32271
+ ${icon} Success! ${res.message}
32272
+ `));
32273
+ } else {
32274
+ console.log(import_chalk5.default.red(`
32275
+ \u2717 Failed: ${res.error}
32276
+ `));
32277
+ process.exit(1);
32278
+ }
32056
32279
  } catch (e) {
32057
32280
  console.error(import_chalk5.default.red(`
32058
32281
  \u2717 ${e.message}
@@ -32160,6 +32383,98 @@ ${isExtension ? ` extensionId: 'publisher.${type}',
32160
32383
  } catch (e) {
32161
32384
  console.error(import_chalk5.default.red(`
32162
32385
  \u2717 ${e.message}
32386
+ `));
32387
+ process.exit(1);
32388
+ }
32389
+ });
32390
+ provider.command("verify <type>").description("Verify provider script behavior (e.g. readChat) against standard formats").action(async (type) => {
32391
+ try {
32392
+ const http = await import("http");
32393
+ const postData = JSON.stringify({ script: "readChat", params: {} });
32394
+ const result = await new Promise((resolve, reject) => {
32395
+ const req = http.request({
32396
+ hostname: "127.0.0.1",
32397
+ port: 19280,
32398
+ path: `/api/providers/${type}/script`,
32399
+ method: "POST",
32400
+ headers: { "Content-Type": "application/json", "Content-Length": Buffer.byteLength(postData) }
32401
+ }, (res2) => {
32402
+ let data = "";
32403
+ res2.on("data", (c) => data += c);
32404
+ res2.on("end", () => {
32405
+ try {
32406
+ resolve(JSON.parse(data));
32407
+ } catch {
32408
+ resolve({ raw: data });
32409
+ }
32410
+ });
32411
+ });
32412
+ req.on("error", () => reject(new Error("DevServer not reachable. Run: adhdev daemon --dev")));
32413
+ req.write(postData);
32414
+ req.end();
32415
+ });
32416
+ if (result.error) {
32417
+ console.log(import_chalk5.default.red(`
32418
+ \u2717 Provider Script Error: ${result.error}
32419
+ `));
32420
+ process.exit(1);
32421
+ }
32422
+ console.log(import_chalk5.default.bold(`
32423
+ \u{1F50D} Verifying [${import_chalk5.default.cyan(type)}] runtime standardization...
32424
+ `));
32425
+ let res = result.result !== void 0 ? result.result : result;
32426
+ if (typeof res === "string") {
32427
+ try {
32428
+ res = JSON.parse(res);
32429
+ } catch {
32430
+ }
32431
+ }
32432
+ let pass = true;
32433
+ if (!res || typeof res !== "object") {
32434
+ console.log(` ${import_chalk5.default.red("\u2717")} readChat did not return an Object/JSON. Type: ${typeof res}`);
32435
+ pass = false;
32436
+ } else {
32437
+ console.log(` ${import_chalk5.default.green("\u2713")} readChat returned Object`);
32438
+ if (!Array.isArray(res.messages)) {
32439
+ console.log(` ${import_chalk5.default.red("\u2717")} 'messages' field is not an Array`);
32440
+ pass = false;
32441
+ } else {
32442
+ console.log(` ${import_chalk5.default.green("\u2713")} Found ${res.messages.length} messages`);
32443
+ const kinds = { standard: 0, thought: 0, terminal: 0, tool: 0 };
32444
+ let missingFields = false;
32445
+ res.messages.forEach((m) => {
32446
+ const k = m.kind || "standard";
32447
+ kinds[k] = (kinds[k] || 0) + 1;
32448
+ if (!m.role || !m.content) missingFields = true;
32449
+ });
32450
+ if (missingFields) {
32451
+ console.log(` ${import_chalk5.default.red("\u2717")} Some messages are missing required 'role' or 'content' fields`);
32452
+ pass = false;
32453
+ } else {
32454
+ console.log(` ${import_chalk5.default.green("\u2713")} All messages have valid 'role' and 'content'`);
32455
+ }
32456
+ console.log(` ${import_chalk5.default.gray("\u2022")} Distribution: ${Object.entries(kinds).map(([k, v]) => `${k}:${v}`).join(", ")}`);
32457
+ }
32458
+ if (!res.status) {
32459
+ console.log(` ${import_chalk5.default.red("\u2717")} 'status' field is missing (idle/generating/waiting_approval)`);
32460
+ pass = false;
32461
+ } else {
32462
+ console.log(` ${import_chalk5.default.green("\u2713")} Status field is valid: ${res.status}`);
32463
+ }
32464
+ }
32465
+ if (pass) {
32466
+ console.log(import_chalk5.default.green(`
32467
+ \u{1F389} Verification Passed! This provider is correctly normalized.
32468
+ `));
32469
+ } else {
32470
+ console.log(import_chalk5.default.red(`
32471
+ \u{1F4A5} Verification Failed! You should fix the DOM script.
32472
+ `));
32473
+ process.exit(1);
32474
+ }
32475
+ } catch (e) {
32476
+ console.error(import_chalk5.default.red(`
32477
+ \u2717 ${e.message}
32163
32478
  `));
32164
32479
  process.exit(1);
32165
32480
  }