@adhdev/daemon-core 0.9.53 → 0.9.55

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.
Files changed (50) hide show
  1. package/dist/boot/daemon-lifecycle.d.ts +5 -0
  2. package/dist/cli-adapters/provider-cli-adapter.d.ts +1 -0
  3. package/dist/cli-adapters/provider-cli-config.d.ts +1 -0
  4. package/dist/cli-adapters/provider-cli-shared.d.ts +2 -0
  5. package/dist/commands/handler.d.ts +7 -0
  6. package/dist/git/git-commands.d.ts +139 -0
  7. package/dist/git/git-diff.d.ts +17 -0
  8. package/dist/git/git-executor.d.ts +34 -0
  9. package/dist/git/git-monitor.d.ts +57 -0
  10. package/dist/git/git-snapshot-store.d.ts +50 -0
  11. package/dist/git/git-status.d.ts +19 -0
  12. package/dist/git/git-summary.d.ts +10 -0
  13. package/dist/git/git-types.d.ts +113 -0
  14. package/dist/git/index.d.ts +16 -0
  15. package/dist/git/turn-snapshot-tracker.d.ts +16 -0
  16. package/dist/index.d.ts +2 -1
  17. package/dist/index.js +1772 -386
  18. package/dist/index.js.map +1 -1
  19. package/dist/index.mjs +1744 -383
  20. package/dist/index.mjs.map +1 -1
  21. package/dist/providers/contracts.d.ts +2 -0
  22. package/dist/shared-types.d.ts +7 -1
  23. package/dist/status/builders.d.ts +2 -0
  24. package/dist/status/snapshot.d.ts +2 -0
  25. package/node_modules/@adhdev/session-host-core/package.json +1 -1
  26. package/package.json +1 -1
  27. package/src/boot/daemon-lifecycle.ts +6 -0
  28. package/src/cli-adapters/provider-cli-adapter.ts +19 -0
  29. package/src/cli-adapters/provider-cli-config.d.ts +1 -0
  30. package/src/cli-adapters/provider-cli-config.ts +2 -0
  31. package/src/cli-adapters/provider-cli-shared.d.ts +2 -0
  32. package/src/cli-adapters/provider-cli-shared.ts +2 -0
  33. package/src/commands/handler.ts +25 -1
  34. package/src/git/git-commands.ts +582 -0
  35. package/src/git/git-diff.ts +303 -0
  36. package/src/git/git-executor.ts +268 -0
  37. package/src/git/git-monitor.ts +194 -0
  38. package/src/git/git-snapshot-store.ts +238 -0
  39. package/src/git/git-status.ts +193 -0
  40. package/src/git/git-summary.ts +43 -0
  41. package/src/git/git-types.ts +154 -0
  42. package/src/git/index.ts +75 -0
  43. package/src/git/turn-snapshot-tracker.ts +31 -0
  44. package/src/index.ts +4 -0
  45. package/src/providers/contracts.d.ts +8 -0
  46. package/src/providers/contracts.ts +2 -0
  47. package/src/providers/provider-schema.ts +1 -0
  48. package/src/shared-types.ts +33 -1
  49. package/src/status/builders.ts +26 -4
  50. package/src/status/snapshot.ts +10 -2
package/dist/index.js CHANGED
@@ -283,13 +283,13 @@ function getDaemonLogDir() {
283
283
  return LOG_DIR;
284
284
  }
285
285
  function getCurrentDaemonLogPath(date = /* @__PURE__ */ new Date()) {
286
- return path6.join(LOG_DIR, `daemon-${date.toISOString().slice(0, 10)}.log`);
286
+ return path9.join(LOG_DIR, `daemon-${date.toISOString().slice(0, 10)}.log`);
287
287
  }
288
288
  function checkDateRotation() {
289
289
  const today = getDateStr();
290
290
  if (today !== currentDate) {
291
291
  currentDate = today;
292
- currentLogFile = path6.join(LOG_DIR, `daemon-${currentDate}.log`);
292
+ currentLogFile = path9.join(LOG_DIR, `daemon-${currentDate}.log`);
293
293
  cleanOldLogs();
294
294
  }
295
295
  }
@@ -303,7 +303,7 @@ function cleanOldLogs() {
303
303
  const dateMatch = file.match(/daemon-(\d{4}-\d{2}-\d{2})/);
304
304
  if (dateMatch && dateMatch[1] < cutoffStr) {
305
305
  try {
306
- fs2.unlinkSync(path6.join(LOG_DIR, file));
306
+ fs2.unlinkSync(path9.join(LOG_DIR, file));
307
307
  } catch {
308
308
  }
309
309
  }
@@ -313,8 +313,8 @@ function cleanOldLogs() {
313
313
  }
314
314
  function rotateSizeIfNeeded() {
315
315
  try {
316
- const stat = fs2.statSync(currentLogFile);
317
- if (stat.size > MAX_LOG_SIZE) {
316
+ const stat2 = fs2.statSync(currentLogFile);
317
+ if (stat2.size > MAX_LOG_SIZE) {
318
318
  const backup = currentLogFile.replace(".log", ".1.log");
319
319
  try {
320
320
  fs2.unlinkSync(backup);
@@ -419,17 +419,17 @@ function installGlobalInterceptor() {
419
419
  writeToFile(`Log file: ${currentLogFile}`);
420
420
  writeToFile(`Log level: ${currentLevel}`);
421
421
  }
422
- var fs2, path6, os4, LEVEL_NUM, LEVEL_LABEL, currentLevel, LOG_DIR, MAX_LOG_SIZE, MAX_LOG_DAYS, currentDate, currentLogFile, writeCount, RING_BUFFER_SIZE, ringBuffer, origConsoleLog, origConsoleError, origConsoleWarn, LOG, interceptorInstalled, LOG_PATH;
422
+ var fs2, path9, os4, LEVEL_NUM, LEVEL_LABEL, currentLevel, LOG_DIR, MAX_LOG_SIZE, MAX_LOG_DAYS, currentDate, currentLogFile, writeCount, RING_BUFFER_SIZE, ringBuffer, origConsoleLog, origConsoleError, origConsoleWarn, LOG, interceptorInstalled, LOG_PATH;
423
423
  var init_logger = __esm({
424
424
  "src/logging/logger.ts"() {
425
425
  "use strict";
426
426
  fs2 = __toESM(require("fs"));
427
- path6 = __toESM(require("path"));
427
+ path9 = __toESM(require("path"));
428
428
  os4 = __toESM(require("os"));
429
429
  LEVEL_NUM = { debug: 0, info: 1, warn: 2, error: 3 };
430
430
  LEVEL_LABEL = { debug: "DBG", info: "INF", warn: "WRN", error: "ERR" };
431
431
  currentLevel = "info";
432
- LOG_DIR = process.platform === "win32" ? path6.join(process.env.LOCALAPPDATA || process.env.APPDATA || path6.join(os4.homedir(), "AppData", "Local"), "adhdev", "logs") : process.platform === "darwin" ? path6.join(os4.homedir(), "Library", "Logs", "adhdev") : path6.join(os4.homedir(), ".local", "share", "adhdev", "logs");
432
+ LOG_DIR = process.platform === "win32" ? path9.join(process.env.LOCALAPPDATA || process.env.APPDATA || path9.join(os4.homedir(), "AppData", "Local"), "adhdev", "logs") : process.platform === "darwin" ? path9.join(os4.homedir(), "Library", "Logs", "adhdev") : path9.join(os4.homedir(), ".local", "share", "adhdev", "logs");
433
433
  MAX_LOG_SIZE = 5 * 1024 * 1024;
434
434
  MAX_LOG_DAYS = 7;
435
435
  try {
@@ -437,16 +437,16 @@ var init_logger = __esm({
437
437
  } catch {
438
438
  }
439
439
  currentDate = getDateStr();
440
- currentLogFile = path6.join(LOG_DIR, `daemon-${currentDate}.log`);
440
+ currentLogFile = path9.join(LOG_DIR, `daemon-${currentDate}.log`);
441
441
  cleanOldLogs();
442
442
  try {
443
- const oldLog = path6.join(LOG_DIR, "daemon.log");
443
+ const oldLog = path9.join(LOG_DIR, "daemon.log");
444
444
  if (fs2.existsSync(oldLog)) {
445
- const stat = fs2.statSync(oldLog);
446
- const oldDate = stat.mtime.toISOString().slice(0, 10);
447
- fs2.renameSync(oldLog, path6.join(LOG_DIR, `daemon-${oldDate}.log`));
445
+ const stat2 = fs2.statSync(oldLog);
446
+ const oldDate = stat2.mtime.toISOString().slice(0, 10);
447
+ fs2.renameSync(oldLog, path9.join(LOG_DIR, `daemon-${oldDate}.log`));
448
448
  }
449
- const oldLogBackup = path6.join(LOG_DIR, "daemon.log.old");
449
+ const oldLogBackup = path9.join(LOG_DIR, "daemon.log.old");
450
450
  if (fs2.existsSync(oldLogBackup)) {
451
451
  fs2.unlinkSync(oldLogBackup);
452
452
  }
@@ -478,7 +478,7 @@ var init_logger = __esm({
478
478
  }
479
479
  };
480
480
  interceptorInstalled = false;
481
- LOG_PATH = path6.join(LOG_DIR, `daemon-${getDateStr()}.log`);
481
+ LOG_PATH = path9.join(LOG_DIR, `daemon-${getDateStr()}.log`);
482
482
  }
483
483
  });
484
484
 
@@ -1382,8 +1382,8 @@ var init_pty_transport = __esm({
1382
1382
  if (cwd) {
1383
1383
  try {
1384
1384
  const fs16 = require("fs");
1385
- const stat = fs16.statSync(cwd);
1386
- if (!stat.isDirectory()) cwd = os8.homedir();
1385
+ const stat2 = fs16.statSync(cwd);
1386
+ if (!stat2.isDirectory()) cwd = os8.homedir();
1387
1387
  } catch {
1388
1388
  cwd = os8.homedir();
1389
1389
  }
@@ -1465,9 +1465,9 @@ function buildCliScreenSnapshot(text) {
1465
1465
  function findBinary(name) {
1466
1466
  const trimmed = String(name || "").trim();
1467
1467
  if (!trimmed) return trimmed;
1468
- const expanded = trimmed.startsWith("~") ? path10.join(os9.homedir(), trimmed.slice(1)) : trimmed;
1469
- if (path10.isAbsolute(expanded) || expanded.includes("/") || expanded.includes("\\")) {
1470
- return path10.isAbsolute(expanded) ? expanded : path10.resolve(expanded);
1468
+ const expanded = trimmed.startsWith("~") ? path13.join(os9.homedir(), trimmed.slice(1)) : trimmed;
1469
+ if (path13.isAbsolute(expanded) || expanded.includes("/") || expanded.includes("\\")) {
1470
+ return path13.isAbsolute(expanded) ? expanded : path13.resolve(expanded);
1471
1471
  }
1472
1472
  const isWin = os9.platform() === "win32";
1473
1473
  try {
@@ -1483,7 +1483,7 @@ function findBinary(name) {
1483
1483
  }
1484
1484
  }
1485
1485
  function isScriptBinary(binaryPath) {
1486
- if (!path10.isAbsolute(binaryPath)) return false;
1486
+ if (!path13.isAbsolute(binaryPath)) return false;
1487
1487
  try {
1488
1488
  const fs16 = require("fs");
1489
1489
  const resolved = fs16.realpathSync(binaryPath);
@@ -1499,7 +1499,7 @@ function isScriptBinary(binaryPath) {
1499
1499
  }
1500
1500
  }
1501
1501
  function looksLikeMachOOrElf(filePath) {
1502
- if (!path10.isAbsolute(filePath)) return false;
1502
+ if (!path13.isAbsolute(filePath)) return false;
1503
1503
  try {
1504
1504
  const fs16 = require("fs");
1505
1505
  const resolved = fs16.realpathSync(filePath);
@@ -1649,12 +1649,12 @@ function normalizeCliProviderForRuntime(raw) {
1649
1649
  }
1650
1650
  };
1651
1651
  }
1652
- var os9, path10, import_child_process4, buildCliSpawnEnv, COMMON_COMPARABLE_WRAP_WORDS;
1652
+ var os9, path13, import_child_process4, buildCliSpawnEnv, COMMON_COMPARABLE_WRAP_WORDS;
1653
1653
  var init_provider_cli_shared = __esm({
1654
1654
  "src/cli-adapters/provider-cli-shared.ts"() {
1655
1655
  "use strict";
1656
1656
  os9 = __toESM(require("os"));
1657
- path10 = __toESM(require("path"));
1657
+ path13 = __toESM(require("path"));
1658
1658
  import_child_process4 = require("child_process");
1659
1659
  init_spawn_env();
1660
1660
  buildCliSpawnEnv = import_session_host_core.sanitizeSpawnEnv;
@@ -1942,6 +1942,7 @@ function resolveCliAdapterConfig(provider) {
1942
1942
  sendDelayMs: typeof provider.sendDelayMs === "number" ? Math.max(0, provider.sendDelayMs) : 0,
1943
1943
  sendKey: typeof provider.sendKey === "string" && provider.sendKey.length > 0 ? provider.sendKey : "\r",
1944
1944
  submitStrategy: provider.submitStrategy === "immediate" ? "immediate" : "wait_for_echo",
1945
+ requirePromptEchoBeforeSubmit: provider.requirePromptEchoBeforeSubmit === true,
1945
1946
  providerResolutionMeta: {
1946
1947
  type: provider.type,
1947
1948
  name: provider.name,
@@ -1971,9 +1972,9 @@ function resolveCliSpawnPlan(options) {
1971
1972
  const allArgs = [...spawnConfig.args, ...extraArgs];
1972
1973
  let shellCmd;
1973
1974
  let shellArgs;
1974
- const useShellUnix = !isWin && (!!spawnConfig.shell || !path11.isAbsolute(binaryPath) || isScriptBinary(binaryPath) || !looksLikeMachOOrElf(binaryPath));
1975
+ const useShellUnix = !isWin && (!!spawnConfig.shell || !path14.isAbsolute(binaryPath) || isScriptBinary(binaryPath) || !looksLikeMachOOrElf(binaryPath));
1975
1976
  const isCmdShim = isWin && /\.(cmd|bat)$/i.test(binaryPath);
1976
- const useShellWin = !!spawnConfig.shell || isCmdShim || !path11.isAbsolute(binaryPath) || isScriptBinary(binaryPath);
1977
+ const useShellWin = !!spawnConfig.shell || isCmdShim || !path14.isAbsolute(binaryPath) || isScriptBinary(binaryPath);
1977
1978
  const useShell = isWin ? useShellWin : useShellUnix;
1978
1979
  if (useShell) {
1979
1980
  shellCmd = isWin ? "cmd.exe" : process.env.SHELL || "/bin/zsh";
@@ -2049,12 +2050,12 @@ function respondToCliTerminalQueries(options) {
2049
2050
  }
2050
2051
  return "";
2051
2052
  }
2052
- var os10, path11, import_session_host_core2;
2053
+ var os10, path14, import_session_host_core2;
2053
2054
  var init_provider_cli_runtime = __esm({
2054
2055
  "src/cli-adapters/provider-cli-runtime.ts"() {
2055
2056
  "use strict";
2056
2057
  os10 = __toESM(require("os"));
2057
- path11 = __toESM(require("path"));
2058
+ path14 = __toESM(require("path"));
2058
2059
  import_session_host_core2 = require("@adhdev/session-host-core");
2059
2060
  init_provider_cli_shared();
2060
2061
  }
@@ -2207,6 +2208,7 @@ var init_provider_cli_adapter = __esm({
2207
2208
  this.sendDelayMs = resolvedConfig.sendDelayMs;
2208
2209
  this.sendKey = resolvedConfig.sendKey;
2209
2210
  this.submitStrategy = resolvedConfig.submitStrategy;
2211
+ this.requirePromptEchoBeforeSubmit = resolvedConfig.requirePromptEchoBeforeSubmit;
2210
2212
  this.providerResolutionMeta = resolvedConfig.providerResolutionMeta;
2211
2213
  this.cliScripts = provider.scripts || {};
2212
2214
  const scriptNames = listCliScriptNames(this.cliScripts);
@@ -2503,6 +2505,7 @@ var init_provider_cli_adapter = __esm({
2503
2505
  sendDelayMs;
2504
2506
  sendKey;
2505
2507
  submitStrategy;
2508
+ requirePromptEchoBeforeSubmit;
2506
2509
  static SCRIPT_STATUS_DEBOUNCE_MS = 3e3;
2507
2510
  /** Inject CLI scripts after construction (e.g. when resolved by ProviderLoader) */
2508
2511
  setCliScripts(scripts) {
@@ -2854,7 +2857,7 @@ var init_provider_cli_adapter = __esm({
2854
2857
  `[${this.cliType}] Waiting for interactive prompt: status=${status} stableMs=${stableMs} recentOutputMs=${recentlyOutput} screen=${JSON.stringify(summarizeCliTraceText(screenText, 220)).slice(0, 260)}`
2855
2858
  );
2856
2859
  }
2857
- await new Promise((resolve12) => setTimeout(resolve12, 50));
2860
+ await new Promise((resolve15) => setTimeout(resolve15, 50));
2858
2861
  }
2859
2862
  const finalScreenText = this.terminalScreen.getText() || "";
2860
2863
  LOG.warn(
@@ -4023,6 +4026,22 @@ var init_provider_cli_adapter = __esm({
4023
4026
  }
4024
4027
  }
4025
4028
  if (elapsed >= state.maxEchoWaitMs) {
4029
+ const diagnostic = {
4030
+ elapsed,
4031
+ maxEchoWaitMs: state.maxEchoWaitMs,
4032
+ submitDelayMs: state.submitDelayMs,
4033
+ promptSnippet: state.normalizedPromptSnippet,
4034
+ requirePromptEchoBeforeSubmit: this.requirePromptEchoBeforeSubmit,
4035
+ screenText: summarizeCliTraceText(screenText, 1e3)
4036
+ };
4037
+ this.recordTrace("submit_echo_missing", diagnostic);
4038
+ if (this.requirePromptEchoBeforeSubmit) {
4039
+ const message = `${this.cliName} prompt echo was not observed on the PTY screen before submit`;
4040
+ LOG.warn("CLI", `[${this.cliType}] ${message} elapsed=${elapsed}ms maxEchoWaitMs=${state.maxEchoWaitMs} screen=${JSON.stringify(diagnostic.screenText).slice(0, 240)}`);
4041
+ completion.rejectOnce(new Error(message));
4042
+ return;
4043
+ }
4044
+ LOG.warn("CLI", `[${this.cliType}] prompt echo was not observed before submit; sending submit key anyway elapsed=${elapsed}ms maxEchoWaitMs=${state.maxEchoWaitMs}`);
4026
4045
  this.submitSendKey(state, completion);
4027
4046
  return;
4028
4047
  }
@@ -4042,7 +4061,7 @@ var init_provider_cli_adapter = __esm({
4042
4061
  const deadline = Date.now() + 1e4;
4043
4062
  while (this.startupParseGate && Date.now() < deadline) {
4044
4063
  this.resolveStartupState("send_wait");
4045
- await new Promise((resolve12) => setTimeout(resolve12, 50));
4064
+ await new Promise((resolve15) => setTimeout(resolve15, 50));
4046
4065
  }
4047
4066
  }
4048
4067
  if (!allowInterventionPrompt) {
@@ -4123,13 +4142,13 @@ var init_provider_cli_adapter = __esm({
4123
4142
  }
4124
4143
  this.responseEpoch += 1;
4125
4144
  this.responseSettleIgnoreUntil = Date.now() + submitDelayMs + this.timeouts.outputSettle + 250;
4126
- await new Promise((resolve12, reject) => {
4145
+ await new Promise((resolve15, reject) => {
4127
4146
  let resolved = false;
4128
4147
  const completion = {
4129
4148
  resolveOnce: () => {
4130
4149
  if (resolved) return;
4131
4150
  resolved = true;
4132
- resolve12();
4151
+ resolve15();
4133
4152
  },
4134
4153
  rejectOnce: (error) => {
4135
4154
  if (resolved) return;
@@ -4291,17 +4310,17 @@ var init_provider_cli_adapter = __esm({
4291
4310
  }
4292
4311
  }
4293
4312
  waitForStopped(timeoutMs) {
4294
- return new Promise((resolve12) => {
4313
+ return new Promise((resolve15) => {
4295
4314
  const startedAt = Date.now();
4296
4315
  const timer = setInterval(() => {
4297
4316
  if (!this.ptyProcess || this.currentStatus === "stopped") {
4298
4317
  clearInterval(timer);
4299
- resolve12(true);
4318
+ resolve15(true);
4300
4319
  return;
4301
4320
  }
4302
4321
  if (Date.now() - startedAt >= timeoutMs) {
4303
4322
  clearInterval(timer);
4304
- resolve12(false);
4323
+ resolve15(false);
4305
4324
  }
4306
4325
  }, 100);
4307
4326
  });
@@ -4487,6 +4506,7 @@ var init_provider_cli_adapter = __esm({
4487
4506
  sendDelayMs: this.sendDelayMs,
4488
4507
  sendKey: this.sendKey,
4489
4508
  submitStrategy: this.submitStrategy,
4509
+ requirePromptEchoBeforeSubmit: this.requirePromptEchoBeforeSubmit,
4490
4510
  submitPendingUntil: this.submitPendingUntil,
4491
4511
  responseSettleIgnoreUntil: this.responseSettleIgnoreUntil,
4492
4512
  resizeSuppressUntil: this.resizeSuppressUntil,
@@ -4541,6 +4561,7 @@ __export(index_exports, {
4541
4561
  DEFAULT_CDP_SCAN_INTERVAL_MS: () => DEFAULT_CDP_SCAN_INTERVAL_MS,
4542
4562
  DEFAULT_CHAT_TAIL_RECENT_MESSAGE_GRACE_MS: () => DEFAULT_CHAT_TAIL_RECENT_MESSAGE_GRACE_MS,
4543
4563
  DEFAULT_DAEMON_PORT: () => DEFAULT_DAEMON_PORT,
4564
+ DEFAULT_GIT_WORKSPACE_POLL_INTERVAL_MS: () => DEFAULT_GIT_WORKSPACE_POLL_INTERVAL_MS,
4544
4565
  DEFAULT_MACHINE_RUNTIME_SUBSCRIPTION_INTERVAL_MS: () => DEFAULT_MACHINE_RUNTIME_SUBSCRIPTION_INTERVAL_MS,
4545
4566
  DEFAULT_SESSION_HOST_APP_NAME: () => DEFAULT_SESSION_HOST_APP_NAME,
4546
4567
  DEFAULT_SESSION_HOST_DIAGNOSTICS_SUBSCRIPTION_INTERVAL_MS: () => DEFAULT_SESSION_HOST_DIAGNOSTICS_SUBSCRIPTION_INTERVAL_MS,
@@ -4559,8 +4580,12 @@ __export(index_exports, {
4559
4580
  DaemonCommandRouter: () => DaemonCommandRouter,
4560
4581
  DaemonStatusReporter: () => DaemonStatusReporter,
4561
4582
  DevServer: () => DevServer,
4583
+ GitCommandError: () => GitCommandError,
4584
+ GitWorkspaceMonitor: () => GitWorkspaceMonitor,
4562
4585
  IdeProviderInstance: () => IdeProviderInstance,
4586
+ InMemoryGitSnapshotStore: () => InMemoryGitSnapshotStore,
4563
4587
  LOG: () => LOG,
4588
+ MIN_GIT_WORKSPACE_POLL_INTERVAL_MS: () => MIN_GIT_WORKSPACE_POLL_INTERVAL_MS,
4564
4589
  MIN_MACHINE_RUNTIME_SUBSCRIPTION_INTERVAL_MS: () => MIN_MACHINE_RUNTIME_SUBSCRIPTION_INTERVAL_MS,
4565
4590
  MIN_SESSION_HOST_DIAGNOSTICS_SUBSCRIPTION_INTERVAL_MS: () => MIN_SESSION_HOST_DIAGNOSTICS_SUBSCRIPTION_INTERVAL_MS,
4566
4591
  NodePtyTransportFactory: () => NodePtyTransportFactory,
@@ -4569,6 +4594,7 @@ __export(index_exports, {
4569
4594
  ProviderLoader: () => ProviderLoader,
4570
4595
  STANDALONE_CDP_SCAN_INTERVAL_MS: () => STANDALONE_CDP_SCAN_INTERVAL_MS,
4571
4596
  SessionHostPtyTransportFactory: () => SessionHostPtyTransportFactory,
4597
+ TurnSnapshotTracker: () => TurnSnapshotTracker,
4572
4598
  VersionArchive: () => VersionArchive,
4573
4599
  appendRecentActivity: () => appendRecentActivity,
4574
4600
  buildAssistantChatMessage: () => buildAssistantChatMessage,
@@ -4588,9 +4614,14 @@ __export(index_exports, {
4588
4614
  buildUserChatMessage: () => buildUserChatMessage,
4589
4615
  classifyHotChatSessionsForSubscriptionFlush: () => classifyHotChatSessionsForSubscriptionFlush,
4590
4616
  clearDebugTrace: () => clearDebugTrace,
4617
+ compareGitSnapshots: () => compareGitSnapshots,
4591
4618
  configureDebugTraceStore: () => configureDebugTraceStore,
4592
4619
  connectCdpManager: () => connectCdpManager,
4593
4620
  createDebugTraceStore: () => createDebugTraceStore,
4621
+ createDefaultGitCommandServices: () => createDefaultGitCommandServices,
4622
+ createGitCompactSummary: () => createGitCompactSummary,
4623
+ createGitSnapshotStore: () => createGitSnapshotStore,
4624
+ createGitWorkspaceMonitor: () => createGitWorkspaceMonitor,
4594
4625
  createInteractionId: () => createInteractionId,
4595
4626
  detectAllVersions: () => detectAllVersions,
4596
4627
  detectCLIs: () => detectCLIs,
@@ -4605,6 +4636,9 @@ __export(index_exports, {
4605
4636
  getCurrentDaemonLogPath: () => getCurrentDaemonLogPath,
4606
4637
  getDaemonLogDir: () => getDaemonLogDir,
4607
4638
  getDebugRuntimeConfig: () => getDebugRuntimeConfig,
4639
+ getGitDiffSummary: () => getGitDiffSummary,
4640
+ getGitFileDiff: () => getGitFileDiff,
4641
+ getGitRepoStatus: () => getGitRepoStatus,
4608
4642
  getHostMemorySnapshot: () => getHostMemorySnapshot,
4609
4643
  getLogLevel: () => getLogLevel,
4610
4644
  getNpmExecOptions: () => getNpmExecOptions,
@@ -4616,6 +4650,7 @@ __export(index_exports, {
4616
4650
  getSessionHostRecoveryLabel: () => getSessionHostRecoveryLabel,
4617
4651
  getSessionHostSurfaceKind: () => getSessionHostSurfaceKind,
4618
4652
  getWorkspaceState: () => getWorkspaceState,
4653
+ handleGitCommand: () => handleGitCommand,
4619
4654
  hasCdpManager: () => hasCdpManager,
4620
4655
  hashSignatureParts: () => hashSignatureParts,
4621
4656
  initDaemonComponents: () => initDaemonComponents,
@@ -4624,9 +4659,11 @@ __export(index_exports, {
4624
4659
  isBuiltinChatMessageKind: () => isBuiltinChatMessageKind,
4625
4660
  isCdpConnected: () => isCdpConnected,
4626
4661
  isExtensionInstalled: () => isExtensionInstalled,
4662
+ isGitCommandName: () => isGitCommandName,
4627
4663
  isIdeRunning: () => isIdeRunning,
4628
4664
  isManagedStatusWaiting: () => isManagedStatusWaiting,
4629
4665
  isManagedStatusWorking: () => isManagedStatusWorking,
4666
+ isPathInside: () => isPathInside,
4630
4667
  isSessionHostLiveRuntime: () => isSessionHostLiveRuntime,
4631
4668
  isSessionHostRecoverySnapshot: () => isSessionHostRecoverySnapshot,
4632
4669
  isSetupComplete: () => isSetupComplete,
@@ -4644,10 +4681,13 @@ __export(index_exports, {
4644
4681
  normalizeChatMessageKind: () => normalizeChatMessageKind,
4645
4682
  normalizeChatMessages: () => normalizeChatMessages,
4646
4683
  normalizeChatTailActiveModal: () => normalizeChatTailActiveModal,
4684
+ normalizeGitOutput: () => normalizeGitOutput,
4685
+ normalizeGitWorkspaceSubscriptionParams: () => normalizeGitWorkspaceSubscriptionParams,
4647
4686
  normalizeInputEnvelope: () => normalizeInputEnvelope,
4648
4687
  normalizeManagedStatus: () => normalizeManagedStatus,
4649
4688
  normalizeMessageParts: () => normalizeMessageParts,
4650
4689
  normalizeSessionModalFields: () => normalizeSessionModalFields,
4690
+ parsePorcelainV2Status: () => parsePorcelainV2Status,
4651
4691
  parseProviderSourceConfigUpdate: () => parseProviderSourceConfigUpdate,
4652
4692
  partitionSessionHostDiagnosticsSessions: () => partitionSessionHostDiagnosticsSessions,
4653
4693
  partitionSessionHostRecords: () => partitionSessionHostRecords,
@@ -4663,9 +4703,11 @@ __export(index_exports, {
4663
4703
  resolveChatMessageKind: () => resolveChatMessageKind,
4664
4704
  resolveCurrentGlobalInstallSurface: () => resolveCurrentGlobalInstallSurface,
4665
4705
  resolveDebugRuntimeConfig: () => resolveDebugRuntimeConfig,
4706
+ resolveGitRepository: () => resolveGitRepository,
4666
4707
  resolveSessionHostAppName: () => resolveSessionHostAppName,
4667
4708
  resolveSessionHostAppNameResolution: () => resolveSessionHostAppNameResolution,
4668
4709
  runAsyncBatch: () => runAsyncBatch,
4710
+ runGit: () => runGit,
4669
4711
  saveConfig: () => saveConfig,
4670
4712
  saveState: () => saveState,
4671
4713
  setDebugRuntimeConfig: () => setDebugRuntimeConfig,
@@ -4676,23 +4718,1304 @@ __export(index_exports, {
4676
4718
  shutdownDaemonComponents: () => shutdownDaemonComponents,
4677
4719
  spawnDetachedDaemonUpgradeHelper: () => spawnDetachedDaemonUpgradeHelper,
4678
4720
  startDaemonDevSupport: () => startDaemonDevSupport,
4721
+ summarizeGitStatus: () => summarizeGitStatus,
4679
4722
  updateConfig: () => updateConfig,
4680
4723
  upsertSavedProviderSession: () => upsertSavedProviderSession
4681
4724
  });
4682
4725
  module.exports = __toCommonJS(index_exports);
4726
+
4727
+ // src/git/git-executor.ts
4728
+ var import_node_child_process = require("child_process");
4729
+ var import_node_fs = require("fs");
4730
+ var import_promises = require("fs/promises");
4731
+ var path = __toESM(require("path"));
4732
+ var import_node_util = require("util");
4733
+ var execFileAsync = (0, import_node_util.promisify)(import_node_child_process.execFile);
4734
+ var DEFAULT_TIMEOUT_MS = 5e3;
4735
+ var DEFAULT_MAX_BUFFER = 1024 * 1024;
4736
+ var GitCommandError = class extends Error {
4737
+ reason;
4738
+ stdout;
4739
+ stderr;
4740
+ exitCode;
4741
+ signal;
4742
+ argv;
4743
+ cwd;
4744
+ constructor(reason, message, details = {}) {
4745
+ super(message);
4746
+ if (details.cause !== void 0) {
4747
+ this.cause = details.cause;
4748
+ }
4749
+ this.name = "GitCommandError";
4750
+ this.reason = reason;
4751
+ this.stdout = normalizeGitOutput(details.stdout);
4752
+ this.stderr = normalizeGitOutput(details.stderr);
4753
+ this.exitCode = details.exitCode;
4754
+ this.signal = details.signal;
4755
+ this.argv = details.argv ? [...details.argv] : void 0;
4756
+ this.cwd = details.cwd;
4757
+ }
4758
+ };
4759
+ async function resolveGitRepository(workspace, options = {}) {
4760
+ const normalizedWorkspace = await validateWorkspace(workspace);
4761
+ const result = await execGitRaw(normalizedWorkspace, ["rev-parse", "--show-toplevel"], options, {
4762
+ mapNotGitRepo: true
4763
+ });
4764
+ const repoRoot = path.resolve(result.stdout.trim());
4765
+ if (!repoRoot) {
4766
+ throw new GitCommandError("not_git_repo", "Git did not return a repository root", {
4767
+ stdout: result.stdout,
4768
+ stderr: result.stderr,
4769
+ argv: ["rev-parse", "--show-toplevel"],
4770
+ cwd: normalizedWorkspace
4771
+ });
4772
+ }
4773
+ return {
4774
+ workspace: normalizedWorkspace,
4775
+ repoRoot,
4776
+ isGitRepo: true
4777
+ };
4778
+ }
4779
+ async function runGit(repoOrWorkspace, argv, options = {}) {
4780
+ validateGitArgv(argv);
4781
+ const repo = typeof repoOrWorkspace === "string" ? await resolveGitRepository(repoOrWorkspace, options) : repoOrWorkspace;
4782
+ if (!repo.repoRoot || !repo.isGitRepo) {
4783
+ throw new GitCommandError("not_git_repo", "Workspace is not a Git repository", {
4784
+ argv,
4785
+ cwd: repo.workspace
4786
+ });
4787
+ }
4788
+ const cwd = options.cwd ? await validateWorkspace(options.cwd) : await validateWorkspace(repo.workspace);
4789
+ const canonicalRepoRoot = await (0, import_promises.realpath)(repo.repoRoot);
4790
+ const canonicalCwd = await (0, import_promises.realpath)(cwd);
4791
+ if (!isPathInside(canonicalRepoRoot, canonicalCwd)) {
4792
+ throw new GitCommandError("path_outside_repo", "Git cwd is outside the repository root", {
4793
+ argv,
4794
+ cwd
4795
+ });
4796
+ }
4797
+ return execGitRaw(cwd, argv, options);
4798
+ }
4799
+ function normalizeGitOutput(value) {
4800
+ if (typeof value === "string") return value.replace(/\r\n/g, "\n");
4801
+ if (Buffer.isBuffer(value)) return value.toString("utf8").replace(/\r\n/g, "\n");
4802
+ if (value == null) return "";
4803
+ return String(value).replace(/\r\n/g, "\n");
4804
+ }
4805
+ function isPathInside(parent, child) {
4806
+ const relative3 = path.relative(path.resolve(parent), path.resolve(child));
4807
+ return relative3 === "" || !relative3.startsWith("..") && !path.isAbsolute(relative3);
4808
+ }
4809
+ async function validateWorkspace(workspace) {
4810
+ if (typeof workspace !== "string" || workspace.length === 0 || workspace.includes("\0")) {
4811
+ throw new GitCommandError("invalid_args", "Workspace must be a non-empty path");
4812
+ }
4813
+ if (!path.isAbsolute(workspace)) {
4814
+ throw new GitCommandError("invalid_args", "Workspace must be an absolute path", { cwd: workspace });
4815
+ }
4816
+ const normalizedWorkspace = path.resolve(workspace);
4817
+ try {
4818
+ const info = await (0, import_promises.stat)(normalizedWorkspace);
4819
+ if (!info.isDirectory()) {
4820
+ throw new GitCommandError("invalid_args", "Workspace must be an existing directory", {
4821
+ cwd: normalizedWorkspace
4822
+ });
4823
+ }
4824
+ await (0, import_promises.access)(normalizedWorkspace, import_node_fs.constants.R_OK);
4825
+ } catch (error) {
4826
+ if (error instanceof GitCommandError) throw error;
4827
+ throw new GitCommandError("invalid_args", "Workspace must be an existing directory", {
4828
+ cwd: normalizedWorkspace,
4829
+ cause: error
4830
+ });
4831
+ }
4832
+ return normalizedWorkspace;
4833
+ }
4834
+ function validateGitArgv(argv) {
4835
+ if (!Array.isArray(argv) || argv.length === 0) {
4836
+ throw new GitCommandError("invalid_args", "Git argv must be a non-empty string array", { argv });
4837
+ }
4838
+ for (const arg of argv) {
4839
+ if (typeof arg !== "string" || arg.length === 0 || arg.includes("\0")) {
4840
+ throw new GitCommandError("invalid_args", "Git argv contains an invalid argument", { argv });
4841
+ }
4842
+ }
4843
+ if (argv.includes("-C") || argv.some((arg) => arg.startsWith("--git-dir") || arg.startsWith("--work-tree"))) {
4844
+ throw new GitCommandError("invalid_args", "Git argv contains unsafe repository override arguments", {
4845
+ argv
4846
+ });
4847
+ }
4848
+ }
4849
+ async function execGitRaw(cwd, argv, options, behavior = {}) {
4850
+ validateGitArgv(argv);
4851
+ try {
4852
+ const result = await execFileAsync("git", [...argv], {
4853
+ cwd,
4854
+ encoding: "utf8",
4855
+ timeout: options.timeoutMs ?? DEFAULT_TIMEOUT_MS,
4856
+ maxBuffer: options.maxBuffer ?? DEFAULT_MAX_BUFFER,
4857
+ windowsHide: true
4858
+ });
4859
+ return {
4860
+ stdout: normalizeGitOutput(result.stdout),
4861
+ stderr: normalizeGitOutput(result.stderr)
4862
+ };
4863
+ } catch (error) {
4864
+ throw mapExecError(error, cwd, argv, behavior);
4865
+ }
4866
+ }
4867
+ function mapExecError(error, cwd, argv, behavior) {
4868
+ const execError = error;
4869
+ const stdout = normalizeGitOutput(execError.stdout);
4870
+ const stderr = normalizeGitOutput(execError.stderr);
4871
+ const code = execError.code;
4872
+ const signal = execError.signal;
4873
+ const message = [stderr.trim(), execError.message].filter(Boolean).join("\n");
4874
+ if (code === "ENOENT") {
4875
+ return new GitCommandError("git_not_installed", "Git executable was not found", {
4876
+ stdout,
4877
+ stderr,
4878
+ exitCode: code,
4879
+ signal,
4880
+ argv,
4881
+ cwd,
4882
+ cause: error
4883
+ });
4884
+ }
4885
+ if (execError.killed || /timed out/i.test(execError.message)) {
4886
+ return new GitCommandError("timeout", "Git command timed out", {
4887
+ stdout,
4888
+ stderr,
4889
+ exitCode: code,
4890
+ signal,
4891
+ argv,
4892
+ cwd,
4893
+ cause: error
4894
+ });
4895
+ }
4896
+ if (behavior.mapNotGitRepo && /not a git repository/i.test(stderr + "\n" + execError.message)) {
4897
+ return new GitCommandError("not_git_repo", "Workspace is not a Git repository", {
4898
+ stdout,
4899
+ stderr,
4900
+ exitCode: code,
4901
+ signal,
4902
+ argv,
4903
+ cwd,
4904
+ cause: error
4905
+ });
4906
+ }
4907
+ return new GitCommandError("git_command_failed", message || "Git command failed", {
4908
+ stdout,
4909
+ stderr,
4910
+ exitCode: code,
4911
+ signal,
4912
+ argv,
4913
+ cwd,
4914
+ cause: error
4915
+ });
4916
+ }
4917
+
4918
+ // src/git/git-status.ts
4919
+ async function getGitRepoStatus(workspace, options = {}) {
4920
+ const lastCheckedAt = Date.now();
4921
+ try {
4922
+ const repo = await resolveGitRepository(workspace, options);
4923
+ const statusOutput = await runGit(repo, ["status", "--porcelain=v2", "--branch"], options);
4924
+ const parsed = parsePorcelainV2Status(statusOutput.stdout);
4925
+ const head = await readHead(repo, options);
4926
+ const stashCount = await readStashCount(repo, options);
4927
+ return {
4928
+ workspace: repo.workspace,
4929
+ repoRoot: repo.repoRoot,
4930
+ isGitRepo: true,
4931
+ branch: parsed.branch,
4932
+ headCommit: head.commit,
4933
+ headMessage: head.message,
4934
+ upstream: parsed.upstream,
4935
+ ahead: parsed.ahead,
4936
+ behind: parsed.behind,
4937
+ staged: parsed.staged,
4938
+ modified: parsed.modified,
4939
+ untracked: parsed.untracked,
4940
+ deleted: parsed.deleted,
4941
+ renamed: parsed.renamed,
4942
+ hasConflicts: parsed.conflictFiles.length > 0,
4943
+ conflictFiles: parsed.conflictFiles,
4944
+ stashCount,
4945
+ lastCheckedAt
4946
+ };
4947
+ } catch (error) {
4948
+ if (error instanceof GitCommandError) {
4949
+ return emptyStatus(workspace, lastCheckedAt, error);
4950
+ }
4951
+ return emptyStatus(
4952
+ workspace,
4953
+ lastCheckedAt,
4954
+ new GitCommandError("git_command_failed", "Failed to read Git status", { cause: error })
4955
+ );
4956
+ }
4957
+ }
4958
+ function parsePorcelainV2Status(output) {
4959
+ const parsed = {
4960
+ branch: null,
4961
+ upstream: null,
4962
+ ahead: 0,
4963
+ behind: 0,
4964
+ staged: 0,
4965
+ modified: 0,
4966
+ untracked: 0,
4967
+ deleted: 0,
4968
+ renamed: 0,
4969
+ conflictFiles: []
4970
+ };
4971
+ for (const line of output.split("\n")) {
4972
+ if (!line) continue;
4973
+ if (line.startsWith("# branch.head ")) {
4974
+ const branch = line.slice("# branch.head ".length).trim();
4975
+ parsed.branch = branch && branch !== "(detached)" ? branch : null;
4976
+ continue;
4977
+ }
4978
+ if (line.startsWith("# branch.upstream ")) {
4979
+ parsed.upstream = line.slice("# branch.upstream ".length).trim() || null;
4980
+ continue;
4981
+ }
4982
+ if (line.startsWith("# branch.ab ")) {
4983
+ const match = line.match(/\+(-?\d+)\s+-(-?\d+)/);
4984
+ if (match) {
4985
+ parsed.ahead = Number.parseInt(match[1] ?? "0", 10) || 0;
4986
+ parsed.behind = Number.parseInt(match[2] ?? "0", 10) || 0;
4987
+ }
4988
+ continue;
4989
+ }
4990
+ if (line.startsWith("? ")) {
4991
+ parsed.untracked += 1;
4992
+ continue;
4993
+ }
4994
+ if (line.startsWith("u ")) {
4995
+ const fields = line.split(" ");
4996
+ const filePath = fields.slice(10).join(" ");
4997
+ if (filePath) parsed.conflictFiles.push(filePath);
4998
+ continue;
4999
+ }
5000
+ if (line.startsWith("1 ") || line.startsWith("2 ")) {
5001
+ const fields = line.split(" ");
5002
+ const xy = fields[1] ?? "..";
5003
+ const indexStatus = xy[0] ?? ".";
5004
+ const worktreeStatus = xy[1] ?? ".";
5005
+ if (isStagedStatus(indexStatus)) parsed.staged += 1;
5006
+ if (worktreeStatus === "M" || worktreeStatus === "T") parsed.modified += 1;
5007
+ if (indexStatus === "D" || worktreeStatus === "D") parsed.deleted += 1;
5008
+ if (indexStatus === "R" || worktreeStatus === "R") parsed.renamed += 1;
5009
+ if (xy.includes("U")) {
5010
+ const filePath = fields.slice(line.startsWith("2 ") ? 9 : 8).join(" ").split(" ")[0] ?? "";
5011
+ if (filePath) parsed.conflictFiles.push(filePath);
5012
+ }
5013
+ }
5014
+ }
5015
+ parsed.conflictFiles = Array.from(new Set(parsed.conflictFiles));
5016
+ return parsed;
5017
+ }
5018
+ async function readHead(repo, options) {
5019
+ try {
5020
+ const result = await runGit(repo, ["log", "-1", "--pretty=%h%x00%s"], options);
5021
+ const text = result.stdout.trimEnd();
5022
+ if (!text) return { commit: null, message: null };
5023
+ const [commit, ...messageParts] = text.split("\0");
5024
+ return {
5025
+ commit: commit || null,
5026
+ message: messageParts.join("\0") || null
5027
+ };
5028
+ } catch {
5029
+ return { commit: null, message: null };
5030
+ }
5031
+ }
5032
+ async function readStashCount(repo, options) {
5033
+ try {
5034
+ const result = await runGit(repo, ["stash", "list", "--format=%gd"], options);
5035
+ return result.stdout.split("\n").filter((line) => line.trim().length > 0).length;
5036
+ } catch {
5037
+ return 0;
5038
+ }
5039
+ }
5040
+ function isStagedStatus(status) {
5041
+ return status !== "." && status !== "?" && status !== "U";
5042
+ }
5043
+ function emptyStatus(workspace, lastCheckedAt, error) {
5044
+ return {
5045
+ workspace,
5046
+ repoRoot: null,
5047
+ isGitRepo: false,
5048
+ branch: null,
5049
+ headCommit: null,
5050
+ headMessage: null,
5051
+ upstream: null,
5052
+ ahead: 0,
5053
+ behind: 0,
5054
+ staged: 0,
5055
+ modified: 0,
5056
+ untracked: 0,
5057
+ deleted: 0,
5058
+ renamed: 0,
5059
+ hasConflicts: false,
5060
+ conflictFiles: [],
5061
+ stashCount: 0,
5062
+ lastCheckedAt,
5063
+ error: error.stderr || error.message,
5064
+ reason: error.reason
5065
+ };
5066
+ }
5067
+
5068
+ // src/git/git-diff.ts
5069
+ var import_promises2 = require("fs/promises");
5070
+ var path2 = __toESM(require("path"));
5071
+ var DEFAULT_MAX_FILES = 200;
5072
+ var DEFAULT_MAX_BYTES = 2e5;
5073
+ async function getGitDiffSummary(workspace, options = {}) {
5074
+ const lastCheckedAt = Date.now();
5075
+ try {
5076
+ const repo = await resolveGitRepository(workspace, options);
5077
+ const repoRoot = repo.repoRoot;
5078
+ const [unstagedNameStatus, unstagedNumstat, stagedNameStatus, stagedNumstat, untracked] = await Promise.all([
5079
+ runGit(repo, ["diff", "--no-ext-diff", "--name-status"], { ...options, cwd: repoRoot }),
5080
+ runGit(repo, ["diff", "--no-ext-diff", "--numstat"], { ...options, cwd: repoRoot }),
5081
+ runGit(repo, ["diff", "--cached", "--no-ext-diff", "--name-status"], { ...options, cwd: repoRoot }),
5082
+ runGit(repo, ["diff", "--cached", "--no-ext-diff", "--numstat"], { ...options, cwd: repoRoot }),
5083
+ runGit(repo, ["ls-files", "--others", "--exclude-standard"], { ...options, cwd: repoRoot })
5084
+ ]);
5085
+ const outputBytes = byteLength(
5086
+ unstagedNameStatus.stdout + unstagedNumstat.stdout + stagedNameStatus.stdout + stagedNumstat.stdout + untracked.stdout
5087
+ );
5088
+ const changes = [
5089
+ ...combineDiffEntries(unstagedNameStatus.stdout, unstagedNumstat.stdout, false),
5090
+ ...combineDiffEntries(stagedNameStatus.stdout, stagedNumstat.stdout, true),
5091
+ ...parseUntrackedFiles(untracked.stdout)
5092
+ ];
5093
+ const maxFiles = normalizePositiveInteger(options.maxFiles, DEFAULT_MAX_FILES);
5094
+ const maxBytes = normalizePositiveInteger(options.maxBytes, DEFAULT_MAX_BYTES);
5095
+ const files = changes.slice(0, maxFiles);
5096
+ const truncated = changes.length > files.length || outputBytes > maxBytes;
5097
+ return {
5098
+ workspace: repo.workspace,
5099
+ repoRoot,
5100
+ isGitRepo: true,
5101
+ files,
5102
+ totalInsertions: files.reduce((sum, file) => sum + file.insertions, 0),
5103
+ totalDeletions: files.reduce((sum, file) => sum + file.deletions, 0),
5104
+ truncated,
5105
+ lastCheckedAt
5106
+ };
5107
+ } catch (error) {
5108
+ const gitError = error instanceof GitCommandError ? error : new GitCommandError("git_command_failed", "Failed to read Git diff summary", { cause: error });
5109
+ return {
5110
+ workspace,
5111
+ repoRoot: null,
5112
+ isGitRepo: false,
5113
+ files: [],
5114
+ totalInsertions: 0,
5115
+ totalDeletions: 0,
5116
+ truncated: false,
5117
+ lastCheckedAt,
5118
+ error: gitError.stderr || gitError.message,
5119
+ reason: gitError.reason
5120
+ };
5121
+ }
5122
+ }
5123
+ async function getGitFileDiff(workspace, filePath, options = {}) {
5124
+ const lastCheckedAt = Date.now();
5125
+ const repo = await resolveGitRepository(workspace, options);
5126
+ const repoRoot = repo.repoRoot;
5127
+ const selected = await resolveRepoFilePath(repoRoot, filePath);
5128
+ const maxBytes = normalizePositiveInteger(options.maxBytes, DEFAULT_MAX_BYTES);
5129
+ const [unstaged, staged] = await Promise.all([
5130
+ runGit(repo, ["diff", "--no-ext-diff", "--", selected.relativePath], { ...options, cwd: repoRoot }),
5131
+ runGit(repo, ["diff", "--cached", "--no-ext-diff", "--", selected.relativePath], { ...options, cwd: repoRoot })
5132
+ ]);
5133
+ let diff = [unstaged.stdout, staged.stdout].filter((part) => part.length > 0).join("\n");
5134
+ if (!diff) {
5135
+ const untracked = await runGit(repo, ["ls-files", "--others", "--exclude-standard", "--", selected.relativePath], {
5136
+ ...options,
5137
+ cwd: repoRoot
5138
+ });
5139
+ const untrackedFiles = untracked.stdout.split("\n").filter(Boolean);
5140
+ if (untrackedFiles.includes(selected.relativePath)) {
5141
+ diff = await buildUntrackedDiff(selected.absolutePath, selected.relativePath, maxBytes + 1);
5142
+ }
5143
+ }
5144
+ const bounded = truncateText(diff, maxBytes);
5145
+ return {
5146
+ workspace: repo.workspace,
5147
+ repoRoot,
5148
+ isGitRepo: true,
5149
+ path: selected.relativePath,
5150
+ diff: bounded.text,
5151
+ truncated: bounded.truncated,
5152
+ lastCheckedAt
5153
+ };
5154
+ }
5155
+ function combineDiffEntries(nameStatusOutput, numstatOutput, staged) {
5156
+ const statusEntries = parseNameStatus(nameStatusOutput);
5157
+ const numstatEntries = parseNumstat(numstatOutput);
5158
+ return statusEntries.map((entry, index) => {
5159
+ const stats = numstatEntries[index];
5160
+ return {
5161
+ path: entry.path,
5162
+ oldPath: entry.oldPath,
5163
+ status: entry.status,
5164
+ staged,
5165
+ insertions: stats?.insertions ?? 0,
5166
+ deletions: stats?.deletions ?? 0,
5167
+ binary: stats?.binary || void 0
5168
+ };
5169
+ });
5170
+ }
5171
+ function parseNameStatus(output) {
5172
+ return output.split("\n").filter(Boolean).map((line) => {
5173
+ const fields = line.split(" ");
5174
+ const code = fields[0] ?? "";
5175
+ const statusLetter = code[0] ?? "M";
5176
+ if (statusLetter === "R") {
5177
+ return {
5178
+ oldPath: fields[1] ?? "",
5179
+ path: fields[2] ?? fields[1] ?? "",
5180
+ status: "renamed"
5181
+ };
5182
+ }
5183
+ if (statusLetter === "C") {
5184
+ return {
5185
+ oldPath: fields[1] ?? "",
5186
+ path: fields[2] ?? fields[1] ?? "",
5187
+ status: "copied"
5188
+ };
5189
+ }
5190
+ return {
5191
+ path: fields[1] ?? "",
5192
+ status: mapNameStatus(statusLetter)
5193
+ };
5194
+ }).filter((entry) => entry.path.length > 0);
5195
+ }
5196
+ function parseNumstat(output) {
5197
+ return output.split("\n").filter(Boolean).map((line) => {
5198
+ const fields = line.split(" ");
5199
+ const insertionsText = fields[0] ?? "0";
5200
+ const deletionsText = fields[1] ?? "0";
5201
+ const binary = insertionsText === "-" || deletionsText === "-";
5202
+ return {
5203
+ path: fields.slice(2).join(" "),
5204
+ insertions: binary ? 0 : Number.parseInt(insertionsText, 10) || 0,
5205
+ deletions: binary ? 0 : Number.parseInt(deletionsText, 10) || 0,
5206
+ binary
5207
+ };
5208
+ });
5209
+ }
5210
+ function parseUntrackedFiles(output) {
5211
+ return output.split("\n").filter(Boolean).map((filePath) => ({
5212
+ path: filePath,
5213
+ status: "untracked",
5214
+ staged: false,
5215
+ insertions: 0,
5216
+ deletions: 0
5217
+ }));
5218
+ }
5219
+ function mapNameStatus(status) {
5220
+ switch (status) {
5221
+ case "A":
5222
+ return "added";
5223
+ case "D":
5224
+ return "deleted";
5225
+ case "R":
5226
+ return "renamed";
5227
+ case "C":
5228
+ return "copied";
5229
+ case "U":
5230
+ return "conflict";
5231
+ case "M":
5232
+ case "T":
5233
+ default:
5234
+ return "modified";
5235
+ }
5236
+ }
5237
+ async function resolveRepoFilePath(repoRoot, filePath) {
5238
+ if (typeof filePath !== "string" || filePath.length === 0 || filePath.includes("\0")) {
5239
+ throw new GitCommandError("invalid_args", "File path must be a non-empty path");
5240
+ }
5241
+ const canonicalRepoRoot = await (0, import_promises2.realpath)(repoRoot).catch(() => path2.resolve(repoRoot));
5242
+ const absolutePath = path2.isAbsolute(filePath) ? path2.resolve(filePath) : path2.resolve(repoRoot, filePath);
5243
+ const checkPath = await (0, import_promises2.realpath)(absolutePath).catch(() => absolutePath);
5244
+ const relativeBase = isPathInside(canonicalRepoRoot, checkPath) ? canonicalRepoRoot : path2.resolve(repoRoot);
5245
+ if (!isPathInside(canonicalRepoRoot, checkPath) && !isPathInside(repoRoot, absolutePath)) {
5246
+ throw new GitCommandError("path_outside_repo", "Selected file path is outside the repository root", {
5247
+ cwd: repoRoot
5248
+ });
5249
+ }
5250
+ const relativePath = path2.relative(relativeBase, checkPath).split(path2.sep).join("/");
5251
+ if (!relativePath || relativePath.startsWith("..") || path2.isAbsolute(relativePath)) {
5252
+ throw new GitCommandError("path_outside_repo", "Selected file path is outside the repository root", {
5253
+ cwd: repoRoot
5254
+ });
5255
+ }
5256
+ return { absolutePath, relativePath };
5257
+ }
5258
+ async function buildUntrackedDiff(absolutePath, relativePath, readLimit) {
5259
+ const content = await (0, import_promises2.readFile)(absolutePath, "utf8");
5260
+ const limitedContent = content.length > readLimit ? content.slice(0, readLimit) : content;
5261
+ const lines = limitedContent.length > 0 ? limitedContent.split("\n") : [];
5262
+ const plusLines = lines.filter((line, index) => index < lines.length - 1 || line.length > 0).map((line) => `+${line}`).join("\n");
5263
+ const lineCount = plusLines ? plusLines.split("\n").length : 0;
5264
+ return [
5265
+ `diff --git a/${relativePath} b/${relativePath}`,
5266
+ "new file mode 100644",
5267
+ "index 0000000..0000000",
5268
+ "--- /dev/null",
5269
+ `+++ b/${relativePath}`,
5270
+ `@@ -0,0 +1,${lineCount} @@`,
5271
+ plusLines
5272
+ ].filter((line) => line.length > 0).join("\n");
5273
+ }
5274
+ function truncateText(text, maxBytes) {
5275
+ if (byteLength(text) <= maxBytes) return { text, truncated: false };
5276
+ return { text: Buffer.from(text, "utf8").subarray(0, maxBytes).toString("utf8"), truncated: true };
5277
+ }
5278
+ function byteLength(text) {
5279
+ return Buffer.byteLength(text, "utf8");
5280
+ }
5281
+ function normalizePositiveInteger(value, fallback) {
5282
+ if (!Number.isFinite(value) || value == null || value <= 0) return fallback;
5283
+ return Math.floor(value);
5284
+ }
5285
+
5286
+ // src/git/git-summary.ts
5287
+ function countStatusChangedFiles(status) {
5288
+ const conflictCount = status.conflictFiles.length > 0 ? status.conflictFiles.length : status.hasConflicts ? 1 : 0;
5289
+ return status.staged + status.modified + status.untracked + status.deleted + status.renamed + conflictCount;
5290
+ }
5291
+ function createGitCompactSummary(status, diffSummary) {
5292
+ const statusChangedFiles = countStatusChangedFiles(status);
5293
+ const diffChangedFiles = diffSummary?.files.length ?? 0;
5294
+ const changedFiles = Math.max(statusChangedFiles, diffChangedFiles);
5295
+ const conflictCount = status.conflictFiles.length > 0 ? status.conflictFiles.length : status.hasConflicts ? 1 : 0;
5296
+ return {
5297
+ isGitRepo: status.isGitRepo,
5298
+ repoRoot: status.repoRoot,
5299
+ branch: status.branch,
5300
+ dirty: status.staged > 0 || status.modified > 0 || status.untracked > 0 || status.deleted > 0 || status.renamed > 0 || conflictCount > 0 || changedFiles > 0,
5301
+ changedFiles,
5302
+ ahead: status.ahead,
5303
+ behind: status.behind,
5304
+ hasConflicts: status.hasConflicts || conflictCount > 0,
5305
+ lastCheckedAt: Math.max(status.lastCheckedAt, diffSummary?.lastCheckedAt ?? status.lastCheckedAt),
5306
+ error: status.error ?? diffSummary?.error,
5307
+ reason: status.reason ?? diffSummary?.reason
5308
+ };
5309
+ }
5310
+ var summarizeGitStatus = createGitCompactSummary;
5311
+
5312
+ // src/git/git-snapshot-store.ts
5313
+ function normalizeCapacity(capacity) {
5314
+ return Math.max(1, Math.floor(capacity ?? 100));
5315
+ }
5316
+ function createEmptyDiffSummary(status) {
5317
+ return {
5318
+ workspace: status.workspace,
5319
+ repoRoot: status.repoRoot,
5320
+ isGitRepo: status.isGitRepo,
5321
+ files: [],
5322
+ totalInsertions: 0,
5323
+ totalDeletions: 0,
5324
+ truncated: false,
5325
+ lastCheckedAt: status.lastCheckedAt,
5326
+ error: status.error,
5327
+ reason: status.reason
5328
+ };
5329
+ }
5330
+ function changedFileKey(file) {
5331
+ return `${file.oldPath ?? ""}\0${file.path}`;
5332
+ }
5333
+ function uniqueSorted(values) {
5334
+ return Array.from(new Set(Array.from(values).filter(Boolean))).sort((a, b) => a.localeCompare(b));
5335
+ }
5336
+ function plural(count, singular, pluralText = `${singular}s`) {
5337
+ return count === 1 ? singular : pluralText;
5338
+ }
5339
+ function compareGitSnapshots(before, after) {
5340
+ const beforeFileKeys = new Set(before.diffSummary.files.map(changedFileKey));
5341
+ const changedAfterFiles = after.diffSummary.files.filter((file) => !beforeFileKeys.has(changedFileKey(file)));
5342
+ const addedFiles = [];
5343
+ const modifiedFiles = [];
5344
+ const deletedFiles = [];
5345
+ const renamedFiles = [];
5346
+ const untrackedFiles = [];
5347
+ const conflictFilesFromDiff = [];
5348
+ let totalInsertions = 0;
5349
+ let totalDeletions = 0;
5350
+ for (const file of changedAfterFiles) {
5351
+ totalInsertions += file.insertions;
5352
+ totalDeletions += file.deletions;
5353
+ switch (file.status) {
5354
+ case "added":
5355
+ case "copied":
5356
+ addedFiles.push(file.path);
5357
+ break;
5358
+ case "modified":
5359
+ modifiedFiles.push(file.path);
5360
+ break;
5361
+ case "deleted":
5362
+ deletedFiles.push(file.path);
5363
+ break;
5364
+ case "renamed":
5365
+ renamedFiles.push({ oldPath: file.oldPath ?? file.path, path: file.path });
5366
+ break;
5367
+ case "untracked":
5368
+ untrackedFiles.push(file.path);
5369
+ break;
5370
+ case "conflict":
5371
+ conflictFilesFromDiff.push(file.path);
5372
+ break;
5373
+ }
5374
+ }
5375
+ renamedFiles.sort((a, b) => `${a.oldPath}\0${a.path}`.localeCompare(`${b.oldPath}\0${b.path}`));
5376
+ const conflictFiles = uniqueSorted([...after.status.conflictFiles, ...conflictFilesFromDiff]);
5377
+ const changedFiles = changedAfterFiles.length;
5378
+ const hasConflicts = after.status.hasConflicts || conflictFiles.length > 0;
5379
+ const summaryParts = [];
5380
+ if (changedFiles > 0) summaryParts.push(`${changedFiles} ${plural(changedFiles, "file")} changed`);
5381
+ if (addedFiles.length > 0) summaryParts.push(`${addedFiles.length} added`);
5382
+ if (modifiedFiles.length > 0) summaryParts.push(`${modifiedFiles.length} modified`);
5383
+ if (deletedFiles.length > 0) summaryParts.push(`${deletedFiles.length} deleted`);
5384
+ if (renamedFiles.length > 0) summaryParts.push(`${renamedFiles.length} renamed`);
5385
+ if (untrackedFiles.length > 0) summaryParts.push(`${untrackedFiles.length} untracked`);
5386
+ if (hasConflicts) summaryParts.push(`${conflictFiles.length || 1} ${plural(conflictFiles.length || 1, "conflict")}`);
5387
+ return {
5388
+ beforeSnapshotId: before.id,
5389
+ afterSnapshotId: after.id,
5390
+ workspace: after.workspace,
5391
+ repoRoot: after.repoRoot,
5392
+ changedFiles,
5393
+ addedFiles: uniqueSorted(addedFiles),
5394
+ modifiedFiles: uniqueSorted(modifiedFiles),
5395
+ deletedFiles: uniqueSorted(deletedFiles),
5396
+ renamedFiles,
5397
+ untrackedFiles: uniqueSorted(untrackedFiles),
5398
+ conflictFiles,
5399
+ totalInsertions,
5400
+ totalDeletions,
5401
+ hasConflicts,
5402
+ currentStatus: after.status,
5403
+ summaryText: summaryParts.length > 0 ? summaryParts.join(", ") : "No file-set changes between snapshots."
5404
+ };
5405
+ }
5406
+ var InMemoryGitSnapshotStore = class {
5407
+ snapshots = /* @__PURE__ */ new Map();
5408
+ order = [];
5409
+ capacity;
5410
+ now;
5411
+ idPrefix;
5412
+ getStatusProvider;
5413
+ getDiffSummaryProvider;
5414
+ counter = 0;
5415
+ constructor(options = {}) {
5416
+ this.capacity = normalizeCapacity(options.capacity);
5417
+ this.now = options.now ?? Date.now;
5418
+ this.idPrefix = options.idPrefix ?? "git-snapshot";
5419
+ this.getStatusProvider = options.getStatus;
5420
+ this.getDiffSummaryProvider = options.getDiffSummary;
5421
+ }
5422
+ async create(input) {
5423
+ const getStatus = input.getStatus ?? this.getStatusProvider;
5424
+ if (!getStatus) {
5425
+ throw new Error("GitSnapshotStore requires an injected getStatus provider");
5426
+ }
5427
+ const status = await getStatus(input.workspace);
5428
+ const getDiffSummary = input.getDiffSummary ?? this.getDiffSummaryProvider;
5429
+ const diffSummary = getDiffSummary ? await getDiffSummary(input.workspace, status) : createEmptyDiffSummary(status);
5430
+ const createdAt = this.now();
5431
+ const id = `${this.idPrefix}-${createdAt}-${++this.counter}`;
5432
+ const snapshot = {
5433
+ id,
5434
+ workspace: input.workspace,
5435
+ repoRoot: status.repoRoot ?? input.workspace,
5436
+ sessionId: input.sessionId,
5437
+ turnId: input.turnId,
5438
+ reason: input.reason,
5439
+ status,
5440
+ diffSummary,
5441
+ createdAt
5442
+ };
5443
+ this.snapshots.set(id, snapshot);
5444
+ this.order.push(id);
5445
+ this.enforceCapacity();
5446
+ return snapshot;
5447
+ }
5448
+ get(id) {
5449
+ return this.snapshots.get(id);
5450
+ }
5451
+ compare(beforeSnapshotId, afterSnapshotId) {
5452
+ const before = this.snapshots.get(beforeSnapshotId);
5453
+ if (!before) throw new Error(`Unknown before snapshot: ${beforeSnapshotId}`);
5454
+ const after = this.snapshots.get(afterSnapshotId);
5455
+ if (!after) throw new Error(`Unknown after snapshot: ${afterSnapshotId}`);
5456
+ return compareGitSnapshots(before, after);
5457
+ }
5458
+ list(query = {}) {
5459
+ const limit = Math.max(1, Math.floor(query.limit ?? this.capacity));
5460
+ return this.order.map((id) => this.snapshots.get(id)).filter((snapshot) => Boolean(snapshot)).filter((snapshot) => !query.workspace || snapshot.workspace === query.workspace).filter((snapshot) => !query.sessionId || snapshot.sessionId === query.sessionId).slice(-limit);
5461
+ }
5462
+ clear() {
5463
+ this.snapshots.clear();
5464
+ this.order.splice(0, this.order.length);
5465
+ }
5466
+ enforceCapacity() {
5467
+ while (this.order.length > this.capacity) {
5468
+ const evictedId = this.order.shift();
5469
+ if (evictedId) this.snapshots.delete(evictedId);
5470
+ }
5471
+ }
5472
+ };
5473
+ function createGitSnapshotStore(options = {}) {
5474
+ return new InMemoryGitSnapshotStore(options);
5475
+ }
5476
+
5477
+ // src/git/git-monitor.ts
5478
+ var DEFAULT_GIT_WORKSPACE_POLL_INTERVAL_MS = 5e3;
5479
+ var MIN_GIT_WORKSPACE_POLL_INTERVAL_MS = 1e3;
5480
+ function defaultStatusProvider(workspace) {
5481
+ return getGitRepoStatus(workspace);
5482
+ }
5483
+ function defaultDiffSummaryProvider(workspace) {
5484
+ return getGitDiffSummary(workspace);
5485
+ }
5486
+ function normalizeIntervalMs(value, defaultIntervalMs, minIntervalMs) {
5487
+ const requested = Number.isFinite(value) ? Math.floor(value) : defaultIntervalMs;
5488
+ return Math.max(minIntervalMs, requested > 0 ? requested : defaultIntervalMs);
5489
+ }
5490
+ function normalizeGitWorkspaceSubscriptionParams(params, options = {}) {
5491
+ const minIntervalMs = Math.max(1, Math.floor(options.minIntervalMs ?? MIN_GIT_WORKSPACE_POLL_INTERVAL_MS));
5492
+ const defaultIntervalMs = Math.max(minIntervalMs, Math.floor(options.defaultIntervalMs ?? DEFAULT_GIT_WORKSPACE_POLL_INTERVAL_MS));
5493
+ return {
5494
+ workspace: params.workspace,
5495
+ includeDiffSummary: Boolean(params.includeDiffSummary),
5496
+ intervalMs: normalizeIntervalMs(params.intervalMs, defaultIntervalMs, minIntervalMs)
5497
+ };
5498
+ }
5499
+ var GitWorkspaceMonitor = class {
5500
+ getStatusProvider;
5501
+ getDiffSummaryProvider;
5502
+ now;
5503
+ minIntervalMs;
5504
+ defaultIntervalMs;
5505
+ keyPrefix;
5506
+ cache = /* @__PURE__ */ new Map();
5507
+ listeners = /* @__PURE__ */ new Set();
5508
+ seq = 0;
5509
+ constructor(options = {}) {
5510
+ this.getStatusProvider = options.getStatus ?? defaultStatusProvider;
5511
+ this.getDiffSummaryProvider = options.getDiffSummary ?? defaultDiffSummaryProvider;
5512
+ this.now = options.now ?? Date.now;
5513
+ this.minIntervalMs = Math.max(1, Math.floor(options.minIntervalMs ?? MIN_GIT_WORKSPACE_POLL_INTERVAL_MS));
5514
+ this.defaultIntervalMs = Math.max(
5515
+ this.minIntervalMs,
5516
+ Math.floor(options.defaultIntervalMs ?? DEFAULT_GIT_WORKSPACE_POLL_INTERVAL_MS)
5517
+ );
5518
+ this.keyPrefix = options.keyPrefix ?? "git";
5519
+ }
5520
+ async refresh(params) {
5521
+ const normalized = this.normalize(typeof params === "string" ? { workspace: params } : params);
5522
+ const status = await this.getStatusProvider(normalized.workspace);
5523
+ const diffSummary = normalized.includeDiffSummary ? await this.getDiffSummaryProvider(normalized.workspace, status) : void 0;
5524
+ const compactSummary = createGitCompactSummary(status, diffSummary);
5525
+ const timestamp = this.now();
5526
+ const seq = ++this.seq;
5527
+ const key = this.keyForWorkspace(normalized.workspace);
5528
+ const update = {
5529
+ topic: "workspace.git",
5530
+ key,
5531
+ workspace: normalized.workspace,
5532
+ status,
5533
+ diffSummary,
5534
+ seq,
5535
+ timestamp
5536
+ };
5537
+ const cacheEntry = {
5538
+ key,
5539
+ workspace: normalized.workspace,
5540
+ status,
5541
+ diffSummary,
5542
+ compactSummary,
5543
+ seq,
5544
+ timestamp
5545
+ };
5546
+ this.cache.set(normalized.workspace, cacheEntry);
5547
+ this.emit(update, cacheEntry);
5548
+ return update;
5549
+ }
5550
+ poll(params) {
5551
+ return this.refresh(params);
5552
+ }
5553
+ getCached(workspace) {
5554
+ return this.cache.get(workspace);
5555
+ }
5556
+ getCompactSummary(workspace) {
5557
+ return this.cache.get(workspace)?.compactSummary;
5558
+ }
5559
+ onUpdate(listener) {
5560
+ this.listeners.add(listener);
5561
+ return () => {
5562
+ this.listeners.delete(listener);
5563
+ };
5564
+ }
5565
+ createSubscription(params, listener) {
5566
+ const normalized = this.normalize(params);
5567
+ const scopedListener = listener ? (update, cacheEntry) => {
5568
+ if (update.workspace === normalized.workspace) listener(update, cacheEntry);
5569
+ } : void 0;
5570
+ const unsubscribe = scopedListener ? this.onUpdate(scopedListener) : () => void 0;
5571
+ return {
5572
+ params: normalized,
5573
+ refresh: () => this.refresh(normalized),
5574
+ getCached: () => this.getCached(normalized.workspace),
5575
+ dispose: unsubscribe
5576
+ };
5577
+ }
5578
+ normalize(params) {
5579
+ return normalizeGitWorkspaceSubscriptionParams(params, {
5580
+ defaultIntervalMs: this.defaultIntervalMs,
5581
+ minIntervalMs: this.minIntervalMs
5582
+ });
5583
+ }
5584
+ keyForWorkspace(workspace) {
5585
+ return `${this.keyPrefix}:${workspace}`;
5586
+ }
5587
+ emit(update, cacheEntry) {
5588
+ for (const listener of this.listeners) {
5589
+ listener(update, cacheEntry);
5590
+ }
5591
+ }
5592
+ };
5593
+ function createGitWorkspaceMonitor(options = {}) {
5594
+ return new GitWorkspaceMonitor(options);
5595
+ }
5596
+
5597
+ // src/git/git-commands.ts
5598
+ var path3 = __toESM(require("path"));
5599
+ var GIT_COMMAND_NAMES = /* @__PURE__ */ new Set([
5600
+ "git_status",
5601
+ "git_diff_summary",
5602
+ "git_diff_file",
5603
+ "git_snapshot_create",
5604
+ "git_snapshot_compare",
5605
+ "git_log",
5606
+ "git_checkpoint",
5607
+ "git_stash_push",
5608
+ "git_stash_pop",
5609
+ "git_checkout_files",
5610
+ "git_remote_url"
5611
+ ]);
5612
+ var SNAPSHOT_REASONS = /* @__PURE__ */ new Set([
5613
+ "session_baseline",
5614
+ "before_user_input_dispatch",
5615
+ "before_agent_work",
5616
+ "after_agent_work",
5617
+ "manual"
5618
+ ]);
5619
+ var FAILURE_REASONS = /* @__PURE__ */ new Set([
5620
+ "not_git_repo",
5621
+ "git_not_installed",
5622
+ "timeout",
5623
+ "path_outside_repo",
5624
+ "dirty_index_required",
5625
+ "conflict",
5626
+ "invalid_args",
5627
+ "git_command_failed"
5628
+ ]);
5629
+ function failure(reason, error) {
5630
+ return { success: false, reason, error };
5631
+ }
5632
+ function serviceNotImplemented(command) {
5633
+ return failure("invalid_args", `${command} is not implemented: daemon-core Git service is not configured`);
5634
+ }
5635
+ var defaultSnapshotStore = createGitSnapshotStore({
5636
+ getStatus: (workspace) => getGitRepoStatus(workspace),
5637
+ getDiffSummary: (workspace) => getGitDiffSummary(workspace)
5638
+ });
5639
+ function createDefaultGitCommandServices() {
5640
+ return {
5641
+ getStatus: ({ workspace }) => getGitRepoStatus(workspace),
5642
+ getDiffSummary: ({ workspace }) => getGitDiffSummary(workspace),
5643
+ getDiffFile: ({ workspace, path: filePath }) => getGitFileDiff(workspace, filePath),
5644
+ createSnapshot: ({ workspace, reason, sessionId, turnId }) => defaultSnapshotStore.create({
5645
+ workspace,
5646
+ reason,
5647
+ sessionId,
5648
+ turnId
5649
+ }),
5650
+ compareSnapshots: ({ beforeSnapshotId, afterSnapshotId }) => defaultSnapshotStore.compare(beforeSnapshotId, afterSnapshotId),
5651
+ getLog: ({ workspace, limit, path: filePath, since, until }) => getGitLog(workspace, { limit, path: filePath, since, until }),
5652
+ checkpoint: async ({ workspace, message, includeUntracked = false }) => gitCheckpoint(workspace, message, includeUntracked),
5653
+ stashPush: async ({ workspace, message, includeUntracked = false }) => gitStashPush(workspace, message, includeUntracked),
5654
+ stashPop: async ({ workspace, stashRef }) => gitStashPop(workspace, stashRef),
5655
+ checkoutFiles: async ({ workspace, paths }) => gitCheckoutFiles(workspace, paths),
5656
+ getRemoteUrl: async ({ workspace, remote = "origin" }) => gitGetRemoteUrl(workspace, remote)
5657
+ };
5658
+ }
5659
+ var defaultGitCommandServices = createDefaultGitCommandServices();
5660
+ function validateWorkspace2(args) {
5661
+ if (typeof args?.workspace !== "string") {
5662
+ return failure("invalid_args", "workspace must be a non-empty absolute path");
5663
+ }
5664
+ const workspace = args.workspace.trim();
5665
+ if (!workspace || !path3.isAbsolute(workspace)) {
5666
+ return failure("invalid_args", "workspace must be a non-empty absolute path");
5667
+ }
5668
+ return { workspace };
5669
+ }
5670
+ function validateRepoPath(args) {
5671
+ if (typeof args?.path !== "string" || !args.path.trim()) {
5672
+ return failure("invalid_args", "path must be a non-empty repository-relative path");
5673
+ }
5674
+ return { path: args.path.trim() };
5675
+ }
5676
+ function validateSnapshotId(args, key) {
5677
+ if (typeof args?.[key] !== "string" || !args[key].trim()) {
5678
+ return failure("invalid_args", `${key} must be a non-empty string`);
5679
+ }
5680
+ return args[key].trim();
5681
+ }
5682
+ function parseSnapshotReason(args) {
5683
+ if (args?.reason === void 0 || args?.reason === null || args?.reason === "") {
5684
+ return "manual";
5685
+ }
5686
+ if (typeof args.reason !== "string" || !SNAPSHOT_REASONS.has(args.reason)) {
5687
+ return failure("invalid_args", "reason must be a valid GitSnapshotReason");
5688
+ }
5689
+ return args.reason;
5690
+ }
5691
+ function optionalString(value) {
5692
+ return typeof value === "string" && value.trim() ? value.trim() : void 0;
5693
+ }
5694
+ function optionalBoolean(value) {
5695
+ return typeof value === "boolean" ? value : void 0;
5696
+ }
5697
+ function boundedLogLimit(value) {
5698
+ if (value === void 0 || value === null || value === "") return 50;
5699
+ const numeric = typeof value === "number" ? value : Number(value);
5700
+ if (!Number.isFinite(numeric)) return 50;
5701
+ return Math.max(1, Math.min(200, Math.floor(numeric)));
5702
+ }
5703
+ function failureReasonFromError(error) {
5704
+ return typeof error?.reason === "string" && FAILURE_REASONS.has(error.reason) ? error.reason : "git_command_failed";
5705
+ }
5706
+ async function runService(fn) {
5707
+ try {
5708
+ return await fn();
5709
+ } catch (error) {
5710
+ return failure(failureReasonFromError(error), error?.message || "Git command failed");
5711
+ }
5712
+ }
5713
+ function isGitCommandName(command) {
5714
+ return GIT_COMMAND_NAMES.has(command);
5715
+ }
5716
+ async function handleGitCommand(command, args, services = defaultGitCommandServices) {
5717
+ if (!isGitCommandName(command)) {
5718
+ return failure("invalid_args", `Unknown Git command: ${command}`);
5719
+ }
5720
+ const workspaceResult = validateWorkspace2(args);
5721
+ if ("success" in workspaceResult) return workspaceResult;
5722
+ const { workspace } = workspaceResult;
5723
+ switch (command) {
5724
+ case "git_status": {
5725
+ if (!services.getStatus) return serviceNotImplemented(command);
5726
+ const status = await runService(() => services.getStatus({ workspace }));
5727
+ return "success" in status ? status : { success: true, status };
5728
+ }
5729
+ case "git_diff_summary": {
5730
+ if (!services.getDiffSummary) return serviceNotImplemented(command);
5731
+ const diffSummary = await runService(() => services.getDiffSummary({ workspace, staged: optionalBoolean(args?.staged) }));
5732
+ return "success" in diffSummary ? diffSummary : { success: true, diffSummary };
5733
+ }
5734
+ case "git_diff_file": {
5735
+ if (!services.getDiffFile) return serviceNotImplemented(command);
5736
+ const pathResult = validateRepoPath(args);
5737
+ if (typeof pathResult !== "object" || "success" in pathResult) return pathResult;
5738
+ const diff = await runService(() => services.getDiffFile({
5739
+ workspace,
5740
+ path: pathResult.path,
5741
+ staged: optionalBoolean(args?.staged)
5742
+ }));
5743
+ return "success" in diff ? diff : { success: true, diff };
5744
+ }
5745
+ case "git_snapshot_create": {
5746
+ if (!services.createSnapshot) return serviceNotImplemented(command);
5747
+ const reason = parseSnapshotReason(args);
5748
+ if (typeof reason !== "string") return reason;
5749
+ const snapshot = await runService(() => services.createSnapshot({
5750
+ workspace,
5751
+ reason,
5752
+ sessionId: optionalString(args?.sessionId),
5753
+ turnId: optionalString(args?.turnId)
5754
+ }));
5755
+ return "success" in snapshot ? snapshot : { success: true, snapshot };
5756
+ }
5757
+ case "git_snapshot_compare": {
5758
+ if (!services.compareSnapshots) return serviceNotImplemented(command);
5759
+ const beforeSnapshotId = validateSnapshotId(args, "beforeSnapshotId");
5760
+ if (typeof beforeSnapshotId !== "string") return beforeSnapshotId;
5761
+ const afterSnapshotId = validateSnapshotId(args, "afterSnapshotId");
5762
+ if (typeof afterSnapshotId !== "string") return afterSnapshotId;
5763
+ const compare = await runService(() => services.compareSnapshots({ workspace, beforeSnapshotId, afterSnapshotId }));
5764
+ return "success" in compare ? compare : { success: true, compare };
5765
+ }
5766
+ case "git_log": {
5767
+ if (!services.getLog) {
5768
+ return failure("invalid_args", "git_log is not implemented: bounded daemon-core Git log service is not configured");
5769
+ }
5770
+ const log = await runService(() => services.getLog({
5771
+ workspace,
5772
+ limit: boundedLogLimit(args?.limit),
5773
+ path: optionalString(args?.path),
5774
+ since: optionalString(args?.since),
5775
+ until: optionalString(args?.until)
5776
+ }));
5777
+ return "success" in log ? log : { success: true, log };
5778
+ }
5779
+ case "git_checkpoint": {
5780
+ if (!services.checkpoint) return serviceNotImplemented(command);
5781
+ const msg = validateMutatingMessage(args?.message);
5782
+ if (typeof msg !== "string") return msg;
5783
+ const includeUntracked = Boolean(args?.includeUntracked);
5784
+ const checkpoint = await runService(() => services.checkpoint({ workspace, message: msg, includeUntracked }));
5785
+ return "success" in checkpoint ? checkpoint : { success: true, checkpoint };
5786
+ }
5787
+ case "git_stash_push": {
5788
+ if (!services.stashPush) return serviceNotImplemented(command);
5789
+ const msg = validateMutatingMessage(args?.message);
5790
+ if (typeof msg !== "string") return msg;
5791
+ const includeUntracked = Boolean(args?.includeUntracked);
5792
+ const stash = await runService(() => services.stashPush({ workspace, message: msg, includeUntracked }));
5793
+ return "success" in stash ? stash : { success: true, stash };
5794
+ }
5795
+ case "git_stash_pop": {
5796
+ if (!services.stashPop) return serviceNotImplemented(command);
5797
+ const stashRef = optionalString(args?.stashRef);
5798
+ if (stashRef !== void 0 && !/^stash@\{\d+\}$/.test(stashRef)) {
5799
+ return failure("invalid_args", "stashRef must match stash@{N} format");
5800
+ }
5801
+ const popResult = await runService(() => services.stashPop({ workspace, stashRef }));
5802
+ if (popResult !== void 0 && "success" in popResult) return popResult;
5803
+ return { success: true, stashPopped: true };
5804
+ }
5805
+ case "git_checkout_files": {
5806
+ if (!services.checkoutFiles) return serviceNotImplemented(command);
5807
+ const paths = args?.paths;
5808
+ if (!Array.isArray(paths) || paths.length === 0) {
5809
+ return failure("invalid_args", "paths must be a non-empty array");
5810
+ }
5811
+ if (paths.length > 50) {
5812
+ return failure("invalid_args", "paths array exceeds maximum of 50 entries");
5813
+ }
5814
+ const checkoutResult = await runService(() => services.checkoutFiles({ workspace, paths }));
5815
+ return "success" in checkoutResult ? checkoutResult : { success: true, checkedOut: checkoutResult.checkedOut };
5816
+ }
5817
+ case "git_remote_url": {
5818
+ if (!services.getRemoteUrl) return serviceNotImplemented(command);
5819
+ const remote = typeof args?.remote === "string" && args.remote.trim() ? args.remote.trim() : "origin";
5820
+ const remoteResult = await runService(() => services.getRemoteUrl({ workspace, remote }));
5821
+ if ("success" in remoteResult) return remoteResult;
5822
+ return { success: true, remoteUrl: remoteResult.remoteUrl, remote: remoteResult.remote };
5823
+ }
5824
+ default:
5825
+ return failure("invalid_args", `Unknown Git command: ${command}`);
5826
+ }
5827
+ }
5828
+ function validateMutatingMessage(value) {
5829
+ if (typeof value !== "string" || !value.trim()) {
5830
+ return failure("invalid_args", "message must be a non-empty string");
5831
+ }
5832
+ const msg = value.trim();
5833
+ if (msg.length > 200) {
5834
+ return failure("invalid_args", "message must be 200 characters or fewer");
5835
+ }
5836
+ return msg;
5837
+ }
5838
+ async function gitCheckpoint(workspace, message, includeUntracked) {
5839
+ const repo = await resolveGitRepository(workspace);
5840
+ const repoRoot = repo.repoRoot;
5841
+ const statusResult = await getGitRepoStatus(workspace);
5842
+ if (statusResult.hasConflicts) {
5843
+ throw new GitCommandError("conflict", "Repository has conflicts \u2014 resolve before checkpointing");
5844
+ }
5845
+ const addArgs = includeUntracked ? ["-A"] : ["-u"];
5846
+ await runGit(repo, ["add", ...addArgs], { cwd: repoRoot });
5847
+ const fullMsg = `adhdev: checkpoint ${message}`;
5848
+ let commitSha;
5849
+ try {
5850
+ await runGit(repo, ["commit", "-m", fullMsg], { cwd: repoRoot });
5851
+ const revResult = await runGit(repo, ["rev-parse", "HEAD"], { cwd: repoRoot });
5852
+ commitSha = revResult.stdout.trim();
5853
+ } catch (err) {
5854
+ const output = (err?.stdout || "") + (err?.stderr || "");
5855
+ if (/nothing to commit/i.test(output)) {
5856
+ throw new GitCommandError("git_command_failed", "Nothing to commit");
5857
+ }
5858
+ throw err;
5859
+ }
5860
+ return {
5861
+ workspace: repo.workspace,
5862
+ repoRoot,
5863
+ isGitRepo: true,
5864
+ commit: commitSha,
5865
+ message: fullMsg,
5866
+ lastCheckedAt: Date.now()
5867
+ };
5868
+ }
5869
+ async function gitStashPush(workspace, message, includeUntracked) {
5870
+ const repo = await resolveGitRepository(workspace);
5871
+ const repoRoot = repo.repoRoot;
5872
+ const stashArgs = ["stash", "push", "-m", message];
5873
+ if (includeUntracked) stashArgs.push("--include-untracked");
5874
+ const result = await runGit(repo, stashArgs, { cwd: repoRoot });
5875
+ if (/No local changes to save/i.test(result.stdout + result.stderr)) {
5876
+ throw new GitCommandError("git_command_failed", "Nothing to stash");
5877
+ }
5878
+ return {
5879
+ workspace: repo.workspace,
5880
+ repoRoot,
5881
+ isGitRepo: true,
5882
+ stashRef: "stash@{0}",
5883
+ message,
5884
+ lastCheckedAt: Date.now()
5885
+ };
5886
+ }
5887
+ async function gitStashPop(workspace, stashRef) {
5888
+ const repo = await resolveGitRepository(workspace);
5889
+ const repoRoot = repo.repoRoot;
5890
+ const popArgs = stashRef ? ["stash", "pop", stashRef] : ["stash", "pop"];
5891
+ await runGit(repo, popArgs, { cwd: repoRoot });
5892
+ }
5893
+ async function gitCheckoutFiles(workspace, paths) {
5894
+ const repo = await resolveGitRepository(workspace);
5895
+ const repoRoot = repo.repoRoot;
5896
+ const normalizedPaths = [];
5897
+ for (const p of paths) {
5898
+ if (typeof p !== "string" || !p.trim() || p.includes("\0")) {
5899
+ throw new GitCommandError("invalid_args", `Invalid path: ${String(p)}`);
5900
+ }
5901
+ if (path3.isAbsolute(p)) {
5902
+ throw new GitCommandError("invalid_args", `Path must be repository-relative, not absolute: ${p}`);
5903
+ }
5904
+ const normalized = path3.normalize(p.trim()).split(path3.sep).join("/");
5905
+ if (normalized.startsWith("../") || normalized === "..") {
5906
+ throw new GitCommandError("path_outside_repo", `Path is outside repository root: ${p}`);
5907
+ }
5908
+ const absolutePath = path3.resolve(repoRoot, normalized);
5909
+ if (!isPathInside(repoRoot, absolutePath)) {
5910
+ throw new GitCommandError("path_outside_repo", `Path is outside repository root: ${p}`);
5911
+ }
5912
+ normalizedPaths.push(normalized);
5913
+ }
5914
+ await runGit(repo, ["checkout", "--", ...normalizedPaths], { cwd: repoRoot });
5915
+ return { checkedOut: normalizedPaths };
5916
+ }
5917
+ async function gitGetRemoteUrl(workspace, remote) {
5918
+ const repo = await resolveGitRepository(workspace);
5919
+ const result = await runGit(repo, ["remote", "get-url", remote], { cwd: repo.repoRoot });
5920
+ const remoteUrl = result.stdout.trim();
5921
+ if (!remoteUrl) {
5922
+ throw new GitCommandError("git_command_failed", `Remote '${remote}' has no URL`);
5923
+ }
5924
+ return { remoteUrl, remote };
5925
+ }
5926
+ function formatOptionalGitLogRangeArg(flag, value) {
5927
+ return value ? [`${flag}=${value}`] : [];
5928
+ }
5929
+ async function getGitLog(workspace, options) {
5930
+ const lastCheckedAt = Date.now();
5931
+ const repo = await resolveGitRepository(workspace);
5932
+ const repoRoot = repo.repoRoot;
5933
+ const boundedLimit = Math.max(1, Math.min(200, Math.floor(options.limit || 50)));
5934
+ const selectedPath = options.path ? validateGitLogPath(repoRoot, options.path) : void 0;
5935
+ const result = await runGit(
5936
+ repo,
5937
+ [
5938
+ "log",
5939
+ `--max-count=${boundedLimit}`,
5940
+ "--format=%H%x00%an%x00%ae%x00%at%x00%ct%x00%s",
5941
+ ...formatOptionalGitLogRangeArg("--since", options.since),
5942
+ ...formatOptionalGitLogRangeArg("--until", options.until),
5943
+ "--",
5944
+ ...selectedPath ? [selectedPath] : []
5945
+ ],
5946
+ { cwd: repoRoot }
5947
+ );
5948
+ const entries = result.stdout.split("\n").filter((line) => line.trim().length > 0).map((line) => {
5949
+ const [commit = "", authorName, authorEmail, authoredAt, committedAt, ...messageParts] = line.split("\0");
5950
+ return {
5951
+ commit,
5952
+ message: messageParts.join("\0"),
5953
+ authorName: authorName || void 0,
5954
+ authorEmail: authorEmail || void 0,
5955
+ authoredAt: authoredAt ? Number.parseInt(authoredAt, 10) * 1e3 : void 0,
5956
+ committedAt: committedAt ? Number.parseInt(committedAt, 10) * 1e3 : void 0
5957
+ };
5958
+ }).filter((entry) => entry.commit.length > 0);
5959
+ return {
5960
+ workspace: repo.workspace,
5961
+ repoRoot,
5962
+ isGitRepo: true,
5963
+ entries,
5964
+ limit: boundedLimit,
5965
+ truncated: entries.length >= boundedLimit,
5966
+ lastCheckedAt
5967
+ };
5968
+ }
5969
+ function validateGitLogPath(repoRoot, filePath) {
5970
+ if (!filePath.trim() || filePath.includes("\0")) {
5971
+ throw new GitCommandError("invalid_args", "path must be a non-empty repository-relative path");
5972
+ }
5973
+ if (path3.isAbsolute(filePath)) {
5974
+ throw new GitCommandError("invalid_args", "path must be repository-relative");
5975
+ }
5976
+ const normalized = path3.normalize(filePath).split(path3.sep).join("/");
5977
+ const absolutePath = path3.resolve(repoRoot, normalized);
5978
+ if (!isPathInside(repoRoot, absolutePath) || normalized.startsWith("../") || normalized === "..") {
5979
+ throw new GitCommandError("path_outside_repo", "Git log path is outside the repository root");
5980
+ }
5981
+ return normalized;
5982
+ }
5983
+
5984
+ // src/git/turn-snapshot-tracker.ts
5985
+ var BUSY_STATUSES = /* @__PURE__ */ new Set(["streaming", "waiting_approval"]);
5986
+ var TERMINAL_STATUSES = /* @__PURE__ */ new Set(["idle", "error"]);
5987
+ var TurnSnapshotTracker = class {
5988
+ lastStatus = /* @__PURE__ */ new Map();
5989
+ onTurnCompleted;
5990
+ constructor(onTurnCompleted) {
5991
+ this.onTurnCompleted = onTurnCompleted;
5992
+ }
5993
+ record(sessionId, status, workspace) {
5994
+ const prev = this.lastStatus.get(sessionId);
5995
+ this.lastStatus.set(sessionId, status);
5996
+ if (workspace && prev && BUSY_STATUSES.has(prev) && TERMINAL_STATUSES.has(status)) {
5997
+ this.onTurnCompleted({ sessionId, workspace });
5998
+ }
5999
+ }
6000
+ forget(sessionId) {
6001
+ this.lastStatus.delete(sessionId);
6002
+ }
6003
+ };
6004
+
6005
+ // src/index.ts
4683
6006
  init_config();
4684
6007
 
4685
6008
  // src/config/workspaces.ts
4686
6009
  var fs = __toESM(require("fs"));
4687
6010
  var os = __toESM(require("os"));
4688
- var path = __toESM(require("path"));
6011
+ var path4 = __toESM(require("path"));
4689
6012
  var import_crypto2 = require("crypto");
4690
6013
  var MAX_WORKSPACES = 50;
4691
6014
  function expandPath(p) {
4692
6015
  const t = (p || "").trim();
4693
6016
  if (!t) return "";
4694
- if (t.startsWith("~")) return path.join(os.homedir(), t.slice(1).replace(/^\//, ""));
4695
- return path.resolve(t);
6017
+ if (t.startsWith("~")) return path4.join(os.homedir(), t.slice(1).replace(/^\//, ""));
6018
+ return path4.resolve(t);
4696
6019
  }
4697
6020
  function validateWorkspacePath(absPath) {
4698
6021
  try {
@@ -4706,7 +6029,7 @@ function validateWorkspacePath(absPath) {
4706
6029
  }
4707
6030
  }
4708
6031
  function defaultWorkspaceLabel(absPath) {
4709
- const base = path.basename(absPath) || absPath;
6032
+ const base = path4.basename(absPath) || absPath;
4710
6033
  return base;
4711
6034
  }
4712
6035
  function getDefaultWorkspacePath(config) {
@@ -4797,9 +6120,9 @@ function resolveIdeLaunchWorkspace(args, config) {
4797
6120
  return getDefaultWorkspacePath(config) || void 0;
4798
6121
  }
4799
6122
  function findWorkspaceByPath(config, rawPath) {
4800
- const abs = path.resolve(expandPath(rawPath));
6123
+ const abs = path4.resolve(expandPath(rawPath));
4801
6124
  if (!abs) return void 0;
4802
- return (config.workspaces || []).find((w) => path.resolve(expandPath(w.path)) === abs);
6125
+ return (config.workspaces || []).find((w) => path4.resolve(expandPath(w.path)) === abs);
4803
6126
  }
4804
6127
  function addWorkspaceEntry(config, rawPath, label, options) {
4805
6128
  const abs = expandPath(rawPath);
@@ -4815,7 +6138,7 @@ function addWorkspaceEntry(config, rawPath, label, options) {
4815
6138
  const v = validateWorkspacePath(abs);
4816
6139
  if (!v.ok) return { error: v.error };
4817
6140
  const list = [...config.workspaces || []];
4818
- if (list.some((w) => path.resolve(w.path) === abs)) {
6141
+ if (list.some((w) => path4.resolve(w.path) === abs)) {
4819
6142
  return { error: "Workspace already in list" };
4820
6143
  }
4821
6144
  if (list.length >= MAX_WORKSPACES) {
@@ -4849,7 +6172,7 @@ function setDefaultWorkspaceId(config, id) {
4849
6172
  }
4850
6173
 
4851
6174
  // src/config/recent-activity.ts
4852
- var path2 = __toESM(require("path"));
6175
+ var path5 = __toESM(require("path"));
4853
6176
 
4854
6177
  // src/providers/summary-metadata.ts
4855
6178
  function normalizeSummaryItem(item) {
@@ -4918,9 +6241,9 @@ var MAX_ACTIVITY = 30;
4918
6241
  function normalizeWorkspace(workspace) {
4919
6242
  if (!workspace) return "";
4920
6243
  try {
4921
- return path2.resolve(expandPath(workspace));
6244
+ return path5.resolve(expandPath(workspace));
4922
6245
  } catch {
4923
- return path2.resolve(workspace);
6246
+ return path5.resolve(workspace);
4924
6247
  }
4925
6248
  }
4926
6249
  function buildRecentActivityKey(entry) {
@@ -5088,14 +6411,14 @@ function markSessionSeen(state, sessionId, seenAt = Date.now(), completionMarker
5088
6411
  }
5089
6412
 
5090
6413
  // src/config/saved-sessions.ts
5091
- var path3 = __toESM(require("path"));
6414
+ var path6 = __toESM(require("path"));
5092
6415
  var MAX_SAVED_SESSIONS = 500;
5093
6416
  function normalizeWorkspace2(workspace) {
5094
6417
  if (!workspace) return "";
5095
6418
  try {
5096
- return path3.resolve(expandPath(workspace));
6419
+ return path6.resolve(expandPath(workspace));
5097
6420
  } catch {
5098
- return path3.resolve(workspace);
6421
+ return path6.resolve(workspace);
5099
6422
  }
5100
6423
  }
5101
6424
  function buildSavedProviderSessionKey(providerSessionId) {
@@ -5214,7 +6537,7 @@ function resetState() {
5214
6537
  var import_child_process = require("child_process");
5215
6538
  var import_fs3 = require("fs");
5216
6539
  var import_os2 = require("os");
5217
- var path4 = __toESM(require("path"));
6540
+ var path7 = __toESM(require("path"));
5218
6541
  var BUILTIN_IDE_DEFINITIONS = [];
5219
6542
  var registeredIDEs = /* @__PURE__ */ new Map();
5220
6543
  function registerIDEDefinition(def) {
@@ -5233,9 +6556,9 @@ function getMergedDefinitions() {
5233
6556
  function findCliCommand(command) {
5234
6557
  const trimmed = String(command || "").trim();
5235
6558
  if (!trimmed) return null;
5236
- if (path4.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~")) {
5237
- const candidate = trimmed.startsWith("~") ? path4.join((0, import_os2.homedir)(), trimmed.slice(1)) : trimmed;
5238
- const resolved = path4.isAbsolute(candidate) ? candidate : path4.resolve(candidate);
6559
+ if (path7.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~")) {
6560
+ const candidate = trimmed.startsWith("~") ? path7.join((0, import_os2.homedir)(), trimmed.slice(1)) : trimmed;
6561
+ const resolved = path7.isAbsolute(candidate) ? candidate : path7.resolve(candidate);
5239
6562
  return (0, import_fs3.existsSync)(resolved) ? resolved : null;
5240
6563
  }
5241
6564
  try {
@@ -5263,7 +6586,7 @@ function getIdeVersion(cliCommand) {
5263
6586
  function checkPathExists(paths) {
5264
6587
  const home = (0, import_os2.homedir)();
5265
6588
  for (const p of paths) {
5266
- const normalized = p.startsWith("~") ? path4.join(home, p.slice(1)) : p;
6589
+ const normalized = p.startsWith("~") ? path7.join(home, p.slice(1)) : p;
5267
6590
  if (normalized.includes("*")) {
5268
6591
  const username = home.split(/[\\/]/).pop() || "";
5269
6592
  const resolved = normalized.replace("*", username);
@@ -5321,7 +6644,7 @@ async function detectIDEs(providerLoader) {
5321
6644
  // src/detection/cli-detector.ts
5322
6645
  var import_child_process2 = require("child_process");
5323
6646
  var os2 = __toESM(require("os"));
5324
- var path5 = __toESM(require("path"));
6647
+ var path8 = __toESM(require("path"));
5325
6648
  var import_fs4 = require("fs");
5326
6649
  function parseVersion(raw) {
5327
6650
  const match = raw.match(/v?(\d+\.\d+(?:\.\d+)?(?:-[a-zA-Z0-9.]+)?)/);
@@ -5334,36 +6657,36 @@ function shellQuote(value) {
5334
6657
  function expandHome(value) {
5335
6658
  const trimmed = value.trim();
5336
6659
  if (!trimmed.startsWith("~")) return trimmed;
5337
- return path5.join(os2.homedir(), trimmed.slice(1));
6660
+ return path8.join(os2.homedir(), trimmed.slice(1));
5338
6661
  }
5339
6662
  function isExplicitCommandPath(command) {
5340
6663
  const trimmed = command.trim();
5341
- return path5.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
6664
+ return path8.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
5342
6665
  }
5343
6666
  function resolveCommandPath(command) {
5344
6667
  const trimmed = command.trim();
5345
6668
  if (!trimmed) return null;
5346
6669
  if (isExplicitCommandPath(trimmed)) {
5347
6670
  const expanded = expandHome(trimmed);
5348
- const candidate = path5.isAbsolute(expanded) ? expanded : path5.resolve(expanded);
6671
+ const candidate = path8.isAbsolute(expanded) ? expanded : path8.resolve(expanded);
5349
6672
  return (0, import_fs4.existsSync)(candidate) ? candidate : null;
5350
6673
  }
5351
6674
  return null;
5352
6675
  }
5353
6676
  function execAsync(cmd, timeoutMs = 5e3) {
5354
- return new Promise((resolve12) => {
6677
+ return new Promise((resolve15) => {
5355
6678
  const child = (0, import_child_process2.exec)(cmd, {
5356
6679
  encoding: "utf-8",
5357
6680
  timeout: timeoutMs,
5358
6681
  ...process.platform === "win32" ? { windowsHide: true } : {}
5359
6682
  }, (err, stdout) => {
5360
6683
  if (err || !stdout?.trim()) {
5361
- resolve12(null);
6684
+ resolve15(null);
5362
6685
  } else {
5363
- resolve12(stdout.trim());
6686
+ resolve15(stdout.trim());
5364
6687
  }
5365
6688
  });
5366
- child.on("error", () => resolve12(null));
6689
+ child.on("error", () => resolve15(null));
5367
6690
  });
5368
6691
  }
5369
6692
  async function detectCLIs(providerLoader, options) {
@@ -5728,7 +7051,7 @@ var DaemonCdpManager = class {
5728
7051
  * Returns multiple entries if multiple IDE windows are open on same port
5729
7052
  */
5730
7053
  static listAllTargets(port) {
5731
- return new Promise((resolve12) => {
7054
+ return new Promise((resolve15) => {
5732
7055
  const req = http.get(`http://127.0.0.1:${port}/json`, (res) => {
5733
7056
  let data = "";
5734
7057
  res.on("data", (chunk) => data += chunk.toString());
@@ -5744,16 +7067,16 @@ var DaemonCdpManager = class {
5744
7067
  (t) => !isNonMain(t.title || "") && t.url?.includes("workbench.html") && !t.url?.includes("agent")
5745
7068
  );
5746
7069
  const fallbackPages = pages.filter((t) => !isNonMain(t.title || ""));
5747
- resolve12(mainPages.length > 0 ? mainPages : fallbackPages);
7070
+ resolve15(mainPages.length > 0 ? mainPages : fallbackPages);
5748
7071
  } catch {
5749
- resolve12([]);
7072
+ resolve15([]);
5750
7073
  }
5751
7074
  });
5752
7075
  });
5753
- req.on("error", () => resolve12([]));
7076
+ req.on("error", () => resolve15([]));
5754
7077
  req.setTimeout(2e3, () => {
5755
7078
  req.destroy();
5756
- resolve12([]);
7079
+ resolve15([]);
5757
7080
  });
5758
7081
  });
5759
7082
  }
@@ -5793,7 +7116,7 @@ var DaemonCdpManager = class {
5793
7116
  }
5794
7117
  }
5795
7118
  findTargetOnPort(port) {
5796
- return new Promise((resolve12) => {
7119
+ return new Promise((resolve15) => {
5797
7120
  const req = http.get(`http://127.0.0.1:${port}/json`, (res) => {
5798
7121
  let data = "";
5799
7122
  res.on("data", (chunk) => data += chunk.toString());
@@ -5804,7 +7127,7 @@ var DaemonCdpManager = class {
5804
7127
  (t) => (t.type === "page" || t.type === "browser" || t.type === "Page") && t.webSocketDebuggerUrl
5805
7128
  );
5806
7129
  if (pages.length === 0) {
5807
- resolve12(targets.find((t) => t.webSocketDebuggerUrl) || null);
7130
+ resolve15(targets.find((t) => t.webSocketDebuggerUrl) || null);
5808
7131
  return;
5809
7132
  }
5810
7133
  const titleFilteredPages = pages.filter((t) => !this.isNonMainTitle(t.title || ""));
@@ -5823,25 +7146,25 @@ var DaemonCdpManager = class {
5823
7146
  this._targetId = selected.target.id;
5824
7147
  }
5825
7148
  this._pageTitle = selected.target.title || "";
5826
- resolve12(selected.target);
7149
+ resolve15(selected.target);
5827
7150
  return;
5828
7151
  }
5829
7152
  if (previousTargetId) {
5830
7153
  this.log(`[CDP] Target ${previousTargetId} not found in page list`);
5831
- resolve12(null);
7154
+ resolve15(null);
5832
7155
  return;
5833
7156
  }
5834
7157
  this._pageTitle = list[0]?.title || "";
5835
- resolve12(list[0]);
7158
+ resolve15(list[0]);
5836
7159
  } catch {
5837
- resolve12(null);
7160
+ resolve15(null);
5838
7161
  }
5839
7162
  });
5840
7163
  });
5841
- req.on("error", () => resolve12(null));
7164
+ req.on("error", () => resolve15(null));
5842
7165
  req.setTimeout(2e3, () => {
5843
7166
  req.destroy();
5844
- resolve12(null);
7167
+ resolve15(null);
5845
7168
  });
5846
7169
  });
5847
7170
  }
@@ -5852,7 +7175,7 @@ var DaemonCdpManager = class {
5852
7175
  this.extensionProviders = providers;
5853
7176
  }
5854
7177
  connectToTarget(wsUrl) {
5855
- return new Promise((resolve12) => {
7178
+ return new Promise((resolve15) => {
5856
7179
  this.ws = new import_ws.default(wsUrl);
5857
7180
  this.ws.on("open", async () => {
5858
7181
  this._connected = true;
@@ -5862,17 +7185,17 @@ var DaemonCdpManager = class {
5862
7185
  }
5863
7186
  this.connectBrowserWs().catch(() => {
5864
7187
  });
5865
- resolve12(true);
7188
+ resolve15(true);
5866
7189
  });
5867
7190
  this.ws.on("message", (data) => {
5868
7191
  try {
5869
7192
  const msg = JSON.parse(data.toString());
5870
7193
  if (msg.id && this.pending.has(msg.id)) {
5871
- const { resolve: resolve13, reject } = this.pending.get(msg.id);
7194
+ const { resolve: resolve16, reject } = this.pending.get(msg.id);
5872
7195
  this.pending.delete(msg.id);
5873
7196
  this.failureCount = 0;
5874
7197
  if (msg.error) reject(new Error(msg.error.message));
5875
- else resolve13(msg.result);
7198
+ else resolve16(msg.result);
5876
7199
  } else if (msg.method === "Runtime.executionContextCreated") {
5877
7200
  this.contexts.add(msg.params.context.id);
5878
7201
  } else if (msg.method === "Runtime.executionContextDestroyed") {
@@ -5895,7 +7218,7 @@ var DaemonCdpManager = class {
5895
7218
  this.ws.on("error", (err) => {
5896
7219
  this.log(`[CDP] WebSocket error: ${err.message}`);
5897
7220
  this._connected = false;
5898
- resolve12(false);
7221
+ resolve15(false);
5899
7222
  });
5900
7223
  });
5901
7224
  }
@@ -5909,7 +7232,7 @@ var DaemonCdpManager = class {
5909
7232
  return;
5910
7233
  }
5911
7234
  this.log(`[CDP] Connecting browser WS for target discovery...`);
5912
- await new Promise((resolve12, reject) => {
7235
+ await new Promise((resolve15, reject) => {
5913
7236
  this.browserWs = new import_ws.default(browserWsUrl);
5914
7237
  this.browserWs.on("open", async () => {
5915
7238
  this._browserConnected = true;
@@ -5919,16 +7242,16 @@ var DaemonCdpManager = class {
5919
7242
  } catch (e) {
5920
7243
  this.log(`[CDP] setDiscoverTargets failed: ${e.message}`);
5921
7244
  }
5922
- resolve12();
7245
+ resolve15();
5923
7246
  });
5924
7247
  this.browserWs.on("message", (data) => {
5925
7248
  try {
5926
7249
  const msg = JSON.parse(data.toString());
5927
7250
  if (msg.id && this.browserPending.has(msg.id)) {
5928
- const { resolve: resolve13, reject: reject2 } = this.browserPending.get(msg.id);
7251
+ const { resolve: resolve16, reject: reject2 } = this.browserPending.get(msg.id);
5929
7252
  this.browserPending.delete(msg.id);
5930
7253
  if (msg.error) reject2(new Error(msg.error.message));
5931
- else resolve13(msg.result);
7254
+ else resolve16(msg.result);
5932
7255
  }
5933
7256
  } catch {
5934
7257
  }
@@ -5948,31 +7271,31 @@ var DaemonCdpManager = class {
5948
7271
  }
5949
7272
  }
5950
7273
  getBrowserWsUrl() {
5951
- return new Promise((resolve12) => {
7274
+ return new Promise((resolve15) => {
5952
7275
  const req = http.get(`http://127.0.0.1:${this.port}/json/version`, (res) => {
5953
7276
  let data = "";
5954
7277
  res.on("data", (chunk) => data += chunk.toString());
5955
7278
  res.on("end", () => {
5956
7279
  try {
5957
7280
  const info = JSON.parse(data);
5958
- resolve12(info.webSocketDebuggerUrl || null);
7281
+ resolve15(info.webSocketDebuggerUrl || null);
5959
7282
  } catch {
5960
- resolve12(null);
7283
+ resolve15(null);
5961
7284
  }
5962
7285
  });
5963
7286
  });
5964
- req.on("error", () => resolve12(null));
7287
+ req.on("error", () => resolve15(null));
5965
7288
  req.setTimeout(3e3, () => {
5966
7289
  req.destroy();
5967
- resolve12(null);
7290
+ resolve15(null);
5968
7291
  });
5969
7292
  });
5970
7293
  }
5971
7294
  sendBrowser(method, params = {}, timeoutMs = 15e3) {
5972
- return new Promise((resolve12, reject) => {
7295
+ return new Promise((resolve15, reject) => {
5973
7296
  if (!this.browserWs || !this._browserConnected) return reject(new Error("Browser WS not connected"));
5974
7297
  const id = this.browserMsgId++;
5975
- this.browserPending.set(id, { resolve: resolve12, reject });
7298
+ this.browserPending.set(id, { resolve: resolve15, reject });
5976
7299
  this.browserWs.send(JSON.stringify({ id, method, params }));
5977
7300
  setTimeout(() => {
5978
7301
  if (this.browserPending.has(id)) {
@@ -6012,11 +7335,11 @@ var DaemonCdpManager = class {
6012
7335
  }
6013
7336
  // ─── CDP Protocol ────────────────────────────────────────
6014
7337
  sendInternal(method, params = {}, timeoutMs = 15e3) {
6015
- return new Promise((resolve12, reject) => {
7338
+ return new Promise((resolve15, reject) => {
6016
7339
  if (!this.ws || !this._connected) return reject(new Error("CDP not connected"));
6017
7340
  if (this.ws.readyState !== import_ws.default.OPEN) return reject(new Error("WebSocket not open"));
6018
7341
  const id = this.msgId++;
6019
- this.pending.set(id, { resolve: resolve12, reject });
7342
+ this.pending.set(id, { resolve: resolve15, reject });
6020
7343
  this.ws.send(JSON.stringify({ id, method, params }));
6021
7344
  setTimeout(() => {
6022
7345
  if (this.pending.has(id)) {
@@ -6265,7 +7588,7 @@ var DaemonCdpManager = class {
6265
7588
  const browserWs = this.browserWs;
6266
7589
  let msgId = this.browserMsgId;
6267
7590
  const sendWs = (method, params = {}, sessionId) => {
6268
- return new Promise((resolve12, reject) => {
7591
+ return new Promise((resolve15, reject) => {
6269
7592
  const mid = msgId++;
6270
7593
  this.browserMsgId = msgId;
6271
7594
  const handler = (raw) => {
@@ -6274,7 +7597,7 @@ var DaemonCdpManager = class {
6274
7597
  if (msg.id === mid) {
6275
7598
  browserWs.removeListener("message", handler);
6276
7599
  if (msg.error) reject(new Error(msg.error.message || JSON.stringify(msg.error)));
6277
- else resolve12(msg.result);
7600
+ else resolve15(msg.result);
6278
7601
  }
6279
7602
  } catch {
6280
7603
  }
@@ -6475,14 +7798,14 @@ var DaemonCdpManager = class {
6475
7798
  if (!ws || ws.readyState !== import_ws.default.OPEN) {
6476
7799
  throw new Error("CDP not connected");
6477
7800
  }
6478
- return new Promise((resolve12, reject) => {
7801
+ return new Promise((resolve15, reject) => {
6479
7802
  const id = getNextId();
6480
7803
  pendingMap.set(id, {
6481
7804
  resolve: (result) => {
6482
7805
  if (result?.result?.subtype === "error") {
6483
7806
  reject(new Error(result.result.description));
6484
7807
  } else {
6485
- resolve12(result?.result?.value);
7808
+ resolve15(result?.result?.value);
6486
7809
  }
6487
7810
  },
6488
7811
  reject
@@ -6514,10 +7837,10 @@ var DaemonCdpManager = class {
6514
7837
  throw new Error("CDP not connected");
6515
7838
  }
6516
7839
  const sendViaSession = (method, params = {}) => {
6517
- return new Promise((resolve12, reject) => {
7840
+ return new Promise((resolve15, reject) => {
6518
7841
  const pendingMap = this._browserConnected ? this.browserPending : this.pending;
6519
7842
  const id = this._browserConnected ? this.browserMsgId++ : this.msgId++;
6520
- pendingMap.set(id, { resolve: resolve12, reject });
7843
+ pendingMap.set(id, { resolve: resolve15, reject });
6521
7844
  ws.send(JSON.stringify({ id, sessionId, method, params }));
6522
7845
  setTimeout(() => {
6523
7846
  if (pendingMap.has(id)) {
@@ -7263,10 +8586,10 @@ ${cleanBody}`;
7263
8586
 
7264
8587
  // src/config/chat-history.ts
7265
8588
  var fs3 = __toESM(require("fs"));
7266
- var path7 = __toESM(require("path"));
8589
+ var path10 = __toESM(require("path"));
7267
8590
  var os5 = __toESM(require("os"));
7268
8591
  init_chat_message_normalization();
7269
- var HISTORY_DIR = path7.join(os5.homedir(), ".adhdev", "history");
8592
+ var HISTORY_DIR = path10.join(os5.homedir(), ".adhdev", "history");
7270
8593
  var RETAIN_DAYS = 30;
7271
8594
  var SAVED_HISTORY_INDEX_VERSION = 1;
7272
8595
  var SAVED_HISTORY_INDEX_FILE = ".saved-history-index.json";
@@ -7429,8 +8752,8 @@ function extractSavedHistorySessionIdFromFile(file) {
7429
8752
  function buildSavedHistoryFileSignatureMap(dir, files) {
7430
8753
  return new Map(files.map((file) => {
7431
8754
  try {
7432
- const stat = fs3.statSync(path7.join(dir, file));
7433
- return [file, `${file}:${stat.size}:${Math.trunc(stat.mtimeMs)}`];
8755
+ const stat2 = fs3.statSync(path10.join(dir, file));
8756
+ return [file, `${file}:${stat2.size}:${Math.trunc(stat2.mtimeMs)}`];
7434
8757
  } catch {
7435
8758
  return [file, `${file}:missing`];
7436
8759
  }
@@ -7440,7 +8763,7 @@ function buildSavedHistoryCacheSignature(files, fileSignatures) {
7440
8763
  return files.map((file) => fileSignatures.get(file) || `${file}:missing`).join("|");
7441
8764
  }
7442
8765
  function getSavedHistoryIndexFilePath(dir) {
7443
- return path7.join(dir, SAVED_HISTORY_INDEX_FILE);
8766
+ return path10.join(dir, SAVED_HISTORY_INDEX_FILE);
7444
8767
  }
7445
8768
  function getSavedHistoryIndexLockPath(dir) {
7446
8769
  return `${getSavedHistoryIndexFilePath(dir)}${SAVED_HISTORY_INDEX_LOCK_SUFFIX}`;
@@ -7493,8 +8816,8 @@ function acquireSavedHistoryIndexLock(dir) {
7493
8816
  } catch (error) {
7494
8817
  if (error?.code !== "EEXIST") return null;
7495
8818
  try {
7496
- const stat = fs3.statSync(lockPath);
7497
- if (Date.now() - stat.mtimeMs > SAVED_HISTORY_INDEX_LOCK_STALE_MS) {
8819
+ const stat2 = fs3.statSync(lockPath);
8820
+ if (Date.now() - stat2.mtimeMs > SAVED_HISTORY_INDEX_LOCK_STALE_MS) {
7498
8821
  fs3.rmSync(lockPath, { recursive: true, force: true });
7499
8822
  continue;
7500
8823
  }
@@ -7542,7 +8865,7 @@ function savePersistedSavedHistoryIndex(dir, entries) {
7542
8865
  }
7543
8866
  for (const file of Array.from(currentEntries.keys())) {
7544
8867
  if (incomingFiles.has(file)) continue;
7545
- if (!fs3.existsSync(path7.join(dir, file))) {
8868
+ if (!fs3.existsSync(path10.join(dir, file))) {
7546
8869
  currentEntries.delete(file);
7547
8870
  }
7548
8871
  }
@@ -7557,8 +8880,8 @@ function invalidatePersistedSavedHistoryIndex(agentType, dir) {
7557
8880
  }
7558
8881
  function buildSavedHistoryIndexFileSignature(dir) {
7559
8882
  try {
7560
- const stat = fs3.statSync(getSavedHistoryIndexFilePath(dir));
7561
- return `index:${stat.size}:${Math.trunc(stat.mtimeMs)}`;
8883
+ const stat2 = fs3.statSync(getSavedHistoryIndexFilePath(dir));
8884
+ return `index:${stat2.size}:${Math.trunc(stat2.mtimeMs)}`;
7562
8885
  } catch {
7563
8886
  return "index:missing";
7564
8887
  }
@@ -7568,8 +8891,8 @@ function historyDirectoryHasFilesNewerThanIndex(dir) {
7568
8891
  const indexStat = fs3.statSync(getSavedHistoryIndexFilePath(dir));
7569
8892
  const files = listHistoryFiles(dir);
7570
8893
  for (const file of files) {
7571
- const stat = fs3.statSync(path7.join(dir, file));
7572
- if (stat.mtimeMs > indexStat.mtimeMs) return true;
8894
+ const stat2 = fs3.statSync(path10.join(dir, file));
8895
+ if (stat2.mtimeMs > indexStat.mtimeMs) return true;
7573
8896
  }
7574
8897
  return false;
7575
8898
  } catch {
@@ -7578,14 +8901,14 @@ function historyDirectoryHasFilesNewerThanIndex(dir) {
7578
8901
  }
7579
8902
  function buildSavedHistoryFileSignature(dir, file) {
7580
8903
  try {
7581
- const stat = fs3.statSync(path7.join(dir, file));
7582
- return `${file}:${stat.size}:${Math.trunc(stat.mtimeMs)}`;
8904
+ const stat2 = fs3.statSync(path10.join(dir, file));
8905
+ return `${file}:${stat2.size}:${Math.trunc(stat2.mtimeMs)}`;
7583
8906
  } catch {
7584
8907
  return `${file}:missing`;
7585
8908
  }
7586
8909
  }
7587
8910
  function persistSavedHistoryFileSummaryEntry(agentType, dir, file, updater) {
7588
- const filePath = path7.join(dir, file);
8911
+ const filePath = path10.join(dir, file);
7589
8912
  const result = withLockedPersistedSavedHistoryIndex(dir, (entries) => {
7590
8913
  const currentEntry = entries.get(file) || null;
7591
8914
  const nextSummary = updater(currentEntry?.summary || null);
@@ -7658,7 +8981,7 @@ function updateSavedHistoryIndexForAppendedMessages(agentType, dir, file, histor
7658
8981
  function computeSavedHistoryFileSummary(dir, file) {
7659
8982
  const historySessionId = extractSavedHistorySessionIdFromFile(file);
7660
8983
  if (!historySessionId) return null;
7661
- const filePath = path7.join(dir, file);
8984
+ const filePath = path10.join(dir, file);
7662
8985
  const content = fs3.readFileSync(filePath, "utf-8");
7663
8986
  const lines = content.split("\n").filter(Boolean);
7664
8987
  let messageCount = 0;
@@ -7745,7 +9068,7 @@ function computeSavedHistorySessionSummaries(agentType, dir, files, fileSignatur
7745
9068
  const summaryBySessionId = /* @__PURE__ */ new Map();
7746
9069
  const nextPersistedEntries = /* @__PURE__ */ new Map();
7747
9070
  for (const file of files.slice().sort()) {
7748
- const filePath = path7.join(dir, file);
9071
+ const filePath = path10.join(dir, file);
7749
9072
  const signature = fileSignatures.get(file) || `${file}:missing`;
7750
9073
  const cached = savedHistoryFileSummaryCache.get(filePath);
7751
9074
  const persisted = persistedEntries.get(file);
@@ -7865,12 +9188,12 @@ var ChatHistoryWriter = class {
7865
9188
  });
7866
9189
  }
7867
9190
  if (newMessages.length === 0) return;
7868
- const dir = path7.join(HISTORY_DIR, this.sanitize(agentType));
9191
+ const dir = path10.join(HISTORY_DIR, this.sanitize(agentType));
7869
9192
  fs3.mkdirSync(dir, { recursive: true });
7870
9193
  const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
7871
9194
  const filePrefix = effectiveHistoryKey ? `${this.sanitize(effectiveHistoryKey)}_` : "";
7872
9195
  const fileName = `${filePrefix}${date}.jsonl`;
7873
- const filePath = path7.join(dir, fileName);
9196
+ const filePath = path10.join(dir, fileName);
7874
9197
  const lines = newMessages.map((m) => JSON.stringify(m)).join("\n") + "\n";
7875
9198
  fs3.appendFileSync(filePath, lines, "utf-8");
7876
9199
  updateSavedHistoryIndexForAppendedMessages(agentType, dir, fileName, effectiveHistoryKey, newMessages);
@@ -7961,11 +9284,11 @@ var ChatHistoryWriter = class {
7961
9284
  const ws = String(workspace || "").trim();
7962
9285
  if (!id || !ws) return;
7963
9286
  try {
7964
- const dir = path7.join(HISTORY_DIR, this.sanitize(agentType));
9287
+ const dir = path10.join(HISTORY_DIR, this.sanitize(agentType));
7965
9288
  fs3.mkdirSync(dir, { recursive: true });
7966
9289
  const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
7967
9290
  const fileName = `${this.sanitize(id)}_${date}.jsonl`;
7968
- const filePath = path7.join(dir, fileName);
9291
+ const filePath = path10.join(dir, fileName);
7969
9292
  const record = {
7970
9293
  ts: (/* @__PURE__ */ new Date()).toISOString(),
7971
9294
  receivedAt: Date.now(),
@@ -8011,14 +9334,14 @@ var ChatHistoryWriter = class {
8011
9334
  this.lastSeenCounts.set(toDedupKey, Math.max(fromCount, this.lastSeenCounts.get(toDedupKey) || 0));
8012
9335
  this.lastSeenCounts.delete(fromDedupKey);
8013
9336
  }
8014
- const dir = path7.join(HISTORY_DIR, this.sanitize(agentType));
9337
+ const dir = path10.join(HISTORY_DIR, this.sanitize(agentType));
8015
9338
  if (!fs3.existsSync(dir)) return;
8016
9339
  const fromPrefix = `${this.sanitize(fromId)}_`;
8017
9340
  const toPrefix = `${this.sanitize(toId)}_`;
8018
9341
  const files = fs3.readdirSync(dir).filter((file) => file.startsWith(fromPrefix) && file.endsWith(".jsonl"));
8019
9342
  for (const file of files) {
8020
- const sourcePath = path7.join(dir, file);
8021
- const targetPath = path7.join(dir, `${toPrefix}${file.slice(fromPrefix.length)}`);
9343
+ const sourcePath = path10.join(dir, file);
9344
+ const targetPath = path10.join(dir, `${toPrefix}${file.slice(fromPrefix.length)}`);
8022
9345
  const sourceLines = fs3.readFileSync(sourcePath, "utf-8").split("\n").filter(Boolean);
8023
9346
  const rewritten = sourceLines.map((line) => {
8024
9347
  try {
@@ -8052,13 +9375,13 @@ var ChatHistoryWriter = class {
8052
9375
  const sessionId = String(historySessionId || "").trim();
8053
9376
  if (!sessionId) return;
8054
9377
  try {
8055
- const dir = path7.join(HISTORY_DIR, this.sanitize(agentType));
9378
+ const dir = path10.join(HISTORY_DIR, this.sanitize(agentType));
8056
9379
  if (!fs3.existsSync(dir)) return;
8057
9380
  const prefix = `${this.sanitize(sessionId)}_`;
8058
9381
  const files = fs3.readdirSync(dir).filter((file) => file.startsWith(prefix) && file.endsWith(".jsonl")).sort();
8059
9382
  const seen = /* @__PURE__ */ new Set();
8060
9383
  for (const file of files) {
8061
- const filePath = path7.join(dir, file);
9384
+ const filePath = path10.join(dir, file);
8062
9385
  const lines = fs3.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
8063
9386
  const next = [];
8064
9387
  for (const line of lines) {
@@ -8112,13 +9435,13 @@ var ChatHistoryWriter = class {
8112
9435
  const cutoff = Date.now() - RETAIN_DAYS * 24 * 60 * 60 * 1e3;
8113
9436
  const agentDirs = fs3.readdirSync(HISTORY_DIR, { withFileTypes: true }).filter((d) => d.isDirectory());
8114
9437
  for (const dir of agentDirs) {
8115
- const dirPath = path7.join(HISTORY_DIR, dir.name);
9438
+ const dirPath = path10.join(HISTORY_DIR, dir.name);
8116
9439
  const files = fs3.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl") || f.endsWith(".terminal.log"));
8117
9440
  let removedAny = false;
8118
9441
  for (const file of files) {
8119
- const filePath = path7.join(dirPath, file);
8120
- const stat = fs3.statSync(filePath);
8121
- if (stat.mtimeMs < cutoff) {
9442
+ const filePath = path10.join(dirPath, file);
9443
+ const stat2 = fs3.statSync(filePath);
9444
+ if (stat2.mtimeMs < cutoff) {
8122
9445
  fs3.unlinkSync(filePath);
8123
9446
  removedAny = true;
8124
9447
  }
@@ -8166,13 +9489,13 @@ function pageHistoryRecords(agentType, records, offset = 0, limit = 30, excludeR
8166
9489
  function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, excludeRecentCount = 0, historyBehavior) {
8167
9490
  try {
8168
9491
  const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
8169
- const dir = path7.join(HISTORY_DIR, sanitized);
9492
+ const dir = path10.join(HISTORY_DIR, sanitized);
8170
9493
  if (!fs3.existsSync(dir)) return { messages: [], hasMore: false };
8171
9494
  const files = listHistoryFiles(dir, historySessionId);
8172
9495
  const allMessages = [];
8173
9496
  const seen = /* @__PURE__ */ new Set();
8174
9497
  for (const file of files) {
8175
- const filePath = path7.join(dir, file);
9498
+ const filePath = path10.join(dir, file);
8176
9499
  const content = fs3.readFileSync(filePath, "utf-8");
8177
9500
  const lines = content.trim().split("\n").filter(Boolean);
8178
9501
  for (let i = 0; i < lines.length; i++) {
@@ -8196,7 +9519,7 @@ function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, ex
8196
9519
  function listSavedHistorySessions(agentType, options = {}, historyBehavior) {
8197
9520
  try {
8198
9521
  const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
8199
- const dir = path7.join(HISTORY_DIR, sanitized);
9522
+ const dir = path10.join(HISTORY_DIR, sanitized);
8200
9523
  if (!fs3.existsSync(dir)) {
8201
9524
  savedHistorySessionCache.delete(sanitized);
8202
9525
  return { sessions: [], hasMore: false };
@@ -8257,11 +9580,11 @@ function listSavedHistorySessions(agentType, options = {}, historyBehavior) {
8257
9580
  }
8258
9581
  function readExistingSessionStartRecord(agentType, historySessionId) {
8259
9582
  try {
8260
- const dir = path7.join(HISTORY_DIR, agentType);
9583
+ const dir = path10.join(HISTORY_DIR, agentType);
8261
9584
  if (!fs3.existsSync(dir)) return null;
8262
9585
  const files = listHistoryFiles(dir, historySessionId).sort();
8263
9586
  for (const file of files) {
8264
- const lines = fs3.readFileSync(path7.join(dir, file), "utf-8").split("\n").filter(Boolean);
9587
+ const lines = fs3.readFileSync(path10.join(dir, file), "utf-8").split("\n").filter(Boolean);
8265
9588
  for (const line of lines) {
8266
9589
  try {
8267
9590
  const parsed = JSON.parse(line);
@@ -8281,16 +9604,16 @@ function readExistingSessionStartRecord(agentType, historySessionId) {
8281
9604
  function rewriteCanonicalSavedHistory(agentType, historySessionId, records) {
8282
9605
  if (records.length === 0) return false;
8283
9606
  try {
8284
- const dir = path7.join(HISTORY_DIR, agentType);
9607
+ const dir = path10.join(HISTORY_DIR, agentType);
8285
9608
  fs3.mkdirSync(dir, { recursive: true });
8286
9609
  const prefix = `${historySessionId.replace(/[^a-zA-Z0-9_-]/g, "_")}_`;
8287
9610
  for (const file of fs3.readdirSync(dir)) {
8288
9611
  if (file.startsWith(prefix) && file.endsWith(".jsonl")) {
8289
- fs3.unlinkSync(path7.join(dir, file));
9612
+ fs3.unlinkSync(path10.join(dir, file));
8290
9613
  }
8291
9614
  }
8292
9615
  const targetDate = new Date(records[records.length - 1].receivedAt || Date.now()).toISOString().slice(0, 10);
8293
- const filePath = path7.join(dir, `${prefix}${targetDate}.jsonl`);
9616
+ const filePath = path10.join(dir, `${prefix}${targetDate}.jsonl`);
8294
9617
  fs3.writeFileSync(filePath, `${records.map((record) => JSON.stringify(record)).join("\n")}
8295
9618
  `, "utf-8");
8296
9619
  invalidatePersistedSavedHistoryIndex(agentType, dir);
@@ -10162,6 +11485,10 @@ function shouldIncludeSessionMetadata(profile) {
10162
11485
  function shouldIncludeRuntimeMetadata(profile) {
10163
11486
  return true;
10164
11487
  }
11488
+ function getGitSummaryForWorkspace(workspace, options) {
11489
+ if (!workspace) return void 0;
11490
+ return options.getGitSummaryForWorkspace?.(workspace) || void 0;
11491
+ }
10165
11492
  function findCdpManager(cdpManagers, key) {
10166
11493
  const exact = cdpManagers.get(key);
10167
11494
  if (exact) return exact.isConnected ? exact : null;
@@ -10217,6 +11544,8 @@ function buildIdeWorkspaceSession(state, cdpManagers, options) {
10217
11544
  const controlValues = normalizeProviderStateControlValues(state.controlValues);
10218
11545
  const includeSessionMetadata = shouldIncludeSessionMetadata(profile);
10219
11546
  const includeSessionControls = shouldIncludeSessionControls(profile);
11547
+ const workspace = state.workspace || null;
11548
+ const git = getGitSummaryForWorkspace(workspace, options);
10220
11549
  const title = activeChat?.title || state.name;
10221
11550
  return {
10222
11551
  id: state.instanceId || state.type,
@@ -10229,7 +11558,8 @@ function buildIdeWorkspaceSession(state, cdpManagers, options) {
10229
11558
  activeModal: activeChat?.activeModal || null
10230
11559
  }),
10231
11560
  title,
10232
- workspace: state.workspace || null,
11561
+ workspace,
11562
+ ...git && { git },
10233
11563
  activeChat,
10234
11564
  ...summaryMetadata && { summaryMetadata },
10235
11565
  ...includeSessionMetadata && { capabilities: state.sessionCapabilities || IDE_SESSION_CAPABILITIES },
@@ -10250,6 +11580,8 @@ function buildExtensionAgentSession(parent, ext, options) {
10250
11580
  const controlValues = normalizeProviderStateControlValues(ext.controlValues);
10251
11581
  const includeSessionMetadata = shouldIncludeSessionMetadata(profile);
10252
11582
  const includeSessionControls = shouldIncludeSessionControls(profile);
11583
+ const workspace = parent.workspace || null;
11584
+ const git = getGitSummaryForWorkspace(workspace, options);
10253
11585
  return {
10254
11586
  id: ext.instanceId || `${parent.instanceId}:${ext.type}`,
10255
11587
  parentId: parent.instanceId || parent.type,
@@ -10262,7 +11594,8 @@ function buildExtensionAgentSession(parent, ext, options) {
10262
11594
  activeModal: activeChat?.activeModal || null
10263
11595
  }),
10264
11596
  title: activeChat?.title || ext.name,
10265
- workspace: parent.workspace || null,
11597
+ workspace,
11598
+ ...git && { git },
10266
11599
  activeChat,
10267
11600
  ...summaryMetadata && { summaryMetadata },
10268
11601
  ...includeSessionMetadata && { capabilities: ext.sessionCapabilities || EXTENSION_SESSION_CAPABILITIES },
@@ -10298,6 +11631,8 @@ function buildCliSession(state, options) {
10298
11631
  const includeSessionMetadata = shouldIncludeSessionMetadata(profile);
10299
11632
  const includeRuntimeMetadata = shouldIncludeRuntimeMetadata(profile);
10300
11633
  const includeSessionControls = shouldIncludeSessionControls(profile);
11634
+ const workspace = state.workspace || null;
11635
+ const git = getGitSummaryForWorkspace(workspace, options);
10301
11636
  return {
10302
11637
  id: state.instanceId,
10303
11638
  parentId: null,
@@ -10310,7 +11645,8 @@ function buildCliSession(state, options) {
10310
11645
  activeModal: activeChat?.activeModal || null
10311
11646
  }),
10312
11647
  title: activeChat?.title || state.name,
10313
- workspace: state.workspace || null,
11648
+ workspace,
11649
+ ...git && { git },
10314
11650
  ...includeRuntimeMetadata && {
10315
11651
  runtimeKey: state.runtime?.runtimeKey,
10316
11652
  runtimeDisplayName: state.runtime?.displayName,
@@ -10345,6 +11681,8 @@ function buildAcpSession(state, options) {
10345
11681
  const controlValues = normalizeProviderStateControlValues(state.controlValues);
10346
11682
  const includeSessionMetadata = shouldIncludeSessionMetadata(profile);
10347
11683
  const includeSessionControls = shouldIncludeSessionControls(profile);
11684
+ const workspace = state.workspace || null;
11685
+ const git = getGitSummaryForWorkspace(workspace, options);
10348
11686
  return {
10349
11687
  id: state.instanceId,
10350
11688
  parentId: null,
@@ -10356,7 +11694,8 @@ function buildAcpSession(state, options) {
10356
11694
  activeModal: activeChat?.activeModal || null
10357
11695
  }),
10358
11696
  title: activeChat?.title || state.name,
10359
- workspace: state.workspace || null,
11697
+ workspace,
11698
+ ...git && { git },
10360
11699
  activeChat,
10361
11700
  ...summaryMetadata && { summaryMetadata },
10362
11701
  ...includeSessionMetadata && { capabilities: ACP_SESSION_CAPABILITIES },
@@ -10475,7 +11814,7 @@ function resolveLegacyProviderScript(fn, scriptName, params) {
10475
11814
  // src/commands/chat-commands.ts
10476
11815
  var fs4 = __toESM(require("fs"));
10477
11816
  var os6 = __toESM(require("os"));
10478
- var path8 = __toESM(require("path"));
11817
+ var path11 = __toESM(require("path"));
10479
11818
  var import_node_crypto = require("crypto");
10480
11819
  init_contracts();
10481
11820
 
@@ -11168,7 +12507,7 @@ function buildDebugBundleText(bundle) {
11168
12507
  }
11169
12508
  function getChatDebugBundleDir() {
11170
12509
  const override = typeof process.env.ADHDEV_DEBUG_BUNDLE_DIR === "string" ? process.env.ADHDEV_DEBUG_BUNDLE_DIR.trim() : "";
11171
- return override || path8.join(os6.homedir(), ".adhdev", "debug-bundles", "chat");
12510
+ return override || path11.join(os6.homedir(), ".adhdev", "debug-bundles", "chat");
11172
12511
  }
11173
12512
  function safeBundleIdSegment(value, fallback) {
11174
12513
  const normalized = String(value || fallback).trim().replace(/[^A-Za-z0-9_.-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
@@ -11201,7 +12540,7 @@ function storeChatDebugBundleOnDaemon(bundle, targetSessionId) {
11201
12540
  const bundleId = createChatDebugBundleId(targetSessionId);
11202
12541
  const dir = getChatDebugBundleDir();
11203
12542
  fs4.mkdirSync(dir, { recursive: true });
11204
- const savedPath = path8.join(dir, `${bundleId}.json`);
12543
+ const savedPath = path11.join(dir, `${bundleId}.json`);
11205
12544
  const json = `${JSON.stringify(bundle, null, 2)}
11206
12545
  `;
11207
12546
  fs4.writeFileSync(savedPath, json, { encoding: "utf8", mode: 384 });
@@ -11395,7 +12734,7 @@ function getCliVisibleTranscriptCount(adapter) {
11395
12734
  async function getStableExtensionBaseline(h) {
11396
12735
  const first = await readExtensionChatState(h);
11397
12736
  if (getStateMessageCount(first) > 0 || getStateLastSignature(first)) return first;
11398
- await new Promise((resolve12) => setTimeout(resolve12, 150));
12737
+ await new Promise((resolve15) => setTimeout(resolve15, 150));
11399
12738
  const second = await readExtensionChatState(h);
11400
12739
  return getStateMessageCount(second) >= getStateMessageCount(first) ? second : first;
11401
12740
  }
@@ -11403,7 +12742,7 @@ async function verifyExtensionSendObserved(h, before) {
11403
12742
  const beforeCount = getStateMessageCount(before);
11404
12743
  const beforeSignature = getStateLastSignature(before);
11405
12744
  for (let attempt = 0; attempt < 12; attempt += 1) {
11406
- await new Promise((resolve12) => setTimeout(resolve12, 250));
12745
+ await new Promise((resolve15) => setTimeout(resolve15, 250));
11407
12746
  const state = await readExtensionChatState(h);
11408
12747
  if (state?.status === "waiting_approval") return true;
11409
12748
  const afterCount = getStateMessageCount(state);
@@ -12339,7 +13678,7 @@ async function handleResolveAction(h, args) {
12339
13678
 
12340
13679
  // src/commands/cdp-commands.ts
12341
13680
  var fs5 = __toESM(require("fs"));
12342
- var path9 = __toESM(require("path"));
13681
+ var path12 = __toESM(require("path"));
12343
13682
  var os7 = __toESM(require("os"));
12344
13683
  var KEY_TO_VK = {
12345
13684
  Backspace: 8,
@@ -12596,25 +13935,25 @@ function resolveSafePath(requestedPath) {
12596
13935
  const inputPath = rawPath || ".";
12597
13936
  const home = os7.homedir();
12598
13937
  if (inputPath.startsWith("~")) {
12599
- return path9.resolve(path9.join(home, inputPath.slice(1)));
13938
+ return path12.resolve(path12.join(home, inputPath.slice(1)));
12600
13939
  }
12601
13940
  if (process.platform === "win32") {
12602
13941
  const normalized = normalizeWindowsRequestedPath(inputPath);
12603
- if (path9.win32.isAbsolute(normalized)) {
12604
- return path9.win32.normalize(normalized);
13942
+ if (path12.win32.isAbsolute(normalized)) {
13943
+ return path12.win32.normalize(normalized);
12605
13944
  }
12606
- return path9.win32.resolve(normalized);
13945
+ return path12.win32.resolve(normalized);
12607
13946
  }
12608
- if (path9.isAbsolute(inputPath)) {
12609
- return path9.normalize(inputPath);
13947
+ if (path12.isAbsolute(inputPath)) {
13948
+ return path12.normalize(inputPath);
12610
13949
  }
12611
- return path9.resolve(inputPath);
13950
+ return path12.resolve(inputPath);
12612
13951
  }
12613
13952
  function listDirectoryEntriesSafe(dirPath) {
12614
13953
  const entries = fs5.readdirSync(dirPath, { withFileTypes: true });
12615
13954
  const files = [];
12616
13955
  for (const entry of entries) {
12617
- const entryPath = path9.join(dirPath, entry.name);
13956
+ const entryPath = path12.join(dirPath, entry.name);
12618
13957
  try {
12619
13958
  if (entry.isDirectory()) {
12620
13959
  files.push({ name: entry.name, type: "directory" });
@@ -12630,11 +13969,11 @@ function listDirectoryEntriesSafe(dirPath) {
12630
13969
  files.push({ name: entry.name, type: "file", size });
12631
13970
  continue;
12632
13971
  }
12633
- const stat = fs5.statSync(entryPath);
13972
+ const stat2 = fs5.statSync(entryPath);
12634
13973
  files.push({
12635
13974
  name: entry.name,
12636
- type: stat.isDirectory() ? "directory" : "file",
12637
- size: stat.isFile() ? stat.size : void 0
13975
+ type: stat2.isDirectory() ? "directory" : "file",
13976
+ size: stat2.isFile() ? stat2.size : void 0
12638
13977
  });
12639
13978
  } catch {
12640
13979
  }
@@ -12668,7 +14007,7 @@ async function handleFileRead(h, args) {
12668
14007
  async function handleFileWrite(h, args) {
12669
14008
  try {
12670
14009
  const filePath = resolveSafePath(args?.path);
12671
- fs5.mkdirSync(path9.dirname(filePath), { recursive: true });
14010
+ fs5.mkdirSync(path12.dirname(filePath), { recursive: true });
12672
14011
  fs5.writeFileSync(filePath, args?.content || "", "utf-8");
12673
14012
  return { success: true, path: filePath };
12674
14013
  } catch (e) {
@@ -13017,7 +14356,7 @@ async function executeProviderScript(h, args, scriptName) {
13017
14356
  const enterCount = cliCommand.enterCount || 1;
13018
14357
  await adapter.writeRaw(cliCommand.text + "\r");
13019
14358
  for (let i = 1; i < enterCount; i += 1) {
13020
- await new Promise((resolve12) => setTimeout(resolve12, 50));
14359
+ await new Promise((resolve15) => setTimeout(resolve15, 50));
13021
14360
  await adapter.writeRaw("\r");
13022
14361
  }
13023
14362
  }
@@ -13511,6 +14850,12 @@ var DaemonCommandHandler = class {
13511
14850
  this._currentRoute = this.resolveRoute(args);
13512
14851
  const startedAt = Date.now();
13513
14852
  this.logCommandStart(cmd, args);
14853
+ let result;
14854
+ if (isGitCommandName(cmd)) {
14855
+ result = await handleGitCommand(cmd, args, this._ctx.gitCommandServices);
14856
+ this.logCommandEnd(cmd, result, startedAt);
14857
+ return result;
14858
+ }
13514
14859
  const sessionScopedCommands = /* @__PURE__ */ new Set([
13515
14860
  "read_chat",
13516
14861
  "get_chat_debug_bundle",
@@ -13536,7 +14881,6 @@ var DaemonCommandHandler = class {
13536
14881
  this.logCommandEnd(cmd, result2, startedAt);
13537
14882
  return result2;
13538
14883
  }
13539
- let result;
13540
14884
  if (!this._currentRoute.session && !this._currentRoute.managerKey && !this._currentRoute.providerType) {
13541
14885
  const cdpCommands = ["send_chat", "read_chat", "list_chats", "new_chat", "switch_chat", "set_mode", "change_model", "set_thought_level", "resolve_action"];
13542
14886
  if (cdpCommands.includes(cmd)) {
@@ -13545,6 +14889,16 @@ var DaemonCommandHandler = class {
13545
14889
  return result;
13546
14890
  }
13547
14891
  }
14892
+ if (cmd === "send_chat" && this._ctx.onBeforeSendChat) {
14893
+ const sessionId = this._currentRoute.session?.sessionId;
14894
+ const workspace = sessionId ? this._ctx.instanceManager?.getInstance(sessionId)?.getState?.()?.workspace : void 0;
14895
+ if (workspace && sessionId) {
14896
+ try {
14897
+ this._ctx.onBeforeSendChat({ workspace, sessionId });
14898
+ } catch {
14899
+ }
14900
+ }
14901
+ }
13548
14902
  try {
13549
14903
  result = await this.dispatch(cmd, args);
13550
14904
  this.logCommandEnd(cmd, result, startedAt);
@@ -13687,7 +15041,7 @@ var DaemonCommandHandler = class {
13687
15041
  try {
13688
15042
  const http3 = await import("http");
13689
15043
  const postData = JSON.stringify(body);
13690
- const result = await new Promise((resolve12, reject) => {
15044
+ const result = await new Promise((resolve15, reject) => {
13691
15045
  const req = http3.request({
13692
15046
  hostname: "127.0.0.1",
13693
15047
  port: 19280,
@@ -13699,9 +15053,9 @@ var DaemonCommandHandler = class {
13699
15053
  res.on("data", (chunk) => data += chunk);
13700
15054
  res.on("end", () => {
13701
15055
  try {
13702
- resolve12(JSON.parse(data));
15056
+ resolve15(JSON.parse(data));
13703
15057
  } catch {
13704
- resolve12({ raw: data });
15058
+ resolve15({ raw: data });
13705
15059
  }
13706
15060
  });
13707
15061
  });
@@ -13719,15 +15073,15 @@ var DaemonCommandHandler = class {
13719
15073
  if (!providerType) return { success: false, error: "providerType required" };
13720
15074
  try {
13721
15075
  const http3 = await import("http");
13722
- const result = await new Promise((resolve12, reject) => {
15076
+ const result = await new Promise((resolve15, reject) => {
13723
15077
  http3.get(`http://127.0.0.1:19280/api/providers/${providerType}/${endpoint}`, (res) => {
13724
15078
  let data = "";
13725
15079
  res.on("data", (chunk) => data += chunk);
13726
15080
  res.on("end", () => {
13727
15081
  try {
13728
- resolve12(JSON.parse(data));
15082
+ resolve15(JSON.parse(data));
13729
15083
  } catch {
13730
- resolve12({ raw: data });
15084
+ resolve15({ raw: data });
13731
15085
  }
13732
15086
  });
13733
15087
  }).on("error", reject);
@@ -13741,7 +15095,7 @@ var DaemonCommandHandler = class {
13741
15095
  try {
13742
15096
  const http3 = await import("http");
13743
15097
  const postData = JSON.stringify(args || {});
13744
- const result = await new Promise((resolve12, reject) => {
15098
+ const result = await new Promise((resolve15, reject) => {
13745
15099
  const req = http3.request({
13746
15100
  hostname: "127.0.0.1",
13747
15101
  port: 19280,
@@ -13753,9 +15107,9 @@ var DaemonCommandHandler = class {
13753
15107
  res.on("data", (chunk) => data += chunk);
13754
15108
  res.on("end", () => {
13755
15109
  try {
13756
- resolve12(JSON.parse(data));
15110
+ resolve15(JSON.parse(data));
13757
15111
  } catch {
13758
- resolve12({ raw: data });
15112
+ resolve15({ raw: data });
13759
15113
  }
13760
15114
  });
13761
15115
  });
@@ -13772,7 +15126,7 @@ var DaemonCommandHandler = class {
13772
15126
 
13773
15127
  // src/commands/cli-manager.ts
13774
15128
  var os13 = __toESM(require("os"));
13775
- var path13 = __toESM(require("path"));
15129
+ var path16 = __toESM(require("path"));
13776
15130
  var crypto4 = __toESM(require("crypto"));
13777
15131
  var import_fs5 = require("fs");
13778
15132
  var import_child_process6 = require("child_process");
@@ -13782,7 +15136,7 @@ init_config();
13782
15136
 
13783
15137
  // src/providers/cli-provider-instance.ts
13784
15138
  var os12 = __toESM(require("os"));
13785
- var path12 = __toESM(require("path"));
15139
+ var path15 = __toESM(require("path"));
13786
15140
  var crypto3 = __toESM(require("crypto"));
13787
15141
  var fs6 = __toESM(require("fs"));
13788
15142
  var import_node_module = require("module");
@@ -13843,7 +15197,7 @@ function buildIncrementalHistoryAppendMessages(previousMessages, currentMessages
13843
15197
  var CachedDatabaseSync = null;
13844
15198
  function getDatabaseSync() {
13845
15199
  if (CachedDatabaseSync) return CachedDatabaseSync;
13846
- const requireFn = typeof require === "function" ? require : (0, import_node_module.createRequire)(path12.join(process.cwd(), "__adhdev_sqlite_loader__.js"));
15200
+ const requireFn = typeof require === "function" ? require : (0, import_node_module.createRequire)(path15.join(process.cwd(), "__adhdev_sqlite_loader__.js"));
13847
15201
  const sqliteModule = requireFn(`node:${"sqlite"}`);
13848
15202
  CachedDatabaseSync = sqliteModule.DatabaseSync;
13849
15203
  if (!CachedDatabaseSync) {
@@ -13881,7 +15235,7 @@ async function waitForCliAdapterReady(adapter, options) {
13881
15235
  if (status === "stopped") {
13882
15236
  throw new Error("CLI runtime stopped before it became ready");
13883
15237
  }
13884
- await new Promise((resolve12) => setTimeout(resolve12, pollMs));
15238
+ await new Promise((resolve15) => setTimeout(resolve15, pollMs));
13885
15239
  }
13886
15240
  throw new Error(`CLI runtime did not become ready within ${timeoutMs}ms`);
13887
15241
  }
@@ -14232,7 +15586,7 @@ var CliProviderInstance = class {
14232
15586
  const enterCount = cliCommand.enterCount || 1;
14233
15587
  await this.adapter.writeRaw(cliCommand.text + "\r");
14234
15588
  for (let i = 1; i < enterCount; i += 1) {
14235
- await new Promise((resolve12) => setTimeout(resolve12, 50));
15589
+ await new Promise((resolve15) => setTimeout(resolve15, 50));
14236
15590
  await this.adapter.writeRaw("\r");
14237
15591
  }
14238
15592
  }
@@ -15346,13 +16700,13 @@ var AcpProviderInstance = class {
15346
16700
  }
15347
16701
  this.currentStatus = "waiting_approval";
15348
16702
  this.detectStatusTransition();
15349
- const approved = await new Promise((resolve12) => {
15350
- this.permissionResolvers.push(resolve12);
16703
+ const approved = await new Promise((resolve15) => {
16704
+ this.permissionResolvers.push(resolve15);
15351
16705
  setTimeout(() => {
15352
- const idx = this.permissionResolvers.indexOf(resolve12);
16706
+ const idx = this.permissionResolvers.indexOf(resolve15);
15353
16707
  if (idx >= 0) {
15354
16708
  this.permissionResolvers.splice(idx, 1);
15355
- resolve12(false);
16709
+ resolve15(false);
15356
16710
  }
15357
16711
  }, 3e5);
15358
16712
  });
@@ -15927,11 +17281,11 @@ function shouldRestoreHostedRuntime(record, managerTag) {
15927
17281
  // src/commands/cli-manager.ts
15928
17282
  function isExplicitCommand(command) {
15929
17283
  const trimmed = command.trim();
15930
- return path13.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
17284
+ return path16.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
15931
17285
  }
15932
17286
  function expandExecutable(command) {
15933
17287
  const trimmed = command.trim();
15934
- return trimmed.startsWith("~") ? path13.join(os13.homedir(), trimmed.slice(1)) : trimmed;
17288
+ return trimmed.startsWith("~") ? path16.join(os13.homedir(), trimmed.slice(1)) : trimmed;
15935
17289
  }
15936
17290
  function commandExists(command) {
15937
17291
  const trimmed = command.trim();
@@ -16212,7 +17566,7 @@ var DaemonCliManager = class {
16212
17566
  async startSession(cliType, workingDir, cliArgs, initialModel, options) {
16213
17567
  const trimmed = (workingDir || "").trim();
16214
17568
  if (!trimmed) throw new Error("working directory required");
16215
- const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os13.homedir()) : path13.resolve(trimmed);
17569
+ const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os13.homedir()) : path16.resolve(trimmed);
16216
17570
  const normalizedType = this.providerLoader.resolveAlias(cliType);
16217
17571
  const rawProvider = this.providerLoader.getByAlias(cliType);
16218
17572
  const provider = rawProvider ? this.providerLoader.resolve(normalizedType) || rawProvider : void 0;
@@ -16713,11 +18067,11 @@ Run 'adhdev doctor' for detailed diagnostics.`
16713
18067
  var import_child_process7 = require("child_process");
16714
18068
  var net = __toESM(require("net"));
16715
18069
  var os15 = __toESM(require("os"));
16716
- var path15 = __toESM(require("path"));
18070
+ var path18 = __toESM(require("path"));
16717
18071
 
16718
18072
  // src/providers/provider-loader.ts
16719
18073
  var fs7 = __toESM(require("fs"));
16720
- var path14 = __toESM(require("path"));
18074
+ var path17 = __toESM(require("path"));
16721
18075
  var os14 = __toESM(require("os"));
16722
18076
  var chokidar = __toESM(require("chokidar"));
16723
18077
  init_logger();
@@ -16780,6 +18134,7 @@ var KNOWN_PROVIDER_FIELDS = /* @__PURE__ */ new Set([
16780
18134
  "sendDelayMs",
16781
18135
  "sendKey",
16782
18136
  "submitStrategy",
18137
+ "requirePromptEchoBeforeSubmit",
16783
18138
  "timeouts",
16784
18139
  "disableUpstream"
16785
18140
  ]);
@@ -16982,7 +18337,7 @@ var ProviderLoader = class _ProviderLoader {
16982
18337
  try {
16983
18338
  if (!fs7.existsSync(candidate) || !fs7.statSync(candidate).isDirectory()) return false;
16984
18339
  return ["ide", "extension", "cli", "acp"].some(
16985
- (category) => fs7.existsSync(path14.join(candidate, category))
18340
+ (category) => fs7.existsSync(path17.join(candidate, category))
16986
18341
  );
16987
18342
  } catch {
16988
18343
  return false;
@@ -16990,20 +18345,20 @@ var ProviderLoader = class _ProviderLoader {
16990
18345
  }
16991
18346
  static hasProviderRootMarker(candidate) {
16992
18347
  try {
16993
- return fs7.existsSync(path14.join(candidate, _ProviderLoader.SIBLING_MARKER_FILE));
18348
+ return fs7.existsSync(path17.join(candidate, _ProviderLoader.SIBLING_MARKER_FILE));
16994
18349
  } catch {
16995
18350
  return false;
16996
18351
  }
16997
18352
  }
16998
18353
  detectDefaultUserDir() {
16999
- const fallback = path14.join(os14.homedir(), ".adhdev", "providers");
18354
+ const fallback = path17.join(os14.homedir(), ".adhdev", "providers");
17000
18355
  const envOptIn = process.env[_ProviderLoader.SIBLING_ENV_VAR] === "1";
17001
18356
  const visited = /* @__PURE__ */ new Set();
17002
18357
  for (const start of this.probeStarts) {
17003
- let current = path14.resolve(start);
18358
+ let current = path17.resolve(start);
17004
18359
  while (!visited.has(current)) {
17005
18360
  visited.add(current);
17006
- const siblingCandidate = path14.join(path14.dirname(current), _ProviderLoader.REPO_PROVIDER_DIRNAME);
18361
+ const siblingCandidate = path17.join(path17.dirname(current), _ProviderLoader.REPO_PROVIDER_DIRNAME);
17007
18362
  if (_ProviderLoader.looksLikeProviderRoot(siblingCandidate)) {
17008
18363
  const hasMarker = _ProviderLoader.hasProviderRootMarker(siblingCandidate);
17009
18364
  if (envOptIn || hasMarker) {
@@ -17025,7 +18380,7 @@ var ProviderLoader = class _ProviderLoader {
17025
18380
  return { path: siblingCandidate, source };
17026
18381
  }
17027
18382
  }
17028
- const parent = path14.dirname(current);
18383
+ const parent = path17.dirname(current);
17029
18384
  if (parent === current) break;
17030
18385
  current = parent;
17031
18386
  }
@@ -17035,11 +18390,11 @@ var ProviderLoader = class _ProviderLoader {
17035
18390
  constructor(options) {
17036
18391
  this.logFn = options?.logFn || LOG.forComponent("Provider").asLogFn();
17037
18392
  this.probeStarts = options?.probeStarts ?? [process.cwd(), __dirname];
17038
- this.defaultProvidersDir = path14.join(os14.homedir(), ".adhdev", "providers");
18393
+ this.defaultProvidersDir = path17.join(os14.homedir(), ".adhdev", "providers");
17039
18394
  const detected = this.detectDefaultUserDir();
17040
18395
  this.userDir = detected.path;
17041
18396
  this.userDirSource = detected.source;
17042
- this.upstreamDir = path14.join(this.defaultProvidersDir, ".upstream");
18397
+ this.upstreamDir = path17.join(this.defaultProvidersDir, ".upstream");
17043
18398
  this.disableUpstream = false;
17044
18399
  this.applySourceConfig({
17045
18400
  userDir: options?.userDir,
@@ -17098,7 +18453,7 @@ var ProviderLoader = class _ProviderLoader {
17098
18453
  this.userDir = detected.path;
17099
18454
  this.userDirSource = detected.source;
17100
18455
  }
17101
- this.upstreamDir = path14.join(this.defaultProvidersDir, ".upstream");
18456
+ this.upstreamDir = path17.join(this.defaultProvidersDir, ".upstream");
17102
18457
  this.disableUpstream = this.sourceMode === "no-upstream";
17103
18458
  if (this.explicitProviderDir) {
17104
18459
  this.log(`Config 'providerDir' applied: ${this.userDir}`);
@@ -17112,7 +18467,7 @@ var ProviderLoader = class _ProviderLoader {
17112
18467
  * Canonical provider directory shape for a given root.
17113
18468
  */
17114
18469
  getProviderDir(root, category, type) {
17115
- return path14.join(root, category, type);
18470
+ return path17.join(root, category, type);
17116
18471
  }
17117
18472
  /**
17118
18473
  * Canonical user override directory for a provider.
@@ -17139,7 +18494,7 @@ var ProviderLoader = class _ProviderLoader {
17139
18494
  resolveProviderFile(type, ...segments) {
17140
18495
  const dir = this.findProviderDirInternal(type);
17141
18496
  if (!dir) return null;
17142
- return path14.join(dir, ...segments);
18497
+ return path17.join(dir, ...segments);
17143
18498
  }
17144
18499
  /**
17145
18500
  * Load all providers (3-tier priority)
@@ -17178,7 +18533,7 @@ var ProviderLoader = class _ProviderLoader {
17178
18533
  if (!fs7.existsSync(this.upstreamDir)) return false;
17179
18534
  try {
17180
18535
  return fs7.readdirSync(this.upstreamDir).some(
17181
- (d) => fs7.statSync(path14.join(this.upstreamDir, d)).isDirectory()
18536
+ (d) => fs7.statSync(path17.join(this.upstreamDir, d)).isDirectory()
17182
18537
  );
17183
18538
  } catch {
17184
18539
  return false;
@@ -17675,8 +19030,8 @@ var ProviderLoader = class _ProviderLoader {
17675
19030
  resolved._resolvedScriptDir = entry.scriptDir;
17676
19031
  resolved._resolvedScriptsSource = `compatibility:${entry.ideVersion}`;
17677
19032
  if (providerDir) {
17678
- const fullDir = path14.join(providerDir, entry.scriptDir);
17679
- resolved._resolvedScriptsPath = fs7.existsSync(path14.join(fullDir, "scripts.js")) ? path14.join(fullDir, "scripts.js") : fullDir;
19033
+ const fullDir = path17.join(providerDir, entry.scriptDir);
19034
+ resolved._resolvedScriptsPath = fs7.existsSync(path17.join(fullDir, "scripts.js")) ? path17.join(fullDir, "scripts.js") : fullDir;
17680
19035
  }
17681
19036
  matched = true;
17682
19037
  }
@@ -17691,8 +19046,8 @@ var ProviderLoader = class _ProviderLoader {
17691
19046
  resolved._resolvedScriptDir = base.defaultScriptDir;
17692
19047
  resolved._resolvedScriptsSource = "defaultScriptDir:version_miss";
17693
19048
  if (providerDir) {
17694
- const fullDir = path14.join(providerDir, base.defaultScriptDir);
17695
- resolved._resolvedScriptsPath = fs7.existsSync(path14.join(fullDir, "scripts.js")) ? path14.join(fullDir, "scripts.js") : fullDir;
19049
+ const fullDir = path17.join(providerDir, base.defaultScriptDir);
19050
+ resolved._resolvedScriptsPath = fs7.existsSync(path17.join(fullDir, "scripts.js")) ? path17.join(fullDir, "scripts.js") : fullDir;
17696
19051
  }
17697
19052
  }
17698
19053
  resolved._versionWarning = `Version ${currentVersion} not in compatibility matrix. Using default scripts.`;
@@ -17709,8 +19064,8 @@ var ProviderLoader = class _ProviderLoader {
17709
19064
  resolved._resolvedScriptDir = dirOverride;
17710
19065
  resolved._resolvedScriptsSource = `versions:${range}`;
17711
19066
  if (providerDir) {
17712
- const fullDir = path14.join(providerDir, dirOverride);
17713
- resolved._resolvedScriptsPath = fs7.existsSync(path14.join(fullDir, "scripts.js")) ? path14.join(fullDir, "scripts.js") : fullDir;
19067
+ const fullDir = path17.join(providerDir, dirOverride);
19068
+ resolved._resolvedScriptsPath = fs7.existsSync(path17.join(fullDir, "scripts.js")) ? path17.join(fullDir, "scripts.js") : fullDir;
17714
19069
  }
17715
19070
  }
17716
19071
  } else if (override.scripts) {
@@ -17726,8 +19081,8 @@ var ProviderLoader = class _ProviderLoader {
17726
19081
  resolved._resolvedScriptDir = base.defaultScriptDir;
17727
19082
  resolved._resolvedScriptsSource = "defaultScriptDir:no_version";
17728
19083
  if (providerDir) {
17729
- const fullDir = path14.join(providerDir, base.defaultScriptDir);
17730
- resolved._resolvedScriptsPath = fs7.existsSync(path14.join(fullDir, "scripts.js")) ? path14.join(fullDir, "scripts.js") : fullDir;
19084
+ const fullDir = path17.join(providerDir, base.defaultScriptDir);
19085
+ resolved._resolvedScriptsPath = fs7.existsSync(path17.join(fullDir, "scripts.js")) ? path17.join(fullDir, "scripts.js") : fullDir;
17731
19086
  }
17732
19087
  }
17733
19088
  }
@@ -17759,14 +19114,14 @@ var ProviderLoader = class _ProviderLoader {
17759
19114
  this.log(` [loadScriptsFromDir] ${type}: providerDir not found`);
17760
19115
  return null;
17761
19116
  }
17762
- const dir = path14.join(providerDir, scriptDir);
19117
+ const dir = path17.join(providerDir, scriptDir);
17763
19118
  if (!fs7.existsSync(dir)) {
17764
19119
  this.log(` [loadScriptsFromDir] ${type}: dir not found: ${dir}`);
17765
19120
  return null;
17766
19121
  }
17767
19122
  const cached = this.scriptsCache.get(dir);
17768
19123
  if (cached) return cached;
17769
- const scriptsJs = path14.join(dir, "scripts.js");
19124
+ const scriptsJs = path17.join(dir, "scripts.js");
17770
19125
  if (fs7.existsSync(scriptsJs)) {
17771
19126
  try {
17772
19127
  delete require.cache[require.resolve(scriptsJs)];
@@ -17808,7 +19163,7 @@ var ProviderLoader = class _ProviderLoader {
17808
19163
  return;
17809
19164
  }
17810
19165
  if (filePath.endsWith(".js") || filePath.endsWith(".json")) {
17811
- this.log(`File changed: ${path14.basename(filePath)}, reloading...`);
19166
+ this.log(`File changed: ${path17.basename(filePath)}, reloading...`);
17812
19167
  this.reload();
17813
19168
  }
17814
19169
  };
@@ -17863,7 +19218,7 @@ var ProviderLoader = class _ProviderLoader {
17863
19218
  }
17864
19219
  const https = require("https");
17865
19220
  const { execSync: execSync7 } = require("child_process");
17866
- const metaPath = path14.join(this.upstreamDir, _ProviderLoader.META_FILE);
19221
+ const metaPath = path17.join(this.upstreamDir, _ProviderLoader.META_FILE);
17867
19222
  let prevEtag = "";
17868
19223
  let prevTimestamp = 0;
17869
19224
  try {
@@ -17880,7 +19235,7 @@ var ProviderLoader = class _ProviderLoader {
17880
19235
  return { updated: false };
17881
19236
  }
17882
19237
  try {
17883
- const etag = await new Promise((resolve12, reject) => {
19238
+ const etag = await new Promise((resolve15, reject) => {
17884
19239
  const options = {
17885
19240
  method: "HEAD",
17886
19241
  hostname: "github.com",
@@ -17898,7 +19253,7 @@ var ProviderLoader = class _ProviderLoader {
17898
19253
  headers: { "User-Agent": "adhdev-launcher" },
17899
19254
  timeout: 1e4
17900
19255
  }, (res2) => {
17901
- resolve12(res2.headers.etag || res2.headers["last-modified"] || "");
19256
+ resolve15(res2.headers.etag || res2.headers["last-modified"] || "");
17902
19257
  });
17903
19258
  req2.on("error", reject);
17904
19259
  req2.on("timeout", () => {
@@ -17907,7 +19262,7 @@ var ProviderLoader = class _ProviderLoader {
17907
19262
  });
17908
19263
  req2.end();
17909
19264
  } else {
17910
- resolve12(res.headers.etag || res.headers["last-modified"] || "");
19265
+ resolve15(res.headers.etag || res.headers["last-modified"] || "");
17911
19266
  }
17912
19267
  });
17913
19268
  req.on("error", reject);
@@ -17923,17 +19278,17 @@ var ProviderLoader = class _ProviderLoader {
17923
19278
  return { updated: false };
17924
19279
  }
17925
19280
  this.log("Downloading latest providers from GitHub...");
17926
- const tmpTar = path14.join(os14.tmpdir(), `adhdev-providers-${Date.now()}.tar.gz`);
17927
- const tmpExtract = path14.join(os14.tmpdir(), `adhdev-providers-extract-${Date.now()}`);
19281
+ const tmpTar = path17.join(os14.tmpdir(), `adhdev-providers-${Date.now()}.tar.gz`);
19282
+ const tmpExtract = path17.join(os14.tmpdir(), `adhdev-providers-extract-${Date.now()}`);
17928
19283
  await this.downloadFile(_ProviderLoader.GITHUB_TARBALL_URL, tmpTar);
17929
19284
  fs7.mkdirSync(tmpExtract, { recursive: true });
17930
19285
  execSync7(`tar -xzf "${tmpTar}" -C "${tmpExtract}"`, { timeout: 3e4 });
17931
19286
  const extracted = fs7.readdirSync(tmpExtract);
17932
19287
  const rootDir = extracted.find(
17933
- (d) => fs7.statSync(path14.join(tmpExtract, d)).isDirectory() && d.startsWith("adhdev-providers")
19288
+ (d) => fs7.statSync(path17.join(tmpExtract, d)).isDirectory() && d.startsWith("adhdev-providers")
17934
19289
  );
17935
19290
  if (!rootDir) throw new Error("Unexpected tarball structure");
17936
- const sourceDir = path14.join(tmpExtract, rootDir);
19291
+ const sourceDir = path17.join(tmpExtract, rootDir);
17937
19292
  const backupDir = this.upstreamDir + ".bak";
17938
19293
  if (fs7.existsSync(this.upstreamDir)) {
17939
19294
  if (fs7.existsSync(backupDir)) fs7.rmSync(backupDir, { recursive: true, force: true });
@@ -17971,7 +19326,7 @@ var ProviderLoader = class _ProviderLoader {
17971
19326
  downloadFile(url, destPath) {
17972
19327
  const https = require("https");
17973
19328
  const http3 = require("http");
17974
- return new Promise((resolve12, reject) => {
19329
+ return new Promise((resolve15, reject) => {
17975
19330
  const doRequest = (reqUrl, redirectCount = 0) => {
17976
19331
  if (redirectCount > 5) {
17977
19332
  reject(new Error("Too many redirects"));
@@ -17991,7 +19346,7 @@ var ProviderLoader = class _ProviderLoader {
17991
19346
  res.pipe(ws);
17992
19347
  ws.on("finish", () => {
17993
19348
  ws.close();
17994
- resolve12();
19349
+ resolve15();
17995
19350
  });
17996
19351
  ws.on("error", reject);
17997
19352
  });
@@ -18008,8 +19363,8 @@ var ProviderLoader = class _ProviderLoader {
18008
19363
  copyDirRecursive(src, dest) {
18009
19364
  fs7.mkdirSync(dest, { recursive: true });
18010
19365
  for (const entry of fs7.readdirSync(src, { withFileTypes: true })) {
18011
- const srcPath = path14.join(src, entry.name);
18012
- const destPath = path14.join(dest, entry.name);
19366
+ const srcPath = path17.join(src, entry.name);
19367
+ const destPath = path17.join(dest, entry.name);
18013
19368
  if (entry.isDirectory()) {
18014
19369
  this.copyDirRecursive(srcPath, destPath);
18015
19370
  } else {
@@ -18020,7 +19375,7 @@ var ProviderLoader = class _ProviderLoader {
18020
19375
  /** .meta.json save */
18021
19376
  writeMeta(metaPath, etag, timestamp) {
18022
19377
  try {
18023
- fs7.mkdirSync(path14.dirname(metaPath), { recursive: true });
19378
+ fs7.mkdirSync(path17.dirname(metaPath), { recursive: true });
18024
19379
  fs7.writeFileSync(metaPath, JSON.stringify({
18025
19380
  etag,
18026
19381
  timestamp,
@@ -18037,7 +19392,7 @@ var ProviderLoader = class _ProviderLoader {
18037
19392
  const scan = (d) => {
18038
19393
  try {
18039
19394
  for (const entry of fs7.readdirSync(d, { withFileTypes: true })) {
18040
- if (entry.isDirectory()) scan(path14.join(d, entry.name));
19395
+ if (entry.isDirectory()) scan(path17.join(d, entry.name));
18041
19396
  else if (entry.name === "provider.json") count++;
18042
19397
  }
18043
19398
  } catch {
@@ -18265,17 +19620,17 @@ var ProviderLoader = class _ProviderLoader {
18265
19620
  for (const root of searchRoots) {
18266
19621
  if (!fs7.existsSync(root)) continue;
18267
19622
  const candidate = this.getProviderDir(root, cat, type);
18268
- if (fs7.existsSync(path14.join(candidate, "provider.json"))) return candidate;
18269
- const catDir = path14.join(root, cat);
19623
+ if (fs7.existsSync(path17.join(candidate, "provider.json"))) return candidate;
19624
+ const catDir = path17.join(root, cat);
18270
19625
  if (fs7.existsSync(catDir)) {
18271
19626
  try {
18272
19627
  for (const entry of fs7.readdirSync(catDir, { withFileTypes: true })) {
18273
19628
  if (!entry.isDirectory()) continue;
18274
- const jsonPath = path14.join(catDir, entry.name, "provider.json");
19629
+ const jsonPath = path17.join(catDir, entry.name, "provider.json");
18275
19630
  if (fs7.existsSync(jsonPath)) {
18276
19631
  try {
18277
19632
  const data = JSON.parse(fs7.readFileSync(jsonPath, "utf-8"));
18278
- if (data.type === type) return path14.join(catDir, entry.name);
19633
+ if (data.type === type) return path17.join(catDir, entry.name);
18279
19634
  } catch {
18280
19635
  }
18281
19636
  }
@@ -18292,7 +19647,7 @@ var ProviderLoader = class _ProviderLoader {
18292
19647
  * (template substitution is NOT applied here — scripts.js handles that)
18293
19648
  */
18294
19649
  buildScriptWrappersFromDir(dir) {
18295
- const scriptsJs = path14.join(dir, "scripts.js");
19650
+ const scriptsJs = path17.join(dir, "scripts.js");
18296
19651
  if (fs7.existsSync(scriptsJs)) {
18297
19652
  try {
18298
19653
  delete require.cache[require.resolve(scriptsJs)];
@@ -18306,7 +19661,7 @@ var ProviderLoader = class _ProviderLoader {
18306
19661
  for (const file of fs7.readdirSync(dir)) {
18307
19662
  if (!file.endsWith(".js")) continue;
18308
19663
  const scriptName = toCamel(file.replace(".js", ""));
18309
- const filePath = path14.join(dir, file);
19664
+ const filePath = path17.join(dir, file);
18310
19665
  result[scriptName] = (...args) => {
18311
19666
  try {
18312
19667
  let content = fs7.readFileSync(filePath, "utf-8");
@@ -18366,7 +19721,7 @@ var ProviderLoader = class _ProviderLoader {
18366
19721
  }
18367
19722
  const hasJson = entries.some((e) => e.name === "provider.json");
18368
19723
  if (hasJson) {
18369
- const jsonPath = path14.join(d, "provider.json");
19724
+ const jsonPath = path17.join(d, "provider.json");
18370
19725
  try {
18371
19726
  const raw = fs7.readFileSync(jsonPath, "utf-8");
18372
19727
  const mod = JSON.parse(raw);
@@ -18387,7 +19742,7 @@ var ProviderLoader = class _ProviderLoader {
18387
19742
  this.log(`\u26A0 Invalid provider at ${jsonPath}: ${validation.errors.join("; ")}`);
18388
19743
  } else {
18389
19744
  const hasCompatibility = Array.isArray(normalizedProvider.compatibility);
18390
- const scriptsPath = path14.join(d, "scripts.js");
19745
+ const scriptsPath = path17.join(d, "scripts.js");
18391
19746
  if (!hasCompatibility && fs7.existsSync(scriptsPath)) {
18392
19747
  try {
18393
19748
  delete require.cache[require.resolve(scriptsPath)];
@@ -18413,7 +19768,7 @@ var ProviderLoader = class _ProviderLoader {
18413
19768
  if (!entry.isDirectory()) continue;
18414
19769
  if (entry.name.startsWith("_") || entry.name.startsWith(".")) continue;
18415
19770
  if (excludeDirs && d === dir && excludeDirs.includes(entry.name)) continue;
18416
- scan(path14.join(d, entry.name));
19771
+ scan(path17.join(d, entry.name));
18417
19772
  }
18418
19773
  }
18419
19774
  };
@@ -18448,9 +19803,9 @@ var ProviderLoader = class _ProviderLoader {
18448
19803
  }
18449
19804
  }
18450
19805
  compareVersions(a, b) {
18451
- const normalize3 = (v) => v.split(/[-_+]/)[0].split(".").map((x) => parseInt(x, 10) || 0);
18452
- const pa = normalize3(a);
18453
- const pb = normalize3(b);
19806
+ const normalize4 = (v) => v.split(/[-_+]/)[0].split(".").map((x) => parseInt(x, 10) || 0);
19807
+ const pa = normalize4(a);
19808
+ const pb = normalize4(b);
18454
19809
  for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
18455
19810
  const va = pa[i] || 0;
18456
19811
  const vb = pb[i] || 0;
@@ -18570,17 +19925,17 @@ async function findFreePort(ports) {
18570
19925
  throw new Error("No free port found");
18571
19926
  }
18572
19927
  function checkPortFree(port) {
18573
- return new Promise((resolve12) => {
19928
+ return new Promise((resolve15) => {
18574
19929
  const server = net.createServer();
18575
19930
  server.unref();
18576
- server.on("error", () => resolve12(false));
19931
+ server.on("error", () => resolve15(false));
18577
19932
  server.listen(port, "127.0.0.1", () => {
18578
- server.close(() => resolve12(true));
19933
+ server.close(() => resolve15(true));
18579
19934
  });
18580
19935
  });
18581
19936
  }
18582
19937
  async function isCdpActive(port) {
18583
- return new Promise((resolve12) => {
19938
+ return new Promise((resolve15) => {
18584
19939
  const req = require("http").get(`http://127.0.0.1:${port}/json/version`, {
18585
19940
  timeout: 2e3
18586
19941
  }, (res) => {
@@ -18589,16 +19944,16 @@ async function isCdpActive(port) {
18589
19944
  res.on("end", () => {
18590
19945
  try {
18591
19946
  const info = JSON.parse(data);
18592
- resolve12(!!info["WebKit-Version"] || !!info["Browser"]);
19947
+ resolve15(!!info["WebKit-Version"] || !!info["Browser"]);
18593
19948
  } catch {
18594
- resolve12(false);
19949
+ resolve15(false);
18595
19950
  }
18596
19951
  });
18597
19952
  });
18598
- req.on("error", () => resolve12(false));
19953
+ req.on("error", () => resolve15(false));
18599
19954
  req.on("timeout", () => {
18600
19955
  req.destroy();
18601
- resolve12(false);
19956
+ resolve15(false);
18602
19957
  });
18603
19958
  });
18604
19959
  }
@@ -18738,8 +20093,8 @@ function detectCurrentWorkspace(ideId) {
18738
20093
  const appNameMap = getMacAppIdentifiers();
18739
20094
  const appName = appNameMap[ideId];
18740
20095
  if (appName) {
18741
- const storagePath = path15.join(
18742
- process.env.APPDATA || path15.join(os15.homedir(), "AppData", "Roaming"),
20096
+ const storagePath = path18.join(
20097
+ process.env.APPDATA || path18.join(os15.homedir(), "AppData", "Roaming"),
18743
20098
  appName,
18744
20099
  "storage.json"
18745
20100
  );
@@ -18917,9 +20272,9 @@ init_logger();
18917
20272
 
18918
20273
  // src/logging/command-log.ts
18919
20274
  var fs8 = __toESM(require("fs"));
18920
- var path16 = __toESM(require("path"));
20275
+ var path19 = __toESM(require("path"));
18921
20276
  var os16 = __toESM(require("os"));
18922
- var LOG_DIR2 = process.platform === "win32" ? path16.join(process.env.LOCALAPPDATA || process.env.APPDATA || path16.join(os16.homedir(), "AppData", "Local"), "adhdev", "logs") : process.platform === "darwin" ? path16.join(os16.homedir(), "Library", "Logs", "adhdev") : path16.join(os16.homedir(), ".local", "share", "adhdev", "logs");
20277
+ var LOG_DIR2 = process.platform === "win32" ? path19.join(process.env.LOCALAPPDATA || process.env.APPDATA || path19.join(os16.homedir(), "AppData", "Local"), "adhdev", "logs") : process.platform === "darwin" ? path19.join(os16.homedir(), "Library", "Logs", "adhdev") : path19.join(os16.homedir(), ".local", "share", "adhdev", "logs");
18923
20278
  var MAX_FILE_SIZE = 5 * 1024 * 1024;
18924
20279
  var MAX_DAYS = 7;
18925
20280
  try {
@@ -18957,13 +20312,13 @@ function getDateStr2() {
18957
20312
  return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
18958
20313
  }
18959
20314
  var currentDate2 = getDateStr2();
18960
- var currentFile = path16.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
20315
+ var currentFile = path19.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
18961
20316
  var writeCount2 = 0;
18962
20317
  function checkRotation() {
18963
20318
  const today = getDateStr2();
18964
20319
  if (today !== currentDate2) {
18965
20320
  currentDate2 = today;
18966
- currentFile = path16.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
20321
+ currentFile = path19.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
18967
20322
  cleanOldFiles();
18968
20323
  }
18969
20324
  }
@@ -18977,7 +20332,7 @@ function cleanOldFiles() {
18977
20332
  const dateMatch = file.match(/commands-(\d{4}-\d{2}-\d{2})/);
18978
20333
  if (dateMatch && dateMatch[1] < cutoffStr) {
18979
20334
  try {
18980
- fs8.unlinkSync(path16.join(LOG_DIR2, file));
20335
+ fs8.unlinkSync(path19.join(LOG_DIR2, file));
18981
20336
  } catch {
18982
20337
  }
18983
20338
  }
@@ -18987,8 +20342,8 @@ function cleanOldFiles() {
18987
20342
  }
18988
20343
  function checkSize() {
18989
20344
  try {
18990
- const stat = fs8.statSync(currentFile);
18991
- if (stat.size > MAX_FILE_SIZE) {
20345
+ const stat2 = fs8.statSync(currentFile);
20346
+ if (stat2.size > MAX_FILE_SIZE) {
18992
20347
  const backup = currentFile.replace(".jsonl", ".1.jsonl");
18993
20348
  try {
18994
20349
  fs8.unlinkSync(backup);
@@ -19274,12 +20629,18 @@ function buildStatusSnapshot(options) {
19274
20629
  const unreadSourceSessions = buildSessionEntries(
19275
20630
  options.allStates,
19276
20631
  options.cdpManagers,
19277
- { profile: "full" }
20632
+ {
20633
+ profile: "full",
20634
+ getGitSummaryForWorkspace: options.getGitSummaryForWorkspace
20635
+ }
19278
20636
  );
19279
20637
  const sessions = profile === "full" ? unreadSourceSessions : profile === "live" ? unreadSourceSessions.map(projectLiveSessionFromFull) : buildSessionEntries(
19280
20638
  options.allStates,
19281
20639
  options.cdpManagers,
19282
- { profile }
20640
+ {
20641
+ profile,
20642
+ getGitSummaryForWorkspace: options.getGitSummaryForWorkspace
20643
+ }
19283
20644
  );
19284
20645
  const sessionsById = new Map(sessions.map((session) => [session.id, session]));
19285
20646
  for (const sourceSession of unreadSourceSessions) {
@@ -19373,13 +20734,13 @@ var import_child_process8 = require("child_process");
19373
20734
  var import_child_process9 = require("child_process");
19374
20735
  var fs9 = __toESM(require("fs"));
19375
20736
  var os18 = __toESM(require("os"));
19376
- var path17 = __toESM(require("path"));
20737
+ var path20 = __toESM(require("path"));
19377
20738
  var UPGRADE_HELPER_ENV = "ADHDEV_DAEMON_UPGRADE_HELPER";
19378
20739
  function getUpgradeLogPath() {
19379
20740
  const home = os18.homedir();
19380
- const dir = path17.join(home, ".adhdev");
20741
+ const dir = path20.join(home, ".adhdev");
19381
20742
  fs9.mkdirSync(dir, { recursive: true });
19382
- return path17.join(dir, "daemon-upgrade.log");
20743
+ return path20.join(dir, "daemon-upgrade.log");
19383
20744
  }
19384
20745
  function appendUpgradeLog(message) {
19385
20746
  const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] ${message}
@@ -19390,14 +20751,14 @@ function appendUpgradeLog(message) {
19390
20751
  }
19391
20752
  }
19392
20753
  function resolveSiblingNpmInvocation(nodeExecutable, platform10 = process.platform) {
19393
- const binDir = path17.dirname(nodeExecutable);
20754
+ const binDir = path20.dirname(nodeExecutable);
19394
20755
  if (platform10 === "win32") {
19395
- const npmCliPath = path17.join(binDir, "node_modules", "npm", "bin", "npm-cli.js");
20756
+ const npmCliPath = path20.join(binDir, "node_modules", "npm", "bin", "npm-cli.js");
19396
20757
  if (fs9.existsSync(npmCliPath)) {
19397
20758
  return { executable: nodeExecutable, argsPrefix: [npmCliPath], execOptions: getNpmExecOptions(platform10) };
19398
20759
  }
19399
20760
  for (const candidate of ["npm.exe", "npm"]) {
19400
- const candidatePath = path17.join(binDir, candidate);
20761
+ const candidatePath = path20.join(binDir, candidate);
19401
20762
  if (fs9.existsSync(candidatePath)) {
19402
20763
  return { executable: candidatePath, argsPrefix: [], execOptions: getNpmExecOptions(platform10) };
19403
20764
  }
@@ -19405,7 +20766,7 @@ function resolveSiblingNpmInvocation(nodeExecutable, platform10 = process.platfo
19405
20766
  return { executable: nodeExecutable, argsPrefix: [npmCliPath], execOptions: getNpmExecOptions(platform10) };
19406
20767
  }
19407
20768
  for (const candidate of ["npm"]) {
19408
- const candidatePath = path17.join(binDir, candidate);
20769
+ const candidatePath = path20.join(binDir, candidate);
19409
20770
  if (fs9.existsSync(candidatePath)) {
19410
20771
  return { executable: candidatePath, argsPrefix: [], execOptions: getNpmExecOptions(platform10) };
19411
20772
  }
@@ -19422,13 +20783,13 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
19422
20783
  let currentDir = resolvedPath;
19423
20784
  try {
19424
20785
  if (fs9.statSync(resolvedPath).isFile()) {
19425
- currentDir = path17.dirname(resolvedPath);
20786
+ currentDir = path20.dirname(resolvedPath);
19426
20787
  }
19427
20788
  } catch {
19428
- currentDir = path17.dirname(resolvedPath);
20789
+ currentDir = path20.dirname(resolvedPath);
19429
20790
  }
19430
20791
  while (true) {
19431
- const packageJsonPath = path17.join(currentDir, "package.json");
20792
+ const packageJsonPath = path20.join(currentDir, "package.json");
19432
20793
  try {
19433
20794
  if (fs9.existsSync(packageJsonPath)) {
19434
20795
  const parsed = JSON.parse(fs9.readFileSync(packageJsonPath, "utf8"));
@@ -19439,7 +20800,7 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
19439
20800
  }
19440
20801
  } catch {
19441
20802
  }
19442
- const parentDir = path17.dirname(currentDir);
20803
+ const parentDir = path20.dirname(currentDir);
19443
20804
  if (parentDir === currentDir) {
19444
20805
  return null;
19445
20806
  }
@@ -19447,13 +20808,13 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
19447
20808
  }
19448
20809
  }
19449
20810
  function resolveInstallPrefixFromPackageRoot(packageRoot, packageName) {
19450
- const nodeModulesDir = packageName.startsWith("@") ? path17.dirname(path17.dirname(packageRoot)) : path17.dirname(packageRoot);
19451
- if (path17.basename(nodeModulesDir) !== "node_modules") {
20811
+ const nodeModulesDir = packageName.startsWith("@") ? path20.dirname(path20.dirname(packageRoot)) : path20.dirname(packageRoot);
20812
+ if (path20.basename(nodeModulesDir) !== "node_modules") {
19452
20813
  return null;
19453
20814
  }
19454
- const maybeLibDir = path17.dirname(nodeModulesDir);
19455
- if (path17.basename(maybeLibDir) === "lib") {
19456
- return path17.dirname(maybeLibDir);
20815
+ const maybeLibDir = path20.dirname(nodeModulesDir);
20816
+ if (path20.basename(maybeLibDir) === "lib") {
20817
+ return path20.dirname(maybeLibDir);
19457
20818
  }
19458
20819
  return maybeLibDir;
19459
20820
  }
@@ -19561,14 +20922,14 @@ async function waitForPidExit(pid, timeoutMs) {
19561
20922
  while (Date.now() - start < timeoutMs) {
19562
20923
  try {
19563
20924
  process.kill(pid, 0);
19564
- await new Promise((resolve12) => setTimeout(resolve12, 250));
20925
+ await new Promise((resolve15) => setTimeout(resolve15, 250));
19565
20926
  } catch {
19566
20927
  return;
19567
20928
  }
19568
20929
  }
19569
20930
  }
19570
20931
  function stopSessionHostProcesses(appName) {
19571
- const pidFile = path17.join(os18.homedir(), ".adhdev", `${appName}-session-host.pid`);
20932
+ const pidFile = path20.join(os18.homedir(), ".adhdev", `${appName}-session-host.pid`);
19572
20933
  try {
19573
20934
  if (fs9.existsSync(pidFile)) {
19574
20935
  const pid = Number.parseInt(fs9.readFileSync(pidFile, "utf8").trim(), 10);
@@ -19585,7 +20946,7 @@ function stopSessionHostProcesses(appName) {
19585
20946
  }
19586
20947
  }
19587
20948
  function removeDaemonPidFile() {
19588
- const pidFile = path17.join(os18.homedir(), ".adhdev", "daemon.pid");
20949
+ const pidFile = path20.join(os18.homedir(), ".adhdev", "daemon.pid");
19589
20950
  try {
19590
20951
  fs9.unlinkSync(pidFile);
19591
20952
  } catch {
@@ -19596,7 +20957,7 @@ function cleanupStaleGlobalInstallDirs(pkgName, surface) {
19596
20957
  const npmRoot = String(execNpmCommandSync(["root", "-g", ...prefixArgs], { encoding: "utf8" }, surface)).trim();
19597
20958
  if (!npmRoot) return;
19598
20959
  const npmPrefix = surface.installPrefix || String(execNpmCommandSync(["prefix", "-g", ...prefixArgs], { encoding: "utf8" }, surface)).trim();
19599
- const binDir = process.platform === "win32" ? npmPrefix : path17.join(npmPrefix, "bin");
20960
+ const binDir = process.platform === "win32" ? npmPrefix : path20.join(npmPrefix, "bin");
19600
20961
  const packageBaseName = pkgName.startsWith("@") ? pkgName.split("/")[1] : pkgName;
19601
20962
  const binNames = /* @__PURE__ */ new Set([packageBaseName]);
19602
20963
  if (pkgName === "@adhdev/daemon-standalone") {
@@ -19604,25 +20965,25 @@ function cleanupStaleGlobalInstallDirs(pkgName, surface) {
19604
20965
  }
19605
20966
  if (pkgName.startsWith("@")) {
19606
20967
  const [scope, name] = pkgName.split("/");
19607
- const scopeDir = path17.join(npmRoot, scope);
20968
+ const scopeDir = path20.join(npmRoot, scope);
19608
20969
  if (!fs9.existsSync(scopeDir)) return;
19609
20970
  for (const entry of fs9.readdirSync(scopeDir)) {
19610
20971
  if (!entry.startsWith(`.${name}-`)) continue;
19611
- fs9.rmSync(path17.join(scopeDir, entry), { recursive: true, force: true });
19612
- appendUpgradeLog(`Removed stale scoped staging dir: ${path17.join(scopeDir, entry)}`);
20972
+ fs9.rmSync(path20.join(scopeDir, entry), { recursive: true, force: true });
20973
+ appendUpgradeLog(`Removed stale scoped staging dir: ${path20.join(scopeDir, entry)}`);
19613
20974
  }
19614
20975
  } else {
19615
20976
  for (const entry of fs9.readdirSync(npmRoot)) {
19616
20977
  if (!entry.startsWith(`.${pkgName}-`)) continue;
19617
- fs9.rmSync(path17.join(npmRoot, entry), { recursive: true, force: true });
19618
- appendUpgradeLog(`Removed stale staging dir: ${path17.join(npmRoot, entry)}`);
20978
+ fs9.rmSync(path20.join(npmRoot, entry), { recursive: true, force: true });
20979
+ appendUpgradeLog(`Removed stale staging dir: ${path20.join(npmRoot, entry)}`);
19619
20980
  }
19620
20981
  }
19621
20982
  if (fs9.existsSync(binDir)) {
19622
20983
  for (const entry of fs9.readdirSync(binDir)) {
19623
20984
  if (!Array.from(binNames).some((name) => entry.startsWith(`.${name}-`))) continue;
19624
- fs9.rmSync(path17.join(binDir, entry), { recursive: true, force: true });
19625
- appendUpgradeLog(`Removed stale bin staging entry: ${path17.join(binDir, entry)}`);
20985
+ fs9.rmSync(path20.join(binDir, entry), { recursive: true, force: true });
20986
+ appendUpgradeLog(`Removed stale bin staging entry: ${path20.join(binDir, entry)}`);
19626
20987
  }
19627
20988
  }
19628
20989
  }
@@ -19672,7 +21033,7 @@ async function runDaemonUpgradeHelper(payload) {
19672
21033
  appendUpgradeLog(installOutput.trim());
19673
21034
  }
19674
21035
  if (process.platform === "win32") {
19675
- await new Promise((resolve12) => setTimeout(resolve12, 500));
21036
+ await new Promise((resolve15) => setTimeout(resolve15, 500));
19676
21037
  cleanupStaleGlobalInstallDirs(payload.packageName, installCommand.surface);
19677
21038
  appendUpgradeLog("Post-install staging cleanup complete");
19678
21039
  }
@@ -21066,7 +22427,7 @@ var ProviderStreamAdapter = class {
21066
22427
  const beforeCount = this.messageCount(before);
21067
22428
  const beforeSignature = this.lastMessageSignature(before);
21068
22429
  for (let attempt = 0; attempt < 12; attempt += 1) {
21069
- await new Promise((resolve12) => setTimeout(resolve12, 250));
22430
+ await new Promise((resolve15) => setTimeout(resolve15, 250));
21070
22431
  let state;
21071
22432
  try {
21072
22433
  state = await this.readChat(evaluate);
@@ -21088,7 +22449,7 @@ var ProviderStreamAdapter = class {
21088
22449
  if (this.messageCount(first) > 0 || this.lastMessageSignature(first)) {
21089
22450
  return first;
21090
22451
  }
21091
- await new Promise((resolve12) => setTimeout(resolve12, 150));
22452
+ await new Promise((resolve15) => setTimeout(resolve15, 150));
21092
22453
  const second = await this.readChat(evaluate);
21093
22454
  return this.messageCount(second) >= this.messageCount(first) ? second : first;
21094
22455
  }
@@ -21239,7 +22600,7 @@ var ProviderStreamAdapter = class {
21239
22600
  if (typeof data.error === "string" && data.error.trim()) return false;
21240
22601
  }
21241
22602
  for (let attempt = 0; attempt < 6; attempt += 1) {
21242
- await new Promise((resolve12) => setTimeout(resolve12, 250));
22603
+ await new Promise((resolve15) => setTimeout(resolve15, 250));
21243
22604
  const state = await this.readChat(evaluate);
21244
22605
  const title = this.getStateTitle(state);
21245
22606
  if (this.titlesMatch(title, sessionId)) return true;
@@ -22100,11 +23461,11 @@ init_chat_message_normalization();
22100
23461
 
22101
23462
  // src/providers/version-archive.ts
22102
23463
  var fs11 = __toESM(require("fs"));
22103
- var path18 = __toESM(require("path"));
23464
+ var path21 = __toESM(require("path"));
22104
23465
  var os19 = __toESM(require("os"));
22105
23466
  var import_child_process10 = require("child_process");
22106
23467
  var import_os3 = require("os");
22107
- var ARCHIVE_PATH = path18.join(os19.homedir(), ".adhdev", "version-history.json");
23468
+ var ARCHIVE_PATH = path21.join(os19.homedir(), ".adhdev", "version-history.json");
22108
23469
  var MAX_ENTRIES_PER_PROVIDER = 20;
22109
23470
  var VersionArchive = class {
22110
23471
  history = {};
@@ -22151,7 +23512,7 @@ var VersionArchive = class {
22151
23512
  }
22152
23513
  save() {
22153
23514
  try {
22154
- fs11.mkdirSync(path18.dirname(ARCHIVE_PATH), { recursive: true });
23515
+ fs11.mkdirSync(path21.dirname(ARCHIVE_PATH), { recursive: true });
22155
23516
  fs11.writeFileSync(ARCHIVE_PATH, JSON.stringify(this.history, null, 2));
22156
23517
  } catch {
22157
23518
  }
@@ -22208,7 +23569,7 @@ function checkPathExists2(paths) {
22208
23569
  for (const p of paths) {
22209
23570
  if (p.includes("*")) {
22210
23571
  const home = os19.homedir();
22211
- const resolved = p.replace(/\*/g, home.split(path18.sep).pop() || "");
23572
+ const resolved = p.replace(/\*/g, home.split(path21.sep).pop() || "");
22212
23573
  if (fs11.existsSync(resolved)) return resolved;
22213
23574
  } else {
22214
23575
  if (fs11.existsSync(p)) return p;
@@ -22218,7 +23579,7 @@ function checkPathExists2(paths) {
22218
23579
  }
22219
23580
  function getMacAppVersion(appPath) {
22220
23581
  if ((0, import_os3.platform)() !== "darwin" || !appPath.endsWith(".app")) return null;
22221
- const plistPath = path18.join(appPath, "Contents", "Info.plist");
23582
+ const plistPath = path21.join(appPath, "Contents", "Info.plist");
22222
23583
  if (!fs11.existsSync(plistPath)) return null;
22223
23584
  const raw = runCommand(`/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "${plistPath}"`);
22224
23585
  return raw || null;
@@ -22244,7 +23605,7 @@ async function detectAllVersions(loader, archive) {
22244
23605
  const cliBin = provider.cli ? findBinary2(provider.cli) : null;
22245
23606
  let resolvedBin = cliBin;
22246
23607
  if (!resolvedBin && appPath && currentOs === "darwin") {
22247
- const bundled = path18.join(appPath, "Contents", "Resources", "app", "bin", provider.cli || "");
23608
+ const bundled = path21.join(appPath, "Contents", "Resources", "app", "bin", provider.cli || "");
22248
23609
  if (provider.cli && fs11.existsSync(bundled)) resolvedBin = bundled;
22249
23610
  }
22250
23611
  info.installed = !!(appPath || resolvedBin);
@@ -22285,7 +23646,7 @@ async function detectAllVersions(loader, archive) {
22285
23646
  // src/daemon/dev-server.ts
22286
23647
  var http2 = __toESM(require("http"));
22287
23648
  var fs15 = __toESM(require("fs"));
22288
- var path22 = __toESM(require("path"));
23649
+ var path25 = __toESM(require("path"));
22289
23650
  init_config();
22290
23651
 
22291
23652
  // src/daemon/scaffold-template.ts
@@ -22636,7 +23997,7 @@ init_logger();
22636
23997
 
22637
23998
  // src/daemon/dev-cdp-handlers.ts
22638
23999
  var fs12 = __toESM(require("fs"));
22639
- var path19 = __toESM(require("path"));
24000
+ var path22 = __toESM(require("path"));
22640
24001
  init_logger();
22641
24002
  async function handleCdpEvaluate(ctx, req, res) {
22642
24003
  const body = await ctx.readBody(req);
@@ -22815,17 +24176,17 @@ async function handleScriptHints(ctx, type, _req, res) {
22815
24176
  return;
22816
24177
  }
22817
24178
  let scriptsPath = "";
22818
- const directScripts = path19.join(dir, "scripts.js");
24179
+ const directScripts = path22.join(dir, "scripts.js");
22819
24180
  if (fs12.existsSync(directScripts)) {
22820
24181
  scriptsPath = directScripts;
22821
24182
  } else {
22822
- const scriptsDir = path19.join(dir, "scripts");
24183
+ const scriptsDir = path22.join(dir, "scripts");
22823
24184
  if (fs12.existsSync(scriptsDir)) {
22824
24185
  const versions = fs12.readdirSync(scriptsDir).filter((d) => {
22825
- return fs12.statSync(path19.join(scriptsDir, d)).isDirectory();
24186
+ return fs12.statSync(path22.join(scriptsDir, d)).isDirectory();
22826
24187
  }).sort().reverse();
22827
24188
  for (const ver of versions) {
22828
- const p = path19.join(scriptsDir, ver, "scripts.js");
24189
+ const p = path22.join(scriptsDir, ver, "scripts.js");
22829
24190
  if (fs12.existsSync(p)) {
22830
24191
  scriptsPath = p;
22831
24192
  break;
@@ -23654,7 +25015,7 @@ async function handleDomContext(ctx, type, req, res) {
23654
25015
 
23655
25016
  // src/daemon/dev-cli-debug.ts
23656
25017
  var fs13 = __toESM(require("fs"));
23657
- var path20 = __toESM(require("path"));
25018
+ var path23 = __toESM(require("path"));
23658
25019
  function slugifyFixtureName(value) {
23659
25020
  const normalized = String(value || "").trim().toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
23660
25021
  return normalized || `fixture-${Date.now()}`;
@@ -23664,11 +25025,11 @@ function getCliFixtureDir(ctx, type) {
23664
25025
  if (!providerDir) {
23665
25026
  throw new Error(`Provider directory not found for '${type}'`);
23666
25027
  }
23667
- return path20.join(providerDir, "fixtures");
25028
+ return path23.join(providerDir, "fixtures");
23668
25029
  }
23669
25030
  function readCliFixture(ctx, type, name) {
23670
25031
  const fixtureDir = getCliFixtureDir(ctx, type);
23671
- const filePath = path20.join(fixtureDir, `${name}.json`);
25032
+ const filePath = path23.join(fixtureDir, `${name}.json`);
23672
25033
  if (!fs13.existsSync(filePath)) {
23673
25034
  throw new Error(`Fixture not found: ${filePath}`);
23674
25035
  }
@@ -23837,7 +25198,7 @@ function getCliTargetBundle(ctx, type, instanceId) {
23837
25198
  return { target, instance, adapter };
23838
25199
  }
23839
25200
  function sleep(ms) {
23840
- return new Promise((resolve12) => setTimeout(resolve12, ms));
25201
+ return new Promise((resolve15) => setTimeout(resolve15, ms));
23841
25202
  }
23842
25203
  async function waitForCliReady(ctx, type, instanceId, timeoutMs) {
23843
25204
  const startedAt = Date.now();
@@ -24135,7 +25496,7 @@ async function runCliAutoImplVerification(ctx, type, verification) {
24135
25496
  return {
24136
25497
  mode: "fixture_replay_suite",
24137
25498
  pass: results.every((item) => item.pass),
24138
- failures: results.flatMap((item) => item.failures.map((failure) => `${item.fixtureName}: ${failure}`)),
25499
+ failures: results.flatMap((item) => item.failures.map((failure2) => `${item.fixtureName}: ${failure2}`)),
24139
25500
  result: firstFailure.result,
24140
25501
  assertions: firstFailure.assertions,
24141
25502
  fixture: firstFailure.fixture,
@@ -24435,7 +25796,7 @@ async function handleCliFixtureCapture(ctx, req, res) {
24435
25796
  },
24436
25797
  notes: typeof body?.notes === "string" ? body.notes : void 0
24437
25798
  };
24438
- const filePath = path20.join(fixtureDir, `${name}.json`);
25799
+ const filePath = path23.join(fixtureDir, `${name}.json`);
24439
25800
  fs13.writeFileSync(filePath, JSON.stringify(fixture, null, 2));
24440
25801
  ctx.json(res, 200, {
24441
25802
  saved: true,
@@ -24459,7 +25820,7 @@ async function handleCliFixtureList(ctx, type, _req, res) {
24459
25820
  return;
24460
25821
  }
24461
25822
  const fixtures = fs13.readdirSync(fixtureDir).filter((file) => file.endsWith(".json")).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" })).map((file) => {
24462
- const fullPath = path20.join(fixtureDir, file);
25823
+ const fullPath = path23.join(fixtureDir, file);
24463
25824
  try {
24464
25825
  const raw = JSON.parse(fs13.readFileSync(fullPath, "utf-8"));
24465
25826
  return {
@@ -24595,7 +25956,7 @@ async function handleCliRaw(ctx, req, res) {
24595
25956
 
24596
25957
  // src/daemon/dev-auto-implement.ts
24597
25958
  var fs14 = __toESM(require("fs"));
24598
- var path21 = __toESM(require("path"));
25959
+ var path24 = __toESM(require("path"));
24599
25960
  var os20 = __toESM(require("os"));
24600
25961
  function getAutoImplPid(ctx) {
24601
25962
  const pid = ctx.autoImplProcess?.pid;
@@ -24645,22 +26006,22 @@ function getLatestScriptVersionDir(scriptsDir) {
24645
26006
  if (!fs14.existsSync(scriptsDir)) return null;
24646
26007
  const versions = fs14.readdirSync(scriptsDir).filter((d) => {
24647
26008
  try {
24648
- return fs14.statSync(path21.join(scriptsDir, d)).isDirectory();
26009
+ return fs14.statSync(path24.join(scriptsDir, d)).isDirectory();
24649
26010
  } catch {
24650
26011
  return false;
24651
26012
  }
24652
26013
  }).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
24653
26014
  if (versions.length === 0) return null;
24654
- return path21.join(scriptsDir, versions[0]);
26015
+ return path24.join(scriptsDir, versions[0]);
24655
26016
  }
24656
26017
  function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
24657
- const canonicalUserDir = path21.resolve(ctx.providerLoader.getUserProviderDir(category, type));
24658
- const desiredDir = requestedDir ? path21.resolve(requestedDir) : canonicalUserDir;
24659
- const upstreamRoot = path21.resolve(ctx.providerLoader.getUpstreamDir());
24660
- if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path21.sep}`)) {
26018
+ const canonicalUserDir = path24.resolve(ctx.providerLoader.getUserProviderDir(category, type));
26019
+ const desiredDir = requestedDir ? path24.resolve(requestedDir) : canonicalUserDir;
26020
+ const upstreamRoot = path24.resolve(ctx.providerLoader.getUpstreamDir());
26021
+ if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path24.sep}`)) {
24661
26022
  return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
24662
26023
  }
24663
- if (path21.basename(desiredDir) !== type) {
26024
+ if (path24.basename(desiredDir) !== type) {
24664
26025
  return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
24665
26026
  }
24666
26027
  const sourceDir = ctx.findProviderDir(type);
@@ -24668,11 +26029,11 @@ function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
24668
26029
  return { dir: null, reason: `Provider source directory not found for '${type}'` };
24669
26030
  }
24670
26031
  if (!fs14.existsSync(desiredDir)) {
24671
- fs14.mkdirSync(path21.dirname(desiredDir), { recursive: true });
26032
+ fs14.mkdirSync(path24.dirname(desiredDir), { recursive: true });
24672
26033
  fs14.cpSync(sourceDir, desiredDir, { recursive: true });
24673
26034
  ctx.log(`Auto-implement writable copy created: ${desiredDir}`);
24674
26035
  }
24675
- const providerJson = path21.join(desiredDir, "provider.json");
26036
+ const providerJson = path24.join(desiredDir, "provider.json");
24676
26037
  if (!fs14.existsSync(providerJson)) {
24677
26038
  return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
24678
26039
  }
@@ -24683,13 +26044,13 @@ function loadAutoImplReferenceScripts(ctx, referenceType) {
24683
26044
  const refDir = ctx.findProviderDir(referenceType);
24684
26045
  if (!refDir || !fs14.existsSync(refDir)) return {};
24685
26046
  const referenceScripts = {};
24686
- const scriptsDir = path21.join(refDir, "scripts");
26047
+ const scriptsDir = path24.join(refDir, "scripts");
24687
26048
  const latestDir = getLatestScriptVersionDir(scriptsDir);
24688
26049
  if (!latestDir) return referenceScripts;
24689
26050
  for (const file of fs14.readdirSync(latestDir)) {
24690
26051
  if (!file.endsWith(".js")) continue;
24691
26052
  try {
24692
- referenceScripts[file] = fs14.readFileSync(path21.join(latestDir, file), "utf-8");
26053
+ referenceScripts[file] = fs14.readFileSync(path24.join(latestDir, file), "utf-8");
24693
26054
  } catch {
24694
26055
  }
24695
26056
  }
@@ -24797,9 +26158,9 @@ async function handleAutoImplement(ctx, type, req, res) {
24797
26158
  });
24798
26159
  const referenceScripts = loadAutoImplReferenceScripts(ctx, resolvedReference);
24799
26160
  const prompt = buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domContext, referenceScripts, comment, resolvedReference, verification);
24800
- const tmpDir = path21.join(os20.tmpdir(), "adhdev-autoimpl");
26161
+ const tmpDir = path24.join(os20.tmpdir(), "adhdev-autoimpl");
24801
26162
  if (!fs14.existsSync(tmpDir)) fs14.mkdirSync(tmpDir, { recursive: true });
24802
- const promptFile = path21.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
26163
+ const promptFile = path24.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
24803
26164
  fs14.writeFileSync(promptFile, prompt, "utf-8");
24804
26165
  ctx.log(`Auto-implement prompt written to ${promptFile} (${prompt.length} chars)`);
24805
26166
  const agentProvider = ctx.providerLoader.resolve(agent) || ctx.providerLoader.getMeta(agent);
@@ -25231,7 +26592,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
25231
26592
  setMode: "set_mode.js"
25232
26593
  };
25233
26594
  const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
25234
- const scriptsDir = path21.join(providerDir, "scripts");
26595
+ const scriptsDir = path24.join(providerDir, "scripts");
25235
26596
  const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
25236
26597
  if (latestScriptsDir) {
25237
26598
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -25242,7 +26603,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
25242
26603
  for (const file of fs14.readdirSync(latestScriptsDir)) {
25243
26604
  if (file.endsWith(".js") && targetFileNames.has(file)) {
25244
26605
  try {
25245
- const content = fs14.readFileSync(path21.join(latestScriptsDir, file), "utf-8");
26606
+ const content = fs14.readFileSync(path24.join(latestScriptsDir, file), "utf-8");
25246
26607
  lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
25247
26608
  lines.push("```javascript");
25248
26609
  lines.push(content);
@@ -25259,7 +26620,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
25259
26620
  lines.push("");
25260
26621
  for (const file of refFiles) {
25261
26622
  try {
25262
- const content = fs14.readFileSync(path21.join(latestScriptsDir, file), "utf-8");
26623
+ const content = fs14.readFileSync(path24.join(latestScriptsDir, file), "utf-8");
25263
26624
  lines.push(`### \`${file}\` \u{1F512}`);
25264
26625
  lines.push("```javascript");
25265
26626
  lines.push(content);
@@ -25300,10 +26661,10 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
25300
26661
  lines.push("");
25301
26662
  }
25302
26663
  }
25303
- const docsDir = path21.join(providerDir, "../../docs");
26664
+ const docsDir = path24.join(providerDir, "../../docs");
25304
26665
  const loadGuide = (name) => {
25305
26666
  try {
25306
- const p = path21.join(docsDir, name);
26667
+ const p = path24.join(docsDir, name);
25307
26668
  if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
25308
26669
  } catch {
25309
26670
  }
@@ -25540,7 +26901,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
25540
26901
  parseApproval: "parse_approval.js"
25541
26902
  };
25542
26903
  const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
25543
- const scriptsDir = path21.join(providerDir, "scripts");
26904
+ const scriptsDir = path24.join(providerDir, "scripts");
25544
26905
  const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
25545
26906
  if (latestScriptsDir) {
25546
26907
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -25552,7 +26913,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
25552
26913
  if (!file.endsWith(".js")) continue;
25553
26914
  if (!targetFileNames.has(file)) continue;
25554
26915
  try {
25555
- const content = fs14.readFileSync(path21.join(latestScriptsDir, file), "utf-8");
26916
+ const content = fs14.readFileSync(path24.join(latestScriptsDir, file), "utf-8");
25556
26917
  lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
25557
26918
  lines.push("```javascript");
25558
26919
  lines.push(content);
@@ -25568,7 +26929,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
25568
26929
  lines.push("");
25569
26930
  for (const file of refFiles) {
25570
26931
  try {
25571
- const content = fs14.readFileSync(path21.join(latestScriptsDir, file), "utf-8");
26932
+ const content = fs14.readFileSync(path24.join(latestScriptsDir, file), "utf-8");
25572
26933
  lines.push(`### \`${file}\` \u{1F512}`);
25573
26934
  lines.push("```javascript");
25574
26935
  lines.push(content);
@@ -25601,10 +26962,10 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
25601
26962
  lines.push("");
25602
26963
  }
25603
26964
  }
25604
- const docsDir = path21.join(providerDir, "../../docs");
26965
+ const docsDir = path24.join(providerDir, "../../docs");
25605
26966
  const loadGuide = (name) => {
25606
26967
  try {
25607
- const p = path21.join(docsDir, name);
26968
+ const p = path24.join(docsDir, name);
25608
26969
  if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
25609
26970
  } catch {
25610
26971
  }
@@ -26051,8 +27412,8 @@ var DevServer = class _DevServer {
26051
27412
  }
26052
27413
  getEndpointList() {
26053
27414
  return this.routes.map((r) => {
26054
- const path23 = typeof r.pattern === "string" ? r.pattern : r.pattern.source.replace(/\\\//g, "/").replace(/\(\[.*?\]\+\)/g, ":type").replace(/[\^$]/g, "");
26055
- return `${r.method.padEnd(5)} ${path23}`;
27415
+ const path26 = typeof r.pattern === "string" ? r.pattern : r.pattern.source.replace(/\\\//g, "/").replace(/\(\[.*?\]\+\)/g, ":type").replace(/[\^$]/g, "");
27416
+ return `${r.method.padEnd(5)} ${path26}`;
26056
27417
  });
26057
27418
  }
26058
27419
  async start(port = DEV_SERVER_PORT) {
@@ -26083,15 +27444,15 @@ var DevServer = class _DevServer {
26083
27444
  this.json(res, 500, { error: e.message });
26084
27445
  }
26085
27446
  });
26086
- return new Promise((resolve12, reject) => {
27447
+ return new Promise((resolve15, reject) => {
26087
27448
  this.server.listen(port, "127.0.0.1", () => {
26088
27449
  this.log(`Dev server listening on http://127.0.0.1:${port}`);
26089
- resolve12();
27450
+ resolve15();
26090
27451
  });
26091
27452
  this.server.on("error", (e) => {
26092
27453
  if (e.code === "EADDRINUSE") {
26093
27454
  this.log(`Port ${port} in use, skipping dev server`);
26094
- resolve12();
27455
+ resolve15();
26095
27456
  } else {
26096
27457
  reject(e);
26097
27458
  }
@@ -26173,20 +27534,20 @@ var DevServer = class _DevServer {
26173
27534
  child.stderr?.on("data", (d) => {
26174
27535
  stderr += d.toString().slice(0, 2e3);
26175
27536
  });
26176
- await new Promise((resolve12) => {
27537
+ await new Promise((resolve15) => {
26177
27538
  const timer = setTimeout(() => {
26178
27539
  child.kill();
26179
- resolve12();
27540
+ resolve15();
26180
27541
  }, 3e3);
26181
27542
  child.on("exit", () => {
26182
27543
  clearTimeout(timer);
26183
- resolve12();
27544
+ resolve15();
26184
27545
  });
26185
27546
  child.stdout?.once("data", () => {
26186
27547
  setTimeout(() => {
26187
27548
  child.kill();
26188
27549
  clearTimeout(timer);
26189
- resolve12();
27550
+ resolve15();
26190
27551
  }, 500);
26191
27552
  });
26192
27553
  });
@@ -26340,12 +27701,12 @@ var DevServer = class _DevServer {
26340
27701
  // ─── DevConsole SPA ───
26341
27702
  getConsoleDistDir() {
26342
27703
  const candidates = [
26343
- path22.resolve(__dirname, "../../web-devconsole/dist"),
26344
- path22.resolve(__dirname, "../../../web-devconsole/dist"),
26345
- path22.join(process.cwd(), "packages/web-devconsole/dist")
27704
+ path25.resolve(__dirname, "../../web-devconsole/dist"),
27705
+ path25.resolve(__dirname, "../../../web-devconsole/dist"),
27706
+ path25.join(process.cwd(), "packages/web-devconsole/dist")
26346
27707
  ];
26347
27708
  for (const dir of candidates) {
26348
- if (fs15.existsSync(path22.join(dir, "index.html"))) return dir;
27709
+ if (fs15.existsSync(path25.join(dir, "index.html"))) return dir;
26349
27710
  }
26350
27711
  return null;
26351
27712
  }
@@ -26355,7 +27716,7 @@ var DevServer = class _DevServer {
26355
27716
  this.json(res, 500, { error: "DevConsole not found. Run: npm run build -w packages/web-devconsole" });
26356
27717
  return;
26357
27718
  }
26358
- const htmlPath = path22.join(distDir, "index.html");
27719
+ const htmlPath = path25.join(distDir, "index.html");
26359
27720
  try {
26360
27721
  const html = fs15.readFileSync(htmlPath, "utf-8");
26361
27722
  res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
@@ -26380,15 +27741,15 @@ var DevServer = class _DevServer {
26380
27741
  this.json(res, 404, { error: "Not found" });
26381
27742
  return;
26382
27743
  }
26383
- const safePath = path22.normalize(pathname).replace(/^\.\.\//, "");
26384
- const filePath = path22.join(distDir, safePath);
27744
+ const safePath = path25.normalize(pathname).replace(/^\.\.\//, "");
27745
+ const filePath = path25.join(distDir, safePath);
26385
27746
  if (!filePath.startsWith(distDir)) {
26386
27747
  this.json(res, 403, { error: "Forbidden" });
26387
27748
  return;
26388
27749
  }
26389
27750
  try {
26390
27751
  const content = fs15.readFileSync(filePath);
26391
- const ext = path22.extname(filePath);
27752
+ const ext = path25.extname(filePath);
26392
27753
  const contentType = _DevServer.MIME_MAP[ext] || "application/octet-stream";
26393
27754
  res.writeHead(200, { "Content-Type": contentType, "Cache-Control": "public, max-age=31536000, immutable" });
26394
27755
  res.end(content);
@@ -26501,10 +27862,10 @@ var DevServer = class _DevServer {
26501
27862
  const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
26502
27863
  if (entry.isDirectory()) {
26503
27864
  files.push({ path: rel, size: 0, type: "dir" });
26504
- scan(path22.join(d, entry.name), rel);
27865
+ scan(path25.join(d, entry.name), rel);
26505
27866
  } else {
26506
- const stat = fs15.statSync(path22.join(d, entry.name));
26507
- files.push({ path: rel, size: stat.size, type: "file" });
27867
+ const stat2 = fs15.statSync(path25.join(d, entry.name));
27868
+ files.push({ path: rel, size: stat2.size, type: "file" });
26508
27869
  }
26509
27870
  }
26510
27871
  } catch {
@@ -26526,7 +27887,7 @@ var DevServer = class _DevServer {
26526
27887
  this.json(res, 404, { error: `Provider directory not found: ${type}` });
26527
27888
  return;
26528
27889
  }
26529
- const fullPath = path22.resolve(dir, path22.normalize(filePath));
27890
+ const fullPath = path25.resolve(dir, path25.normalize(filePath));
26530
27891
  if (!fullPath.startsWith(dir)) {
26531
27892
  this.json(res, 403, { error: "Forbidden" });
26532
27893
  return;
@@ -26551,14 +27912,14 @@ var DevServer = class _DevServer {
26551
27912
  this.json(res, 404, { error: `Provider directory not found: ${type}` });
26552
27913
  return;
26553
27914
  }
26554
- const fullPath = path22.resolve(dir, path22.normalize(filePath));
27915
+ const fullPath = path25.resolve(dir, path25.normalize(filePath));
26555
27916
  if (!fullPath.startsWith(dir)) {
26556
27917
  this.json(res, 403, { error: "Forbidden" });
26557
27918
  return;
26558
27919
  }
26559
27920
  try {
26560
27921
  if (fs15.existsSync(fullPath)) fs15.copyFileSync(fullPath, fullPath + ".bak");
26561
- fs15.mkdirSync(path22.dirname(fullPath), { recursive: true });
27922
+ fs15.mkdirSync(path25.dirname(fullPath), { recursive: true });
26562
27923
  fs15.writeFileSync(fullPath, content, "utf-8");
26563
27924
  this.log(`File saved: ${fullPath} (${content.length} chars)`);
26564
27925
  this.providerLoader.reload();
@@ -26575,7 +27936,7 @@ var DevServer = class _DevServer {
26575
27936
  return;
26576
27937
  }
26577
27938
  for (const name of ["scripts.js", "provider.json"]) {
26578
- const p = path22.join(dir, name);
27939
+ const p = path25.join(dir, name);
26579
27940
  if (fs15.existsSync(p)) {
26580
27941
  const source = fs15.readFileSync(p, "utf-8");
26581
27942
  this.json(res, 200, { type, path: p, source, lines: source.split("\n").length });
@@ -26596,8 +27957,8 @@ var DevServer = class _DevServer {
26596
27957
  this.json(res, 404, { error: `Provider not found: ${type}` });
26597
27958
  return;
26598
27959
  }
26599
- const target = fs15.existsSync(path22.join(dir, "scripts.js")) ? "scripts.js" : "provider.json";
26600
- const targetPath = path22.join(dir, target);
27960
+ const target = fs15.existsSync(path25.join(dir, "scripts.js")) ? "scripts.js" : "provider.json";
27961
+ const targetPath = path25.join(dir, target);
26601
27962
  try {
26602
27963
  if (fs15.existsSync(targetPath)) fs15.copyFileSync(targetPath, targetPath + ".bak");
26603
27964
  fs15.writeFileSync(targetPath, source, "utf-8");
@@ -26689,14 +28050,14 @@ var DevServer = class _DevServer {
26689
28050
  child.stderr?.on("data", (d) => {
26690
28051
  stderr += d.toString();
26691
28052
  });
26692
- await new Promise((resolve12) => {
28053
+ await new Promise((resolve15) => {
26693
28054
  const timer = setTimeout(() => {
26694
28055
  child.kill();
26695
- resolve12();
28056
+ resolve15();
26696
28057
  }, timeout);
26697
28058
  child.on("exit", () => {
26698
28059
  clearTimeout(timer);
26699
- resolve12();
28060
+ resolve15();
26700
28061
  });
26701
28062
  });
26702
28063
  const elapsed = Date.now() - start;
@@ -26744,7 +28105,7 @@ var DevServer = class _DevServer {
26744
28105
  }
26745
28106
  let targetDir;
26746
28107
  targetDir = this.providerLoader.getUserProviderDir(category, type);
26747
- const jsonPath = path22.join(targetDir, "provider.json");
28108
+ const jsonPath = path25.join(targetDir, "provider.json");
26748
28109
  if (fs15.existsSync(jsonPath)) {
26749
28110
  this.json(res, 409, { error: `Provider already exists at ${targetDir}`, path: targetDir });
26750
28111
  return;
@@ -26756,8 +28117,8 @@ var DevServer = class _DevServer {
26756
28117
  const createdFiles = ["provider.json"];
26757
28118
  if (result.files) {
26758
28119
  for (const [relPath, content] of Object.entries(result.files)) {
26759
- const fullPath = path22.join(targetDir, relPath);
26760
- fs15.mkdirSync(path22.dirname(fullPath), { recursive: true });
28120
+ const fullPath = path25.join(targetDir, relPath);
28121
+ fs15.mkdirSync(path25.dirname(fullPath), { recursive: true });
26761
28122
  fs15.writeFileSync(fullPath, content, "utf-8");
26762
28123
  createdFiles.push(relPath);
26763
28124
  }
@@ -26810,22 +28171,22 @@ var DevServer = class _DevServer {
26810
28171
  if (!fs15.existsSync(scriptsDir)) return null;
26811
28172
  const versions = fs15.readdirSync(scriptsDir).filter((d) => {
26812
28173
  try {
26813
- return fs15.statSync(path22.join(scriptsDir, d)).isDirectory();
28174
+ return fs15.statSync(path25.join(scriptsDir, d)).isDirectory();
26814
28175
  } catch {
26815
28176
  return false;
26816
28177
  }
26817
28178
  }).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
26818
28179
  if (versions.length === 0) return null;
26819
- return path22.join(scriptsDir, versions[0]);
28180
+ return path25.join(scriptsDir, versions[0]);
26820
28181
  }
26821
28182
  resolveAutoImplWritableProviderDir(category, type, requestedDir) {
26822
- const canonicalUserDir = path22.resolve(this.providerLoader.getUserProviderDir(category, type));
26823
- const desiredDir = requestedDir ? path22.resolve(requestedDir) : canonicalUserDir;
26824
- const upstreamRoot = path22.resolve(this.providerLoader.getUpstreamDir());
26825
- if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path22.sep}`)) {
28183
+ const canonicalUserDir = path25.resolve(this.providerLoader.getUserProviderDir(category, type));
28184
+ const desiredDir = requestedDir ? path25.resolve(requestedDir) : canonicalUserDir;
28185
+ const upstreamRoot = path25.resolve(this.providerLoader.getUpstreamDir());
28186
+ if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path25.sep}`)) {
26826
28187
  return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
26827
28188
  }
26828
- if (path22.basename(desiredDir) !== type) {
28189
+ if (path25.basename(desiredDir) !== type) {
26829
28190
  return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
26830
28191
  }
26831
28192
  const sourceDir = this.findProviderDir(type);
@@ -26833,11 +28194,11 @@ var DevServer = class _DevServer {
26833
28194
  return { dir: null, reason: `Provider source directory not found for '${type}'` };
26834
28195
  }
26835
28196
  if (!fs15.existsSync(desiredDir)) {
26836
- fs15.mkdirSync(path22.dirname(desiredDir), { recursive: true });
28197
+ fs15.mkdirSync(path25.dirname(desiredDir), { recursive: true });
26837
28198
  fs15.cpSync(sourceDir, desiredDir, { recursive: true });
26838
28199
  this.log(`Auto-implement writable copy created: ${desiredDir}`);
26839
28200
  }
26840
- const providerJson = path22.join(desiredDir, "provider.json");
28201
+ const providerJson = path25.join(desiredDir, "provider.json");
26841
28202
  if (!fs15.existsSync(providerJson)) {
26842
28203
  return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
26843
28204
  }
@@ -26873,7 +28234,7 @@ var DevServer = class _DevServer {
26873
28234
  setMode: "set_mode.js"
26874
28235
  };
26875
28236
  const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
26876
- const scriptsDir = path22.join(providerDir, "scripts");
28237
+ const scriptsDir = path25.join(providerDir, "scripts");
26877
28238
  const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
26878
28239
  if (latestScriptsDir) {
26879
28240
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -26884,7 +28245,7 @@ var DevServer = class _DevServer {
26884
28245
  for (const file of fs15.readdirSync(latestScriptsDir)) {
26885
28246
  if (file.endsWith(".js") && targetFileNames.has(file)) {
26886
28247
  try {
26887
- const content = fs15.readFileSync(path22.join(latestScriptsDir, file), "utf-8");
28248
+ const content = fs15.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
26888
28249
  lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
26889
28250
  lines.push("```javascript");
26890
28251
  lines.push(content);
@@ -26901,7 +28262,7 @@ var DevServer = class _DevServer {
26901
28262
  lines.push("");
26902
28263
  for (const file of refFiles) {
26903
28264
  try {
26904
- const content = fs15.readFileSync(path22.join(latestScriptsDir, file), "utf-8");
28265
+ const content = fs15.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
26905
28266
  lines.push(`### \`${file}\` \u{1F512}`);
26906
28267
  lines.push("```javascript");
26907
28268
  lines.push(content);
@@ -26942,10 +28303,10 @@ var DevServer = class _DevServer {
26942
28303
  lines.push("");
26943
28304
  }
26944
28305
  }
26945
- const docsDir = path22.join(providerDir, "../../docs");
28306
+ const docsDir = path25.join(providerDir, "../../docs");
26946
28307
  const loadGuide = (name) => {
26947
28308
  try {
26948
- const p = path22.join(docsDir, name);
28309
+ const p = path25.join(docsDir, name);
26949
28310
  if (fs15.existsSync(p)) return fs15.readFileSync(p, "utf-8");
26950
28311
  } catch {
26951
28312
  }
@@ -27119,7 +28480,7 @@ var DevServer = class _DevServer {
27119
28480
  parseApproval: "parse_approval.js"
27120
28481
  };
27121
28482
  const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
27122
- const scriptsDir = path22.join(providerDir, "scripts");
28483
+ const scriptsDir = path25.join(providerDir, "scripts");
27123
28484
  const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
27124
28485
  if (latestScriptsDir) {
27125
28486
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -27131,7 +28492,7 @@ var DevServer = class _DevServer {
27131
28492
  if (!file.endsWith(".js")) continue;
27132
28493
  if (!targetFileNames.has(file)) continue;
27133
28494
  try {
27134
- const content = fs15.readFileSync(path22.join(latestScriptsDir, file), "utf-8");
28495
+ const content = fs15.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
27135
28496
  lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
27136
28497
  lines.push("```javascript");
27137
28498
  lines.push(content);
@@ -27147,7 +28508,7 @@ var DevServer = class _DevServer {
27147
28508
  lines.push("");
27148
28509
  for (const file of refFiles) {
27149
28510
  try {
27150
- const content = fs15.readFileSync(path22.join(latestScriptsDir, file), "utf-8");
28511
+ const content = fs15.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
27151
28512
  lines.push(`### \`${file}\` \u{1F512}`);
27152
28513
  lines.push("```javascript");
27153
28514
  lines.push(content);
@@ -27180,10 +28541,10 @@ var DevServer = class _DevServer {
27180
28541
  lines.push("");
27181
28542
  }
27182
28543
  }
27183
- const docsDir = path22.join(providerDir, "../../docs");
28544
+ const docsDir = path25.join(providerDir, "../../docs");
27184
28545
  const loadGuide = (name) => {
27185
28546
  try {
27186
- const p = path22.join(docsDir, name);
28547
+ const p = path25.join(docsDir, name);
27187
28548
  if (fs15.existsSync(p)) return fs15.readFileSync(p, "utf-8");
27188
28549
  } catch {
27189
28550
  }
@@ -27366,14 +28727,14 @@ data: ${JSON.stringify(msg.data)}
27366
28727
  res.end(JSON.stringify(data, null, 2));
27367
28728
  }
27368
28729
  async readBody(req) {
27369
- return new Promise((resolve12) => {
28730
+ return new Promise((resolve15) => {
27370
28731
  let body = "";
27371
28732
  req.on("data", (chunk) => body += chunk);
27372
28733
  req.on("end", () => {
27373
28734
  try {
27374
- resolve12(JSON.parse(body));
28735
+ resolve15(JSON.parse(body));
27375
28736
  } catch {
27376
- resolve12({});
28737
+ resolve15({});
27377
28738
  }
27378
28739
  });
27379
28740
  });
@@ -27883,7 +29244,7 @@ async function waitForReady(endpoint, timeoutMs = STARTUP_TIMEOUT_MS) {
27883
29244
  const deadline = Date.now() + timeoutMs;
27884
29245
  while (Date.now() < deadline) {
27885
29246
  if (await canConnect(endpoint)) return;
27886
- await new Promise((resolve12) => setTimeout(resolve12, STARTUP_POLL_MS));
29247
+ await new Promise((resolve15) => setTimeout(resolve15, STARTUP_POLL_MS));
27887
29248
  }
27888
29249
  throw new Error(`Session host did not become ready within ${timeoutMs}ms`);
27889
29250
  }
@@ -28061,10 +29422,10 @@ async function installExtension(ide, extension) {
28061
29422
  const buffer = Buffer.from(await res.arrayBuffer());
28062
29423
  const fs16 = await import("fs");
28063
29424
  fs16.writeFileSync(vsixPath, buffer);
28064
- return new Promise((resolve12) => {
29425
+ return new Promise((resolve15) => {
28065
29426
  const cmd = `"${ide.cliCommand}" --install-extension "${vsixPath}" --force`;
28066
29427
  (0, import_child_process11.exec)(cmd, { timeout: 6e4 }, (error, _stdout, stderr) => {
28067
- resolve12({
29428
+ resolve15({
28068
29429
  extensionId: extension.id,
28069
29430
  marketplaceId: extension.marketplaceId,
28070
29431
  success: !error,
@@ -28077,11 +29438,11 @@ async function installExtension(ide, extension) {
28077
29438
  } catch (e) {
28078
29439
  }
28079
29440
  }
28080
- return new Promise((resolve12) => {
29441
+ return new Promise((resolve15) => {
28081
29442
  const cmd = `"${ide.cliCommand}" --install-extension ${extension.marketplaceId} --force`;
28082
29443
  (0, import_child_process11.exec)(cmd, { timeout: 6e4 }, (error, stdout, stderr) => {
28083
29444
  if (error) {
28084
- resolve12({
29445
+ resolve15({
28085
29446
  extensionId: extension.id,
28086
29447
  marketplaceId: extension.marketplaceId,
28087
29448
  success: false,
@@ -28089,7 +29450,7 @@ async function installExtension(ide, extension) {
28089
29450
  error: stderr || error.message
28090
29451
  });
28091
29452
  } else {
28092
- resolve12({
29453
+ resolve15({
28093
29454
  extensionId: extension.id,
28094
29455
  marketplaceId: extension.marketplaceId,
28095
29456
  success: true,
@@ -28293,6 +29654,7 @@ async function initDaemonComponents(config) {
28293
29654
  providerLoader,
28294
29655
  instanceManager,
28295
29656
  sessionRegistry,
29657
+ gitCommandServices: createDefaultGitCommandServices(),
28296
29658
  onProviderSettingChanged: async (providerType) => {
28297
29659
  await refreshProviderAvailability(providerType);
28298
29660
  config.onStatusChange?.();
@@ -28300,7 +29662,8 @@ async function initDaemonComponents(config) {
28300
29662
  onProviderSourceConfigChanged: async () => {
28301
29663
  await refreshProviderAvailability();
28302
29664
  config.onStatusChange?.();
28303
- }
29665
+ },
29666
+ onBeforeSendChat: config.onBeforeSendChat
28304
29667
  });
28305
29668
  agentStreamManager = new DaemonAgentStreamManager(
28306
29669
  LOG.forComponent("AgentStream").asLogFn(),
@@ -28419,6 +29782,7 @@ async function shutdownDaemonComponents(components) {
28419
29782
  DEFAULT_CDP_SCAN_INTERVAL_MS,
28420
29783
  DEFAULT_CHAT_TAIL_RECENT_MESSAGE_GRACE_MS,
28421
29784
  DEFAULT_DAEMON_PORT,
29785
+ DEFAULT_GIT_WORKSPACE_POLL_INTERVAL_MS,
28422
29786
  DEFAULT_MACHINE_RUNTIME_SUBSCRIPTION_INTERVAL_MS,
28423
29787
  DEFAULT_SESSION_HOST_APP_NAME,
28424
29788
  DEFAULT_SESSION_HOST_DIAGNOSTICS_SUBSCRIPTION_INTERVAL_MS,
@@ -28437,8 +29801,12 @@ async function shutdownDaemonComponents(components) {
28437
29801
  DaemonCommandRouter,
28438
29802
  DaemonStatusReporter,
28439
29803
  DevServer,
29804
+ GitCommandError,
29805
+ GitWorkspaceMonitor,
28440
29806
  IdeProviderInstance,
29807
+ InMemoryGitSnapshotStore,
28441
29808
  LOG,
29809
+ MIN_GIT_WORKSPACE_POLL_INTERVAL_MS,
28442
29810
  MIN_MACHINE_RUNTIME_SUBSCRIPTION_INTERVAL_MS,
28443
29811
  MIN_SESSION_HOST_DIAGNOSTICS_SUBSCRIPTION_INTERVAL_MS,
28444
29812
  NodePtyTransportFactory,
@@ -28447,6 +29815,7 @@ async function shutdownDaemonComponents(components) {
28447
29815
  ProviderLoader,
28448
29816
  STANDALONE_CDP_SCAN_INTERVAL_MS,
28449
29817
  SessionHostPtyTransportFactory,
29818
+ TurnSnapshotTracker,
28450
29819
  VersionArchive,
28451
29820
  appendRecentActivity,
28452
29821
  buildAssistantChatMessage,
@@ -28466,9 +29835,14 @@ async function shutdownDaemonComponents(components) {
28466
29835
  buildUserChatMessage,
28467
29836
  classifyHotChatSessionsForSubscriptionFlush,
28468
29837
  clearDebugTrace,
29838
+ compareGitSnapshots,
28469
29839
  configureDebugTraceStore,
28470
29840
  connectCdpManager,
28471
29841
  createDebugTraceStore,
29842
+ createDefaultGitCommandServices,
29843
+ createGitCompactSummary,
29844
+ createGitSnapshotStore,
29845
+ createGitWorkspaceMonitor,
28472
29846
  createInteractionId,
28473
29847
  detectAllVersions,
28474
29848
  detectCLIs,
@@ -28483,6 +29857,9 @@ async function shutdownDaemonComponents(components) {
28483
29857
  getCurrentDaemonLogPath,
28484
29858
  getDaemonLogDir,
28485
29859
  getDebugRuntimeConfig,
29860
+ getGitDiffSummary,
29861
+ getGitFileDiff,
29862
+ getGitRepoStatus,
28486
29863
  getHostMemorySnapshot,
28487
29864
  getLogLevel,
28488
29865
  getNpmExecOptions,
@@ -28494,6 +29871,7 @@ async function shutdownDaemonComponents(components) {
28494
29871
  getSessionHostRecoveryLabel,
28495
29872
  getSessionHostSurfaceKind,
28496
29873
  getWorkspaceState,
29874
+ handleGitCommand,
28497
29875
  hasCdpManager,
28498
29876
  hashSignatureParts,
28499
29877
  initDaemonComponents,
@@ -28502,9 +29880,11 @@ async function shutdownDaemonComponents(components) {
28502
29880
  isBuiltinChatMessageKind,
28503
29881
  isCdpConnected,
28504
29882
  isExtensionInstalled,
29883
+ isGitCommandName,
28505
29884
  isIdeRunning,
28506
29885
  isManagedStatusWaiting,
28507
29886
  isManagedStatusWorking,
29887
+ isPathInside,
28508
29888
  isSessionHostLiveRuntime,
28509
29889
  isSessionHostRecoverySnapshot,
28510
29890
  isSetupComplete,
@@ -28522,10 +29902,13 @@ async function shutdownDaemonComponents(components) {
28522
29902
  normalizeChatMessageKind,
28523
29903
  normalizeChatMessages,
28524
29904
  normalizeChatTailActiveModal,
29905
+ normalizeGitOutput,
29906
+ normalizeGitWorkspaceSubscriptionParams,
28525
29907
  normalizeInputEnvelope,
28526
29908
  normalizeManagedStatus,
28527
29909
  normalizeMessageParts,
28528
29910
  normalizeSessionModalFields,
29911
+ parsePorcelainV2Status,
28529
29912
  parseProviderSourceConfigUpdate,
28530
29913
  partitionSessionHostDiagnosticsSessions,
28531
29914
  partitionSessionHostRecords,
@@ -28541,9 +29924,11 @@ async function shutdownDaemonComponents(components) {
28541
29924
  resolveChatMessageKind,
28542
29925
  resolveCurrentGlobalInstallSurface,
28543
29926
  resolveDebugRuntimeConfig,
29927
+ resolveGitRepository,
28544
29928
  resolveSessionHostAppName,
28545
29929
  resolveSessionHostAppNameResolution,
28546
29930
  runAsyncBatch,
29931
+ runGit,
28547
29932
  saveConfig,
28548
29933
  saveState,
28549
29934
  setDebugRuntimeConfig,
@@ -28554,6 +29939,7 @@ async function shutdownDaemonComponents(components) {
28554
29939
  shutdownDaemonComponents,
28555
29940
  spawnDetachedDaemonUpgradeHelper,
28556
29941
  startDaemonDevSupport,
29942
+ summarizeGitStatus,
28557
29943
  updateConfig,
28558
29944
  upsertSavedProviderSession
28559
29945
  });