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/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
  });
@@ -4822,6 +4824,15 @@ var init_handler = __esm({
4822
4824
  return handleExtensionScript(this, args, "listModes");
4823
4825
  case "set_extension_mode":
4824
4826
  return handleExtensionScript(this, args, "setMode");
4827
+ // ─── Provider Auto-Fix / Clone (DevServer proxy) ──────────
4828
+ case "provider_auto_fix":
4829
+ return this.proxyDevServerPost(args, "auto-implement");
4830
+ case "provider_auto_fix_cancel":
4831
+ return this.proxyDevServerPost(args, "auto-implement/cancel");
4832
+ case "provider_auto_fix_status":
4833
+ return this.proxyDevServerGet(args, "auto-implement/status");
4834
+ case "provider_clone":
4835
+ return this.proxyDevServerScaffold(args);
4825
4836
  default:
4826
4837
  return { success: false, error: `Unknown command: ${cmd}` };
4827
4838
  }
@@ -4849,6 +4860,95 @@ var init_handler = __esm({
4849
4860
  }
4850
4861
  return { success: false, error: "ProviderLoader not initialized" };
4851
4862
  }
4863
+ // ─── DevServer HTTP proxy helpers ─────────────────
4864
+ // These bridge WS commands to the DevServer REST API (localhost:19280)
4865
+ async proxyDevServerPost(args, endpoint) {
4866
+ const { providerType, ...body } = args || {};
4867
+ if (!providerType) return { success: false, error: "providerType required" };
4868
+ try {
4869
+ const http3 = await import("http");
4870
+ const postData = JSON.stringify(body);
4871
+ const result = await new Promise((resolve8, reject) => {
4872
+ const req = http3.request({
4873
+ hostname: "127.0.0.1",
4874
+ port: 19280,
4875
+ path: `/api/providers/${providerType}/${endpoint}`,
4876
+ method: "POST",
4877
+ headers: { "Content-Type": "application/json", "Content-Length": Buffer.byteLength(postData) }
4878
+ }, (res) => {
4879
+ let data = "";
4880
+ res.on("data", (chunk) => data += chunk);
4881
+ res.on("end", () => {
4882
+ try {
4883
+ resolve8(JSON.parse(data));
4884
+ } catch {
4885
+ resolve8({ raw: data });
4886
+ }
4887
+ });
4888
+ });
4889
+ req.on("error", reject);
4890
+ req.write(postData);
4891
+ req.end();
4892
+ });
4893
+ return { success: true, ...result };
4894
+ } catch (e) {
4895
+ return { success: false, error: `DevServer unreachable: ${e.message}. Start daemon with --dev flag.` };
4896
+ }
4897
+ }
4898
+ async proxyDevServerGet(args, endpoint) {
4899
+ const { providerType } = args || {};
4900
+ if (!providerType) return { success: false, error: "providerType required" };
4901
+ try {
4902
+ const http3 = await import("http");
4903
+ const result = await new Promise((resolve8, reject) => {
4904
+ http3.get(`http://127.0.0.1:19280/api/providers/${providerType}/${endpoint}`, (res) => {
4905
+ let data = "";
4906
+ res.on("data", (chunk) => data += chunk);
4907
+ res.on("end", () => {
4908
+ try {
4909
+ resolve8(JSON.parse(data));
4910
+ } catch {
4911
+ resolve8({ raw: data });
4912
+ }
4913
+ });
4914
+ }).on("error", reject);
4915
+ });
4916
+ return { success: true, ...result };
4917
+ } catch (e) {
4918
+ return { success: false, error: `DevServer unreachable: ${e.message}. Start daemon with --dev flag.` };
4919
+ }
4920
+ }
4921
+ async proxyDevServerScaffold(args) {
4922
+ try {
4923
+ const http3 = await import("http");
4924
+ const postData = JSON.stringify(args || {});
4925
+ const result = await new Promise((resolve8, reject) => {
4926
+ const req = http3.request({
4927
+ hostname: "127.0.0.1",
4928
+ port: 19280,
4929
+ path: "/api/scaffold",
4930
+ method: "POST",
4931
+ headers: { "Content-Type": "application/json", "Content-Length": Buffer.byteLength(postData) }
4932
+ }, (res) => {
4933
+ let data = "";
4934
+ res.on("data", (chunk) => data += chunk);
4935
+ res.on("end", () => {
4936
+ try {
4937
+ resolve8(JSON.parse(data));
4938
+ } catch {
4939
+ resolve8({ raw: data });
4940
+ }
4941
+ });
4942
+ });
4943
+ req.on("error", reject);
4944
+ req.write(postData);
4945
+ req.end();
4946
+ });
4947
+ return { success: true, ...result };
4948
+ } catch (e) {
4949
+ return { success: false, error: `DevServer unreachable: ${e.message}. Start daemon with --dev flag.` };
4950
+ }
4951
+ }
4852
4952
  };
4853
4953
  }
4854
4954
  });
@@ -4868,6 +4968,7 @@ var init_provider_loader = __esm({
4868
4968
  builtinDirs;
4869
4969
  userDir;
4870
4970
  upstreamDir;
4971
+ disableUpstream;
4871
4972
  watchers = [];
4872
4973
  logFn;
4873
4974
  versionArchive = null;
@@ -4886,6 +4987,7 @@ var init_provider_loader = __esm({
4886
4987
  }
4887
4988
  this.userDir = options?.userDir || path6.join(os7.homedir(), ".adhdev", "providers");
4888
4989
  this.upstreamDir = path6.join(this.userDir, ".upstream");
4990
+ this.disableUpstream = options?.disableUpstream ?? false;
4889
4991
  this.logFn = options?.logFn || LOG.forComponent("Provider").asLogFn();
4890
4992
  }
4891
4993
  log(msg) {
@@ -4902,11 +5004,13 @@ var init_provider_loader = __esm({
4902
5004
  loadAll() {
4903
5005
  this.providers.clear();
4904
5006
  let upstreamCount = 0;
4905
- if (fs5.existsSync(this.upstreamDir)) {
5007
+ if (!this.disableUpstream && fs5.existsSync(this.upstreamDir)) {
4906
5008
  upstreamCount = this.loadDir(this.upstreamDir);
4907
5009
  if (upstreamCount > 0) {
4908
5010
  this.log(`Loaded ${upstreamCount} upstream providers (auto-updated)`);
4909
5011
  }
5012
+ } else if (this.disableUpstream) {
5013
+ this.log("Upstream loading disabled (disableUpstream=true)");
4910
5014
  }
4911
5015
  if (fs5.existsSync(this.userDir)) {
4912
5016
  const userCount = this.loadDir(this.userDir, [".upstream"]);
@@ -5309,6 +5413,10 @@ var init_provider_loader = __esm({
5309
5413
  * @returns Whether an update occurred
5310
5414
  */
5311
5415
  async fetchLatest() {
5416
+ if (this.disableUpstream) {
5417
+ this.log("Upstream fetch skipped (disableUpstream=true)");
5418
+ return { updated: false };
5419
+ }
5312
5420
  const https = require("https");
5313
5421
  const { execSync: execSync6 } = require("child_process");
5314
5422
  const metaPath = path6.join(this.upstreamDir, _ProviderLoader.META_FILE);
@@ -6619,12 +6727,6 @@ var init_reporter = __esm({
6619
6727
  emitStatusEvent(event) {
6620
6728
  LOG.info("StatusEvent", `${event.event} (${event.providerType || event.ideType || ""})`);
6621
6729
  this.deps.serverConn?.sendMessage("status_event", event);
6622
- if (this.deps.p2p?.isConnected) {
6623
- try {
6624
- this.deps.p2p.sendStatusEvent?.(event);
6625
- } catch {
6626
- }
6627
- }
6628
6730
  }
6629
6731
  removeAgentTracking(_key) {
6630
6732
  }
@@ -6702,6 +6804,7 @@ var init_reporter = __esm({
6702
6804
  peers: p2p?.connectedPeerCount || 0,
6703
6805
  screenshotActive: p2p?.screenshotActive || false
6704
6806
  },
6807
+ screenshotUsage: this.deps.getScreenshotUsage?.() || null,
6705
6808
  connectedExtensions: [],
6706
6809
  detectedIdes: this.deps.detectedIdes || [],
6707
6810
  availableProviders: this.deps.providerLoader.getAll().map((p) => ({
@@ -28214,7 +28317,7 @@ var init_dev_server = __esm({
28214
28317
  // ─── Phase 2: Auto-Implement Backend ───
28215
28318
  async handleAutoImplement(type, req, res) {
28216
28319
  const body = await this.readBody(req);
28217
- const { agent = "claude-cli", functions, reference = "antigravity", model } = body;
28320
+ const { agent = "claude-cli", functions, reference = "antigravity", model, comment } = body;
28218
28321
  if (!functions || !Array.isArray(functions) || functions.length === 0) {
28219
28322
  this.json(res, 400, { error: 'functions[] is required (e.g. ["readChat", "sendMessage"])' });
28220
28323
  return;
@@ -28263,7 +28366,7 @@ var init_dev_server = __esm({
28263
28366
  }
28264
28367
  }
28265
28368
  }
28266
- const prompt = this.buildAutoImplPrompt(type, provider, providerDir, functions, domContext, referenceScripts);
28369
+ const prompt = this.buildAutoImplPrompt(type, provider, providerDir, functions, domContext, referenceScripts, comment);
28267
28370
  const tmpDir = path12.join(os14.tmpdir(), "adhdev-autoimpl");
28268
28371
  if (!fs9.existsSync(tmpDir)) fs9.mkdirSync(tmpDir, { recursive: true });
28269
28372
  const promptFile = path12.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
@@ -28446,6 +28549,7 @@ var init_dev_server = __esm({
28446
28549
  }
28447
28550
  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)` } });
28448
28551
  this.autoImplStatus = { running: true, type, progress: [] };
28552
+ const spawnedAt = Date.now();
28449
28553
  let child;
28450
28554
  let isPty = false;
28451
28555
  const { spawn: spawnFn } = await import("child_process");
@@ -28498,8 +28602,9 @@ var init_dev_server = __esm({
28498
28602
  const checkAutoApproval = (chunk, writeFn) => {
28499
28603
  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, " ");
28500
28604
  approvalBuffer = (approvalBuffer + cleanData).slice(-1500);
28501
- if (approvalBuffer.includes("AUTO_IMPLEMENT_FINISHED")) {
28502
- this.log("Agent finished task. Terminating interactive CLI session to unblock pipeline.");
28605
+ const elapsed = Date.now() - spawnedAt;
28606
+ if (elapsed > 15e3 && approvalBuffer.includes("AUTO_IMPLEMENT_FINISHED")) {
28607
+ this.log(`Agent finished task after ${Math.round(elapsed / 1e3)}s. Terminating interactive CLI session to unblock pipeline.`);
28503
28608
  this.sendAutoImplSSE({ event: "output", data: { chunk: `
28504
28609
  [\u{1F916} ADHDev Pipeline] Completion token detected. Proceeding...
28505
28610
  `, stream: "stdout" } });
@@ -28601,7 +28706,7 @@ var init_dev_server = __esm({
28601
28706
  this.json(res, 500, { error: `Auto-implement failed: ${e.message}` });
28602
28707
  }
28603
28708
  }
28604
- buildAutoImplPrompt(type, provider, providerDir, functions, domContext, referenceScripts) {
28709
+ buildAutoImplPrompt(type, provider, providerDir, functions, domContext, referenceScripts, userComment) {
28605
28710
  const lines = [];
28606
28711
  lines.push("You are implementing browser automation scripts for an IDE provider.");
28607
28712
  lines.push("Be concise. Do NOT explain your reasoning. Just edit files directly.");
@@ -28713,6 +28818,22 @@ var init_dev_server = __esm({
28713
28818
  lines.push("| focusEditor | `{ focused: true/false }` |");
28714
28819
  lines.push("| openPanel | `{ opened: true/false }` |");
28715
28820
  lines.push("");
28821
+ lines.push("## \u{1F534} CRITICAL: readChat `status` Lifecycle");
28822
+ lines.push("The `status` field in readChat controls how the dashboard and daemon auto-approve-loop behave.");
28823
+ lines.push("Getting this wrong will break the entire automation pipeline. The status MUST reflect the ACTUAL current state:");
28824
+ lines.push("");
28825
+ lines.push("| Status | When to use | How to detect |");
28826
+ lines.push("|---|---|---|");
28827
+ lines.push("| `idle` | AI is NOT generating, no approval needed | Default state. No stop button, no spinners, no approval pills/buttons |");
28828
+ 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 |");
28829
+ lines.push("| `waiting_approval` | AI stopped and needs user action | Actionable buttons like Run/Skip/Accept/Reject are visible AND clickable |");
28830
+ lines.push("");
28831
+ lines.push("### \u26A0\uFE0F Status Detection Gotchas (MUST READ!)");
28832
+ 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.');
28833
+ 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`.');
28834
+ 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.");
28835
+ 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`.");
28836
+ lines.push("");
28716
28837
  lines.push("## Action");
28717
28838
  lines.push("1. Edit the script files to implement working code");
28718
28839
  lines.push("2. After editing, TEST each function using the DevConsole API (see below)");
@@ -28737,7 +28858,7 @@ var init_dev_server = __esm({
28737
28858
  lines.push("Once you save the file, test it by running:");
28738
28859
  lines.push("```bash");
28739
28860
  lines.push(`curl -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/providers/reload`);
28740
- 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"}'`);
28861
+ 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}"}'`);
28741
28862
  lines.push("```");
28742
28863
  lines.push("");
28743
28864
  lines.push("### Task Workflow");
@@ -28749,12 +28870,51 @@ var init_dev_server = __esm({
28749
28870
  lines.push("### \u{1F525} Advanced UI Parsing (CRUCIAL for `readChat`)");
28750
28871
  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.");
28751
28872
  lines.push("To achieve this, you MUST generate a live test scenario:");
28752
- lines.push("1. Early in your process, send a rich prompt to the IDE using the API:");
28753
- 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"}}\'`');
28873
+ lines.push(`1. Early in your process, send a rich prompt to the IDE using the API:`);
28874
+ 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"}}'\``);
28754
28875
  lines.push("2. Wait a few seconds for the IDE AI to generate these elements in the UI.");
28755
28876
  lines.push("3. Use CDP evaluate to deeply inspect the DOM structure of the newly generated tables, code blocks, thought blocks, and tool calls.");
28756
28877
  lines.push("4. Ensure `readChat` extracts `content` with precise markdown formatting (especially for tables/code) and assigns correct `kind` tags (`thought`, `tool`, `terminal`).");
28757
28878
  lines.push("");
28879
+ lines.push("## \u{1F9EA} MANDATORY: Status Integration Test");
28880
+ lines.push("Before finishing, you MUST run this end-to-end test to verify readChat status transitions work:");
28881
+ lines.push("");
28882
+ lines.push("### Step 1: Baseline \u2014 confirm idle");
28883
+ lines.push("```bash");
28884
+ lines.push(`curl -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/providers/reload`);
28885
+ 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}"}')`);
28886
+ 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')"`);
28887
+ lines.push("```");
28888
+ lines.push("");
28889
+ lines.push("### Step 2: Send a message that triggers generation");
28890
+ lines.push("```bash");
28891
+ 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"}}'`);
28892
+ lines.push("sleep 2");
28893
+ lines.push("```");
28894
+ lines.push("");
28895
+ lines.push("### Step 3: Check generating OR completed");
28896
+ lines.push("The AI may still be generating OR may have finished already. Either generating or idle is acceptable:");
28897
+ lines.push("```bash");
28898
+ 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}"}')`);
28899
+ 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}')"`);
28900
+ lines.push("```");
28901
+ lines.push("");
28902
+ lines.push("### Step 4: Wait for completion and verify new message");
28903
+ lines.push("```bash");
28904
+ lines.push("sleep 10");
28905
+ 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}"}')`);
28906
+ 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)}')"`);
28907
+ lines.push("```");
28908
+ lines.push("");
28909
+ lines.push("If ANY step fails, fix your implementation and re-run the test. Do NOT finish until all 4 steps pass.");
28910
+ lines.push("");
28911
+ if (userComment) {
28912
+ lines.push("## \u26A0\uFE0F User Instructions (HIGH PRIORITY)");
28913
+ lines.push("The user has provided the following additional instructions. Follow them strictly:");
28914
+ lines.push("");
28915
+ lines.push(userComment);
28916
+ lines.push("");
28917
+ }
28758
28918
  lines.push("Start NOW. Do not ask for permission. Explore the DOM -> Code -> Test.");
28759
28919
  return lines.join("\n");
28760
28920
  }
@@ -29101,10 +29261,13 @@ var init_installer = __esm({
29101
29261
  // ../daemon-core/src/boot/daemon-lifecycle.ts
29102
29262
  async function initDaemonComponents(config2) {
29103
29263
  installGlobalInterceptor();
29264
+ const appConfig = loadConfig();
29265
+ const disableUpstream = appConfig.disableUpstream ?? false;
29104
29266
  const providerLoader = new ProviderLoader({
29105
- logFn: config2.providerLogFn
29267
+ logFn: config2.providerLogFn,
29268
+ disableUpstream
29106
29269
  });
29107
- if (!providerLoader.hasUpstream()) {
29270
+ if (!disableUpstream && !providerLoader.hasUpstream()) {
29108
29271
  LOG.info("Provider", "No upstream providers found \u2014 downloading from GitHub...");
29109
29272
  try {
29110
29273
  await providerLoader.fetchLatest();
@@ -30074,24 +30237,6 @@ ${e?.stack || ""}`);
30074
30237
  }
30075
30238
  return sentAny;
30076
30239
  }
30077
- /** Send status_event directly via P2P (generating_started/completed etc.) */
30078
- sendStatusEvent(event) {
30079
- const payload = JSON.stringify({
30080
- type: "status_event",
30081
- payload: event,
30082
- timestamp: Date.now()
30083
- });
30084
- let sentAny = false;
30085
- for (const peer of this.peers.values()) {
30086
- if (peer.state !== "connected" || !peer.dataChannel) continue;
30087
- try {
30088
- peer.dataChannel.sendMessage(payload);
30089
- sentAny = true;
30090
- } catch {
30091
- }
30092
- }
30093
- return sentAny;
30094
- }
30095
30240
  /** Broadcast PTY output to all connected peers */
30096
30241
  broadcastPtyOutput(cliType, data) {
30097
30242
  const prev = this.ptyScrollback.get(cliType) || "";
@@ -30500,6 +30645,15 @@ var init_screenshot_controller = __esm({
30500
30645
  LOG.info("Screenshot", `Daily budget reset (${this.dailyBudgetMinutes}min for today)`);
30501
30646
  }
30502
30647
  }
30648
+ /** Returns current usage stats for reporting to server/dashboard */
30649
+ getUsageStats() {
30650
+ this.checkBudgetReset();
30651
+ return {
30652
+ dailyUsedMinutes: Math.round(this.dailyUsedMs / 6e4),
30653
+ dailyBudgetMinutes: this.dailyBudgetMinutes,
30654
+ budgetExhausted: this.budgetExhausted
30655
+ };
30656
+ }
30503
30657
  // ─── Hash ─────────────────────────────────────
30504
30658
  /** FNV-1a hash of first 1KB + last 1KB for fast delta detection */
30505
30659
  static fnvHash(buf) {
@@ -30580,7 +30734,7 @@ var init_adhdev_daemon = __esm({
30580
30734
  fs11 = __toESM(require("fs"));
30581
30735
  path14 = __toESM(require("path"));
30582
30736
  import_chalk2 = __toESM(require("chalk"));
30583
- pkgVersion = "0.6.19";
30737
+ pkgVersion = "0.6.22";
30584
30738
  if (pkgVersion === "unknown") {
30585
30739
  try {
30586
30740
  const possiblePaths = [
@@ -30647,8 +30801,9 @@ ${err?.stack || ""}`);
30647
30801
  }
30648
30802
  writeDaemonPid(process.pid);
30649
30803
  const config2 = loadConfig();
30650
- if (!config2.connectionToken) {
30651
- console.log(import_chalk2.default.red("\n\u2717 No connection token found."));
30804
+ const authToken = config2.machineSecret || config2.connectionToken;
30805
+ if (!authToken) {
30806
+ console.log(import_chalk2.default.red("\n\u2717 No credentials found."));
30652
30807
  console.log(import_chalk2.default.gray(" Run `adhdev setup` first.\n"));
30653
30808
  process.exit(1);
30654
30809
  }
@@ -30698,7 +30853,7 @@ ${err?.stack || ""}`);
30698
30853
  const instanceId = `daemon_${config2.machineId}`;
30699
30854
  this.serverConn = new ServerConnection({
30700
30855
  serverUrl: options.serverUrl || config2.serverUrl,
30701
- token: config2.connectionToken,
30856
+ token: authToken,
30702
30857
  daemonVersion: pkgVersion,
30703
30858
  cliInfo: {
30704
30859
  type: "adhdev-daemon",
@@ -30790,7 +30945,8 @@ ${err?.stack || ""}`);
30790
30945
  detectedIdes: this.components.detectedIdes.value,
30791
30946
  ideType: this.ideType,
30792
30947
  daemonVersion: pkgVersion,
30793
- instanceManager: this.components.instanceManager
30948
+ instanceManager: this.components.instanceManager,
30949
+ getScreenshotUsage: () => this.screenshotController?.getUsageStats() || null
30794
30950
  });
30795
30951
  this.statusReporter.startReporting();
30796
30952
  this.components.instanceManager.onEvent((event) => {
@@ -31093,11 +31249,17 @@ async function quickSetup() {
31093
31249
  }
31094
31250
  markSetupComplete(["daemon"], ["adhdev"]);
31095
31251
  if (loginResult) {
31096
- updateConfig({
31252
+ const configUpdate = {
31097
31253
  connectionToken: loginResult.connectionToken,
31098
31254
  userEmail: loginResult.email,
31099
31255
  userName: loginResult.name
31100
- });
31256
+ };
31257
+ if (loginResult.machineId && loginResult.machineSecret) {
31258
+ configUpdate.machineId = loginResult.machineId;
31259
+ configUpdate.machineSecret = loginResult.machineSecret;
31260
+ console.log(import_chalk3.default.green(` \u2713 Machine registered`));
31261
+ }
31262
+ updateConfig(configUpdate);
31101
31263
  }
31102
31264
  await installCliOnly();
31103
31265
  await startDaemonFlow();
@@ -31133,7 +31295,16 @@ async function loginFlow() {
31133
31295
  let userCode;
31134
31296
  let verificationUrl;
31135
31297
  try {
31136
- const res = await fetch(`${SERVER_URL}/auth/cli/init`, { method: "POST" });
31298
+ const os17 = await import("os");
31299
+ const res = await fetch(`${SERVER_URL}/auth/cli/init`, {
31300
+ method: "POST",
31301
+ headers: { "Content-Type": "application/json" },
31302
+ body: JSON.stringify({
31303
+ hostname: os17.hostname(),
31304
+ platform: os17.platform(),
31305
+ arch: os17.arch()
31306
+ })
31307
+ });
31137
31308
  if (!res.ok) {
31138
31309
  spinner.fail("Failed to connect to server");
31139
31310
  return null;
@@ -31180,10 +31351,27 @@ async function loginFlow() {
31180
31351
  pollSpinner.succeed(`Authenticated as ${import_chalk3.default.bold(data.user?.email || "user")}`);
31181
31352
  return {
31182
31353
  connectionToken: data.connectionToken,
31354
+ machineId: data.machineId || void 0,
31355
+ machineSecret: data.machineSecret || void 0,
31183
31356
  email: data.user?.email,
31184
31357
  name: data.user?.name
31185
31358
  };
31186
31359
  }
31360
+ if (data.status === "limit_reached") {
31361
+ pollSpinner.fail("Machine limit reached");
31362
+ console.log();
31363
+ 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.`));
31364
+ console.log();
31365
+ console.log(import_chalk3.default.yellow(" To fix this, do one of the following:"));
31366
+ console.log(import_chalk3.default.gray(" 1. Remove an unused machine from the dashboard:"));
31367
+ console.log(import_chalk3.default.gray(" https://adhf.dev/account \u2192 Registered Machines \u2192 \u2715 Remove"));
31368
+ console.log(import_chalk3.default.gray(" 2. Upgrade your plan:"));
31369
+ console.log(import_chalk3.default.gray(" https://adhf.dev/account?tab=billing"));
31370
+ console.log();
31371
+ console.log(import_chalk3.default.gray(" Then run `adhdev setup` again."));
31372
+ console.log();
31373
+ return null;
31374
+ }
31187
31375
  } catch {
31188
31376
  }
31189
31377
  }