adhdev 0.6.19 → 0.6.22

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
@@ -362,9 +362,11 @@ var init_config = __esm({
362
362
  recentWorkspaceActivity: [],
363
363
  machineNickname: null,
364
364
  machineId: void 0,
365
+ machineSecret: null,
365
366
  cliHistory: [],
366
367
  providerSettings: {},
367
- ideSettings: {}
368
+ ideSettings: {},
369
+ disableUpstream: false
368
370
  };
369
371
  }
370
372
  });
@@ -4990,6 +4992,15 @@ var init_handler = __esm({
4990
4992
  return handleExtensionScript(this, args, "listModes");
4991
4993
  case "set_extension_mode":
4992
4994
  return handleExtensionScript(this, args, "setMode");
4995
+ // ─── Provider Auto-Fix / Clone (DevServer proxy) ──────────
4996
+ case "provider_auto_fix":
4997
+ return this.proxyDevServerPost(args, "auto-implement");
4998
+ case "provider_auto_fix_cancel":
4999
+ return this.proxyDevServerPost(args, "auto-implement/cancel");
5000
+ case "provider_auto_fix_status":
5001
+ return this.proxyDevServerGet(args, "auto-implement/status");
5002
+ case "provider_clone":
5003
+ return this.proxyDevServerScaffold(args);
4993
5004
  default:
4994
5005
  return { success: false, error: `Unknown command: ${cmd}` };
4995
5006
  }
@@ -5017,6 +5028,95 @@ var init_handler = __esm({
5017
5028
  }
5018
5029
  return { success: false, error: "ProviderLoader not initialized" };
5019
5030
  }
5031
+ // ─── DevServer HTTP proxy helpers ─────────────────
5032
+ // These bridge WS commands to the DevServer REST API (localhost:19280)
5033
+ async proxyDevServerPost(args, endpoint) {
5034
+ const { providerType, ...body } = args || {};
5035
+ if (!providerType) return { success: false, error: "providerType required" };
5036
+ try {
5037
+ const http3 = await import("http");
5038
+ const postData = JSON.stringify(body);
5039
+ const result = await new Promise((resolve8, reject) => {
5040
+ const req = http3.request({
5041
+ hostname: "127.0.0.1",
5042
+ port: 19280,
5043
+ path: `/api/providers/${providerType}/${endpoint}`,
5044
+ method: "POST",
5045
+ headers: { "Content-Type": "application/json", "Content-Length": Buffer.byteLength(postData) }
5046
+ }, (res) => {
5047
+ let data = "";
5048
+ res.on("data", (chunk) => data += chunk);
5049
+ res.on("end", () => {
5050
+ try {
5051
+ resolve8(JSON.parse(data));
5052
+ } catch {
5053
+ resolve8({ raw: data });
5054
+ }
5055
+ });
5056
+ });
5057
+ req.on("error", reject);
5058
+ req.write(postData);
5059
+ req.end();
5060
+ });
5061
+ return { success: true, ...result };
5062
+ } catch (e) {
5063
+ return { success: false, error: `DevServer unreachable: ${e.message}. Start daemon with --dev flag.` };
5064
+ }
5065
+ }
5066
+ async proxyDevServerGet(args, endpoint) {
5067
+ const { providerType } = args || {};
5068
+ if (!providerType) return { success: false, error: "providerType required" };
5069
+ try {
5070
+ const http3 = await import("http");
5071
+ const result = await new Promise((resolve8, reject) => {
5072
+ http3.get(`http://127.0.0.1:19280/api/providers/${providerType}/${endpoint}`, (res) => {
5073
+ let data = "";
5074
+ res.on("data", (chunk) => data += chunk);
5075
+ res.on("end", () => {
5076
+ try {
5077
+ resolve8(JSON.parse(data));
5078
+ } catch {
5079
+ resolve8({ raw: data });
5080
+ }
5081
+ });
5082
+ }).on("error", reject);
5083
+ });
5084
+ return { success: true, ...result };
5085
+ } catch (e) {
5086
+ return { success: false, error: `DevServer unreachable: ${e.message}. Start daemon with --dev flag.` };
5087
+ }
5088
+ }
5089
+ async proxyDevServerScaffold(args) {
5090
+ try {
5091
+ const http3 = await import("http");
5092
+ const postData = JSON.stringify(args || {});
5093
+ const result = await new Promise((resolve8, reject) => {
5094
+ const req = http3.request({
5095
+ hostname: "127.0.0.1",
5096
+ port: 19280,
5097
+ path: "/api/scaffold",
5098
+ method: "POST",
5099
+ headers: { "Content-Type": "application/json", "Content-Length": Buffer.byteLength(postData) }
5100
+ }, (res) => {
5101
+ let data = "";
5102
+ res.on("data", (chunk) => data += chunk);
5103
+ res.on("end", () => {
5104
+ try {
5105
+ resolve8(JSON.parse(data));
5106
+ } catch {
5107
+ resolve8({ raw: data });
5108
+ }
5109
+ });
5110
+ });
5111
+ req.on("error", reject);
5112
+ req.write(postData);
5113
+ req.end();
5114
+ });
5115
+ return { success: true, ...result };
5116
+ } catch (e) {
5117
+ return { success: false, error: `DevServer unreachable: ${e.message}. Start daemon with --dev flag.` };
5118
+ }
5119
+ }
5020
5120
  };
5021
5121
  }
5022
5122
  });
@@ -5036,6 +5136,7 @@ var init_provider_loader = __esm({
5036
5136
  builtinDirs;
5037
5137
  userDir;
5038
5138
  upstreamDir;
5139
+ disableUpstream;
5039
5140
  watchers = [];
5040
5141
  logFn;
5041
5142
  versionArchive = null;
@@ -5054,6 +5155,7 @@ var init_provider_loader = __esm({
5054
5155
  }
5055
5156
  this.userDir = options?.userDir || path6.join(os7.homedir(), ".adhdev", "providers");
5056
5157
  this.upstreamDir = path6.join(this.userDir, ".upstream");
5158
+ this.disableUpstream = options?.disableUpstream ?? false;
5057
5159
  this.logFn = options?.logFn || LOG.forComponent("Provider").asLogFn();
5058
5160
  }
5059
5161
  log(msg) {
@@ -5070,11 +5172,13 @@ var init_provider_loader = __esm({
5070
5172
  loadAll() {
5071
5173
  this.providers.clear();
5072
5174
  let upstreamCount = 0;
5073
- if (fs5.existsSync(this.upstreamDir)) {
5175
+ if (!this.disableUpstream && fs5.existsSync(this.upstreamDir)) {
5074
5176
  upstreamCount = this.loadDir(this.upstreamDir);
5075
5177
  if (upstreamCount > 0) {
5076
5178
  this.log(`Loaded ${upstreamCount} upstream providers (auto-updated)`);
5077
5179
  }
5180
+ } else if (this.disableUpstream) {
5181
+ this.log("Upstream loading disabled (disableUpstream=true)");
5078
5182
  }
5079
5183
  if (fs5.existsSync(this.userDir)) {
5080
5184
  const userCount = this.loadDir(this.userDir, [".upstream"]);
@@ -5477,6 +5581,10 @@ var init_provider_loader = __esm({
5477
5581
  * @returns Whether an update occurred
5478
5582
  */
5479
5583
  async fetchLatest() {
5584
+ if (this.disableUpstream) {
5585
+ this.log("Upstream fetch skipped (disableUpstream=true)");
5586
+ return { updated: false };
5587
+ }
5480
5588
  const https = require("https");
5481
5589
  const { execSync: execSync7 } = require("child_process");
5482
5590
  const metaPath = path6.join(this.upstreamDir, _ProviderLoader.META_FILE);
@@ -6815,12 +6923,6 @@ var init_reporter = __esm({
6815
6923
  emitStatusEvent(event) {
6816
6924
  LOG.info("StatusEvent", `${event.event} (${event.providerType || event.ideType || ""})`);
6817
6925
  this.deps.serverConn?.sendMessage("status_event", event);
6818
- if (this.deps.p2p?.isConnected) {
6819
- try {
6820
- this.deps.p2p.sendStatusEvent?.(event);
6821
- } catch {
6822
- }
6823
- }
6824
6926
  }
6825
6927
  removeAgentTracking(_key) {
6826
6928
  }
@@ -6898,6 +7000,7 @@ var init_reporter = __esm({
6898
7000
  peers: p2p?.connectedPeerCount || 0,
6899
7001
  screenshotActive: p2p?.screenshotActive || false
6900
7002
  },
7003
+ screenshotUsage: this.deps.getScreenshotUsage?.() || null,
6901
7004
  connectedExtensions: [],
6902
7005
  detectedIdes: this.deps.detectedIdes || [],
6903
7006
  availableProviders: this.deps.providerLoader.getAll().map((p) => ({
@@ -28411,7 +28514,7 @@ var init_dev_server = __esm({
28411
28514
  // ─── Phase 2: Auto-Implement Backend ───
28412
28515
  async handleAutoImplement(type, req, res) {
28413
28516
  const body = await this.readBody(req);
28414
- const { agent = "claude-cli", functions, reference = "antigravity", model } = body;
28517
+ const { agent = "claude-cli", functions, reference = "antigravity", model, comment } = body;
28415
28518
  if (!functions || !Array.isArray(functions) || functions.length === 0) {
28416
28519
  this.json(res, 400, { error: 'functions[] is required (e.g. ["readChat", "sendMessage"])' });
28417
28520
  return;
@@ -28460,7 +28563,7 @@ var init_dev_server = __esm({
28460
28563
  }
28461
28564
  }
28462
28565
  }
28463
- const prompt = this.buildAutoImplPrompt(type, provider, providerDir, functions, domContext, referenceScripts);
28566
+ const prompt = this.buildAutoImplPrompt(type, provider, providerDir, functions, domContext, referenceScripts, comment);
28464
28567
  const tmpDir = path12.join(os14.tmpdir(), "adhdev-autoimpl");
28465
28568
  if (!fs9.existsSync(tmpDir)) fs9.mkdirSync(tmpDir, { recursive: true });
28466
28569
  const promptFile = path12.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
@@ -28643,6 +28746,7 @@ var init_dev_server = __esm({
28643
28746
  }
28644
28747
  this.sendAutoImplSSE({ event: "progress", data: { function: "_init", status: "spawning", message: `\uC5D0\uC774\uC804\uD2B8 \uC2E4\uD589 \uC911: ${shellCmd.substring(0, 200)}... (prompt: ${prompt.length} chars)` } });
28645
28748
  this.autoImplStatus = { running: true, type, progress: [] };
28749
+ const spawnedAt = Date.now();
28646
28750
  let child;
28647
28751
  let isPty = false;
28648
28752
  const { spawn: spawnFn } = await import("child_process");
@@ -28695,8 +28799,9 @@ var init_dev_server = __esm({
28695
28799
  const checkAutoApproval = (chunk, writeFn) => {
28696
28800
  const cleanData = chunk.replace(/\x1B\[\d*[A-HJKSTfG]/g, " ").replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g, "").replace(/\x1B\][^\x07]*\x07/g, "").replace(/\x1B\][^\x1B]*\x1B\\/g, "").replace(/ +/g, " ");
28697
28801
  approvalBuffer = (approvalBuffer + cleanData).slice(-1500);
28698
- if (approvalBuffer.includes("AUTO_IMPLEMENT_FINISHED")) {
28699
- this.log("Agent finished task. Terminating interactive CLI session to unblock pipeline.");
28802
+ const elapsed = Date.now() - spawnedAt;
28803
+ if (elapsed > 15e3 && approvalBuffer.includes("AUTO_IMPLEMENT_FINISHED")) {
28804
+ this.log(`Agent finished task after ${Math.round(elapsed / 1e3)}s. Terminating interactive CLI session to unblock pipeline.`);
28700
28805
  this.sendAutoImplSSE({ event: "output", data: { chunk: `
28701
28806
  [\u{1F916} ADHDev Pipeline] Completion token detected. Proceeding...
28702
28807
  `, stream: "stdout" } });
@@ -28798,7 +28903,7 @@ var init_dev_server = __esm({
28798
28903
  this.json(res, 500, { error: `Auto-implement failed: ${e.message}` });
28799
28904
  }
28800
28905
  }
28801
- buildAutoImplPrompt(type, provider, providerDir, functions, domContext, referenceScripts) {
28906
+ buildAutoImplPrompt(type, provider, providerDir, functions, domContext, referenceScripts, userComment) {
28802
28907
  const lines = [];
28803
28908
  lines.push("You are implementing browser automation scripts for an IDE provider.");
28804
28909
  lines.push("Be concise. Do NOT explain your reasoning. Just edit files directly.");
@@ -28910,6 +29015,22 @@ var init_dev_server = __esm({
28910
29015
  lines.push("| focusEditor | `{ focused: true/false }` |");
28911
29016
  lines.push("| openPanel | `{ opened: true/false }` |");
28912
29017
  lines.push("");
29018
+ lines.push("## \u{1F534} CRITICAL: readChat `status` Lifecycle");
29019
+ lines.push("The `status` field in readChat controls how the dashboard and daemon auto-approve-loop behave.");
29020
+ lines.push("Getting this wrong will break the entire automation pipeline. The status MUST reflect the ACTUAL current state:");
29021
+ lines.push("");
29022
+ lines.push("| Status | When to use | How to detect |");
29023
+ lines.push("|---|---|---|");
29024
+ lines.push("| `idle` | AI is NOT generating, no approval needed | Default state. No stop button, no spinners, no approval pills/buttons |");
29025
+ lines.push("| `generating` | AI is actively streaming/thinking | ANY of: (1) Stop/Cancel button visible, (2) CSS animation (animate-spin/pulse/bounce), (3) floating state text like Thinking/Generating/Sailing, (4) streaming indicator class |");
29026
+ lines.push("| `waiting_approval` | AI stopped and needs user action | Actionable buttons like Run/Skip/Accept/Reject are visible AND clickable |");
29027
+ lines.push("");
29028
+ lines.push("### \u26A0\uFE0F Status Detection Gotchas (MUST READ!)");
29029
+ lines.push('1. **FALSE POSITIVES from old messages**: Chat history may contain text like "Command Awaiting Approval" from PAST turns. If you search the entire chat panel for this text, you will get false matches from parent divs whose innerText includes ALL child text. ONLY match small leaf elements (under 80 chars) or use explicit button/pill selectors.');
29030
+ lines.push('2. **Awaiting Approval pill without actions**: Some IDEs show a floating pill/banner saying "Awaiting Approval" that is just a scroll-to indicator (not an actual approval dialog). If this pill exists but NO actionable buttons (Run/Skip/Accept/Reject) exist anywhere in the panel, the status should be `idle`, NOT `waiting_approval`.');
29031
+ lines.push("3. **generating detection must be multi-signal**: Do NOT rely on just one indicator. Check ALL of: stop buttons, CSS animations, floating state labels, streaming classes. IDEs differ widely.");
29032
+ lines.push("4. **activeModal must include actions**: When `status` is `waiting_approval`, the `activeModal` object MUST include a non-empty `actions` array listing the button labels. If you cannot find any action buttons, the status is NOT `waiting_approval`.");
29033
+ lines.push("");
28913
29034
  lines.push("## Action");
28914
29035
  lines.push("1. Edit the script files to implement working code");
28915
29036
  lines.push("2. After editing, TEST each function using the DevConsole API (see below)");
@@ -28934,7 +29055,7 @@ var init_dev_server = __esm({
28934
29055
  lines.push("Once you save the file, test it by running:");
28935
29056
  lines.push("```bash");
28936
29057
  lines.push(`curl -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/providers/reload`);
28937
- 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"}'`);
29058
+ lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/scripts/run -H "Content-Type: application/json" -d '{"script": "readChat", "type": "${type}", "ideType": "${type}"}'`);
28938
29059
  lines.push("```");
28939
29060
  lines.push("");
28940
29061
  lines.push("### Task Workflow");
@@ -28946,12 +29067,51 @@ var init_dev_server = __esm({
28946
29067
  lines.push("### \u{1F525} Advanced UI Parsing (CRUCIAL for `readChat`)");
28947
29068
  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.");
28948
29069
  lines.push("To achieve this, you MUST generate a live test scenario:");
28949
- lines.push("1. Early in your process, send a rich prompt to the IDE using the API:");
28950
- 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"}}\'`');
29070
+ lines.push(`1. Early in your process, send a rich prompt to the IDE using the API:`);
29071
+ lines.push(` \`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/scripts/run -H "Content-Type: application/json" -d '{"script": "sendMessage", "type": "${type}", "ideType": "${type}", "args": {"message": "Write a python script, draw a markdown table, use a tool, and show your reasoning/thought process"}}'\``);
28951
29072
  lines.push("2. Wait a few seconds for the IDE AI to generate these elements in the UI.");
28952
29073
  lines.push("3. Use CDP evaluate to deeply inspect the DOM structure of the newly generated tables, code blocks, thought blocks, and tool calls.");
28953
29074
  lines.push("4. Ensure `readChat` extracts `content` with precise markdown formatting (especially for tables/code) and assigns correct `kind` tags (`thought`, `tool`, `terminal`).");
28954
29075
  lines.push("");
29076
+ lines.push("## \u{1F9EA} MANDATORY: Status Integration Test");
29077
+ lines.push("Before finishing, you MUST run this end-to-end test to verify readChat status transitions work:");
29078
+ lines.push("");
29079
+ lines.push("### Step 1: Baseline \u2014 confirm idle");
29080
+ lines.push("```bash");
29081
+ lines.push(`curl -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/providers/reload`);
29082
+ lines.push(`RESULT=$(curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/scripts/run -H "Content-Type: application/json" -d '{"script": "readChat", "type": "${type}", "ideType": "${type}"}')`);
29083
+ lines.push(`echo "$RESULT" | python3 -c "import sys,json; d=json.load(sys.stdin); r=d.get('result',d); r=json.loads(r) if isinstance(r,str) else r; assert r.get('status')=='idle', f'Expected idle, got {r.get(chr(34)+chr(115)+chr(116)+chr(97)+chr(116)+chr(117)+chr(115)+chr(34))}'; print('Step 1 PASS: status=idle')"`);
29084
+ lines.push("```");
29085
+ lines.push("");
29086
+ lines.push("### Step 2: Send a message that triggers generation");
29087
+ lines.push("```bash");
29088
+ lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/scripts/run -H "Content-Type: application/json" -d '{"script": "sendMessage", "type": "${type}", "ideType": "${type}", "args": {"message": "Say hello in one word"}}'`);
29089
+ lines.push("sleep 2");
29090
+ lines.push("```");
29091
+ lines.push("");
29092
+ lines.push("### Step 3: Check generating OR completed");
29093
+ lines.push("The AI may still be generating OR may have finished already. Either generating or idle is acceptable:");
29094
+ lines.push("```bash");
29095
+ lines.push(`RESULT=$(curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/scripts/run -H "Content-Type: application/json" -d '{"script": "readChat", "type": "${type}", "ideType": "${type}"}')`);
29096
+ lines.push(`echo "$RESULT" | python3 -c "import sys,json; d=json.load(sys.stdin); r=d.get('result',d); r=json.loads(r) if isinstance(r,str) else r; s=r.get('status'); assert s in ('generating','idle','waiting_approval'), f'Unexpected: {s}'; print(f'Step 3 PASS: status={s}')"`);
29097
+ lines.push("```");
29098
+ lines.push("");
29099
+ lines.push("### Step 4: Wait for completion and verify new message");
29100
+ lines.push("```bash");
29101
+ lines.push("sleep 10");
29102
+ lines.push(`RESULT=$(curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/scripts/run -H "Content-Type: application/json" -d '{"script": "readChat", "type": "${type}", "ideType": "${type}"}')`);
29103
+ lines.push(`echo "$RESULT" | python3 -c "import sys,json; d=json.load(sys.stdin); r=d.get('result',d); r=json.loads(r) if isinstance(r,str) else r; s=r.get('status'); msgs=r.get('messages',[]); assert s=='idle', f'Expected idle, got {s}'; assert len(msgs)>0, 'No messages'; print(f'Step 4 PASS: status={s}, messages={len(msgs)}')"`);
29104
+ lines.push("```");
29105
+ lines.push("");
29106
+ lines.push("If ANY step fails, fix your implementation and re-run the test. Do NOT finish until all 4 steps pass.");
29107
+ lines.push("");
29108
+ if (userComment) {
29109
+ lines.push("## \u26A0\uFE0F User Instructions (HIGH PRIORITY)");
29110
+ lines.push("The user has provided the following additional instructions. Follow them strictly:");
29111
+ lines.push("");
29112
+ lines.push(userComment);
29113
+ lines.push("");
29114
+ }
28955
29115
  lines.push("Start NOW. Do not ask for permission. Explore the DOM -> Code -> Test.");
28956
29116
  return lines.join("\n");
28957
29117
  }
@@ -29476,10 +29636,13 @@ var init_installer = __esm({
29476
29636
  // ../daemon-core/src/boot/daemon-lifecycle.ts
29477
29637
  async function initDaemonComponents(config2) {
29478
29638
  installGlobalInterceptor();
29639
+ const appConfig = loadConfig();
29640
+ const disableUpstream = appConfig.disableUpstream ?? false;
29479
29641
  const providerLoader = new ProviderLoader({
29480
- logFn: config2.providerLogFn
29642
+ logFn: config2.providerLogFn,
29643
+ disableUpstream
29481
29644
  });
29482
- if (!providerLoader.hasUpstream()) {
29645
+ if (!disableUpstream && !providerLoader.hasUpstream()) {
29483
29646
  LOG.info("Provider", "No upstream providers found \u2014 downloading from GitHub...");
29484
29647
  try {
29485
29648
  await providerLoader.fetchLatest();
@@ -30514,24 +30677,6 @@ ${e?.stack || ""}`);
30514
30677
  }
30515
30678
  return sentAny;
30516
30679
  }
30517
- /** Send status_event directly via P2P (generating_started/completed etc.) */
30518
- sendStatusEvent(event) {
30519
- const payload = JSON.stringify({
30520
- type: "status_event",
30521
- payload: event,
30522
- timestamp: Date.now()
30523
- });
30524
- let sentAny = false;
30525
- for (const peer of this.peers.values()) {
30526
- if (peer.state !== "connected" || !peer.dataChannel) continue;
30527
- try {
30528
- peer.dataChannel.sendMessage(payload);
30529
- sentAny = true;
30530
- } catch {
30531
- }
30532
- }
30533
- return sentAny;
30534
- }
30535
30680
  /** Broadcast PTY output to all connected peers */
30536
30681
  broadcastPtyOutput(cliType, data) {
30537
30682
  const prev = this.ptyScrollback.get(cliType) || "";
@@ -30940,6 +31085,15 @@ var init_screenshot_controller = __esm({
30940
31085
  LOG.info("Screenshot", `Daily budget reset (${this.dailyBudgetMinutes}min for today)`);
30941
31086
  }
30942
31087
  }
31088
+ /** Returns current usage stats for reporting to server/dashboard */
31089
+ getUsageStats() {
31090
+ this.checkBudgetReset();
31091
+ return {
31092
+ dailyUsedMinutes: Math.round(this.dailyUsedMs / 6e4),
31093
+ dailyBudgetMinutes: this.dailyBudgetMinutes,
31094
+ budgetExhausted: this.budgetExhausted
31095
+ };
31096
+ }
30943
31097
  // ─── Hash ─────────────────────────────────────
30944
31098
  /** FNV-1a hash of first 1KB + last 1KB for fast delta detection */
30945
31099
  static fnvHash(buf) {
@@ -31020,7 +31174,7 @@ var init_adhdev_daemon = __esm({
31020
31174
  fs11 = __toESM(require("fs"));
31021
31175
  path14 = __toESM(require("path"));
31022
31176
  import_chalk2 = __toESM(require("chalk"));
31023
- pkgVersion = "0.6.19";
31177
+ pkgVersion = "0.6.22";
31024
31178
  if (pkgVersion === "unknown") {
31025
31179
  try {
31026
31180
  const possiblePaths = [
@@ -31087,8 +31241,9 @@ ${err?.stack || ""}`);
31087
31241
  }
31088
31242
  writeDaemonPid(process.pid);
31089
31243
  const config2 = loadConfig();
31090
- if (!config2.connectionToken) {
31091
- console.log(import_chalk2.default.red("\n\u2717 No connection token found."));
31244
+ const authToken = config2.machineSecret || config2.connectionToken;
31245
+ if (!authToken) {
31246
+ console.log(import_chalk2.default.red("\n\u2717 No credentials found."));
31092
31247
  console.log(import_chalk2.default.gray(" Run `adhdev setup` first.\n"));
31093
31248
  process.exit(1);
31094
31249
  }
@@ -31138,7 +31293,7 @@ ${err?.stack || ""}`);
31138
31293
  const instanceId = `daemon_${config2.machineId}`;
31139
31294
  this.serverConn = new ServerConnection({
31140
31295
  serverUrl: options.serverUrl || config2.serverUrl,
31141
- token: config2.connectionToken,
31296
+ token: authToken,
31142
31297
  daemonVersion: pkgVersion,
31143
31298
  cliInfo: {
31144
31299
  type: "adhdev-daemon",
@@ -31230,7 +31385,8 @@ ${err?.stack || ""}`);
31230
31385
  detectedIdes: this.components.detectedIdes.value,
31231
31386
  ideType: this.ideType,
31232
31387
  daemonVersion: pkgVersion,
31233
- instanceManager: this.components.instanceManager
31388
+ instanceManager: this.components.instanceManager,
31389
+ getScreenshotUsage: () => this.screenshotController?.getUsageStats() || null
31234
31390
  });
31235
31391
  this.statusReporter.startReporting();
31236
31392
  this.components.instanceManager.onEvent((event) => {
@@ -31508,11 +31664,17 @@ async function quickSetup() {
31508
31664
  }
31509
31665
  markSetupComplete(["daemon"], ["adhdev"]);
31510
31666
  if (loginResult) {
31511
- updateConfig({
31667
+ const configUpdate = {
31512
31668
  connectionToken: loginResult.connectionToken,
31513
31669
  userEmail: loginResult.email,
31514
31670
  userName: loginResult.name
31515
- });
31671
+ };
31672
+ if (loginResult.machineId && loginResult.machineSecret) {
31673
+ configUpdate.machineId = loginResult.machineId;
31674
+ configUpdate.machineSecret = loginResult.machineSecret;
31675
+ console.log(import_chalk3.default.green(` \u2713 Machine registered`));
31676
+ }
31677
+ updateConfig(configUpdate);
31516
31678
  }
31517
31679
  await installCliOnly();
31518
31680
  await startDaemonFlow();
@@ -31548,7 +31710,16 @@ async function loginFlow() {
31548
31710
  let userCode;
31549
31711
  let verificationUrl;
31550
31712
  try {
31551
- const res = await fetch(`${SERVER_URL}/auth/cli/init`, { method: "POST" });
31713
+ const os17 = await import("os");
31714
+ const res = await fetch(`${SERVER_URL}/auth/cli/init`, {
31715
+ method: "POST",
31716
+ headers: { "Content-Type": "application/json" },
31717
+ body: JSON.stringify({
31718
+ hostname: os17.hostname(),
31719
+ platform: os17.platform(),
31720
+ arch: os17.arch()
31721
+ })
31722
+ });
31552
31723
  if (!res.ok) {
31553
31724
  spinner.fail("Failed to connect to server");
31554
31725
  return null;
@@ -31595,10 +31766,27 @@ async function loginFlow() {
31595
31766
  pollSpinner.succeed(`Authenticated as ${import_chalk3.default.bold(data.user?.email || "user")}`);
31596
31767
  return {
31597
31768
  connectionToken: data.connectionToken,
31769
+ machineId: data.machineId || void 0,
31770
+ machineSecret: data.machineSecret || void 0,
31598
31771
  email: data.user?.email,
31599
31772
  name: data.user?.name
31600
31773
  };
31601
31774
  }
31775
+ if (data.status === "limit_reached") {
31776
+ pollSpinner.fail("Machine limit reached");
31777
+ console.log();
31778
+ console.log(import_chalk3.default.red(` \u2717 Your ${import_chalk3.default.bold(data.plan || "free")} plan allows ${data.limit} machine(s), and you have ${data.current} registered.`));
31779
+ console.log();
31780
+ console.log(import_chalk3.default.yellow(" To fix this, do one of the following:"));
31781
+ console.log(import_chalk3.default.gray(" 1. Remove an unused machine from the dashboard:"));
31782
+ console.log(import_chalk3.default.gray(" https://adhf.dev/account \u2192 Registered Machines \u2192 \u2715 Remove"));
31783
+ console.log(import_chalk3.default.gray(" 2. Upgrade your plan:"));
31784
+ console.log(import_chalk3.default.gray(" https://adhf.dev/account?tab=billing"));
31785
+ console.log();
31786
+ console.log(import_chalk3.default.gray(" Then run `adhdev setup` again."));
31787
+ console.log();
31788
+ return null;
31789
+ }
31602
31790
  } catch {
31603
31791
  }
31604
31792
  }
@@ -32619,7 +32807,7 @@ function registerProviderCommands(program2) {
32619
32807
  process.exit(1);
32620
32808
  }
32621
32809
  });
32622
- provider.command("fix [type] [scripts...]").description("Auto-implement provider scripts using AI reading the target IDE DOM").option("-a, --agent <agent>", "AI agent to use (e.g. claude-cli, gemini-cli, codex-cli, or any ACP provider like cline-acp)", "codex-cli").option("-m, --model <model>", "Model override (e.g. claude-sonnet-3.5, gemini-2.0-pro)").option("-r, --reference <ref>", "Reference provider to learn from", "antigravity").action(async (typeArg, scripts, options) => {
32810
+ provider.command("fix [type] [scripts...]").description("Auto-implement provider scripts using AI reading the target IDE DOM").option("-a, --agent <agent>", "AI agent to use (e.g. claude-cli, gemini-cli, codex-cli, or any ACP provider like cline-acp)", "codex-cli").option("-m, --model <model>", "Model override (e.g. claude-sonnet-3.5, gemini-2.0-pro)").option("-r, --reference <ref>", "Reference provider to learn from", "antigravity").option("-c, --comment <text>", 'Additional instructions for the AI agent (e.g. "focus on shadow DOM handling")').action(async (typeArg, scripts, options) => {
32623
32811
  try {
32624
32812
  const http3 = await import("http");
32625
32813
  const inquirer2 = (await import("inquirer")).default;
@@ -32749,14 +32937,27 @@ function registerProviderCommands(program2) {
32749
32937
  process.exit(0);
32750
32938
  }
32751
32939
  }
32940
+ let userComment = options.comment || "";
32941
+ if (!typeArg && !userComment) {
32942
+ const commentAnswer = await inquirer2.prompt([{
32943
+ type: "input",
32944
+ name: "comment",
32945
+ message: "Additional instructions for the agent (press Enter to skip):"
32946
+ }]);
32947
+ userComment = commentAnswer.comment || "";
32948
+ }
32752
32949
  let consecutiveFailures = 0;
32753
32950
  console.log(import_chalk6.default.bold(`
32754
32951
  \u25B6\uFE0F Generating [${functionsToFix.length}] function(s) natively via autonomous agent for ${type}...`));
32952
+ if (userComment) {
32953
+ console.log(import_chalk6.default.gray(` \u{1F4AC} Comment: ${userComment}`));
32954
+ }
32755
32955
  try {
32756
32956
  const postData = JSON.stringify({
32757
32957
  functions: functionsToFix,
32758
32958
  agent: agentName,
32759
32959
  ...modelName ? { model: modelName } : {},
32960
+ ...userComment ? { comment: userComment } : {},
32760
32961
  reference
32761
32962
  });
32762
32963
  const startResult = await new Promise((resolve8, reject) => {