adhdev 0.9.2 → 0.9.5

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
@@ -1249,35 +1249,6 @@ var init_saved_sessions = __esm({
1249
1249
  }
1250
1250
  });
1251
1251
 
1252
- // ../../oss/packages/daemon-core/src/providers/provider-session-id.ts
1253
- function normalizeProviderSessionId(providerType, providerSessionId) {
1254
- const normalizedProviderType = typeof providerType === "string" ? providerType.trim() : "";
1255
- const normalizedId = typeof providerSessionId === "string" ? providerSessionId.trim() : "";
1256
- if (!normalizedId) return "";
1257
- const lowered = normalizedId.toLowerCase();
1258
- if (lowered === "undefined" || lowered === "null") return "";
1259
- if (normalizedProviderType === "hermes-cli" && !HERMES_SESSION_ID_RE.test(normalizedId)) {
1260
- return "";
1261
- }
1262
- if (normalizedProviderType === "claude-cli" && !CLAUDE_SESSION_ID_RE.test(normalizedId)) {
1263
- return "";
1264
- }
1265
- return normalizedId;
1266
- }
1267
- function isLegacyVolatileSessionReadKey(key) {
1268
- const normalizedKey = typeof key === "string" ? key.trim() : "";
1269
- if (!normalizedKey) return false;
1270
- return normalizedKey.startsWith("provider:codex:vscode-webview://");
1271
- }
1272
- var HERMES_SESSION_ID_RE, CLAUDE_SESSION_ID_RE;
1273
- var init_provider_session_id = __esm({
1274
- "../../oss/packages/daemon-core/src/providers/provider-session-id.ts"() {
1275
- "use strict";
1276
- HERMES_SESSION_ID_RE = /^\d{8}_\d{6}_[a-z0-9]+$/i;
1277
- CLAUDE_SESSION_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
1278
- }
1279
- });
1280
-
1281
1252
  // ../../oss/packages/daemon-core/src/config/state-store.ts
1282
1253
  function isPlainObject2(value) {
1283
1254
  return !!value && typeof value === "object" && !Array.isArray(value);
@@ -1289,31 +1260,24 @@ function normalizeState(raw) {
1289
1260
  const parsed = isPlainObject2(raw) ? raw : {};
1290
1261
  const recentActivity = (Array.isArray(parsed.recentActivity) ? parsed.recentActivity : []).filter((entry) => {
1291
1262
  if (!isPlainObject2(entry)) return false;
1292
- const normalizedId = normalizeProviderSessionId(
1293
- typeof entry.providerType === "string" ? entry.providerType : "",
1294
- typeof entry.providerSessionId === "string" ? entry.providerSessionId : ""
1295
- );
1296
- if (typeof entry.providerSessionId === "string" && !normalizedId) return false;
1263
+ if (typeof entry.providerSessionId === "string" && !entry.providerSessionId.trim()) return false;
1297
1264
  return true;
1298
1265
  });
1299
1266
  const savedProviderSessions = (Array.isArray(parsed.savedProviderSessions) ? parsed.savedProviderSessions : []).filter((entry) => {
1300
1267
  if (!isPlainObject2(entry)) return false;
1301
- return !!normalizeProviderSessionId(
1302
- typeof entry.providerType === "string" ? entry.providerType : "",
1303
- typeof entry.providerSessionId === "string" ? entry.providerSessionId : ""
1304
- );
1268
+ return typeof entry.providerSessionId === "string" && !!entry.providerSessionId.trim();
1305
1269
  });
1306
1270
  const sessionReads = Object.fromEntries(
1307
- Object.entries(isPlainObject2(parsed.sessionReads) ? parsed.sessionReads : {}).filter(([key, value]) => !isLegacyVolatileSessionReadKey(key) && typeof value === "number" && Number.isFinite(value))
1271
+ Object.entries(isPlainObject2(parsed.sessionReads) ? parsed.sessionReads : {}).filter(([, value]) => typeof value === "number" && Number.isFinite(value))
1308
1272
  );
1309
1273
  const sessionReadMarkers = Object.fromEntries(
1310
- Object.entries(isPlainObject2(parsed.sessionReadMarkers) ? parsed.sessionReadMarkers : {}).filter(([key, value]) => !isLegacyVolatileSessionReadKey(key) && typeof value === "string")
1274
+ Object.entries(isPlainObject2(parsed.sessionReadMarkers) ? parsed.sessionReadMarkers : {}).filter(([, value]) => typeof value === "string")
1311
1275
  );
1312
1276
  const sessionNotificationDismissals = Object.fromEntries(
1313
- Object.entries(isPlainObject2(parsed.sessionNotificationDismissals) ? parsed.sessionNotificationDismissals : {}).filter(([key, value]) => !isLegacyVolatileSessionReadKey(key) && typeof value === "string" && value.length > 0)
1277
+ Object.entries(isPlainObject2(parsed.sessionNotificationDismissals) ? parsed.sessionNotificationDismissals : {}).filter(([, value]) => typeof value === "string" && value.length > 0)
1314
1278
  );
1315
1279
  const sessionNotificationUnreadOverrides = Object.fromEntries(
1316
- Object.entries(isPlainObject2(parsed.sessionNotificationUnreadOverrides) ? parsed.sessionNotificationUnreadOverrides : {}).filter(([key, value]) => !isLegacyVolatileSessionReadKey(key) && typeof value === "string" && value.length > 0)
1280
+ Object.entries(isPlainObject2(parsed.sessionNotificationUnreadOverrides) ? parsed.sessionNotificationUnreadOverrides : {}).filter(([, value]) => typeof value === "string" && value.length > 0)
1317
1281
  );
1318
1282
  return {
1319
1283
  recentActivity,
@@ -1351,7 +1315,6 @@ var init_state_store = __esm({
1351
1315
  import_fs2 = require("fs");
1352
1316
  import_path2 = require("path");
1353
1317
  init_config();
1354
- init_provider_session_id();
1355
1318
  DEFAULT_STATE = {
1356
1319
  recentActivity: [],
1357
1320
  savedProviderSessions: [],
@@ -1433,8 +1396,8 @@ async function detectIDEs(providerLoader) {
1433
1396
  if ((0, import_fs3.existsSync)(bundledCli)) resolvedCli = bundledCli;
1434
1397
  }
1435
1398
  if (!resolvedCli && appPath && os31 === "win32") {
1436
- const { dirname: dirname10 } = await import("path");
1437
- const appDir = dirname10(appPath);
1399
+ const { dirname: dirname11 } = await import("path");
1400
+ const appDir = dirname11(appPath);
1438
1401
  const candidates = [
1439
1402
  `${appDir}\\\\bin\\\\${def.cli}.cmd`,
1440
1403
  `${appDir}\\\\bin\\\\${def.cli}`,
@@ -4046,12 +4009,21 @@ var init_control_effects = __esm({
4046
4009
  function normalizeHistoryComparable(text) {
4047
4010
  return String(text || "").replace(/\s+/g, " ").trim();
4048
4011
  }
4049
- function cleanupHistoryContent(agentType, role, content) {
4012
+ function cleanupHistoryContent(agentType, role, content, historyBehavior) {
4050
4013
  let value = String(content || "").replace(/\r\n/g, "\n").trim();
4051
4014
  if (!value) return "";
4052
- if (agentType === "codex-cli" && role === "assistant") {
4053
- const filtered = value.split("\n").filter((line) => !CODEX_STARTER_PROMPT_RE.test(line.trim())).join("\n").replace(/\n{3,}/g, "\n\n").trim();
4054
- value = filtered;
4015
+ if (role === "assistant" && historyBehavior?.filterAssistantPatterns?.length) {
4016
+ const filters = historyBehavior.filterAssistantPatterns.map((p) => {
4017
+ try {
4018
+ return new RegExp(p, "i");
4019
+ } catch {
4020
+ return null;
4021
+ }
4022
+ }).filter(Boolean);
4023
+ if (filters.length > 0) {
4024
+ const filtered = value.split("\n").filter((line) => !filters.some((re) => re.test(line.trim()))).join("\n").replace(/\n{3,}/g, "\n\n").trim();
4025
+ value = filtered;
4026
+ }
4055
4027
  }
4056
4028
  return value;
4057
4029
  }
@@ -4068,8 +4040,8 @@ function isAdjacentHistoryDuplicate(agentType, previous, next) {
4068
4040
  if (!previous || !next) return false;
4069
4041
  return buildHistoryMessageSignature(agentType, previous) === buildHistoryMessageSignature(agentType, next);
4070
4042
  }
4071
- function collapseReplayAssistantTurns(agentType, messages) {
4072
- if (agentType !== "codex-cli") return messages;
4043
+ function collapseReplayAssistantTurns(messages, historyBehavior) {
4044
+ if (!historyBehavior?.collapseConsecutiveAssistantTurns) return messages;
4073
4045
  const collapsed = [];
4074
4046
  let sawAssistantSinceLastUser = false;
4075
4047
  for (const message of messages) {
@@ -4174,16 +4146,12 @@ function listHistoryFiles(dir, historySessionId) {
4174
4146
  return true;
4175
4147
  }).sort().reverse();
4176
4148
  }
4177
- function normalizeSavedHistorySessionId(agentType, historySessionId) {
4178
- const normalizedId = String(historySessionId || "").trim();
4179
- if (!normalizedId) return "";
4180
- const strictProviderId = normalizeProviderSessionId(agentType, normalizedId);
4181
- if (strictProviderId) return strictProviderId;
4182
- return agentType === "hermes-cli" ? "" : normalizedId;
4149
+ function normalizeSavedHistorySessionId(historySessionId) {
4150
+ return String(historySessionId || "").trim();
4183
4151
  }
4184
- function extractSavedHistorySessionIdFromFile(agentType, file2) {
4152
+ function extractSavedHistorySessionIdFromFile(file2) {
4185
4153
  const match = file2.match(/^([A-Za-z0-9_-]+)_\d{4}-\d{2}-\d{2}\.jsonl$/);
4186
- return normalizeSavedHistorySessionId(agentType, match?.[1] || "");
4154
+ return normalizeSavedHistorySessionId(match?.[1] || "");
4187
4155
  }
4188
4156
  function buildSavedHistoryFileSignatureMap(dir, files) {
4189
4157
  return new Map(files.map((file2) => {
@@ -4362,7 +4330,7 @@ function persistSavedHistoryFileSummaryEntry(agentType, dir, file2, updater) {
4362
4330
  }
4363
4331
  }
4364
4332
  function updateSavedHistoryIndexForSessionStart(agentType, dir, file2, historySessionId, workspace) {
4365
- const normalizedSessionId = normalizeSavedHistorySessionId(agentType, historySessionId);
4333
+ const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId);
4366
4334
  const normalizedWorkspace = String(workspace || "").trim();
4367
4335
  if (!normalizedSessionId || !normalizedWorkspace) return;
4368
4336
  persistSavedHistoryFileSummaryEntry(agentType, dir, file2, (currentSummary) => ({
@@ -4377,7 +4345,7 @@ function updateSavedHistoryIndexForSessionStart(agentType, dir, file2, historySe
4377
4345
  }));
4378
4346
  }
4379
4347
  function updateSavedHistoryIndexForAppendedMessages(agentType, dir, file2, historySessionId, messages) {
4380
- const normalizedSessionId = normalizeSavedHistorySessionId(agentType, historySessionId || "");
4348
+ const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId || "");
4381
4349
  if (!normalizedSessionId || messages.length === 0) return;
4382
4350
  persistSavedHistoryFileSummaryEntry(agentType, dir, file2, (currentSummary) => {
4383
4351
  const nextSummary = {
@@ -4414,8 +4382,8 @@ function updateSavedHistoryIndexForAppendedMessages(agentType, dir, file2, histo
4414
4382
  return nextSummary;
4415
4383
  });
4416
4384
  }
4417
- function computeSavedHistoryFileSummary(agentType, dir, file2) {
4418
- const historySessionId = extractSavedHistorySessionIdFromFile(agentType, file2);
4385
+ function computeSavedHistoryFileSummary(dir, file2) {
4386
+ const historySessionId = extractSavedHistorySessionIdFromFile(file2);
4419
4387
  if (!historySessionId) return null;
4420
4388
  const filePath = path7.join(dir, file2);
4421
4389
  const content = fs3.readFileSync(filePath, "utf-8");
@@ -4509,7 +4477,7 @@ function computeSavedHistorySessionSummaries(agentType, dir, files, fileSignatur
4509
4477
  const cached2 = savedHistoryFileSummaryCache.get(filePath);
4510
4478
  const persisted = persistedEntries.get(file2);
4511
4479
  const reusableEntry = cached2?.signature === signature ? cached2 : persisted?.signature === signature ? persisted : null;
4512
- const fileSummary = reusableEntry?.summary || computeSavedHistoryFileSummary(agentType, dir, file2);
4480
+ const fileSummary = reusableEntry?.summary || computeSavedHistoryFileSummary(dir, file2);
4513
4481
  const nextEntry = reusableEntry || {
4514
4482
  signature,
4515
4483
  summary: fileSummary
@@ -4555,7 +4523,7 @@ function computeSavedHistorySessionSummaries(agentType, dir, files, fileSignatur
4555
4523
  persistedEntries: nextPersistedEntries
4556
4524
  };
4557
4525
  }
4558
- function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, excludeRecentCount = 0) {
4526
+ function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, excludeRecentCount = 0, historyBehavior) {
4559
4527
  try {
4560
4528
  const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
4561
4529
  const dir = path7.join(HISTORY_DIR, sanitized);
@@ -4590,7 +4558,7 @@ function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, ex
4590
4558
  chronological.push(message);
4591
4559
  if (message.role !== "system") lastTurn = message;
4592
4560
  }
4593
- const collapsed = collapseReplayAssistantTurns(agentType, chronological);
4561
+ const collapsed = collapseReplayAssistantTurns(chronological, historyBehavior);
4594
4562
  const boundedLimit = Math.max(1, limit);
4595
4563
  const boundedOffset = Math.max(0, offset);
4596
4564
  const boundedExclude = Math.max(0, Math.min(excludeRecentCount, collapsed.length));
@@ -4603,7 +4571,7 @@ function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, ex
4603
4571
  return { messages: [], hasMore: false };
4604
4572
  }
4605
4573
  }
4606
- function listSavedHistorySessions(agentType, options = {}) {
4574
+ function listSavedHistorySessions(agentType, options = {}, historyBehavior) {
4607
4575
  try {
4608
4576
  const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
4609
4577
  const dir = path7.join(HISTORY_DIR, sanitized);
@@ -4734,7 +4702,7 @@ function rewriteCanonicalSavedHistory(agentType, historySessionId, records) {
4734
4702
  }
4735
4703
  }
4736
4704
  function rebuildHermesSavedHistoryFromCanonicalSession(historySessionId) {
4737
- const normalizedSessionId = normalizeSavedHistorySessionId("hermes-cli", historySessionId);
4705
+ const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId);
4738
4706
  if (!normalizedSessionId) return false;
4739
4707
  try {
4740
4708
  const sessionFilePath = path7.join(os6.homedir(), ".hermes", "sessions", `session_${normalizedSessionId}.json`);
@@ -4883,7 +4851,7 @@ function extractClaudeUserContentParts(content) {
4883
4851
  return parts;
4884
4852
  }
4885
4853
  function rebuildClaudeSavedHistoryFromNativeProject(historySessionId, workspace) {
4886
- const normalizedSessionId = normalizeSavedHistorySessionId("claude-cli", historySessionId);
4854
+ const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId);
4887
4855
  if (!normalizedSessionId) return false;
4888
4856
  try {
4889
4857
  const transcriptPath = resolveClaudeProjectTranscriptPath(normalizedSessionId, workspace);
@@ -4960,7 +4928,7 @@ function rebuildClaudeSavedHistoryFromNativeProject(historySessionId, workspace)
4960
4928
  return false;
4961
4929
  }
4962
4930
  }
4963
- var fs3, path7, os6, HISTORY_DIR, RETAIN_DAYS, SAVED_HISTORY_INDEX_VERSION, SAVED_HISTORY_INDEX_FILE, SAVED_HISTORY_INDEX_LOCK_SUFFIX, SAVED_HISTORY_INDEX_LOCK_WAIT_MS, SAVED_HISTORY_INDEX_LOCK_STALE_MS, SAVED_HISTORY_INDEX_LOCK_POLL_MS, SAVED_HISTORY_ROLLUP_THRESHOLD_BYTES, savedHistorySessionCache, savedHistoryFileSummaryCache, savedHistoryBackgroundRefresh, savedHistoryRollupInFlight, CODEX_STARTER_PROMPT_RE, ChatHistoryWriter;
4931
+ var fs3, path7, os6, HISTORY_DIR, RETAIN_DAYS, SAVED_HISTORY_INDEX_VERSION, SAVED_HISTORY_INDEX_FILE, SAVED_HISTORY_INDEX_LOCK_SUFFIX, SAVED_HISTORY_INDEX_LOCK_WAIT_MS, SAVED_HISTORY_INDEX_LOCK_STALE_MS, SAVED_HISTORY_INDEX_LOCK_POLL_MS, SAVED_HISTORY_ROLLUP_THRESHOLD_BYTES, savedHistorySessionCache, savedHistoryFileSummaryCache, savedHistoryBackgroundRefresh, savedHistoryRollupInFlight, ChatHistoryWriter;
4964
4932
  var init_chat_history = __esm({
4965
4933
  "../../oss/packages/daemon-core/src/config/chat-history.ts"() {
4966
4934
  "use strict";
@@ -4968,7 +4936,6 @@ var init_chat_history = __esm({
4968
4936
  path7 = __toESM(require("path"));
4969
4937
  os6 = __toESM(require("os"));
4970
4938
  init_chat_message_normalization();
4971
- init_provider_session_id();
4972
4939
  HISTORY_DIR = path7.join(os6.homedir(), ".adhdev", "history");
4973
4940
  RETAIN_DAYS = 30;
4974
4941
  SAVED_HISTORY_INDEX_VERSION = 1;
@@ -4982,7 +4949,6 @@ var init_chat_history = __esm({
4982
4949
  savedHistoryFileSummaryCache = /* @__PURE__ */ new Map();
4983
4950
  savedHistoryBackgroundRefresh = /* @__PURE__ */ new Set();
4984
4951
  savedHistoryRollupInFlight = /* @__PURE__ */ new Set();
4985
- CODEX_STARTER_PROMPT_RE = /^(?:[›❯]\s*)?(?:Find and fix a bug in @filename|Improve documentation in @filename|Write tests for @filename|Explain this codebase|Summarize recent commits|Implement \{feature\}|Use \/skills(?: to list available skills)?|Run \/review on my current changes)$/i;
4986
4952
  ChatHistoryWriter = class {
4987
4953
  /** Last seen message count per agent (deduplication) */
4988
4954
  lastSeenCounts = /* @__PURE__ */ new Map();
@@ -5235,7 +5201,7 @@ var init_chat_history = __esm({
5235
5201
  } catch {
5236
5202
  }
5237
5203
  }
5238
- compactHistorySession(agentType, historySessionId) {
5204
+ compactHistorySession(agentType, historySessionId, historyBehavior) {
5239
5205
  const sessionId = String(historySessionId || "").trim();
5240
5206
  if (!sessionId) return;
5241
5207
  try {
@@ -5273,7 +5239,7 @@ var init_chat_history = __esm({
5273
5239
  dedupedAdjacent.push(entry);
5274
5240
  if (entry.role !== "system") lastTurn = entry;
5275
5241
  }
5276
- const collapsed = collapseReplayAssistantTurns(agentType, dedupedAdjacent);
5242
+ const collapsed = collapseReplayAssistantTurns(dedupedAdjacent, historyBehavior);
5277
5243
  if (collapsed.length === 0) {
5278
5244
  fs3.unlinkSync(filePath);
5279
5245
  continue;
@@ -9718,7 +9684,8 @@ async function executeProviderScript(h, args, scriptName) {
9718
9684
  }
9719
9685
  const managed = runtimeSessionId ? h.agentStream?.getManagedSession(runtimeSessionId) : null;
9720
9686
  const targetSessionId = managed?.cdpSessionId || null;
9721
- const IDE_LEVEL_SCRIPTS = provider.type === "claude-code-vscode" ? ["listModes", "setMode", "listModels", "setModel", "setModelGui"] : ["listModes", "setMode", "listModels", "setModel"];
9687
+ const DEFAULT_IDE_LEVEL_SCRIPTS = ["listModes", "setMode", "listModels", "setModel"];
9688
+ const IDE_LEVEL_SCRIPTS = provider.ideLevelScripts ?? DEFAULT_IDE_LEVEL_SCRIPTS;
9722
9689
  if (IDE_LEVEL_SCRIPTS.includes(scriptName)) {
9723
9690
  if (targetSessionId) {
9724
9691
  try {
@@ -14066,10 +14033,6 @@ ${data.message || ""}`.trim();
14066
14033
  throw new Error(`${this.cliName} is still processing the previous prompt`);
14067
14034
  }
14068
14035
  }
14069
- const blockingModal = this.activeModal || this.getStartupConfirmationModal(this.terminalScreen.getText() || "");
14070
- if (blockingModal || this.currentStatus === "waiting_approval") {
14071
- throw new Error(`${this.cliName} is awaiting confirmation before it can accept a prompt`);
14072
- }
14073
14036
  this.isWaitingForResponse = true;
14074
14037
  this.responseBuffer = "";
14075
14038
  this.finishRetryCount = 0;
@@ -14603,6 +14566,28 @@ ${data.message || ""}`.trim();
14603
14566
  }
14604
14567
  });
14605
14568
 
14569
+ // ../../oss/packages/daemon-core/src/providers/provider-session-id.ts
14570
+ function normalizeProviderSessionId(provider, providerSessionId) {
14571
+ const normalizedId = typeof providerSessionId === "string" ? providerSessionId.trim() : "";
14572
+ if (!normalizedId) return "";
14573
+ const lowered = normalizedId.toLowerCase();
14574
+ if (lowered === "undefined" || lowered === "null") return "";
14575
+ const sessionIdPattern = provider?.sessionIdPattern;
14576
+ if (sessionIdPattern) {
14577
+ try {
14578
+ const re = new RegExp(sessionIdPattern, "i");
14579
+ if (!re.test(normalizedId)) return "";
14580
+ } catch {
14581
+ }
14582
+ }
14583
+ return normalizedId;
14584
+ }
14585
+ var init_provider_session_id = __esm({
14586
+ "../../oss/packages/daemon-core/src/providers/provider-session-id.ts"() {
14587
+ "use strict";
14588
+ }
14589
+ });
14590
+
14606
14591
  // ../../oss/packages/daemon-core/src/providers/cli-provider-instance.ts
14607
14592
  function normalizePersistableCliHistoryContent(content) {
14608
14593
  return flattenContent(content).replace(/\s+/g, " ").trim();
@@ -14780,32 +14765,10 @@ var init_cli_provider_instance = __esm({
14780
14765
  }
14781
14766
  async onTick() {
14782
14767
  if (this.providerSessionId) return;
14783
- if (this.type === "hermes-cli" && this.launchMode === "new") return;
14784
- let probedSessionId = null;
14768
+ if (this.provider.resume?.skipProbeOnNewSession && this.launchMode === "new") return;
14785
14769
  const probeConfig = this.provider.sessionProbe;
14786
- if (probeConfig) {
14787
- probedSessionId = this.probeSessionIdFromConfig(probeConfig);
14788
- } else {
14789
- if (this.type === "opencode-cli") {
14790
- probedSessionId = this.probeSessionIdFromConfig({
14791
- dbPath: "~/.local/share/opencode/opencode.db",
14792
- query: "select id from session where directory in ({dirs}) and time_created >= ? and time_archived is null order by time_updated desc limit 1",
14793
- timestampFormat: "unix_ms"
14794
- });
14795
- } else if (this.type === "codex-cli") {
14796
- probedSessionId = this.probeSessionIdFromConfig({
14797
- dbPath: "~/.codex/state_5.sqlite",
14798
- query: "select id from threads where cwd in ({dirs}) and updated_at >= ? and archived = 0 order by updated_at desc limit 1",
14799
- timestampFormat: "unix_s"
14800
- });
14801
- } else if (this.type === "goose-cli") {
14802
- probedSessionId = this.probeSessionIdFromConfig({
14803
- dbPath: "~/.local/share/goose/sessions/sessions.db",
14804
- query: "select id from sessions where working_dir in ({dirs}) and created_at >= ? order by updated_at desc limit 1",
14805
- timestampFormat: "iso"
14806
- });
14807
- }
14808
- }
14770
+ if (!probeConfig) return;
14771
+ const probedSessionId = this.probeSessionIdFromConfig(probeConfig);
14809
14772
  if (probedSessionId) {
14810
14773
  this.promoteProviderSessionId(probedSessionId);
14811
14774
  }
@@ -14857,7 +14820,7 @@ var init_cli_provider_instance = __esm({
14857
14820
  const autoApproveActive = adapterStatus.status === "waiting_approval" && this.shouldAutoApprove();
14858
14821
  const visibleStatus = parseErrorMessage ? "error" : autoApproveActive ? "generating" : adapterStatus.status;
14859
14822
  const parsedProviderSessionId = normalizeProviderSessionId(
14860
- this.type,
14823
+ this.provider,
14861
14824
  typeof parsedStatus?.providerSessionId === "string" ? parsedStatus.providerSessionId : ""
14862
14825
  );
14863
14826
  if (parsedProviderSessionId) {
@@ -15147,7 +15110,7 @@ var init_cli_provider_instance = __esm({
15147
15110
  applyProviderResponse(data, options) {
15148
15111
  if (!data || typeof data !== "object") return;
15149
15112
  const patchedProviderSessionId = normalizeProviderSessionId(
15150
- this.type,
15113
+ this.provider,
15151
15114
  typeof data.providerSessionId === "string" ? data.providerSessionId : ""
15152
15115
  );
15153
15116
  if (patchedProviderSessionId) {
@@ -15385,52 +15348,39 @@ ${effect.notification.body || ""}`.trim();
15385
15348
  }
15386
15349
  syncCanonicalSavedHistoryIfNeeded() {
15387
15350
  if (!this.providerSessionId) return false;
15388
- if (this.type === "hermes-cli") {
15389
- try {
15390
- const canonicalPath = path12.join(os14.homedir(), ".hermes", "sessions", `session_${this.providerSessionId}.json`);
15391
- if (!fs5.existsSync(canonicalPath)) return false;
15392
- const stat4 = fs5.statSync(canonicalPath);
15351
+ const canonicalHistory = this.provider.canonicalHistory;
15352
+ if (!canonicalHistory) return false;
15353
+ try {
15354
+ let rebuilt = false;
15355
+ if (canonicalHistory.format === "hermes-json") {
15356
+ const watchPath = canonicalHistory.watchPath.replace(/^~/, os14.homedir()).replace("{{sessionId}}", this.providerSessionId);
15357
+ if (!fs5.existsSync(watchPath)) return false;
15358
+ const stat4 = fs5.statSync(watchPath);
15393
15359
  if (stat4.mtimeMs <= this.lastCanonicalHermesSyncMtimeMs) return true;
15394
- const rebuilt = rebuildHermesSavedHistoryFromCanonicalSession(this.providerSessionId);
15395
- if (!rebuilt) return false;
15396
- this.lastCanonicalHermesSyncMtimeMs = stat4.mtimeMs;
15397
- const restoredHistory = readChatHistory(this.type, 0, Number.MAX_SAFE_INTEGER, this.providerSessionId);
15398
- this.lastPersistedHistoryMessages = restoredHistory.messages.map((message) => ({
15399
- role: message.role,
15400
- content: message.content,
15401
- kind: message.kind,
15402
- senderName: message.senderName,
15403
- receivedAt: message.receivedAt
15404
- }));
15405
- return true;
15406
- } catch {
15407
- return false;
15408
- }
15409
- }
15410
- if (this.type === "claude-cli") {
15411
- try {
15412
- const rebuilt = rebuildClaudeSavedHistoryFromNativeProject(this.providerSessionId, this.workingDir);
15413
- if (!rebuilt) return false;
15414
- const restoredHistory = readChatHistory(this.type, 0, Number.MAX_SAFE_INTEGER, this.providerSessionId);
15415
- this.lastPersistedHistoryMessages = restoredHistory.messages.map((message) => ({
15416
- role: message.role,
15417
- content: message.content,
15418
- kind: message.kind,
15419
- senderName: message.senderName,
15420
- receivedAt: message.receivedAt
15421
- }));
15422
- return true;
15423
- } catch {
15424
- return false;
15425
- }
15360
+ rebuilt = rebuildHermesSavedHistoryFromCanonicalSession(this.providerSessionId);
15361
+ if (rebuilt) this.lastCanonicalHermesSyncMtimeMs = stat4.mtimeMs;
15362
+ } else if (canonicalHistory.format === "claude-jsonl") {
15363
+ rebuilt = rebuildClaudeSavedHistoryFromNativeProject(this.providerSessionId, this.workingDir);
15364
+ }
15365
+ if (!rebuilt) return false;
15366
+ const restoredHistory = readChatHistory(this.type, 0, Number.MAX_SAFE_INTEGER, this.providerSessionId, 0, this.provider.historyBehavior);
15367
+ this.lastPersistedHistoryMessages = restoredHistory.messages.map((message) => ({
15368
+ role: message.role,
15369
+ content: message.content,
15370
+ kind: message.kind,
15371
+ senderName: message.senderName,
15372
+ receivedAt: message.receivedAt
15373
+ }));
15374
+ return true;
15375
+ } catch {
15376
+ return false;
15426
15377
  }
15427
- return false;
15428
15378
  }
15429
15379
  restorePersistedHistoryFromCurrentSession() {
15430
15380
  if (!this.providerSessionId) return;
15431
15381
  this.syncCanonicalSavedHistoryIfNeeded();
15432
- this.historyWriter.compactHistorySession(this.type, this.providerSessionId);
15433
- const restoredHistory = readChatHistory(this.type, 0, Number.MAX_SAFE_INTEGER, this.providerSessionId);
15382
+ this.historyWriter.compactHistorySession(this.type, this.providerSessionId, this.provider.historyBehavior);
15383
+ const restoredHistory = readChatHistory(this.type, 0, Number.MAX_SAFE_INTEGER, this.providerSessionId, 0, this.provider.historyBehavior);
15434
15384
  this.historyWriter.seedSessionHistory(
15435
15385
  this.type,
15436
15386
  restoredHistory.messages,
@@ -32982,14 +32932,15 @@ function expandResumeArgs(template, sessionId) {
32982
32932
  if (!Array.isArray(template) || template.length === 0) return void 0;
32983
32933
  return template.map((part) => part === "{{id}}" ? sessionId : part);
32984
32934
  }
32985
- function readCodexResumeSessionId(args) {
32986
- const resumeIndex = args.findIndex((arg) => arg === "resume" || arg === "fork");
32935
+ function readSubcommandSessionId(args, subcommands) {
32936
+ const resumeIndex = args.findIndex((arg) => subcommands.includes(arg));
32987
32937
  if (resumeIndex < 0) return void 0;
32988
32938
  const candidate = args[resumeIndex + 1];
32989
32939
  if (!candidate || candidate.startsWith("-")) return void 0;
32990
32940
  return candidate;
32991
32941
  }
32992
- function detectExplicitProviderSessionId(normalizedType, args) {
32942
+ function detectExplicitProviderSessionId(provider, args) {
32943
+ const resume = provider?.resume;
32993
32944
  const explicitResumeId = readArgValue(args, ["--resume", "-r"]);
32994
32945
  if (explicitResumeId) {
32995
32946
  return { providerSessionId: explicitResumeId, launchMode: "resume" };
@@ -33003,19 +32954,20 @@ function detectExplicitProviderSessionId(normalizedType, args) {
33003
32954
  }
33004
32955
  const explicitSessionId = readArgValue(args, ["--session-id"]);
33005
32956
  if (explicitSessionId) {
33006
- if (normalizedType === "goose-cli" && !hasArg(args, ["--resume", "-r"])) {
32957
+ if (resume?.sessionIdIsNewByDefault && !hasArg(args, ["--resume", "-r"])) {
33007
32958
  return { launchMode: "manual" };
33008
32959
  }
33009
- const isResume = normalizedType === "goose-cli" ? hasArg(args, ["--resume", "-r"]) : hasArg(args, ["--continue"]) || hasArg(args, ["--resume", "-r"]);
32960
+ const isResume = resume?.sessionIdIsNewByDefault ? hasArg(args, ["--resume", "-r"]) : hasArg(args, ["--continue"]) || hasArg(args, ["--resume", "-r"]);
33010
32961
  return {
33011
32962
  providerSessionId: explicitSessionId,
33012
32963
  launchMode: isResume ? "resume" : "new"
33013
32964
  };
33014
32965
  }
33015
- if (normalizedType === "codex-cli") {
33016
- const codexSessionId = readCodexResumeSessionId(args);
33017
- if (codexSessionId) {
33018
- return { providerSessionId: codexSessionId, launchMode: "resume" };
32966
+ const subcommands = resume?.sessionIdFromSubcommand;
32967
+ if (Array.isArray(subcommands) && subcommands.length > 0) {
32968
+ const subcommandSessionId = readSubcommandSessionId(args, subcommands);
32969
+ if (subcommandSessionId) {
32970
+ return { providerSessionId: subcommandSessionId, launchMode: "resume" };
33019
32971
  }
33020
32972
  }
33021
32973
  return { launchMode: "manual" };
@@ -33032,7 +32984,7 @@ function resolveCliSessionBinding(provider, normalizedType, cliArgs, requestedRe
33032
32984
  if (!resume?.supported) {
33033
32985
  return { cliArgs: baseArgs, launchMode: "manual" };
33034
32986
  }
33035
- const explicit = detectExplicitProviderSessionId(normalizedType, baseArgs || []);
32987
+ const explicit = detectExplicitProviderSessionId(provider, baseArgs || []);
33036
32988
  if (explicit.providerSessionId) {
33037
32989
  return {
33038
32990
  cliArgs: baseArgs,
@@ -33040,6 +32992,12 @@ function resolveCliSessionBinding(provider, normalizedType, cliArgs, requestedRe
33040
32992
  launchMode: explicit.launchMode
33041
32993
  };
33042
32994
  }
32995
+ if (explicit.launchMode === "manual" && hasArg(baseArgs || [], ["--session-id"])) {
32996
+ return {
32997
+ cliArgs: baseArgs,
32998
+ launchMode: "manual"
32999
+ };
33000
+ }
33043
33001
  if (requestedResumeSessionId) {
33044
33002
  if (resume.sessionIdFormat === "uuid" && !isUuid(requestedResumeSessionId)) {
33045
33003
  throw new Error(`Invalid ${provider?.displayName || provider?.name || normalizedType} session ID: ${requestedResumeSessionId}`);
@@ -33907,10 +33865,10 @@ var init_readdirp = __esm({
33907
33865
  }
33908
33866
  async _formatEntry(dirent, path35) {
33909
33867
  let entry;
33910
- const basename9 = this._isDirent ? dirent.name : dirent;
33868
+ const basename10 = this._isDirent ? dirent.name : dirent;
33911
33869
  try {
33912
- const fullPath = (0, import_node_path.resolve)((0, import_node_path.join)(path35, basename9));
33913
- entry = { path: (0, import_node_path.relative)(this._root, fullPath), fullPath, basename: basename9 };
33870
+ const fullPath = (0, import_node_path.resolve)((0, import_node_path.join)(path35, basename10));
33871
+ entry = { path: (0, import_node_path.relative)(this._root, fullPath), fullPath, basename: basename10 };
33914
33872
  entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
33915
33873
  } catch (err) {
33916
33874
  this._onError(err);
@@ -34441,9 +34399,9 @@ var init_handler2 = __esm({
34441
34399
  _watchWithNodeFs(path35, listener) {
34442
34400
  const opts = this.fsw.options;
34443
34401
  const directory = sp.dirname(path35);
34444
- const basename9 = sp.basename(path35);
34402
+ const basename10 = sp.basename(path35);
34445
34403
  const parent = this.fsw._getWatchedDir(directory);
34446
- parent.add(basename9);
34404
+ parent.add(basename10);
34447
34405
  const absolutePath = sp.resolve(path35);
34448
34406
  const options = {
34449
34407
  persistent: opts.persistent
@@ -34453,7 +34411,7 @@ var init_handler2 = __esm({
34453
34411
  let closer;
34454
34412
  if (opts.usePolling) {
34455
34413
  const enableBin = opts.interval !== opts.binaryInterval;
34456
- options.interval = enableBin && isBinaryPath(basename9) ? opts.binaryInterval : opts.interval;
34414
+ options.interval = enableBin && isBinaryPath(basename10) ? opts.binaryInterval : opts.interval;
34457
34415
  closer = setFsWatchFileListener(path35, absolutePath, options, {
34458
34416
  listener,
34459
34417
  rawEmitter: this.fsw._emitRaw
@@ -34475,11 +34433,11 @@ var init_handler2 = __esm({
34475
34433
  if (this.fsw.closed) {
34476
34434
  return;
34477
34435
  }
34478
- const dirname10 = sp.dirname(file2);
34479
- const basename9 = sp.basename(file2);
34480
- const parent = this.fsw._getWatchedDir(dirname10);
34436
+ const dirname11 = sp.dirname(file2);
34437
+ const basename10 = sp.basename(file2);
34438
+ const parent = this.fsw._getWatchedDir(dirname11);
34481
34439
  let prevStats = stats;
34482
- if (parent.has(basename9))
34440
+ if (parent.has(basename10))
34483
34441
  return;
34484
34442
  const listener = async (path35, newStats) => {
34485
34443
  if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file2, 5))
@@ -34504,9 +34462,9 @@ var init_handler2 = __esm({
34504
34462
  prevStats = newStats2;
34505
34463
  }
34506
34464
  } catch (error48) {
34507
- this.fsw._remove(dirname10, basename9);
34465
+ this.fsw._remove(dirname11, basename10);
34508
34466
  }
34509
- } else if (parent.has(basename9)) {
34467
+ } else if (parent.has(basename10)) {
34510
34468
  const at = newStats.atimeMs;
34511
34469
  const mt = newStats.mtimeMs;
34512
34470
  if (!at || at <= mt || mt !== prevStats.mtimeMs) {
@@ -35642,6 +35600,11 @@ var init_provider_schema = __esm({
35642
35600
  "resume",
35643
35601
  "sessionProbe",
35644
35602
  "approvalPositiveHints",
35603
+ "sessionIdPattern",
35604
+ "historyBehavior",
35605
+ "canonicalHistory",
35606
+ "autoFixProfile",
35607
+ "ideLevelScripts",
35645
35608
  "scripts",
35646
35609
  "vscodeCommands",
35647
35610
  "inputMethod",
@@ -37821,9 +37784,82 @@ function appendUpgradeLog(message) {
37821
37784
  } catch {
37822
37785
  }
37823
37786
  }
37824
- function getNpmExecutable() {
37787
+ function resolveSiblingNpmExecutable(nodeExecutable) {
37788
+ const binDir = path17.dirname(nodeExecutable);
37789
+ const candidates = process.platform === "win32" ? ["npm.cmd", "npm.exe", "npm"] : ["npm"];
37790
+ for (const candidate of candidates) {
37791
+ const candidatePath = path17.join(binDir, candidate);
37792
+ if (fs8.existsSync(candidatePath)) {
37793
+ return candidatePath;
37794
+ }
37795
+ }
37825
37796
  return "npm";
37826
37797
  }
37798
+ function findCurrentPackageRoot(currentCliPath, packageName) {
37799
+ if (!currentCliPath) return null;
37800
+ let resolvedPath = currentCliPath;
37801
+ try {
37802
+ resolvedPath = fs8.realpathSync.native(currentCliPath);
37803
+ } catch {
37804
+ }
37805
+ let currentDir = resolvedPath;
37806
+ try {
37807
+ if (fs8.statSync(resolvedPath).isFile()) {
37808
+ currentDir = path17.dirname(resolvedPath);
37809
+ }
37810
+ } catch {
37811
+ currentDir = path17.dirname(resolvedPath);
37812
+ }
37813
+ while (true) {
37814
+ const packageJsonPath = path17.join(currentDir, "package.json");
37815
+ try {
37816
+ if (fs8.existsSync(packageJsonPath)) {
37817
+ const parsed = JSON.parse(fs8.readFileSync(packageJsonPath, "utf8"));
37818
+ if (parsed?.name === packageName) {
37819
+ const normalized = currentDir.replace(/\\/g, "/");
37820
+ return normalized.includes("/node_modules/") ? currentDir : null;
37821
+ }
37822
+ }
37823
+ } catch {
37824
+ }
37825
+ const parentDir = path17.dirname(currentDir);
37826
+ if (parentDir === currentDir) {
37827
+ return null;
37828
+ }
37829
+ currentDir = parentDir;
37830
+ }
37831
+ }
37832
+ function resolveInstallPrefixFromPackageRoot(packageRoot, packageName) {
37833
+ const nodeModulesDir = packageName.startsWith("@") ? path17.dirname(path17.dirname(packageRoot)) : path17.dirname(packageRoot);
37834
+ if (path17.basename(nodeModulesDir) !== "node_modules") {
37835
+ return null;
37836
+ }
37837
+ const maybeLibDir = path17.dirname(nodeModulesDir);
37838
+ if (path17.basename(maybeLibDir) === "lib") {
37839
+ return path17.dirname(maybeLibDir);
37840
+ }
37841
+ return maybeLibDir;
37842
+ }
37843
+ function resolveCurrentGlobalInstallSurface(options) {
37844
+ const packageRoot = findCurrentPackageRoot(options.currentCliPath || process.argv[1], options.packageName);
37845
+ return {
37846
+ npmExecutable: resolveSiblingNpmExecutable(options.nodeExecutable || process.execPath),
37847
+ packageRoot,
37848
+ installPrefix: packageRoot ? resolveInstallPrefixFromPackageRoot(packageRoot, options.packageName) : null
37849
+ };
37850
+ }
37851
+ function buildPinnedGlobalInstallCommand(options) {
37852
+ const surface = resolveCurrentGlobalInstallSurface(options);
37853
+ const args = ["install", "-g", `${options.packageName}@${options.targetVersion || "latest"}`, "--force"];
37854
+ if (surface.installPrefix) {
37855
+ args.push("--prefix", surface.installPrefix);
37856
+ }
37857
+ return {
37858
+ command: surface.npmExecutable,
37859
+ args,
37860
+ surface
37861
+ };
37862
+ }
37827
37863
  function getNpmExecOptions() {
37828
37864
  return { shell: process.platform === "win32" };
37829
37865
  }
@@ -37886,11 +37922,12 @@ function removeDaemonPidFile() {
37886
37922
  } catch {
37887
37923
  }
37888
37924
  }
37889
- function cleanupStaleGlobalInstallDirs(pkgName) {
37925
+ function cleanupStaleGlobalInstallDirs(pkgName, surface) {
37890
37926
  const npmExecOpts = getNpmExecOptions();
37891
- const npmRoot = (0, import_child_process7.execFileSync)(getNpmExecutable(), ["root", "-g"], { encoding: "utf8", ...npmExecOpts }).trim();
37927
+ const prefixArgs = surface.installPrefix ? ["--prefix", surface.installPrefix] : [];
37928
+ const npmRoot = (0, import_child_process7.execFileSync)(surface.npmExecutable, ["root", "-g", ...prefixArgs], { encoding: "utf8", ...npmExecOpts }).trim();
37892
37929
  if (!npmRoot) return;
37893
- const npmPrefix = (0, import_child_process7.execFileSync)(getNpmExecutable(), ["prefix", "-g"], { encoding: "utf8", ...npmExecOpts }).trim();
37930
+ const npmPrefix = surface.installPrefix || (0, import_child_process7.execFileSync)(surface.npmExecutable, ["prefix", "-g", ...prefixArgs], { encoding: "utf8", ...npmExecOpts }).trim();
37894
37931
  const binDir = process.platform === "win32" ? npmPrefix : path17.join(npmPrefix, "bin");
37895
37932
  const packageBaseName = pkgName.startsWith("@") ? pkgName.split("/")[1] : pkgName;
37896
37933
  const binNames = /* @__PURE__ */ new Set([packageBaseName]);
@@ -37915,7 +37952,7 @@ function cleanupStaleGlobalInstallDirs(pkgName) {
37915
37952
  }
37916
37953
  if (fs8.existsSync(binDir)) {
37917
37954
  for (const entry of fs8.readdirSync(binDir)) {
37918
- if (![...binNames].some((name) => entry.startsWith(`.${name}-`))) continue;
37955
+ if (!Array.from(binNames).some((name) => entry.startsWith(`.${name}-`))) continue;
37919
37956
  fs8.rmSync(path17.join(binDir, entry), { recursive: true, force: true });
37920
37957
  appendUpgradeLog(`Removed stale bin staging entry: ${path17.join(binDir, entry)}`);
37921
37958
  }
@@ -37935,19 +37972,27 @@ function spawnDetachedDaemonUpgradeHelper(payload) {
37935
37972
  async function runDaemonUpgradeHelper(payload) {
37936
37973
  const restartArgv = Array.isArray(payload.restartArgv) ? payload.restartArgv : [];
37937
37974
  const sessionHostAppName = payload.sessionHostAppName || process.env.ADHDEV_SESSION_HOST_NAME || "adhdev";
37975
+ const installCommand = buildPinnedGlobalInstallCommand({
37976
+ packageName: payload.packageName,
37977
+ targetVersion: payload.targetVersion
37978
+ });
37938
37979
  appendUpgradeLog(`Upgrade helper started for ${payload.packageName}@${payload.targetVersion}`);
37980
+ appendUpgradeLog(`Using npm executable: ${installCommand.command}`);
37981
+ if (installCommand.surface.installPrefix) {
37982
+ appendUpgradeLog(`Pinned install prefix: ${installCommand.surface.installPrefix}`);
37983
+ }
37939
37984
  if (Number.isFinite(payload.parentPid) && payload.parentPid > 0) {
37940
37985
  appendUpgradeLog(`Waiting for parent pid ${payload.parentPid} to exit`);
37941
37986
  await waitForPidExit(payload.parentPid, 15e3);
37942
37987
  }
37943
37988
  stopSessionHostProcesses(sessionHostAppName);
37944
37989
  removeDaemonPidFile();
37945
- cleanupStaleGlobalInstallDirs(payload.packageName);
37990
+ cleanupStaleGlobalInstallDirs(payload.packageName, installCommand.surface);
37946
37991
  const spec = `${payload.packageName}@${payload.targetVersion || "latest"}`;
37947
37992
  appendUpgradeLog(`Installing ${spec}`);
37948
37993
  const installOutput = (0, import_child_process7.execFileSync)(
37949
- getNpmExecutable(),
37950
- ["install", "-g", spec, "--force"],
37994
+ installCommand.command,
37995
+ installCommand.args,
37951
37996
  {
37952
37997
  encoding: "utf8",
37953
37998
  stdio: "pipe",
@@ -37960,7 +38005,7 @@ async function runDaemonUpgradeHelper(payload) {
37960
38005
  }
37961
38006
  if (process.platform === "win32") {
37962
38007
  await new Promise((resolve18) => setTimeout(resolve18, 500));
37963
- cleanupStaleGlobalInstallDirs(payload.packageName);
38008
+ cleanupStaleGlobalInstallDirs(payload.packageName, installCommand.surface);
37964
38009
  appendUpgradeLog("Post-install staging cleanup complete");
37965
38010
  }
37966
38011
  if (restartArgv.length > 0) {
@@ -42911,20 +42956,13 @@ function tryKillAutoImplProcess(processRef, signal) {
42911
42956
  } catch {
42912
42957
  }
42913
42958
  }
42959
+ function shouldScheduleAutoStopOnQuiet(options) {
42960
+ return !!options.verification && options.autoImpl?.autoStopOnQuiet === true;
42961
+ }
42914
42962
  function getDefaultAutoImplReference(ctx, category, type) {
42915
- if (category === "cli") {
42916
- return type === "codex-cli" ? "claude-cli" : "codex-cli";
42917
- }
42918
- if (category === "extension") {
42919
- const preferred = ["claude-code-vscode", "codex", "cline", "roo-code"];
42920
- for (const ref of preferred) {
42921
- if (ref === type) continue;
42922
- if (ctx.providerLoader.resolve(ref) || ctx.providerLoader.getMeta(ref)) return ref;
42923
- }
42924
- const all = ctx.providerLoader.getAll();
42925
- const fb = all.find((p) => p.category === "extension" && p.type !== type);
42926
- if (fb?.type) return fb.type;
42927
- }
42963
+ const all = ctx.providerLoader.getAll();
42964
+ const sameCategoryOther = all.find((p) => p.category === category && p.type !== type);
42965
+ if (sameCategoryOther?.type) return sameCategoryOther.type;
42928
42966
  return "antigravity";
42929
42967
  }
42930
42968
  function resolveAutoImplReference(ctx, category, requestedReference, targetType) {
@@ -43242,37 +43280,33 @@ async function handleAutoImplement(ctx, type, req, res) {
43242
43280
  return;
43243
43281
  }
43244
43282
  const command = spawn6.command;
43283
+ const autoImpl = spawn6.autoImpl;
43245
43284
  const interactiveFlags = ["--yolo", "--interactive", "-i"];
43246
43285
  const baseArgs = [...spawn6.args || []].filter((a) => !interactiveFlags.includes(a));
43247
43286
  let shellCmd;
43248
43287
  const isWin = os23.platform() === "win32";
43249
43288
  const escapeArg = (a) => isWin ? `"${a.replace(/"/g, '""')}"` : `'${a.replace(/'/g, "'\\''")}'`;
43250
- if (command === "claude") {
43251
- const args = [...baseArgs, "--dangerously-skip-permissions"];
43289
+ const promptMode = autoImpl?.promptMode ?? "stdin";
43290
+ const extraArgs = autoImpl?.extraArgs ?? [];
43291
+ const rawMetaPrompt = autoImpl?.metaPrompt ? autoImpl.metaPrompt.replace("{{promptFile}}", promptFile) : `Read the file at ${promptFile} and follow ALL the instructions in it exactly. Do not ask questions, just execute.`;
43292
+ if (promptMode === "flag") {
43293
+ const flag = autoImpl?.promptFlag ?? "-p";
43294
+ const args = [...baseArgs, ...extraArgs];
43252
43295
  if (model) args.push("--model", model);
43253
43296
  const escapedArgs = args.map(escapeArg).join(" ");
43254
- const metaPrompt = `Read the file at ${promptFile} and follow ALL the instructions. Implement the specific function requested, then test it via CDP curl targeting 127.0.0.1:19280, wait for confirmation of success, and then close. DO NOT start working on other features not listed in the prompt constraint.`;
43255
- shellCmd = `${command} ${escapedArgs} -p ${escapeArg(metaPrompt)}`;
43256
- } else if (command === "gemini") {
43257
- const args = [...baseArgs, "-y", "-s", "false"];
43258
- if (model) args.push("-m", model);
43259
- const escapedArgs = args.map(escapeArg).join(" ");
43260
- const metaPrompt = `Read the file at ${promptFile} and follow ALL the instructions in it exactly. Do not ask questions, just execute.`;
43261
- shellCmd = `${command} ${escapedArgs} -p ${escapeArg(metaPrompt)}`;
43262
- } else if (command === "codex") {
43263
- const args = ["exec", ...baseArgs];
43264
- if (!args.includes("--dangerously-bypass-approvals-and-sandbox")) {
43265
- args.push("--dangerously-bypass-approvals-and-sandbox");
43266
- }
43267
- if (!args.includes("--skip-git-repo-check")) {
43268
- args.push("--skip-git-repo-check");
43297
+ shellCmd = `${command} ${escapedArgs} ${flag} ${escapeArg(rawMetaPrompt)}`;
43298
+ } else if (promptMode === "subcommand") {
43299
+ const subcommand = autoImpl?.subcommand ?? "";
43300
+ const args = subcommand ? [subcommand, ...baseArgs] : [...baseArgs];
43301
+ for (const extra of extraArgs) {
43302
+ if (!args.includes(extra)) args.push(extra);
43269
43303
  }
43270
43304
  if (model) args.push("--model", model);
43271
43305
  const escapedArgs = args.map(escapeArg).join(" ");
43272
- const metaPrompt = `Read the file at ${promptFile} and follow ALL instructions strictly. DO NOT spend time exploring the filesystem or other providers. You have full authority to implement ALL required script files and independently test them against 127.0.0.1:19280 via CDP CURL. Upon complete validation of ALL assigned files, print exactly "_PIPELINE_COMPLETE_SIGNAL_" to gracefully close the pipeline. DO NOT WAIT FOR APPROVAL, execute completely autonomously.`;
43273
- shellCmd = `${command} ${escapedArgs} ${escapeArg(metaPrompt)}`;
43306
+ shellCmd = `${command} ${escapedArgs} ${escapeArg(rawMetaPrompt)}`;
43274
43307
  } else {
43275
- const escapedArgs = baseArgs.map(escapeArg).join(" ");
43308
+ const args = [...baseArgs, ...extraArgs];
43309
+ const escapedArgs = args.map(escapeArg).join(" ");
43276
43310
  if (isWin) {
43277
43311
  shellCmd = `type "${promptFile}" | ${command} ${escapedArgs}`;
43278
43312
  } else {
@@ -43307,8 +43341,7 @@ async function handleAutoImplement(ctx, type, req, res) {
43307
43341
  stdio: ["pipe", "pipe", "pipe"],
43308
43342
  env: {
43309
43343
  ...process.env,
43310
- ...spawn6.env || {},
43311
- ...command === "gemini" ? { SANDBOX: "1", GEMINI_CLI_NO_RELAUNCH: "1" } : {}
43344
+ ...spawn6.env || {}
43312
43345
  }
43313
43346
  });
43314
43347
  child.on("error", (err2) => {
@@ -43370,7 +43403,7 @@ async function handleAutoImplement(ctx, type, req, res) {
43370
43403
  }
43371
43404
  };
43372
43405
  const scheduleAutoStopForVerification = () => {
43373
- if (!verification || command !== "codex" || completionSignalSeen || autoStopIssued) return;
43406
+ if (!shouldScheduleAutoStopOnQuiet({ verification, autoImpl }) || completionSignalSeen || autoStopIssued) return;
43374
43407
  const elapsed = Date.now() - spawnedAt;
43375
43408
  if (elapsed < 3e4) return;
43376
43409
  clearAutoStopTimer();
@@ -46848,6 +46881,7 @@ __export(src_exports, {
46848
46881
  buildChatMessageSignature: () => buildChatMessageSignature,
46849
46882
  buildChatTailDeliverySignature: () => buildChatTailDeliverySignature,
46850
46883
  buildMachineInfo: () => buildMachineInfo,
46884
+ buildPinnedGlobalInstallCommand: () => buildPinnedGlobalInstallCommand,
46851
46885
  buildRuntimeSystemChatMessage: () => buildRuntimeSystemChatMessage,
46852
46886
  buildSessionEntries: () => buildSessionEntries,
46853
46887
  buildSessionModalDeliverySignature: () => buildSessionModalDeliverySignature,
@@ -46930,6 +46964,7 @@ __export(src_exports, {
46930
46964
  resetDebugRuntimeConfig: () => resetDebugRuntimeConfig,
46931
46965
  resetState: () => resetState,
46932
46966
  resolveChatMessageKind: () => resolveChatMessageKind,
46967
+ resolveCurrentGlobalInstallSurface: () => resolveCurrentGlobalInstallSurface,
46933
46968
  resolveDebugRuntimeConfig: () => resolveDebugRuntimeConfig,
46934
46969
  resolveSessionHostAppName: () => resolveSessionHostAppName,
46935
46970
  resolveSessionHostAppNameResolution: () => resolveSessionHostAppNameResolution,
@@ -78239,6 +78274,33 @@ var init_open = __esm({
78239
78274
  }
78240
78275
  });
78241
78276
 
78277
+ // src/version.ts
78278
+ function resolvePackageVersion(options) {
78279
+ const injectedVersion = options?.injectedVersion || "unknown";
78280
+ const dir = options?.dirname || __dirname;
78281
+ const possiblePaths = [
78282
+ (0, import_path3.join)(dir, "..", "..", "package.json"),
78283
+ (0, import_path3.join)(dir, "..", "package.json"),
78284
+ (0, import_path3.join)(dir, "package.json")
78285
+ ];
78286
+ for (const p of possiblePaths) {
78287
+ try {
78288
+ const data = JSON.parse((0, import_fs6.readFileSync)(p, "utf-8"));
78289
+ if (data.version) return data.version;
78290
+ } catch {
78291
+ }
78292
+ }
78293
+ return injectedVersion;
78294
+ }
78295
+ var import_fs6, import_path3;
78296
+ var init_version = __esm({
78297
+ "src/version.ts"() {
78298
+ "use strict";
78299
+ import_fs6 = require("fs");
78300
+ import_path3 = require("path");
78301
+ }
78302
+ });
78303
+
78242
78304
  // src/server-connection.ts
78243
78305
  var import_ws2, ServerConnection;
78244
78306
  var init_server_connection = __esm({
@@ -86927,33 +86989,6 @@ var init_session_host_controller = __esm({
86927
86989
  }
86928
86990
  });
86929
86991
 
86930
- // src/version.ts
86931
- function resolvePackageVersion(options) {
86932
- const injectedVersion = options?.injectedVersion || "unknown";
86933
- const dir = options?.dirname || __dirname;
86934
- const possiblePaths = [
86935
- (0, import_path3.join)(dir, "..", "..", "package.json"),
86936
- (0, import_path3.join)(dir, "..", "package.json"),
86937
- (0, import_path3.join)(dir, "package.json")
86938
- ];
86939
- for (const p of possiblePaths) {
86940
- try {
86941
- const data = JSON.parse((0, import_fs6.readFileSync)(p, "utf-8"));
86942
- if (data.version) return data.version;
86943
- } catch {
86944
- }
86945
- }
86946
- return injectedVersion;
86947
- }
86948
- var import_fs6, import_path3;
86949
- var init_version = __esm({
86950
- "src/version.ts"() {
86951
- "use strict";
86952
- import_fs6 = require("fs");
86953
- import_path3 = require("path");
86954
- }
86955
- });
86956
-
86957
86992
  // src/adhdev-daemon.ts
86958
86993
  var adhdev_daemon_exports = {};
86959
86994
  __export(adhdev_daemon_exports, {
@@ -87095,7 +87130,7 @@ var init_adhdev_daemon = __esm({
87095
87130
  init_version();
87096
87131
  init_src();
87097
87132
  init_runtime_defaults();
87098
- pkgVersion = resolvePackageVersion({ injectedVersion: "0.9.2" });
87133
+ pkgVersion = resolvePackageVersion({ injectedVersion: "0.9.5" });
87099
87134
  AdhdevDaemon = class _AdhdevDaemon {
87100
87135
  localHttpServer = null;
87101
87136
  localWss = null;
@@ -88153,6 +88188,36 @@ function hasCloudMachineAuth() {
88153
88188
  const config2 = loadConfig();
88154
88189
  return Boolean(config2.machineSecret && config2.machineSecret.trim());
88155
88190
  }
88191
+ function readLatestPublishedCliVersion(execFileSyncLocal) {
88192
+ const surface = resolveCurrentGlobalInstallSurface({ packageName: "adhdev" });
88193
+ try {
88194
+ return execFileSyncLocal(surface.npmExecutable, ["view", "adhdev", "version"], {
88195
+ encoding: "utf-8",
88196
+ timeout: 5e3,
88197
+ stdio: ["pipe", "pipe", "pipe"]
88198
+ }).trim();
88199
+ } catch {
88200
+ return null;
88201
+ }
88202
+ }
88203
+ function readInstalledGlobalCliVersion(execFileSyncLocal) {
88204
+ const surface = resolveCurrentGlobalInstallSurface({ packageName: "adhdev" });
88205
+ const args = ["list", "-g", "adhdev", "--json"];
88206
+ if (surface.installPrefix) {
88207
+ args.push("--prefix", surface.installPrefix);
88208
+ }
88209
+ try {
88210
+ const result = execFileSyncLocal(surface.npmExecutable, args, {
88211
+ encoding: "utf-8",
88212
+ timeout: 5e3,
88213
+ stdio: ["pipe", "pipe", "pipe"]
88214
+ });
88215
+ const parsed = JSON.parse(result);
88216
+ return parsed.dependencies?.adhdev?.version || null;
88217
+ } catch {
88218
+ return null;
88219
+ }
88220
+ }
88156
88221
  async function runWizard(options = {}) {
88157
88222
  console.log(LOGO);
88158
88223
  if (isSetupComplete() && hasCloudMachineAuth() && !options.force) {
@@ -88168,27 +88233,10 @@ async function runWizard(options = {}) {
88168
88233
  }
88169
88234
  async function checkForUpdate() {
88170
88235
  try {
88171
- const { execSync: execSync8 } = await import("child_process");
88172
- let currentVersion = null;
88173
- try {
88174
- currentVersion = execSync8("adhdev --version", {
88175
- encoding: "utf-8",
88176
- timeout: 3e3,
88177
- stdio: ["pipe", "pipe", "pipe"]
88178
- }).trim();
88179
- } catch {
88180
- return;
88181
- }
88182
- let latestVersion = null;
88183
- try {
88184
- latestVersion = execSync8("npm show adhdev version", {
88185
- encoding: "utf-8",
88186
- timeout: 5e3,
88187
- stdio: ["pipe", "pipe", "pipe"]
88188
- }).trim();
88189
- } catch {
88190
- return;
88191
- }
88236
+ const { execFileSync: execFileSync5 } = await import("child_process");
88237
+ const currentVersion = resolvePackageVersion();
88238
+ const latestVersion = readLatestPublishedCliVersion(execFileSync5);
88239
+ if (!latestVersion) return;
88192
88240
  if (!currentVersion || !latestVersion || currentVersion === latestVersion) return;
88193
88241
  console.log(source_default.yellow(` Update available: ${currentVersion} \u2192 ${latestVersion}`));
88194
88242
  const { doUpdate } = await (await Promise.resolve().then(() => (init_lib(), lib_exports))).default.prompt([{
@@ -88203,7 +88251,8 @@ async function checkForUpdate() {
88203
88251
  }
88204
88252
  const spinner = (await Promise.resolve().then(() => (init_ora(), ora_exports))).default("Updating adhdev CLI...").start();
88205
88253
  try {
88206
- execSync8("npm install -g adhdev@latest", {
88254
+ const installCommand = buildPinnedGlobalInstallCommand({ packageName: "adhdev", targetVersion: "latest" });
88255
+ execFileSync5(installCommand.command, installCommand.args, {
88207
88256
  encoding: "utf-8",
88208
88257
  timeout: 6e4,
88209
88258
  stdio: ["pipe", "pipe", "pipe"]
@@ -88441,18 +88490,8 @@ async function startDaemonFlow() {
88441
88490
  }
88442
88491
  }
88443
88492
  async function installCliOnly() {
88444
- const { execSync: execSyncLocal } = await import("child_process");
88445
- let currentVersion = null;
88446
- try {
88447
- const result = execSyncLocal("npm list -g adhdev --json 2>/dev/null || npm list -g adhdev --json 2>nul", {
88448
- encoding: "utf-8",
88449
- timeout: 5e3,
88450
- stdio: ["pipe", "pipe", "pipe"]
88451
- });
88452
- const parsed = JSON.parse(result);
88453
- currentVersion = parsed.dependencies?.adhdev?.version || null;
88454
- } catch {
88455
- }
88493
+ const { execFileSync: execFileSyncLocal } = await import("child_process");
88494
+ const currentVersion = readInstalledGlobalCliVersion(execFileSyncLocal);
88456
88495
  const isNpx = process.env.npm_execpath?.includes("npx") || process.argv[1]?.includes("npx") || process.argv[1]?.includes("_npx");
88457
88496
  console.log(source_default.bold("\n\u{1F527} ADHDev CLI\n"));
88458
88497
  console.log(source_default.gray(" The `adhdev` command lets you:"));
@@ -88463,15 +88502,7 @@ async function installCliOnly() {
88463
88502
  console.log();
88464
88503
  if (currentVersion) {
88465
88504
  console.log(source_default.green(` \u2713 Currently installed: v${currentVersion}`));
88466
- let latestVersion = null;
88467
- try {
88468
- latestVersion = execSyncLocal("npm show adhdev version", {
88469
- encoding: "utf-8",
88470
- timeout: 5e3,
88471
- stdio: ["pipe", "pipe", "pipe"]
88472
- }).trim();
88473
- } catch {
88474
- }
88505
+ const latestVersion = readLatestPublishedCliVersion(execFileSyncLocal);
88475
88506
  if (latestVersion && currentVersion === latestVersion) {
88476
88507
  console.log(source_default.gray(" (Already up to date)"));
88477
88508
  return;
@@ -88506,20 +88537,13 @@ async function installCliOnly() {
88506
88537
  }
88507
88538
  const installSpinner = ora2("Installing adhdev CLI...").start();
88508
88539
  try {
88509
- execSyncLocal("npm install -g adhdev@latest", {
88540
+ const installCommand = buildPinnedGlobalInstallCommand({ packageName: "adhdev", targetVersion: "latest" });
88541
+ execFileSyncLocal(installCommand.command, installCommand.args, {
88510
88542
  encoding: "utf-8",
88511
88543
  timeout: 6e4,
88512
88544
  stdio: ["pipe", "pipe", "pipe"]
88513
88545
  });
88514
- let newVersion = "latest";
88515
- try {
88516
- newVersion = execSyncLocal("adhdev --version 2>/dev/null || adhdev --version 2>nul", {
88517
- encoding: "utf-8",
88518
- timeout: 5e3,
88519
- stdio: ["pipe", "pipe", "pipe"]
88520
- }).trim();
88521
- } catch {
88522
- }
88546
+ const newVersion = readInstalledGlobalCliVersion(execFileSyncLocal) || "latest";
88523
88547
  installSpinner.succeed(`adhdev CLI ${currentVersion ? "updated" : "installed"} \u2713 (v${newVersion})`);
88524
88548
  console.log(source_default.gray(" Try: adhdev daemon"));
88525
88549
  console.log();
@@ -88543,6 +88567,7 @@ var init_wizard = __esm({
88543
88567
  init_ora();
88544
88568
  init_open();
88545
88569
  init_src();
88570
+ init_version();
88546
88571
  SERVER_URL = process.env.ADHDEV_SERVER_URL || "https://api.adhf.dev";
88547
88572
  LOGO = `
88548
88573
  ${source_default.cyan("\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557")}
@@ -88901,14 +88926,25 @@ var init_supported = __esm({
88901
88926
  "source": "docs/site/data/provider-catalog.mjs"
88902
88927
  },
88903
88928
  "cursor-cli": {
88904
- "status": "unverified",
88905
- "testedOn": [],
88906
- "testedVersions": [],
88907
- "validatedFlows": [],
88908
- "lastValidated": null,
88909
- "notes": "",
88910
- "evidence": "",
88911
- "owner": "community",
88929
+ "status": "partial",
88930
+ "testedOn": [
88931
+ "macOS 26.4"
88932
+ ],
88933
+ "testedVersions": [
88934
+ "Cursor 3.0.16",
88935
+ "cursor-agent 2026.04.17-787b533"
88936
+ ],
88937
+ "validatedFlows": [
88938
+ "launch",
88939
+ "send_chat",
88940
+ "read_chat",
88941
+ "resume",
88942
+ "list_models"
88943
+ ],
88944
+ "lastValidated": "2026-04-23",
88945
+ "notes": "Provider root was updated to launch `cursor agent` instead of the obsolete standalone `agent` binary. Fresh launch via ADHDev plus headless send/read, explicit UUID resume, plan mode, and model listing were validated locally after Cursor login. Interactive in-session `/model` switching now has provider controls/scripts but still needs a direct ADHDev live-session validation before this provider can move beyond partial.",
88946
+ "evidence": "Manual local validation with `adhdev launch cursor-cli`, `cursor agent --print`, `cursor agent --resume`, `cursor agent --list-models`, and provider contract tests on 2026-04-23",
88947
+ "owner": "core",
88912
88948
  "source": "docs/site/data/provider-catalog.mjs"
88913
88949
  },
88914
88950
  "gemini-cli": {
@@ -89422,7 +89458,7 @@ var init_supported = __esm({
89422
89458
  "aider-cli": "unverified",
89423
89459
  "claude-cli": "partial",
89424
89460
  "codex-cli": "partial",
89425
- "cursor-cli": "unverified",
89461
+ "cursor-cli": "partial",
89426
89462
  "gemini-cli": "unverified",
89427
89463
  "github-copilot-cli": "unverified",
89428
89464
  "goose-cli": "unverified",
@@ -91512,9 +91548,9 @@ function registerDaemonCommands(program2, pkgVersion3) {
91512
91548
  // src/cli/doctor-commands.ts
91513
91549
  init_source();
91514
91550
  var import_child_process13 = require("child_process");
91515
- var fs25 = __toESM(require("fs"));
91516
- var os29 = __toESM(require("os"));
91517
- var path31 = __toESM(require("path"));
91551
+ var fs26 = __toESM(require("fs"));
91552
+ var os30 = __toESM(require("os"));
91553
+ var path33 = __toESM(require("path"));
91518
91554
  init_src();
91519
91555
  init_session_host();
91520
91556
 
@@ -91588,6 +91624,27 @@ function evaluateNodeInstallDrift(probe) {
91588
91624
  detail: `node install drift: current runtime ${currentNodeVersion} vs resolved binary ${commandNodeVersion}`
91589
91625
  };
91590
91626
  }
91627
+ function evaluateServiceDefinitionDrift(probe) {
91628
+ const serviceLabel = probe.serviceKind === "launchd" ? "launchd" : "startup script";
91629
+ const installed = String(probe.installedDefinition || "").trim();
91630
+ const expected = String(probe.expectedDefinition || "").trim();
91631
+ if (!installed || !expected) {
91632
+ return {
91633
+ ok: true,
91634
+ detail: `${serviceLabel} definition unavailable for comparison (${probe.servicePath})`
91635
+ };
91636
+ }
91637
+ if (installed === expected) {
91638
+ return {
91639
+ ok: true,
91640
+ detail: `${serviceLabel} service definition matches current install (${probe.servicePath})`
91641
+ };
91642
+ }
91643
+ return {
91644
+ ok: false,
91645
+ detail: `outdated service definition (${probe.servicePath})`
91646
+ };
91647
+ }
91591
91648
  function buildDoctorAdvice(input) {
91592
91649
  const advice = [];
91593
91650
  if (input.adhdevCheck && !input.adhdevCheck.ok) {
@@ -91602,16 +91659,385 @@ function buildDoctorAdvice(input) {
91602
91659
  if (input.nodeDriftCheck && !input.nodeDriftCheck.ok) {
91603
91660
  advice.push("Align the Node version that launches adhdev with the Node install root that owns the PATH binary (for nvm users: run `nvm use <version>` and reopen the shell).");
91604
91661
  }
91662
+ if (input.serviceCheck && !input.serviceCheck.ok) {
91663
+ advice.push(`Reinstall the background service${input.servicePath ? ` at ${input.servicePath}` : ""} so it points at the current adhdev install. Run: adhdev service install`);
91664
+ }
91605
91665
  return advice;
91606
91666
  }
91607
91667
 
91668
+ // src/cli/service-commands.ts
91669
+ var import_node_fs6 = __toESM(require("fs"));
91670
+ var import_node_path4 = __toESM(require("path"));
91671
+ var import_node_os6 = __toESM(require("os"));
91672
+ var import_node_child_process6 = require("child_process");
91673
+ init_source();
91674
+ init_src();
91675
+ var DEFAULT_LOCAL_DAEMON_HEALTH_TIMEOUT_MS3 = 1500;
91676
+ var LAUNCHD_LABEL = "dev.adhf.daemon";
91677
+ var ADHDEV_DIR = import_node_path4.default.join(import_node_os6.default.homedir(), ".adhdev");
91678
+ var LOG_OUT = import_node_path4.default.join(ADHDEV_DIR, "daemon-launchd.out");
91679
+ var LOG_ERR = import_node_path4.default.join(ADHDEV_DIR, "daemon-launchd.err");
91680
+ var MAX_LOG_SIZE2 = 10 * 1024 * 1024;
91681
+ function getDarwinPlistPath() {
91682
+ return import_node_path4.default.join(import_node_os6.default.homedir(), "Library", "LaunchAgents", `${LAUNCHD_LABEL}.plist`);
91683
+ }
91684
+ function getWindowsStartupDir() {
91685
+ const appData = process.env.APPDATA || import_node_path4.default.join(import_node_os6.default.homedir(), "AppData", "Roaming");
91686
+ return import_node_path4.default.join(appData, "Microsoft", "Windows", "Start Menu", "Programs", "Startup");
91687
+ }
91688
+ function getWindowsVbsPath() {
91689
+ return import_node_path4.default.join(getWindowsStartupDir(), "adhdev-daemon.vbs");
91690
+ }
91691
+ function resolveCliPath() {
91692
+ return import_node_fs6.default.realpathSync(process.argv[1]);
91693
+ }
91694
+ function ensureDir(dir) {
91695
+ if (!import_node_fs6.default.existsSync(dir)) import_node_fs6.default.mkdirSync(dir, { recursive: true });
91696
+ }
91697
+ async function fetchHealth() {
91698
+ const controller = new AbortController();
91699
+ const timer = setTimeout(() => controller.abort(), DEFAULT_LOCAL_DAEMON_HEALTH_TIMEOUT_MS3);
91700
+ try {
91701
+ const res = await fetch(`http://127.0.0.1:${DEFAULT_DAEMON_PORT}/health`, { signal: controller.signal });
91702
+ if (!res.ok) return null;
91703
+ return await res.json();
91704
+ } catch {
91705
+ return null;
91706
+ } finally {
91707
+ clearTimeout(timer);
91708
+ }
91709
+ }
91710
+ function getProcessInfo(pid) {
91711
+ try {
91712
+ if (process.platform === "win32") {
91713
+ const out = (0, import_node_child_process6.execSync)(`tasklist /FI "PID eq ${pid}" /FO CSV /NH`, { encoding: "utf-8" });
91714
+ const match = out.match(/"(\d[\d,]+)\sK"/);
91715
+ const memKB = match ? parseInt(match[1].replace(/,/g, ""), 10) : 0;
91716
+ return { uptime: "-", memMB: Math.round(memKB / 1024) };
91717
+ } else {
91718
+ const out = (0, import_node_child_process6.execSync)(`ps -o etime=,rss= -p ${pid}`, { encoding: "utf-8" }).trim();
91719
+ const parts = out.split(/\s+/);
91720
+ const etime = parts[0] || "-";
91721
+ const rssKB = parseInt(parts[1] || "0", 10);
91722
+ return { uptime: formatElapsed(etime), memMB: Math.round(rssKB / 1024) };
91723
+ }
91724
+ } catch {
91725
+ return null;
91726
+ }
91727
+ }
91728
+ function formatElapsed(etime) {
91729
+ const parts = etime.replace("-", ":").split(":").map(Number);
91730
+ if (parts.length === 4) return `${parts[0]}d ${parts[1]}h ${parts[2]}m`;
91731
+ if (parts.length === 3) return `${parts[0]}h ${parts[1]}m`;
91732
+ if (parts.length === 2) return `${parts[0]}m ${parts[1]}s`;
91733
+ return etime;
91734
+ }
91735
+ function rotateLogIfNeeded(logPath) {
91736
+ try {
91737
+ if (!import_node_fs6.default.existsSync(logPath)) return;
91738
+ const stat4 = import_node_fs6.default.statSync(logPath);
91739
+ if (stat4.size > MAX_LOG_SIZE2) {
91740
+ const rotated = logPath + ".old";
91741
+ if (import_node_fs6.default.existsSync(rotated)) import_node_fs6.default.unlinkSync(rotated);
91742
+ import_node_fs6.default.renameSync(logPath, rotated);
91743
+ import_node_fs6.default.writeFileSync(logPath, `[log rotated at ${(/* @__PURE__ */ new Date()).toISOString()}]
91744
+ `, "utf-8");
91745
+ }
91746
+ } catch {
91747
+ }
91748
+ }
91749
+ function rotateLogs() {
91750
+ rotateLogIfNeeded(LOG_OUT);
91751
+ rotateLogIfNeeded(LOG_ERR);
91752
+ }
91753
+ function buildPlist(nodeExe, cliExe) {
91754
+ const brewPrefix = import_node_fs6.default.existsSync("/opt/homebrew/bin") ? "/opt/homebrew/bin" : "/usr/local/bin";
91755
+ const nodeDir = import_node_path4.default.dirname(nodeExe);
91756
+ const pathEntries = /* @__PURE__ */ new Set([nodeDir, brewPrefix, "/usr/local/bin", "/usr/bin", "/bin", "/usr/sbin", "/sbin"]);
91757
+ const pathValue = Array.from(pathEntries).join(":");
91758
+ return `<?xml version="1.0" encoding="UTF-8"?>
91759
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
91760
+ <plist version="1.0">
91761
+ <dict>
91762
+ <key>Label</key>
91763
+ <string>${LAUNCHD_LABEL}</string>
91764
+ <key>ProgramArguments</key>
91765
+ <array>
91766
+ <string>${nodeExe}</string>
91767
+ <string>${cliExe}</string>
91768
+ <string>daemon</string>
91769
+ </array>
91770
+ <key>RunAtLoad</key>
91771
+ <true/>
91772
+ <key>KeepAlive</key>
91773
+ <dict>
91774
+ <key>SuccessfulExit</key>
91775
+ <false/>
91776
+ </dict>
91777
+ <key>ThrottleInterval</key>
91778
+ <integer>30</integer>
91779
+ <key>StandardOutPath</key>
91780
+ <string>${LOG_OUT}</string>
91781
+ <key>StandardErrorPath</key>
91782
+ <string>${LOG_ERR}</string>
91783
+ <key>EnvironmentVariables</key>
91784
+ <dict>
91785
+ <key>PATH</key>
91786
+ <string>${pathValue}</string>
91787
+ </dict>
91788
+ </dict>
91789
+ </plist>`;
91790
+ }
91791
+ function installDarwin(nodeExe, cliExe) {
91792
+ const plistPath = getDarwinPlistPath();
91793
+ ensureDir(ADHDEV_DIR);
91794
+ ensureDir(import_node_path4.default.dirname(plistPath));
91795
+ import_node_fs6.default.writeFileSync(plistPath, buildPlist(nodeExe, cliExe), "utf-8");
91796
+ console.log(source_default.gray(` Plist: ${plistPath}`));
91797
+ try {
91798
+ (0, import_node_child_process6.execSync)(`launchctl unload "${plistPath}" 2>/dev/null`, { stdio: "ignore" });
91799
+ } catch {
91800
+ }
91801
+ try {
91802
+ (0, import_node_child_process6.execSync)(`launchctl load -w "${plistPath}"`, { stdio: "ignore" });
91803
+ console.log(source_default.green("\n \u2713 Registered as LaunchAgent \u2014 daemon will start on login."));
91804
+ console.log(source_default.gray(` Logs: ~/.adhdev/daemon-launchd.{out,err}`));
91805
+ } catch (e) {
91806
+ console.log(source_default.red(`
91807
+ \u2717 launchctl load failed: ${e.message}`));
91808
+ }
91809
+ }
91810
+ function uninstallDarwin() {
91811
+ const plistPath = getDarwinPlistPath();
91812
+ if (!import_node_fs6.default.existsSync(plistPath)) {
91813
+ console.log(source_default.yellow("\n \u26A0 Service is not installed."));
91814
+ return;
91815
+ }
91816
+ try {
91817
+ (0, import_node_child_process6.execSync)(`launchctl unload "${plistPath}" 2>/dev/null`, { stdio: "ignore" });
91818
+ } catch {
91819
+ }
91820
+ import_node_fs6.default.unlinkSync(plistPath);
91821
+ console.log(source_default.green("\n \u2713 Removed LaunchAgent. Daemon will no longer auto-start."));
91822
+ }
91823
+ function isInstalledDarwin() {
91824
+ return import_node_fs6.default.existsSync(getDarwinPlistPath());
91825
+ }
91826
+ function buildVbs(nodeExe, cliExe) {
91827
+ const logFile = import_node_path4.default.join(ADHDEV_DIR, "daemon-service.log").replace(/\\/g, "\\\\");
91828
+ const escapedNodeExe = nodeExe.replace(/\\/g, "\\\\");
91829
+ const escapedCliExe = cliExe.replace(/\\/g, "\\\\");
91830
+ return `' ADHDev Daemon Auto-Start (generated by adhdev service install)
91831
+ Set WshShell = CreateObject("WScript.Shell")
91832
+ WshShell.Run "cmd.exe /c """"${escapedNodeExe}"""" """"${escapedCliExe}"""" daemon >> """"${logFile}"""" 2>&1", 0, False
91833
+ `;
91834
+ }
91835
+ function installWindows(nodeExe, cliExe) {
91836
+ const vbsPath = getWindowsVbsPath();
91837
+ ensureDir(ADHDEV_DIR);
91838
+ ensureDir(import_node_path4.default.dirname(vbsPath));
91839
+ import_node_fs6.default.writeFileSync(vbsPath, buildVbs(nodeExe, cliExe), "utf-8");
91840
+ console.log(source_default.gray(` Startup script: ${vbsPath}`));
91841
+ console.log(source_default.green("\n \u2713 Registered in Startup folder \u2014 daemon will start on login (hidden)."));
91842
+ console.log(source_default.gray(` Logs: ${import_node_path4.default.join(ADHDEV_DIR, "daemon-service.log")}`));
91843
+ console.log(source_default.gray(" To start now without rebooting, run: adhdev daemon"));
91844
+ }
91845
+ function uninstallWindows() {
91846
+ const vbsPath = getWindowsVbsPath();
91847
+ if (!import_node_fs6.default.existsSync(vbsPath)) {
91848
+ console.log(source_default.yellow("\n \u26A0 Service is not installed."));
91849
+ return;
91850
+ }
91851
+ import_node_fs6.default.unlinkSync(vbsPath);
91852
+ console.log(source_default.green("\n \u2713 Removed Startup script. Daemon will no longer auto-start."));
91853
+ console.log(source_default.gray(" Note: a currently running daemon is not affected. Stop with: adhdev daemon:stop"));
91854
+ }
91855
+ function isInstalledWindows() {
91856
+ return import_node_fs6.default.existsSync(getWindowsVbsPath());
91857
+ }
91858
+ function registerServiceCommands(program2) {
91859
+ const svc = program2.command("service").description("\u{1F50C} Manage ADHDev as an OS background auto-start service");
91860
+ svc.command("install").description("Register ADHDev daemon to start automatically on login").action(async () => {
91861
+ console.log(source_default.bold("\n \u{1F680} Installing ADHDev Background Service"));
91862
+ const platform13 = import_node_os6.default.platform();
91863
+ const nodeExe = process.execPath;
91864
+ const cliExe = resolveCliPath();
91865
+ console.log(source_default.gray(` Node: ${nodeExe}`));
91866
+ console.log(source_default.gray(` CLI: ${cliExe}`));
91867
+ console.log(source_default.gray(` Platform: ${platform13}`));
91868
+ if (platform13 === "darwin") {
91869
+ installDarwin(nodeExe, cliExe);
91870
+ } else if (platform13 === "win32") {
91871
+ installWindows(nodeExe, cliExe);
91872
+ } else {
91873
+ console.log(source_default.yellow("\n \u26A0 Auto-start service install is not supported on this platform."));
91874
+ console.log(source_default.gray(" On Linux, create a systemd user unit manually:"));
91875
+ console.log(source_default.gray(" ~/.config/systemd/user/adhdev-daemon.service"));
91876
+ }
91877
+ console.log();
91878
+ });
91879
+ svc.command("uninstall").description("Remove the OS background service").action(async () => {
91880
+ console.log(source_default.bold("\n \u{1F5D1}\uFE0F Removing ADHDev Background Service"));
91881
+ const platform13 = import_node_os6.default.platform();
91882
+ if (platform13 === "darwin") {
91883
+ uninstallDarwin();
91884
+ } else if (platform13 === "win32") {
91885
+ uninstallWindows();
91886
+ } else {
91887
+ console.log(source_default.yellow("\n \u26A0 Not supported on this platform."));
91888
+ }
91889
+ console.log();
91890
+ });
91891
+ svc.command("status").description("Show service installation state and live daemon health").action(async () => {
91892
+ const platform13 = import_node_os6.default.platform();
91893
+ const installed = platform13 === "darwin" ? isInstalledDarwin() : platform13 === "win32" ? isInstalledWindows() : false;
91894
+ if (installed) {
91895
+ console.log(source_default.green("\n \u2713 Service is installed."));
91896
+ if (platform13 === "darwin") console.log(source_default.gray(` Plist: ${getDarwinPlistPath()}`));
91897
+ else console.log(source_default.gray(` Script: ${getWindowsVbsPath()}`));
91898
+ } else {
91899
+ console.log(source_default.gray("\n \u2717 Service is not installed. Run: adhdev service install"));
91900
+ }
91901
+ const health = await fetchHealth();
91902
+ if (health?.ok && health.pid) {
91903
+ const info = getProcessInfo(health.pid);
91904
+ if (info) {
91905
+ console.log(source_default.green(` \u2713 Daemon running \u2014 PID ${health.pid}, uptime ${info.uptime}, ${info.memMB} MB`));
91906
+ } else {
91907
+ console.log(source_default.green(` \u2713 Daemon running \u2014 PID ${health.pid}`));
91908
+ }
91909
+ } else {
91910
+ console.log(source_default.yellow(" \u2717 Daemon is not running."));
91911
+ }
91912
+ const outSize = import_node_fs6.default.existsSync(LOG_OUT) ? import_node_fs6.default.statSync(LOG_OUT).size : 0;
91913
+ const errSize = import_node_fs6.default.existsSync(LOG_ERR) ? import_node_fs6.default.statSync(LOG_ERR).size : 0;
91914
+ if (outSize > 0 || errSize > 0) {
91915
+ console.log(source_default.gray(` Logs: stdout ${formatBytes(outSize)}, stderr ${formatBytes(errSize)}`));
91916
+ }
91917
+ console.log();
91918
+ });
91919
+ svc.command("logs").description("View daemon service logs").option("--err", "Show stderr log instead of stdout").option("--clear", "Truncate all log files").option("-n, --lines <count>", "Number of lines to show", "30").action(async (options) => {
91920
+ if (options.clear) {
91921
+ for (const f of [LOG_OUT, LOG_ERR]) {
91922
+ if (import_node_fs6.default.existsSync(f)) import_node_fs6.default.writeFileSync(f, "", "utf-8");
91923
+ }
91924
+ console.log(source_default.green("\n \u2713 Logs cleared.\n"));
91925
+ return;
91926
+ }
91927
+ const logFile = options.err ? LOG_ERR : LOG_OUT;
91928
+ if (!import_node_fs6.default.existsSync(logFile)) {
91929
+ console.log(source_default.gray(`
91930
+ No log file found: ${logFile}
91931
+ `));
91932
+ return;
91933
+ }
91934
+ const lines = parseInt(options.lines, 10) || 30;
91935
+ console.log(source_default.gray(`
91936
+ \u2500\u2500 ${options.err ? "stderr" : "stdout"}: ${logFile} (last ${lines} lines) \u2500\u2500
91937
+ `));
91938
+ const content = import_node_fs6.default.readFileSync(logFile, "utf-8");
91939
+ const allLines = content.split("\n");
91940
+ const lastLines = allLines.slice(-lines).join("\n");
91941
+ if (lastLines.trim()) console.log(lastLines);
91942
+ console.log(source_default.gray("\n (watching for new output, Ctrl+C to stop)\n"));
91943
+ let offset = Buffer.byteLength(content, "utf-8");
91944
+ const watcher = import_node_fs6.default.watchFile(logFile, { interval: 500 }, () => {
91945
+ try {
91946
+ const stat4 = import_node_fs6.default.statSync(logFile);
91947
+ if (stat4.size > offset) {
91948
+ const fd = import_node_fs6.default.openSync(logFile, "r");
91949
+ const buf = Buffer.alloc(stat4.size - offset);
91950
+ import_node_fs6.default.readSync(fd, buf, 0, buf.length, offset);
91951
+ import_node_fs6.default.closeSync(fd);
91952
+ process.stdout.write(buf.toString("utf-8"));
91953
+ offset = stat4.size;
91954
+ } else if (stat4.size < offset) {
91955
+ offset = 0;
91956
+ }
91957
+ } catch {
91958
+ }
91959
+ });
91960
+ const cleanup = () => {
91961
+ import_node_fs6.default.unwatchFile(logFile);
91962
+ process.exit(0);
91963
+ };
91964
+ process.on("SIGINT", cleanup);
91965
+ process.on("SIGTERM", cleanup);
91966
+ });
91967
+ svc.command("restart").description("Restart the daemon process (service will auto-relaunch)").action(async () => {
91968
+ const platform13 = import_node_os6.default.platform();
91969
+ const installed = platform13 === "darwin" ? isInstalledDarwin() : platform13 === "win32" ? isInstalledWindows() : false;
91970
+ if (!installed) {
91971
+ console.log(source_default.yellow("\n \u26A0 Service is not installed. Use `adhdev daemon:restart` for manual restart."));
91972
+ console.log(source_default.gray(" Or install the service first: adhdev service install\n"));
91973
+ return;
91974
+ }
91975
+ rotateLogs();
91976
+ const health = await fetchHealth();
91977
+ if (!health?.pid) {
91978
+ console.log(source_default.yellow("\n \u26A0 Daemon is not currently running."));
91979
+ if (platform13 === "darwin") {
91980
+ console.log(source_default.gray(" Starting via launchctl..."));
91981
+ try {
91982
+ (0, import_node_child_process6.execSync)(`launchctl start ${LAUNCHD_LABEL}`, { stdio: "ignore" });
91983
+ console.log(source_default.green(" \u2713 Started.\n"));
91984
+ } catch {
91985
+ console.log(source_default.red(" \u2717 Failed to start. Check: adhdev service logs --err\n"));
91986
+ }
91987
+ } else {
91988
+ console.log(source_default.gray(" Start with: adhdev daemon\n"));
91989
+ }
91990
+ return;
91991
+ }
91992
+ console.log(source_default.cyan(`
91993
+ Stopping daemon (PID ${health.pid})...`));
91994
+ try {
91995
+ process.kill(health.pid, "SIGTERM");
91996
+ } catch {
91997
+ console.log(source_default.yellow(" Could not send SIGTERM. Process may have already exited."));
91998
+ }
91999
+ await new Promise((r) => setTimeout(r, 2e3));
92000
+ if (platform13 === "win32") {
92001
+ const vbsPath = getWindowsVbsPath();
92002
+ if (import_node_fs6.default.existsSync(vbsPath)) {
92003
+ try {
92004
+ (0, import_node_child_process6.execSync)(`wscript.exe "${vbsPath}"`, { stdio: "ignore", windowsHide: true });
92005
+ } catch {
92006
+ }
92007
+ }
92008
+ }
92009
+ let restarted = false;
92010
+ for (let i = 0; i < 8; i++) {
92011
+ await new Promise((r) => setTimeout(r, 1e3));
92012
+ const newHealth = await fetchHealth();
92013
+ if (newHealth?.ok && newHealth.pid !== health.pid) {
92014
+ restarted = true;
92015
+ const info = getProcessInfo(newHealth.pid);
92016
+ console.log(source_default.green(` \u2713 Daemon restarted \u2014 new PID ${newHealth.pid}${info ? `, ${info.memMB} MB` : ""}`));
92017
+ break;
92018
+ }
92019
+ }
92020
+ if (!restarted) {
92021
+ console.log(source_default.yellow(" \u26A0 Daemon did not restart within 10s."));
92022
+ console.log(source_default.gray(" Check: adhdev service logs --err"));
92023
+ }
92024
+ console.log();
92025
+ });
92026
+ }
92027
+ function formatBytes(bytes) {
92028
+ if (bytes === 0) return "0 B";
92029
+ if (bytes < 1024) return `${bytes} B`;
92030
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
92031
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
92032
+ }
92033
+
91608
92034
  // src/cli/doctor-commands.ts
91609
92035
  function resolvePackageRoot() {
91610
- return path31.resolve(__dirname, "..", "..");
92036
+ return path33.resolve(__dirname, "..", "..");
91611
92037
  }
91612
92038
  function isLinkedInstall(packageRoot) {
91613
- const normalized = path31.normalize(packageRoot);
91614
- return !normalized.includes(`${path31.sep}node_modules${path31.sep}adhdev`);
92039
+ const normalized = path33.normalize(packageRoot);
92040
+ return !normalized.includes(`${path33.sep}node_modules${path33.sep}adhdev`);
91615
92041
  }
91616
92042
  function formatCheck(check2) {
91617
92043
  const icon = check2.ok ? source_default.green("\u2713") : source_default.red("\u2717");
@@ -91695,11 +92121,11 @@ function probeSharpRuntime(packageRoot, nativeSharpPackage) {
91695
92121
  }
91696
92122
  }
91697
92123
  function probeConfigAccess() {
91698
- const configDir = path31.join(os29.homedir(), ".adhdev");
91699
- const configPath = path31.join(configDir, "config.json");
92124
+ const configDir = path33.join(os30.homedir(), ".adhdev");
92125
+ const configPath = path33.join(configDir, "config.json");
91700
92126
  const checks = [];
91701
92127
  try {
91702
- fs25.mkdirSync(configDir, { recursive: true });
92128
+ fs26.mkdirSync(configDir, { recursive: true });
91703
92129
  checks.push({
91704
92130
  label: "Config directory",
91705
92131
  ok: true,
@@ -91714,8 +92140,8 @@ function probeConfigAccess() {
91714
92140
  }];
91715
92141
  }
91716
92142
  try {
91717
- if (fs25.existsSync(configPath)) {
91718
- fs25.readFileSync(configPath, "utf-8");
92143
+ if (fs26.existsSync(configPath)) {
92144
+ fs26.readFileSync(configPath, "utf-8");
91719
92145
  checks.push({
91720
92146
  label: "Config file",
91721
92147
  ok: true,
@@ -91736,10 +92162,10 @@ function probeConfigAccess() {
91736
92162
  fatal: true
91737
92163
  });
91738
92164
  }
91739
- const probePath = path31.join(configDir, `.doctor-write-${process.pid}-${Date.now()}.tmp`);
92165
+ const probePath = path33.join(configDir, `.doctor-write-${process.pid}-${Date.now()}.tmp`);
91740
92166
  try {
91741
- fs25.writeFileSync(probePath, "ok", "utf-8");
91742
- fs25.rmSync(probePath, { force: true });
92167
+ fs26.writeFileSync(probePath, "ok", "utf-8");
92168
+ fs26.rmSync(probePath, { force: true });
91743
92169
  checks.push({
91744
92170
  label: "Config write",
91745
92171
  ok: true,
@@ -91747,7 +92173,7 @@ function probeConfigAccess() {
91747
92173
  });
91748
92174
  } catch (error48) {
91749
92175
  try {
91750
- fs25.rmSync(probePath, { force: true });
92176
+ fs26.rmSync(probePath, { force: true });
91751
92177
  } catch {
91752
92178
  }
91753
92179
  checks.push({
@@ -91803,9 +92229,9 @@ function probeCliBinary(commandPath, currentVersion) {
91803
92229
  return probe;
91804
92230
  }
91805
92231
  function readLogHints(logPath) {
91806
- if (!fs25.existsSync(logPath)) return [];
92232
+ if (!fs26.existsSync(logPath)) return [];
91807
92233
  try {
91808
- const content = fs25.readFileSync(logPath, "utf-8");
92234
+ const content = fs26.readFileSync(logPath, "utf-8");
91809
92235
  const lines = content.split(/\r?\n/);
91810
92236
  const recent = lines.slice(-400);
91811
92237
  const hits = recent.filter(
@@ -91819,11 +92245,11 @@ function readLogHints(logPath) {
91819
92245
  function buildBrowseProbeChecks() {
91820
92246
  const probes = process.platform === "win32" ? [
91821
92247
  process.env.SystemDrive ? `${process.env.SystemDrive.replace(/[\\/]+$/, "")}\\` : "C:\\",
91822
- os29.homedir()
91823
- ] : ["/", os29.homedir()];
92248
+ os30.homedir()
92249
+ ] : ["/", os30.homedir()];
91824
92250
  return probes.map((probePath, index) => {
91825
92251
  try {
91826
- const entries = fs25.readdirSync(probePath, { withFileTypes: true });
92252
+ const entries = fs26.readdirSync(probePath, { withFileTypes: true });
91827
92253
  const directoryCount = entries.filter((entry) => entry.isDirectory()).length;
91828
92254
  return {
91829
92255
  label: index === 0 ? "Folder browse root" : "Folder browse home",
@@ -91843,7 +92269,7 @@ function buildBrowseProbeChecks() {
91843
92269
  function registerDoctorCommands(program2, pkgVersion3) {
91844
92270
  program2.command("doctor").description("Diagnose install, native dependencies, CLI resolution, and folder browse access").action(async () => {
91845
92271
  const packageRoot = resolvePackageRoot();
91846
- const cliPath = fs25.realpathSync(process.argv[1]);
92272
+ const cliPath = fs26.realpathSync(process.argv[1]);
91847
92273
  const linked = isLinkedInstall(packageRoot);
91848
92274
  const logPath = getCurrentDaemonLogPath();
91849
92275
  const claudePaths = findCommandPaths("claude");
@@ -91891,6 +92317,8 @@ function registerDoctorCommands(program2, pkgVersion3) {
91891
92317
  let runtimeSurfaceCheck = null;
91892
92318
  let nodeDriftCheck = null;
91893
92319
  let adhmuxHelpCheck = null;
92320
+ let serviceDefinitionCheck = null;
92321
+ let serviceDefinitionPath;
91894
92322
  if (adhdevPaths.length > 0) {
91895
92323
  const runtimeSurfaceProbe = probeCliBinary(adhdevPaths[0], pkgVersion3);
91896
92324
  runtimeSurfaceCheck = evaluateCliDriftCheck(runtimeSurfaceProbe);
@@ -91922,6 +92350,22 @@ function registerDoctorCommands(program2, pkgVersion3) {
91922
92350
  detail: adhmuxHelpCheck.detail
91923
92351
  });
91924
92352
  }
92353
+ if (process.platform === "darwin") {
92354
+ serviceDefinitionPath = path33.join(os30.homedir(), "Library", "LaunchAgents", "dev.adhf.daemon.plist");
92355
+ if (fs26.existsSync(serviceDefinitionPath)) {
92356
+ serviceDefinitionCheck = evaluateServiceDefinitionDrift({
92357
+ serviceKind: "launchd",
92358
+ servicePath: serviceDefinitionPath,
92359
+ installedDefinition: fs26.readFileSync(serviceDefinitionPath, "utf8"),
92360
+ expectedDefinition: buildPlist(process.execPath, cliPath)
92361
+ });
92362
+ checks.push({
92363
+ label: "Service definition",
92364
+ ok: serviceDefinitionCheck.ok,
92365
+ detail: serviceDefinitionCheck.detail
92366
+ });
92367
+ }
92368
+ }
91925
92369
  try {
91926
92370
  const sessionHostPid = getSessionHostPid();
91927
92371
  const probe = await probeSessionHostStatus();
@@ -91976,14 +92420,16 @@ function registerDoctorCommands(program2, pkgVersion3) {
91976
92420
  adhmuxPath: adhmuxPaths[0],
91977
92421
  adhmuxCheck: adhmuxHelpCheck || void 0,
91978
92422
  nodeDriftCheck: nodeDriftCheck || void 0,
92423
+ servicePath: serviceDefinitionPath,
92424
+ serviceCheck: serviceDefinitionCheck || void 0,
91979
92425
  sourceCliExample: "node --import tsx packages/daemon-cloud/src/cli/index.ts doctor"
91980
92426
  });
91981
- const sessionHostLogPath = path31.join(os29.homedir(), ".adhdev", "logs", "session-host.log");
92427
+ const sessionHostLogPath = path33.join(os30.homedir(), ".adhdev", "logs", "session-host.log");
91982
92428
  console.log(source_default.bold("\n\u{1FA7A} ADHDev Doctor\n"));
91983
92429
  console.log(source_default.gray(` Version: ${pkgVersion3}`));
91984
92430
  console.log(source_default.gray(` Platform: ${process.platform} ${process.arch}`));
91985
92431
  console.log(source_default.gray(` Node: ${process.version}`));
91986
- console.log(source_default.gray(` Home: ${os29.homedir()}`));
92432
+ console.log(source_default.gray(` Home: ${os30.homedir()}`));
91987
92433
  console.log(source_default.gray(` Log file: ${logPath}`));
91988
92434
  console.log(source_default.gray(` SH log: ${sessionHostLogPath}`));
91989
92435
  console.log();
@@ -92020,7 +92466,7 @@ function registerDoctorCommands(program2, pkgVersion3) {
92020
92466
 
92021
92467
  // src/cli/provider-commands.ts
92022
92468
  init_source();
92023
- var path33 = __toESM(require("path"));
92469
+ var path34 = __toESM(require("path"));
92024
92470
  init_cdp_utils();
92025
92471
  var DEV_SERVER_PORT3 = 19280;
92026
92472
  var IDE_AUTO_FIX_FUNCTIONS = [
@@ -92048,105 +92494,24 @@ function getAutoFixFunctions(category) {
92048
92494
  return IDE_AUTO_FIX_FUNCTIONS;
92049
92495
  }
92050
92496
  function getDefaultAutoFixReference(category, type, providers) {
92051
- if (category === "cli") {
92052
- const preferred = ["codex-cli", "claude-cli", "gemini-cli"];
92053
- const picked = preferred.find(
92054
- (ref) => ref !== type && providers.some((p) => p.type === ref && p.category === "cli")
92055
- );
92056
- if (picked) return picked;
92057
- const fallback2 = providers.find((p) => p.category === "cli" && p.type !== type);
92058
- return fallback2?.type || "codex-cli";
92059
- }
92060
- if (category === "extension") {
92061
- const preferred = ["claude-code-vscode", "codex", "cline", "roo-code"];
92062
- const picked = preferred.find(
92063
- (ref) => ref !== type && providers.some((p) => p.type === ref && p.category === "extension")
92064
- );
92065
- if (picked) return picked;
92066
- const fallback2 = providers.find((p) => p.category === "extension" && p.type !== type);
92067
- if (fallback2?.type) return fallback2.type;
92068
- }
92497
+ const sameCategoryOther = providers.find((p) => p.category === category && p.type !== type);
92498
+ if (sameCategoryOther?.type) return sameCategoryOther.type;
92499
+ if (category === "extension") return "antigravity";
92069
92500
  return "antigravity";
92070
92501
  }
92071
92502
  function escapeRegex2(value) {
92072
92503
  return String(value || "").replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
92073
92504
  }
92074
92505
  var CLI_PROVIDER_FIX_PROMPT = 'Create a file at tmp/adhdev_provider_fix_test.py that prints the current working directory and the squares of 1 through 5, then run python3 tmp/adhdev_provider_fix_test.py and tell me the exact output. Start the final answer with "Exact output:" and include the working directory plus the command stdout verbatim.';
92075
- var CLI_AUTO_FIX_VERIFICATION_PROFILES = {
92076
- "codex-cli": {
92077
- fixtureName: "codex-cli-provider-fix",
92078
- inspectFields: [
92079
- "debug.messages",
92080
- "trace.entries[].payload.parsedLastAssistant",
92081
- "trace.entries[].payload.detectStatus",
92082
- "trace.entries[].payload.parsedStatus"
92083
- ],
92084
- focusAreas: [
92085
- "Startup or trust screens must be classified as approval/current chrome, not assistant transcript content.",
92086
- "Prefer fixing provider.json submit/approval behavior before piling on parser heuristics.",
92087
- "The final assistant transcript must preserve the exact stdout block and current working directory."
92088
- ],
92089
- lastAssistantMustContainAny: [
92090
- "Exact output:",
92091
- "1",
92092
- "4",
92093
- "9",
92094
- "16",
92095
- "25"
92096
- ],
92097
- lastAssistantMustNotContainAny: [
92098
- "Do you trust the contents of this directory?",
92099
- "OpenAI Codex",
92100
- "Tip: New",
92101
- "Summarize recent commits"
92102
- ],
92103
- description: "Codex CLI must classify startup/trust screens correctly, transition idle -> generating -> idle, and preserve the exact stdout block in the final assistant transcript.",
92104
- timeoutMs: 9e4
92105
- },
92106
- "claude-cli": {
92107
- fixtureName: "claude-cli-provider-fix",
92108
- inspectFields: [
92109
- "statusesSeen",
92110
- "approvalsResolved",
92111
- "debug.messages",
92112
- "trace.entries[].payload.detectStatus",
92113
- "trace.entries[].payload.parsedStatus",
92114
- "trace.entries[].payload.parsedLastAssistant",
92115
- "trace.entries[].payload.approval"
92116
- ],
92117
- focusAreas: [
92118
- "Some environments show a startup trust or safety confirmation before the first prompt; treat that screen as waiting_approval, not assistant content.",
92119
- "Single-action startup confirmations should resolve with Enter/confirm handling instead of assuming numbered approval options.",
92120
- "Do not leak footer chrome like shortcuts help, version banners, /effort text, or startup trust wording into the parsed transcript."
92121
- ],
92122
- lastAssistantMustContainAny: [
92123
- "Exact output:",
92124
- "1",
92125
- "4",
92126
- "9",
92127
- "16",
92128
- "25"
92129
- ],
92130
- lastAssistantMustNotContainAny: [
92131
- "Quick safety check",
92132
- "Is this a project you trust",
92133
- "Enter to confirm",
92134
- "Claude Code",
92135
- "Type your message"
92136
- ],
92137
- description: "Claude CLI must survive startup trust/safety prompts, resolve them cleanly, transition back to generating/idle, and keep startup chrome out of the final assistant transcript.",
92138
- timeoutMs: 12e4
92139
- }
92140
- };
92141
- function getCliAutoFixVerification(type, providerDir) {
92142
- const profile = CLI_AUTO_FIX_VERIFICATION_PROFILES[type];
92506
+ function getCliAutoFixVerification(provider, providerDir) {
92507
+ const profile = provider?.autoFixProfile;
92143
92508
  if (!profile) return null;
92144
92509
  const normalizedDir = providerDir.replace(/\\/g, "/");
92145
92510
  const escapedDir = escapeRegex2(normalizedDir);
92146
92511
  return {
92147
92512
  fixtureName: profile.fixtureName,
92148
92513
  request: {
92149
- type,
92514
+ type: provider?.type,
92150
92515
  workingDir: providerDir,
92151
92516
  freshSession: true,
92152
92517
  autoLaunch: true,
@@ -92184,7 +92549,7 @@ function getProviderSourceCandidatePaths(options) {
92184
92549
  const results = [];
92185
92550
  for (const root of roots) {
92186
92551
  for (const name of relativeNames) {
92187
- results.push(path33.join(root, options.category, options.type, name));
92552
+ results.push(path34.join(root, options.category, options.type, name));
92188
92553
  }
92189
92554
  }
92190
92555
  return results;
@@ -92516,21 +92881,26 @@ function registerProviderCommands(program2) {
92516
92881
  console.log(source_default.green(`
92517
92882
  \u2713 Writable local copy ready at [${targetDir2}]`));
92518
92883
  }
92519
- let agentName = options.agent || "codex-cli";
92884
+ let agentName = options.agent;
92520
92885
  const modelName = options.model;
92521
92886
  const reference = options.reference || getDefaultAutoFixReference(providerToFix.category, type, allProviders);
92522
- if (!typeArg && agentName === "codex-cli") {
92887
+ if (!agentName) {
92523
92888
  const inquirer3 = (await Promise.resolve().then(() => (init_lib(), lib_exports))).default;
92524
92889
  const { SUPPORTED_CLI_AGENTS: SUPPORTED_CLI_AGENTS2 } = await Promise.resolve().then(() => (init_supported(), supported_exports));
92890
+ const availableAgentChoices = SUPPORTED_CLI_AGENTS2.filter(
92891
+ (agent) => allProviders.some((provider2) => provider2.category === "cli" && provider2.type === agent.id)
92892
+ );
92893
+ const choices = (availableAgentChoices.length > 0 ? availableAgentChoices : SUPPORTED_CLI_AGENTS2).map((agent) => ({
92894
+ name: `${agent.icon} ${source_default.green(agent.name)}`,
92895
+ value: agent.id
92896
+ }));
92897
+ const defaultAgent = choices[0]?.value || "codex-cli";
92525
92898
  const agentAnswer = await inquirer3.prompt([{
92526
92899
  type: "list",
92527
92900
  name: "selected",
92528
92901
  message: "Select the AI agent to use for auto-fix:",
92529
- choices: SUPPORTED_CLI_AGENTS2.map((agent) => ({
92530
- name: `${agent.icon} ${source_default.green(agent.name)}`,
92531
- value: agent.id
92532
- })),
92533
- default: "codex-cli"
92902
+ choices,
92903
+ default: defaultAgent
92534
92904
  }]);
92535
92905
  agentName = agentAnswer.selected;
92536
92906
  }
@@ -92580,7 +92950,7 @@ function registerProviderCommands(program2) {
92580
92950
  console.log(source_default.gray(` \u{1F4AC} Comment: ${userComment}`));
92581
92951
  }
92582
92952
  try {
92583
- const verification = providerToFix.category === "cli" ? getCliAutoFixVerification(type, targetDir) : null;
92953
+ const verification = providerToFix.category === "cli" ? getCliAutoFixVerification(providerToFix, targetDir) : null;
92584
92954
  const postData = JSON.stringify({
92585
92955
  functions: functionsToFix,
92586
92956
  agent: agentName,
@@ -93153,372 +93523,6 @@ function registerCdpCommands(program2) {
93153
93523
  });
93154
93524
  }
93155
93525
 
93156
- // src/cli/service-commands.ts
93157
- var import_node_fs6 = __toESM(require("fs"));
93158
- var import_node_path4 = __toESM(require("path"));
93159
- var import_node_os6 = __toESM(require("os"));
93160
- var import_node_child_process6 = require("child_process");
93161
- init_source();
93162
- init_src();
93163
- var DEFAULT_LOCAL_DAEMON_HEALTH_TIMEOUT_MS3 = 1500;
93164
- var LAUNCHD_LABEL = "dev.adhf.daemon";
93165
- var ADHDEV_DIR = import_node_path4.default.join(import_node_os6.default.homedir(), ".adhdev");
93166
- var LOG_OUT = import_node_path4.default.join(ADHDEV_DIR, "daemon-launchd.out");
93167
- var LOG_ERR = import_node_path4.default.join(ADHDEV_DIR, "daemon-launchd.err");
93168
- var MAX_LOG_SIZE2 = 10 * 1024 * 1024;
93169
- function getDarwinPlistPath() {
93170
- return import_node_path4.default.join(import_node_os6.default.homedir(), "Library", "LaunchAgents", `${LAUNCHD_LABEL}.plist`);
93171
- }
93172
- function getWindowsStartupDir() {
93173
- const appData = process.env.APPDATA || import_node_path4.default.join(import_node_os6.default.homedir(), "AppData", "Roaming");
93174
- return import_node_path4.default.join(appData, "Microsoft", "Windows", "Start Menu", "Programs", "Startup");
93175
- }
93176
- function getWindowsVbsPath() {
93177
- return import_node_path4.default.join(getWindowsStartupDir(), "adhdev-daemon.vbs");
93178
- }
93179
- function resolveCliPath() {
93180
- return import_node_fs6.default.realpathSync(process.argv[1]);
93181
- }
93182
- function ensureDir(dir) {
93183
- if (!import_node_fs6.default.existsSync(dir)) import_node_fs6.default.mkdirSync(dir, { recursive: true });
93184
- }
93185
- async function fetchHealth() {
93186
- const controller = new AbortController();
93187
- const timer = setTimeout(() => controller.abort(), DEFAULT_LOCAL_DAEMON_HEALTH_TIMEOUT_MS3);
93188
- try {
93189
- const res = await fetch(`http://127.0.0.1:${DEFAULT_DAEMON_PORT}/health`, { signal: controller.signal });
93190
- if (!res.ok) return null;
93191
- return await res.json();
93192
- } catch {
93193
- return null;
93194
- } finally {
93195
- clearTimeout(timer);
93196
- }
93197
- }
93198
- function getProcessInfo(pid) {
93199
- try {
93200
- if (process.platform === "win32") {
93201
- const out = (0, import_node_child_process6.execSync)(`tasklist /FI "PID eq ${pid}" /FO CSV /NH`, { encoding: "utf-8" });
93202
- const match = out.match(/"(\d[\d,]+)\sK"/);
93203
- const memKB = match ? parseInt(match[1].replace(/,/g, ""), 10) : 0;
93204
- return { uptime: "-", memMB: Math.round(memKB / 1024) };
93205
- } else {
93206
- const out = (0, import_node_child_process6.execSync)(`ps -o etime=,rss= -p ${pid}`, { encoding: "utf-8" }).trim();
93207
- const parts = out.split(/\s+/);
93208
- const etime = parts[0] || "-";
93209
- const rssKB = parseInt(parts[1] || "0", 10);
93210
- return { uptime: formatElapsed(etime), memMB: Math.round(rssKB / 1024) };
93211
- }
93212
- } catch {
93213
- return null;
93214
- }
93215
- }
93216
- function formatElapsed(etime) {
93217
- const parts = etime.replace("-", ":").split(":").map(Number);
93218
- if (parts.length === 4) return `${parts[0]}d ${parts[1]}h ${parts[2]}m`;
93219
- if (parts.length === 3) return `${parts[0]}h ${parts[1]}m`;
93220
- if (parts.length === 2) return `${parts[0]}m ${parts[1]}s`;
93221
- return etime;
93222
- }
93223
- function rotateLogIfNeeded(logPath) {
93224
- try {
93225
- if (!import_node_fs6.default.existsSync(logPath)) return;
93226
- const stat4 = import_node_fs6.default.statSync(logPath);
93227
- if (stat4.size > MAX_LOG_SIZE2) {
93228
- const rotated = logPath + ".old";
93229
- if (import_node_fs6.default.existsSync(rotated)) import_node_fs6.default.unlinkSync(rotated);
93230
- import_node_fs6.default.renameSync(logPath, rotated);
93231
- import_node_fs6.default.writeFileSync(logPath, `[log rotated at ${(/* @__PURE__ */ new Date()).toISOString()}]
93232
- `, "utf-8");
93233
- }
93234
- } catch {
93235
- }
93236
- }
93237
- function rotateLogs() {
93238
- rotateLogIfNeeded(LOG_OUT);
93239
- rotateLogIfNeeded(LOG_ERR);
93240
- }
93241
- function buildPlist(nodeExe, cliExe) {
93242
- const brewPrefix = import_node_fs6.default.existsSync("/opt/homebrew/bin") ? "/opt/homebrew/bin" : "/usr/local/bin";
93243
- const nodeDir = import_node_path4.default.dirname(nodeExe);
93244
- const pathEntries = /* @__PURE__ */ new Set([nodeDir, brewPrefix, "/usr/local/bin", "/usr/bin", "/bin", "/usr/sbin", "/sbin"]);
93245
- const pathValue = [...pathEntries].join(":");
93246
- return `<?xml version="1.0" encoding="UTF-8"?>
93247
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
93248
- <plist version="1.0">
93249
- <dict>
93250
- <key>Label</key>
93251
- <string>${LAUNCHD_LABEL}</string>
93252
- <key>ProgramArguments</key>
93253
- <array>
93254
- <string>${nodeExe}</string>
93255
- <string>${cliExe}</string>
93256
- <string>daemon</string>
93257
- </array>
93258
- <key>RunAtLoad</key>
93259
- <true/>
93260
- <key>KeepAlive</key>
93261
- <dict>
93262
- <key>SuccessfulExit</key>
93263
- <false/>
93264
- </dict>
93265
- <key>ThrottleInterval</key>
93266
- <integer>30</integer>
93267
- <key>StandardOutPath</key>
93268
- <string>${LOG_OUT}</string>
93269
- <key>StandardErrorPath</key>
93270
- <string>${LOG_ERR}</string>
93271
- <key>EnvironmentVariables</key>
93272
- <dict>
93273
- <key>PATH</key>
93274
- <string>${pathValue}</string>
93275
- </dict>
93276
- </dict>
93277
- </plist>`;
93278
- }
93279
- function installDarwin(nodeExe, cliExe) {
93280
- const plistPath = getDarwinPlistPath();
93281
- ensureDir(ADHDEV_DIR);
93282
- ensureDir(import_node_path4.default.dirname(plistPath));
93283
- import_node_fs6.default.writeFileSync(plistPath, buildPlist(nodeExe, cliExe), "utf-8");
93284
- console.log(source_default.gray(` Plist: ${plistPath}`));
93285
- try {
93286
- (0, import_node_child_process6.execSync)(`launchctl unload "${plistPath}" 2>/dev/null`, { stdio: "ignore" });
93287
- } catch {
93288
- }
93289
- try {
93290
- (0, import_node_child_process6.execSync)(`launchctl load -w "${plistPath}"`, { stdio: "ignore" });
93291
- console.log(source_default.green("\n \u2713 Registered as LaunchAgent \u2014 daemon will start on login."));
93292
- console.log(source_default.gray(` Logs: ~/.adhdev/daemon-launchd.{out,err}`));
93293
- } catch (e) {
93294
- console.log(source_default.red(`
93295
- \u2717 launchctl load failed: ${e.message}`));
93296
- }
93297
- }
93298
- function uninstallDarwin() {
93299
- const plistPath = getDarwinPlistPath();
93300
- if (!import_node_fs6.default.existsSync(plistPath)) {
93301
- console.log(source_default.yellow("\n \u26A0 Service is not installed."));
93302
- return;
93303
- }
93304
- try {
93305
- (0, import_node_child_process6.execSync)(`launchctl unload "${plistPath}" 2>/dev/null`, { stdio: "ignore" });
93306
- } catch {
93307
- }
93308
- import_node_fs6.default.unlinkSync(plistPath);
93309
- console.log(source_default.green("\n \u2713 Removed LaunchAgent. Daemon will no longer auto-start."));
93310
- }
93311
- function isInstalledDarwin() {
93312
- return import_node_fs6.default.existsSync(getDarwinPlistPath());
93313
- }
93314
- function buildVbs(nodeExe, cliExe) {
93315
- const logFile = import_node_path4.default.join(ADHDEV_DIR, "daemon-service.log").replace(/\\/g, "\\\\");
93316
- const escapedNodeExe = nodeExe.replace(/\\/g, "\\\\");
93317
- const escapedCliExe = cliExe.replace(/\\/g, "\\\\");
93318
- return `' ADHDev Daemon Auto-Start (generated by adhdev service install)
93319
- Set WshShell = CreateObject("WScript.Shell")
93320
- WshShell.Run "cmd.exe /c """"${escapedNodeExe}"""" """"${escapedCliExe}"""" daemon >> """"${logFile}"""" 2>&1", 0, False
93321
- `;
93322
- }
93323
- function installWindows(nodeExe, cliExe) {
93324
- const vbsPath = getWindowsVbsPath();
93325
- ensureDir(ADHDEV_DIR);
93326
- ensureDir(import_node_path4.default.dirname(vbsPath));
93327
- import_node_fs6.default.writeFileSync(vbsPath, buildVbs(nodeExe, cliExe), "utf-8");
93328
- console.log(source_default.gray(` Startup script: ${vbsPath}`));
93329
- console.log(source_default.green("\n \u2713 Registered in Startup folder \u2014 daemon will start on login (hidden)."));
93330
- console.log(source_default.gray(` Logs: ${import_node_path4.default.join(ADHDEV_DIR, "daemon-service.log")}`));
93331
- console.log(source_default.gray(" To start now without rebooting, run: adhdev daemon"));
93332
- }
93333
- function uninstallWindows() {
93334
- const vbsPath = getWindowsVbsPath();
93335
- if (!import_node_fs6.default.existsSync(vbsPath)) {
93336
- console.log(source_default.yellow("\n \u26A0 Service is not installed."));
93337
- return;
93338
- }
93339
- import_node_fs6.default.unlinkSync(vbsPath);
93340
- console.log(source_default.green("\n \u2713 Removed Startup script. Daemon will no longer auto-start."));
93341
- console.log(source_default.gray(" Note: a currently running daemon is not affected. Stop with: adhdev daemon:stop"));
93342
- }
93343
- function isInstalledWindows() {
93344
- return import_node_fs6.default.existsSync(getWindowsVbsPath());
93345
- }
93346
- function registerServiceCommands(program2) {
93347
- const svc = program2.command("service").description("\u{1F50C} Manage ADHDev as an OS background auto-start service");
93348
- svc.command("install").description("Register ADHDev daemon to start automatically on login").action(async () => {
93349
- console.log(source_default.bold("\n \u{1F680} Installing ADHDev Background Service"));
93350
- const platform13 = import_node_os6.default.platform();
93351
- const nodeExe = process.execPath;
93352
- const cliExe = resolveCliPath();
93353
- console.log(source_default.gray(` Node: ${nodeExe}`));
93354
- console.log(source_default.gray(` CLI: ${cliExe}`));
93355
- console.log(source_default.gray(` Platform: ${platform13}`));
93356
- if (platform13 === "darwin") {
93357
- installDarwin(nodeExe, cliExe);
93358
- } else if (platform13 === "win32") {
93359
- installWindows(nodeExe, cliExe);
93360
- } else {
93361
- console.log(source_default.yellow("\n \u26A0 Auto-start service install is not supported on this platform."));
93362
- console.log(source_default.gray(" On Linux, create a systemd user unit manually:"));
93363
- console.log(source_default.gray(" ~/.config/systemd/user/adhdev-daemon.service"));
93364
- }
93365
- console.log();
93366
- });
93367
- svc.command("uninstall").description("Remove the OS background service").action(async () => {
93368
- console.log(source_default.bold("\n \u{1F5D1}\uFE0F Removing ADHDev Background Service"));
93369
- const platform13 = import_node_os6.default.platform();
93370
- if (platform13 === "darwin") {
93371
- uninstallDarwin();
93372
- } else if (platform13 === "win32") {
93373
- uninstallWindows();
93374
- } else {
93375
- console.log(source_default.yellow("\n \u26A0 Not supported on this platform."));
93376
- }
93377
- console.log();
93378
- });
93379
- svc.command("status").description("Show service installation state and live daemon health").action(async () => {
93380
- const platform13 = import_node_os6.default.platform();
93381
- const installed = platform13 === "darwin" ? isInstalledDarwin() : platform13 === "win32" ? isInstalledWindows() : false;
93382
- if (installed) {
93383
- console.log(source_default.green("\n \u2713 Service is installed."));
93384
- if (platform13 === "darwin") console.log(source_default.gray(` Plist: ${getDarwinPlistPath()}`));
93385
- else console.log(source_default.gray(` Script: ${getWindowsVbsPath()}`));
93386
- } else {
93387
- console.log(source_default.gray("\n \u2717 Service is not installed. Run: adhdev service install"));
93388
- }
93389
- const health = await fetchHealth();
93390
- if (health?.ok && health.pid) {
93391
- const info = getProcessInfo(health.pid);
93392
- if (info) {
93393
- console.log(source_default.green(` \u2713 Daemon running \u2014 PID ${health.pid}, uptime ${info.uptime}, ${info.memMB} MB`));
93394
- } else {
93395
- console.log(source_default.green(` \u2713 Daemon running \u2014 PID ${health.pid}`));
93396
- }
93397
- } else {
93398
- console.log(source_default.yellow(" \u2717 Daemon is not running."));
93399
- }
93400
- const outSize = import_node_fs6.default.existsSync(LOG_OUT) ? import_node_fs6.default.statSync(LOG_OUT).size : 0;
93401
- const errSize = import_node_fs6.default.existsSync(LOG_ERR) ? import_node_fs6.default.statSync(LOG_ERR).size : 0;
93402
- if (outSize > 0 || errSize > 0) {
93403
- console.log(source_default.gray(` Logs: stdout ${formatBytes(outSize)}, stderr ${formatBytes(errSize)}`));
93404
- }
93405
- console.log();
93406
- });
93407
- svc.command("logs").description("View daemon service logs").option("--err", "Show stderr log instead of stdout").option("--clear", "Truncate all log files").option("-n, --lines <count>", "Number of lines to show", "30").action(async (options) => {
93408
- if (options.clear) {
93409
- for (const f of [LOG_OUT, LOG_ERR]) {
93410
- if (import_node_fs6.default.existsSync(f)) import_node_fs6.default.writeFileSync(f, "", "utf-8");
93411
- }
93412
- console.log(source_default.green("\n \u2713 Logs cleared.\n"));
93413
- return;
93414
- }
93415
- const logFile = options.err ? LOG_ERR : LOG_OUT;
93416
- if (!import_node_fs6.default.existsSync(logFile)) {
93417
- console.log(source_default.gray(`
93418
- No log file found: ${logFile}
93419
- `));
93420
- return;
93421
- }
93422
- const lines = parseInt(options.lines, 10) || 30;
93423
- console.log(source_default.gray(`
93424
- \u2500\u2500 ${options.err ? "stderr" : "stdout"}: ${logFile} (last ${lines} lines) \u2500\u2500
93425
- `));
93426
- const content = import_node_fs6.default.readFileSync(logFile, "utf-8");
93427
- const allLines = content.split("\n");
93428
- const lastLines = allLines.slice(-lines).join("\n");
93429
- if (lastLines.trim()) console.log(lastLines);
93430
- console.log(source_default.gray("\n (watching for new output, Ctrl+C to stop)\n"));
93431
- let offset = Buffer.byteLength(content, "utf-8");
93432
- const watcher = import_node_fs6.default.watchFile(logFile, { interval: 500 }, () => {
93433
- try {
93434
- const stat4 = import_node_fs6.default.statSync(logFile);
93435
- if (stat4.size > offset) {
93436
- const fd = import_node_fs6.default.openSync(logFile, "r");
93437
- const buf = Buffer.alloc(stat4.size - offset);
93438
- import_node_fs6.default.readSync(fd, buf, 0, buf.length, offset);
93439
- import_node_fs6.default.closeSync(fd);
93440
- process.stdout.write(buf.toString("utf-8"));
93441
- offset = stat4.size;
93442
- } else if (stat4.size < offset) {
93443
- offset = 0;
93444
- }
93445
- } catch {
93446
- }
93447
- });
93448
- const cleanup = () => {
93449
- import_node_fs6.default.unwatchFile(logFile);
93450
- process.exit(0);
93451
- };
93452
- process.on("SIGINT", cleanup);
93453
- process.on("SIGTERM", cleanup);
93454
- });
93455
- svc.command("restart").description("Restart the daemon process (service will auto-relaunch)").action(async () => {
93456
- const platform13 = import_node_os6.default.platform();
93457
- const installed = platform13 === "darwin" ? isInstalledDarwin() : platform13 === "win32" ? isInstalledWindows() : false;
93458
- if (!installed) {
93459
- console.log(source_default.yellow("\n \u26A0 Service is not installed. Use `adhdev daemon:restart` for manual restart."));
93460
- console.log(source_default.gray(" Or install the service first: adhdev service install\n"));
93461
- return;
93462
- }
93463
- rotateLogs();
93464
- const health = await fetchHealth();
93465
- if (!health?.pid) {
93466
- console.log(source_default.yellow("\n \u26A0 Daemon is not currently running."));
93467
- if (platform13 === "darwin") {
93468
- console.log(source_default.gray(" Starting via launchctl..."));
93469
- try {
93470
- (0, import_node_child_process6.execSync)(`launchctl start ${LAUNCHD_LABEL}`, { stdio: "ignore" });
93471
- console.log(source_default.green(" \u2713 Started.\n"));
93472
- } catch {
93473
- console.log(source_default.red(" \u2717 Failed to start. Check: adhdev service logs --err\n"));
93474
- }
93475
- } else {
93476
- console.log(source_default.gray(" Start with: adhdev daemon\n"));
93477
- }
93478
- return;
93479
- }
93480
- console.log(source_default.cyan(`
93481
- Stopping daemon (PID ${health.pid})...`));
93482
- try {
93483
- process.kill(health.pid, "SIGTERM");
93484
- } catch {
93485
- console.log(source_default.yellow(" Could not send SIGTERM. Process may have already exited."));
93486
- }
93487
- await new Promise((r) => setTimeout(r, 2e3));
93488
- if (platform13 === "win32") {
93489
- const vbsPath = getWindowsVbsPath();
93490
- if (import_node_fs6.default.existsSync(vbsPath)) {
93491
- try {
93492
- (0, import_node_child_process6.execSync)(`wscript.exe "${vbsPath}"`, { stdio: "ignore", windowsHide: true });
93493
- } catch {
93494
- }
93495
- }
93496
- }
93497
- let restarted = false;
93498
- for (let i = 0; i < 8; i++) {
93499
- await new Promise((r) => setTimeout(r, 1e3));
93500
- const newHealth = await fetchHealth();
93501
- if (newHealth?.ok && newHealth.pid !== health.pid) {
93502
- restarted = true;
93503
- const info = getProcessInfo(newHealth.pid);
93504
- console.log(source_default.green(` \u2713 Daemon restarted \u2014 new PID ${newHealth.pid}${info ? `, ${info.memMB} MB` : ""}`));
93505
- break;
93506
- }
93507
- }
93508
- if (!restarted) {
93509
- console.log(source_default.yellow(" \u26A0 Daemon did not restart within 10s."));
93510
- console.log(source_default.gray(" Check: adhdev service logs --err"));
93511
- }
93512
- console.log();
93513
- });
93514
- }
93515
- function formatBytes(bytes) {
93516
- if (bytes === 0) return "0 B";
93517
- if (bytes < 1024) return `${bytes} B`;
93518
- if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
93519
- return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
93520
- }
93521
-
93522
93526
  // src/cli/index.ts
93523
93527
  init_version();
93524
93528
  var pkgVersion2 = resolvePackageVersion();