adhdev 0.9.82-rc.1 → 0.9.82-rc.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/index.js CHANGED
@@ -784,8 +784,14 @@ async function getGitRepoStatus(workspace, options = {}) {
784
784
  const includeSubmodules = options.includeSubmodules !== false;
785
785
  try {
786
786
  const repo = await resolveGitRepository(workspace, options);
787
- const statusOutput = await runGit(repo, ["status", "--porcelain=v2", "--branch"], options);
788
- const parsed = parsePorcelainV2Status(statusOutput.stdout);
787
+ let parsed = await readPorcelainStatus(repo, options);
788
+ let upstreamProbe = getInitialUpstreamProbe(parsed);
789
+ if (options.refreshUpstream) {
790
+ upstreamProbe = await refreshTrackedUpstream(repo, parsed, options);
791
+ if (upstreamProbe.upstreamStatus === "fresh") {
792
+ parsed = await readPorcelainStatus(repo, options);
793
+ }
794
+ }
789
795
  const head = await readHead(repo, options);
790
796
  const stashCount = await readStashCount(repo, options);
791
797
  let submodules;
@@ -800,6 +806,9 @@ async function getGitRepoStatus(workspace, options = {}) {
800
806
  headCommit: head.commit,
801
807
  headMessage: head.message,
802
808
  upstream: parsed.upstream,
809
+ upstreamStatus: parsed.upstream ? upstreamProbe.upstreamStatus : "no_upstream",
810
+ upstreamFetchedAt: upstreamProbe.upstreamFetchedAt,
811
+ upstreamFetchError: upstreamProbe.upstreamFetchError,
803
812
  ahead: parsed.ahead,
804
813
  behind: parsed.behind,
805
814
  staged: parsed.staged,
@@ -824,6 +833,60 @@ async function getGitRepoStatus(workspace, options = {}) {
824
833
  );
825
834
  }
826
835
  }
836
+ async function readPorcelainStatus(repo, options) {
837
+ const statusOutput = await runGit(repo, ["status", "--porcelain=v2", "--branch"], options);
838
+ return parsePorcelainV2Status(statusOutput.stdout);
839
+ }
840
+ function getInitialUpstreamProbe(parsed) {
841
+ return {
842
+ upstreamStatus: parsed.upstream ? "unchecked" : "no_upstream"
843
+ };
844
+ }
845
+ async function refreshTrackedUpstream(repo, parsed, options) {
846
+ if (!parsed.upstream || !parsed.branch) {
847
+ return { upstreamStatus: "no_upstream" };
848
+ }
849
+ const remoteName = await readBranchRemote(repo, parsed.branch, options) ?? inferRemoteName(parsed.upstream);
850
+ if (!remoteName) {
851
+ return {
852
+ upstreamStatus: "stale",
853
+ upstreamFetchError: `Unable to resolve remote for upstream '${parsed.upstream}'`
854
+ };
855
+ }
856
+ try {
857
+ await runGit(repo, ["fetch", "--quiet", "--prune", "--no-tags", remoteName], options);
858
+ return {
859
+ upstreamStatus: "fresh",
860
+ upstreamFetchedAt: Date.now()
861
+ };
862
+ } catch (error48) {
863
+ return {
864
+ upstreamStatus: "stale",
865
+ upstreamFetchError: formatGitError(error48)
866
+ };
867
+ }
868
+ }
869
+ async function readBranchRemote(repo, branch, options) {
870
+ try {
871
+ const result = await runGit(repo, ["config", "--get", `branch.${branch}.remote`], options);
872
+ return result.stdout.trim() || null;
873
+ } catch {
874
+ return null;
875
+ }
876
+ }
877
+ function inferRemoteName(upstream) {
878
+ const [remoteName] = upstream.split("/");
879
+ return remoteName?.trim() || null;
880
+ }
881
+ function formatGitError(error48) {
882
+ if (error48 instanceof GitCommandError) {
883
+ return error48.stderr || error48.message;
884
+ }
885
+ if (error48 instanceof Error) {
886
+ return error48.message;
887
+ }
888
+ return String(error48);
889
+ }
827
890
  function parsePorcelainV2Status(output) {
828
891
  const parsed = {
829
892
  branch: null,
@@ -918,6 +981,7 @@ function emptyStatus(workspace, lastCheckedAt, error48) {
918
981
  headCommit: null,
919
982
  headMessage: null,
920
983
  upstream: null,
984
+ upstreamStatus: "unavailable",
921
985
  ahead: 0,
922
986
  behind: 0,
923
987
  staged: 0,
@@ -1210,6 +1274,9 @@ function createGitCompactSummary(status, diffSummary) {
1210
1274
  isGitRepo: status.isGitRepo,
1211
1275
  repoRoot: status.repoRoot,
1212
1276
  branch: status.branch,
1277
+ upstreamStatus: status.upstreamStatus,
1278
+ upstreamFetchedAt: status.upstreamFetchedAt,
1279
+ upstreamFetchError: status.upstreamFetchError,
1213
1280
  dirty: status.staged > 0 || status.modified > 0 || status.untracked > 0 || status.deleted > 0 || status.renamed > 0 || conflictCount > 0 || changedFiles > 0,
1214
1281
  changedFiles,
1215
1282
  ahead: status.ahead,
@@ -1537,7 +1604,7 @@ function serviceNotImplemented(command) {
1537
1604
  }
1538
1605
  function createDefaultGitCommandServices() {
1539
1606
  return {
1540
- getStatus: ({ workspace }) => getGitRepoStatus(workspace),
1607
+ getStatus: ({ workspace, refreshUpstream }) => getGitRepoStatus(workspace, { refreshUpstream }),
1541
1608
  getDiffSummary: ({ workspace }) => getGitDiffSummary(workspace),
1542
1609
  getDiffFile: ({ workspace, path: filePath }) => getGitFileDiff(workspace, filePath),
1543
1610
  createSnapshot: ({ workspace, reason, sessionId, turnId }) => defaultSnapshotStore.create({
@@ -1622,7 +1689,7 @@ async function handleGitCommand(command, args, services = defaultGitCommandServi
1622
1689
  switch (command) {
1623
1690
  case "git_status": {
1624
1691
  if (!services.getStatus) return serviceNotImplemented(command);
1625
- const status = await runService(() => services.getStatus({ workspace }));
1692
+ const status = await runService(() => services.getStatus({ workspace, refreshUpstream: optionalBoolean(args?.refreshUpstream) }));
1626
1693
  return "success" in status ? status : { success: true, status };
1627
1694
  }
1628
1695
  case "git_diff_summary": {
@@ -4279,10 +4346,18 @@ __export(mesh_events_exports, {
4279
4346
  drainPendingMeshCoordinatorEvents: () => drainPendingMeshCoordinatorEvents,
4280
4347
  getPendingMeshCoordinatorEvents: () => getPendingMeshCoordinatorEvents,
4281
4348
  handleMeshForwardEvent: () => handleMeshForwardEvent,
4349
+ queuePendingMeshCoordinatorEvent: () => queuePendingMeshCoordinatorEvent,
4282
4350
  setupMeshEventForwarding: () => setupMeshEventForwarding,
4283
4351
  triggerMeshQueue: () => triggerMeshQueue,
4284
4352
  tryAssignQueueTask: () => tryAssignQueueTask
4285
4353
  });
4354
+ function queuePendingMeshCoordinatorEvent(event) {
4355
+ if (pendingMeshCoordinatorEvents.length >= MAX_PENDING_EVENTS) {
4356
+ return false;
4357
+ }
4358
+ pendingMeshCoordinatorEvents.push(event);
4359
+ return true;
4360
+ }
4286
4361
  function drainPendingMeshCoordinatorEvents() {
4287
4362
  return pendingMeshCoordinatorEvents.splice(0);
4288
4363
  }
@@ -4854,17 +4929,18 @@ function injectMeshSystemMessage(components, args) {
4854
4929
  return true;
4855
4930
  });
4856
4931
  if (coordinatorInstances.length === 0) {
4857
- if (pendingMeshCoordinatorEvents.length < MAX_PENDING_EVENTS) {
4858
- pendingMeshCoordinatorEvents.push({
4859
- event: args.event,
4860
- meshId: args.meshId,
4861
- nodeLabel: args.nodeLabel,
4862
- metadataEvent: {
4863
- ...args.metadataEvent,
4864
- ...recoveryContext ? { recoveryContext } : {}
4865
- },
4866
- queuedAt: Date.now()
4867
- });
4932
+ if (queuePendingMeshCoordinatorEvent({
4933
+ event: args.event,
4934
+ meshId: args.meshId,
4935
+ nodeLabel: args.nodeLabel,
4936
+ nodeId: args.nodeId || void 0,
4937
+ workspace: readNonEmptyString(args.metadataEvent.workspace),
4938
+ metadataEvent: {
4939
+ ...args.metadataEvent,
4940
+ ...recoveryContext ? { recoveryContext } : {}
4941
+ },
4942
+ queuedAt: Date.now()
4943
+ })) {
4868
4944
  LOG.info("MeshEvents", `Queued ${args.event} for MCP coordinator (mesh ${args.meshId})`);
4869
4945
  }
4870
4946
  return { success: true, forwarded: 0 };
@@ -46381,6 +46457,240 @@ function readProviderPriorityFromPolicy(policy) {
46381
46457
  return true;
46382
46458
  });
46383
46459
  }
46460
+ function readObjectRecord(value) {
46461
+ return value && typeof value === "object" && !Array.isArray(value) ? value : {};
46462
+ }
46463
+ function readStringValue(...values) {
46464
+ for (const value of values) {
46465
+ if (typeof value === "string" && value.trim()) return value.trim();
46466
+ }
46467
+ return void 0;
46468
+ }
46469
+ function readNumberValue(...values) {
46470
+ for (const value of values) {
46471
+ if (typeof value === "number" && Number.isFinite(value)) return value;
46472
+ }
46473
+ return void 0;
46474
+ }
46475
+ function readBooleanValue(...values) {
46476
+ for (const value of values) {
46477
+ if (typeof value === "boolean") return value;
46478
+ }
46479
+ return void 0;
46480
+ }
46481
+ function readGitSubmodules(value) {
46482
+ if (!Array.isArray(value)) return void 0;
46483
+ const submodules = value.map((entry) => {
46484
+ const submodule = readObjectRecord(entry);
46485
+ const path42 = readStringValue(submodule.path);
46486
+ const commit = readStringValue(submodule.commit);
46487
+ const repoPath = readStringValue(submodule.repoPath, submodule.repo_root);
46488
+ if (!path42 || !commit || !repoPath) return null;
46489
+ return {
46490
+ path: path42,
46491
+ commit,
46492
+ repoPath,
46493
+ dirty: readBooleanValue(submodule.dirty) ?? false,
46494
+ outOfSync: readBooleanValue(submodule.outOfSync, submodule.out_of_sync) ?? false,
46495
+ lastCheckedAt: readNumberValue(submodule.lastCheckedAt, submodule.last_checked_at) ?? Date.now(),
46496
+ ...readStringValue(submodule.error) ? { error: readStringValue(submodule.error) } : {}
46497
+ };
46498
+ }).filter((entry) => entry !== null);
46499
+ return submodules.length > 0 ? submodules : void 0;
46500
+ }
46501
+ function buildCachedInlineMeshGitStatus(node) {
46502
+ const cachedStatus = readObjectRecord(node?.cachedStatus);
46503
+ const cachedGit = readObjectRecord(cachedStatus.git);
46504
+ if (Object.keys(cachedGit).length) {
46505
+ const conflictFiles2 = Array.isArray(cachedGit.conflictFiles) ? cachedGit.conflictFiles.filter((value) => typeof value === "string") : [];
46506
+ const conflictCount2 = readNumberValue(cachedGit.conflicts) ?? conflictFiles2.length;
46507
+ const hasConflicts2 = readBooleanValue(cachedGit.hasConflicts) ?? conflictCount2 > 0;
46508
+ const isGitRepo2 = readBooleanValue(cachedGit.isGitRepo);
46509
+ if (isGitRepo2 !== void 0) {
46510
+ const submodules2 = readGitSubmodules(cachedGit.submodules);
46511
+ return {
46512
+ workspace: readStringValue(cachedGit.workspace, node?.workspace) || "",
46513
+ repoRoot: readStringValue(cachedGit.repoRoot, node?.repoRoot, node?.workspace) || null,
46514
+ isGitRepo: isGitRepo2,
46515
+ branch: readStringValue(cachedGit.branch) ?? null,
46516
+ headCommit: readStringValue(cachedGit.headCommit) ?? null,
46517
+ headMessage: readStringValue(cachedGit.headMessage) ?? null,
46518
+ upstream: readStringValue(cachedGit.upstream) ?? null,
46519
+ ahead: readNumberValue(cachedGit.ahead) ?? 0,
46520
+ behind: readNumberValue(cachedGit.behind) ?? 0,
46521
+ staged: readNumberValue(cachedGit.staged) ?? 0,
46522
+ modified: readNumberValue(cachedGit.modified) ?? 0,
46523
+ untracked: readNumberValue(cachedGit.untracked) ?? 0,
46524
+ deleted: readNumberValue(cachedGit.deleted) ?? 0,
46525
+ renamed: readNumberValue(cachedGit.renamed) ?? 0,
46526
+ hasConflicts: hasConflicts2,
46527
+ conflictFiles: conflictFiles2,
46528
+ stashCount: readNumberValue(cachedGit.stashCount) ?? 0,
46529
+ lastCheckedAt: readNumberValue(cachedGit.lastCheckedAt) ?? Date.now(),
46530
+ ...submodules2 ? { submodules: submodules2 } : {}
46531
+ };
46532
+ }
46533
+ }
46534
+ const rawGit = readObjectRecord(node?.lastGit ?? node?.last_git);
46535
+ const gitResult = readObjectRecord(rawGit.result);
46536
+ const directStatus = readObjectRecord(rawGit.status);
46537
+ const nestedStatus = readObjectRecord(gitResult.status);
46538
+ const rawProbe = readObjectRecord(node?.lastProbe ?? node?.last_probe);
46539
+ const probeGit = readObjectRecord(rawProbe.git);
46540
+ const probeGitResult = readObjectRecord(probeGit.result);
46541
+ const probeDirectStatus = readObjectRecord(probeGit.status);
46542
+ const probeNestedStatus = readObjectRecord(probeGitResult.status);
46543
+ const status = Object.keys(directStatus).length ? directStatus : Object.keys(nestedStatus).length ? nestedStatus : Object.keys(probeDirectStatus).length ? probeDirectStatus : Object.keys(probeNestedStatus).length ? probeNestedStatus : {};
46544
+ const isGitRepo = readBooleanValue(status.isGitRepo);
46545
+ if (!Object.keys(status).length || isGitRepo === void 0) return void 0;
46546
+ const conflictFiles = Array.isArray(status.conflictFiles) ? status.conflictFiles.filter((value) => typeof value === "string") : [];
46547
+ const conflictCount = readNumberValue(status.conflicts) ?? conflictFiles.length;
46548
+ const hasConflicts = readBooleanValue(status.hasConflicts) ?? conflictCount > 0;
46549
+ const submodules = readGitSubmodules(status.submodules);
46550
+ return {
46551
+ workspace: readStringValue(status.workspace, node?.workspace) || "",
46552
+ repoRoot: readStringValue(status.repoRoot, node?.repoRoot, node?.workspace) || null,
46553
+ isGitRepo,
46554
+ branch: readStringValue(status.branch) ?? null,
46555
+ headCommit: readStringValue(status.headCommit) ?? null,
46556
+ headMessage: readStringValue(status.headMessage) ?? null,
46557
+ upstream: readStringValue(status.upstream) ?? null,
46558
+ ahead: readNumberValue(status.ahead) ?? 0,
46559
+ behind: readNumberValue(status.behind) ?? 0,
46560
+ staged: readNumberValue(status.staged) ?? 0,
46561
+ modified: readNumberValue(status.modified) ?? 0,
46562
+ untracked: readNumberValue(status.untracked) ?? 0,
46563
+ deleted: readNumberValue(status.deleted) ?? 0,
46564
+ renamed: readNumberValue(status.renamed) ?? 0,
46565
+ hasConflicts,
46566
+ conflictFiles,
46567
+ stashCount: readNumberValue(status.stashCount) ?? 0,
46568
+ lastCheckedAt: Date.now(),
46569
+ ...submodules ? { submodules } : {}
46570
+ };
46571
+ }
46572
+ function hasGitWorktreeChanges(git) {
46573
+ if (!git) return false;
46574
+ return Number(git.staged || 0) + Number(git.modified || 0) + Number(git.untracked || 0) + Number(git.deleted || 0) + Number(git.renamed || 0) > 0;
46575
+ }
46576
+ function getGitSubmoduleDriftState(git) {
46577
+ const submodules = Array.isArray(git?.submodules) ? git.submodules : [];
46578
+ let dirty = false;
46579
+ let outOfSync = false;
46580
+ for (const entry of submodules) {
46581
+ const submodule = readObjectRecord(entry);
46582
+ if (readBooleanValue(submodule.dirty) === true) dirty = true;
46583
+ if (readBooleanValue(submodule.outOfSync) === true || !!readStringValue(submodule.error)) outOfSync = true;
46584
+ }
46585
+ return { dirty, outOfSync };
46586
+ }
46587
+ function deriveMeshNodeHealthFromGit(git) {
46588
+ if (!git || readBooleanValue(git.isGitRepo) === false) return "degraded";
46589
+ const branch = readStringValue(git.branch);
46590
+ if (!branch) return "degraded";
46591
+ const submoduleDrift = getGitSubmoduleDriftState(git);
46592
+ if (submoduleDrift.outOfSync) return "degraded";
46593
+ if (submoduleDrift.dirty || hasGitWorktreeChanges(git)) return "dirty";
46594
+ return "online";
46595
+ }
46596
+ function readCachedInlineMeshActiveSessions(node) {
46597
+ const cachedStatus = readObjectRecord(node?.cachedStatus);
46598
+ const activeSession = readObjectRecord(cachedStatus.activeSession);
46599
+ const fallbackSession = Object.keys(activeSession).length ? activeSession : readObjectRecord(node?.activeSession ?? node?.active_session);
46600
+ const sessionId = readStringValue(fallbackSession.id, fallbackSession.sessionId, fallbackSession.session_id, node?.activeSessionId, node?.active_session_id, node?.sessionId, node?.session_id);
46601
+ return sessionId ? [sessionId] : [];
46602
+ }
46603
+ function readCachedInlineMeshActiveSessionDetails(node) {
46604
+ const cachedStatus = readObjectRecord(node?.cachedStatus);
46605
+ const activeSession = readObjectRecord(cachedStatus.activeSession);
46606
+ const fallbackSession = Object.keys(activeSession).length ? activeSession : readObjectRecord(node?.activeSession ?? node?.active_session);
46607
+ const sessionId = readStringValue(
46608
+ fallbackSession.id,
46609
+ fallbackSession.sessionId,
46610
+ fallbackSession.session_id,
46611
+ node?.activeSessionId,
46612
+ node?.active_session_id,
46613
+ node?.sessionId,
46614
+ node?.session_id
46615
+ );
46616
+ if (!sessionId) return [];
46617
+ return [{
46618
+ sessionId,
46619
+ providerType: readStringValue(
46620
+ fallbackSession.providerType,
46621
+ fallbackSession.provider_type,
46622
+ fallbackSession.cliType,
46623
+ fallbackSession.cli_type,
46624
+ fallbackSession.provider,
46625
+ node?.providerType,
46626
+ node?.provider_type
46627
+ ),
46628
+ state: readStringValue(fallbackSession.status, fallbackSession.state, fallbackSession.lifecycle),
46629
+ lifecycle: readStringValue(fallbackSession.lifecycle),
46630
+ title: readStringValue(fallbackSession.title, fallbackSession.displayName, fallbackSession.display_name) ?? null,
46631
+ workspace: readStringValue(fallbackSession.workspace, node?.workspace) ?? null,
46632
+ lastActivityAt: readStringValue(fallbackSession.lastActivityAt, fallbackSession.last_activity_at) ?? null,
46633
+ recoveryState: readStringValue(fallbackSession.recoveryState, fallbackSession.recovery_state) ?? null,
46634
+ isCached: true
46635
+ }];
46636
+ }
46637
+ function readLiveMeshSessionState(record2) {
46638
+ return readStringValue(
46639
+ record2?.meta?.sessionStatus,
46640
+ record2?.meta?.status,
46641
+ record2?.meta?.providerStatus,
46642
+ record2?.status,
46643
+ record2?.state,
46644
+ record2?.lifecycle
46645
+ );
46646
+ }
46647
+ function toIsoTimestamp(value) {
46648
+ if (typeof value === "number" && Number.isFinite(value)) return new Date(value).toISOString();
46649
+ const stringValue = readStringValue(value);
46650
+ return stringValue || null;
46651
+ }
46652
+ function summarizeMeshSessionRecord(record2) {
46653
+ return {
46654
+ sessionId: readStringValue(record2?.sessionId) || "unknown",
46655
+ providerType: readStringValue(record2?.providerType),
46656
+ state: readLiveMeshSessionState(record2),
46657
+ lifecycle: readStringValue(record2?.lifecycle),
46658
+ surfaceKind: getSessionHostSurfaceKind(record2),
46659
+ recoveryState: readStringValue(record2?.meta?.runtimeRecoveryState) ?? null,
46660
+ workspace: readStringValue(record2?.workspace) ?? null,
46661
+ title: readStringValue(record2?.displayName, record2?.workspaceLabel) ?? null,
46662
+ lastActivityAt: toIsoTimestamp(record2?.updatedAt ?? record2?.lastActivityAt ?? record2?.last_activity_at),
46663
+ isCached: false
46664
+ };
46665
+ }
46666
+ function applyCachedInlineMeshNodeStatus(status, node) {
46667
+ const cachedStatus = readObjectRecord(node?.cachedStatus);
46668
+ const git = buildCachedInlineMeshGitStatus(node);
46669
+ const error48 = readStringValue(cachedStatus.error, node?.error);
46670
+ const health = readStringValue(cachedStatus.health, node?.health);
46671
+ const machineStatus = readStringValue(cachedStatus.machineStatus, node?.machineStatus);
46672
+ const lastSeenAt = toIsoTimestamp(cachedStatus.lastSeenAt ?? cachedStatus.last_seen_at ?? node?.lastSeenAt ?? node?.last_seen_at);
46673
+ const updatedAt = toIsoTimestamp(cachedStatus.updatedAt ?? cachedStatus.updated_at ?? node?.updatedAt ?? node?.updated_at);
46674
+ const activeSessions = readCachedInlineMeshActiveSessions(node);
46675
+ const activeSessionDetails = readCachedInlineMeshActiveSessionDetails(node);
46676
+ if (!git && !error48 && !health && !machineStatus && !lastSeenAt && !updatedAt && activeSessions.length === 0) return false;
46677
+ if (git) status.git = git;
46678
+ if (error48) status.error = error48;
46679
+ if (machineStatus) status.machineStatus = machineStatus;
46680
+ if (lastSeenAt) status.lastSeenAt = lastSeenAt;
46681
+ if (updatedAt) status.updatedAt = updatedAt;
46682
+ if (activeSessions.length > 0) status.activeSessions = activeSessions;
46683
+ if (activeSessionDetails.length > 0) status.activeSessionDetails = activeSessionDetails;
46684
+ if (health) {
46685
+ status.health = health;
46686
+ return true;
46687
+ }
46688
+ if (git) {
46689
+ status.health = deriveMeshNodeHealthFromGit(git);
46690
+ return true;
46691
+ }
46692
+ return activeSessions.length > 0 || !!machineStatus || !!lastSeenAt || !!updatedAt;
46693
+ }
46384
46694
  async function resolveProviderTypeFromPriority(args) {
46385
46695
  if (!args.providerPriority.length) {
46386
46696
  return { error: `Node '${args.nodeId}' has no providerPriority policy; pass cliType explicitly or configure node.policy.providerPriority` };
@@ -46769,6 +47079,7 @@ var init_router = __esm({
46769
47079
  init_chat_history();
46770
47080
  init_ide_detector();
46771
47081
  init_cli_detector();
47082
+ init_git_status();
46772
47083
  init_logger();
46773
47084
  init_command_log();
46774
47085
  init_js_yaml();
@@ -46818,7 +47129,12 @@ var init_router = __esm({
46818
47129
  }
46819
47130
  return this.inlineMeshCache.get(meshId);
46820
47131
  }
46821
- async getMeshForCommand(meshId, inlineMesh) {
47132
+ async getMeshForCommand(meshId, inlineMesh, options) {
47133
+ const preferInline = options?.preferInline === true;
47134
+ if (preferInline) {
47135
+ const cached3 = this.getCachedInlineMesh(meshId, inlineMesh);
47136
+ if (cached3) return { mesh: cached3, inline: true };
47137
+ }
46822
47138
  try {
46823
47139
  const { getMesh: getMesh3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
46824
47140
  const mesh = getMesh3(meshId);
@@ -48641,7 +48957,7 @@ ${block}`);
48641
48957
  const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
48642
48958
  if (!meshId) return { success: false, error: "meshId required" };
48643
48959
  try {
48644
- const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
48960
+ const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
48645
48961
  const mesh = meshRecord?.mesh;
48646
48962
  if (!mesh) return { success: false, error: "Mesh not found" };
48647
48963
  const { getMeshQueueStats: getMeshQueueStats2, getQueue: getQueue2 } = await Promise.resolve().then(() => (init_mesh_work_queue(), mesh_work_queue_exports));
@@ -48650,84 +48966,102 @@ ${block}`);
48650
48966
  const { readLedgerEntries: readLedgerEntries2, getLedgerSummary: getLedgerSummary2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
48651
48967
  const ledgerEntries = readLedgerEntries2(meshId, { tail: 20 });
48652
48968
  const ledgerSummary = getLedgerSummary2(meshId);
48969
+ const sessionHostRecords = this.deps.sessionHostControl?.listSessions ? await this.deps.sessionHostControl.listSessions().catch(() => []) : [];
48970
+ const liveMeshSessions = partitionSessionHostRecords(Array.isArray(sessionHostRecords) ? sessionHostRecords : []).liveRuntimes;
48971
+ const localMachineId = loadConfig().machineId || "";
48972
+ const inlineCoordinatorNodeId = meshRecord?.inline && Array.isArray(mesh.nodes) ? readStringValue(mesh.nodes[0]?.id, mesh.nodes[0]?.nodeId) : void 0;
48973
+ const refreshedAt = (/* @__PURE__ */ new Date()).toISOString();
48653
48974
  const nodeStatuses = [];
48654
- for (const node of mesh.nodes || []) {
48975
+ for (const [nodeIndex, node] of (mesh.nodes || []).entries()) {
48976
+ const nodeId = String(node.id || node.nodeId || "");
48977
+ const daemonId = readStringValue(node.daemonId);
48978
+ const providerPriority = readProviderPriorityFromPolicy(node.policy);
48979
+ const isSelfNode = Boolean(
48980
+ nodeId && inlineCoordinatorNodeId && nodeId === inlineCoordinatorNodeId
48981
+ ) || Boolean(
48982
+ daemonId && (daemonId === localMachineId || daemonId === this.deps.statusInstanceId)
48983
+ ) || Boolean(meshRecord?.inline && nodeIndex === 0);
48655
48984
  const status = {
48656
- nodeId: node.id || node.nodeId,
48985
+ nodeId,
48657
48986
  machineLabel: node.machineLabel || node.id || node.nodeId,
48658
48987
  workspace: node.workspace,
48659
48988
  repoRoot: node.repoRoot,
48660
48989
  isLocalWorktree: node.isLocalWorktree,
48661
48990
  worktreeBranch: node.worktreeBranch,
48662
- daemonId: node.daemonId,
48991
+ daemonId,
48663
48992
  machineId: node.machineId,
48993
+ machineStatus: node.machineStatus,
48664
48994
  health: "unknown",
48665
48995
  providers: node.providers || [],
48666
- activeSessions: []
48996
+ providerPriority,
48997
+ activeSessions: [],
48998
+ activeSessionDetails: [],
48999
+ launchReady: false
48667
49000
  };
49001
+ if (isSelfNode) {
49002
+ status.connection = {
49003
+ perspective: "selected_coordinator",
49004
+ source: "mesh_peer_status",
49005
+ state: "self",
49006
+ transport: "local",
49007
+ reported: true,
49008
+ reason: "Selected coordinator daemon",
49009
+ lastStateChangeAt: refreshedAt
49010
+ };
49011
+ } else if (daemonId) {
49012
+ const connection = this.deps.getMeshPeerConnectionStatus?.(daemonId);
49013
+ status.connection = connection ?? {
49014
+ perspective: "selected_coordinator",
49015
+ source: "not_reported",
49016
+ state: "unknown",
49017
+ transport: "unknown",
49018
+ reported: false,
49019
+ reason: "No live mesh peer telemetry reported by the selected coordinator yet."
49020
+ };
49021
+ } else {
49022
+ status.connection = {
49023
+ perspective: "selected_coordinator",
49024
+ source: "not_reported",
49025
+ state: "unknown",
49026
+ transport: "unknown",
49027
+ reported: false,
49028
+ reason: "Node has no daemon id, so mesh transport cannot be reported from the selected coordinator."
49029
+ };
49030
+ }
49031
+ const matchedLiveSessionRecords = liveMeshSessions.filter((record2) => this.sessionMatchesMeshNode(record2, node, nodeId));
49032
+ if (matchedLiveSessionRecords.length > 0) {
49033
+ const sessionIds = matchedLiveSessionRecords.map((record2) => typeof record2?.sessionId === "string" ? record2.sessionId : "").filter(Boolean);
49034
+ const providerTypes = matchedLiveSessionRecords.map((record2) => readStringValue(record2?.providerType)).filter(Boolean);
49035
+ status.activeSessions = sessionIds;
49036
+ status.activeSessionDetails = matchedLiveSessionRecords.map(summarizeMeshSessionRecord);
49037
+ if (providerTypes.length > 0) {
49038
+ status.providers = Array.from(/* @__PURE__ */ new Set([...Array.isArray(status.providers) ? status.providers : [], ...providerTypes]));
49039
+ }
49040
+ }
48668
49041
  if (node.workspace && typeof node.workspace === "string") {
49042
+ if (!fs10.existsSync(node.workspace) && applyCachedInlineMeshNodeStatus(status, node)) {
49043
+ status.launchReady = !!daemonId && (readStringValue(status.machineStatus) === "online" || isSelfNode);
49044
+ nodeStatuses.push(status);
49045
+ continue;
49046
+ }
48669
49047
  try {
48670
- const { execFile: execFile3 } = await import("child_process");
48671
- const { promisify: promisify3 } = await import("util");
48672
- const execFileAsync3 = promisify3(execFile3);
48673
- const runGit2 = async (args2) => {
48674
- const result = await execFileAsync3("git", ["-C", node.workspace, ...args2], {
48675
- encoding: "utf8",
48676
- timeout: 1e4
48677
- });
48678
- return result.stdout.trim();
48679
- };
48680
- const branch = await runGit2(["branch", "--show-current"]).catch(() => "");
48681
- const porc = await runGit2(["status", "--porcelain"]).catch(() => "");
48682
- const headCommit = await runGit2(["rev-parse", "--short", "HEAD"]).catch(() => null);
48683
- const headMessage = await runGit2(["log", "-1", "--format=%s"]).catch(() => null);
48684
- const upstream = await runGit2(["rev-parse", "--abbrev-ref", "@{upstream}"]).catch(() => null);
48685
- const aheadBehind = await runGit2(["rev-list", "--left-right", "--count", "@{upstream}...HEAD"]).catch(() => "");
48686
- const stashCount = await runGit2(["stash", "list"]).catch(() => "");
48687
- let ahead = 0, behind = 0;
48688
- if (aheadBehind) {
48689
- const parts = aheadBehind.split(/\s+/);
48690
- if (parts.length >= 2) {
48691
- behind = parseInt(parts[0], 10) || 0;
48692
- ahead = parseInt(parts[1], 10) || 0;
48693
- }
48694
- }
48695
- const dirty = porc.length > 0;
48696
- const lines = porc ? porc.split("\n").filter(Boolean) : [];
48697
- let staged = 0, modified = 0, untracked = 0, deleted = 0, renamed2 = 0;
48698
- for (const line of lines) {
48699
- const xy = line.slice(0, 2);
48700
- if (xy[0] !== " " && xy[0] !== "?") staged++;
48701
- if (xy[1] === "M") modified++;
48702
- if (xy[1] === "D") deleted++;
48703
- if (xy[0] === "R" || xy[1] === "R") renamed2++;
48704
- if (xy === "??") untracked++;
49048
+ const gitStatus = await getGitRepoStatus(node.workspace, { timeoutMs: 1e4, refreshUpstream: true });
49049
+ status.git = gitStatus;
49050
+ if (gitStatus.isGitRepo) {
49051
+ status.health = deriveMeshNodeHealthFromGit(gitStatus);
49052
+ } else {
49053
+ status.health = "degraded";
49054
+ if (gitStatus.error && !status.error) status.error = gitStatus.error;
48705
49055
  }
48706
- status.git = {
48707
- workspace: node.workspace,
48708
- repoRoot: node.workspace,
48709
- isGitRepo: true,
48710
- branch: branch || null,
48711
- headCommit,
48712
- headMessage,
48713
- upstream,
48714
- ahead,
48715
- behind,
48716
- staged,
48717
- modified,
48718
- untracked,
48719
- deleted,
48720
- renamed: renamed2,
48721
- hasConflicts: false,
48722
- conflictFiles: [],
48723
- stashCount: stashCount ? stashCount.split("\n").filter(Boolean).length : 0,
48724
- lastCheckedAt: Date.now()
48725
- };
48726
- status.health = branch ? dirty ? "dirty" : "online" : "degraded";
48727
49056
  } catch {
48728
- status.health = "degraded";
49057
+ if (!applyCachedInlineMeshNodeStatus(status, node)) {
49058
+ status.health = "degraded";
49059
+ }
48729
49060
  }
49061
+ } else {
49062
+ applyCachedInlineMeshNodeStatus(status, node);
48730
49063
  }
49064
+ status.launchReady = !!daemonId && (readStringValue(status.machineStatus) === "online" || isSelfNode);
48731
49065
  nodeStatuses.push(status);
48732
49066
  }
48733
49067
  return {
@@ -48736,6 +49070,7 @@ ${block}`);
48736
49070
  meshName: mesh.name,
48737
49071
  repoIdentity: mesh.repoIdentity,
48738
49072
  defaultBranch: mesh.defaultBranch,
49073
+ refreshedAt: (/* @__PURE__ */ new Date()).toISOString(),
48739
49074
  nodes: nodeStatuses,
48740
49075
  queue: { tasks: queue, summary: queueSummary },
48741
49076
  ledger: { entries: ledgerEntries, summary: ledgerSummary }
@@ -56814,6 +57149,7 @@ async function initDaemonComponents(config2) {
56814
57149
  sessionHostControl: config2.sessionHostControl,
56815
57150
  statusInstanceId: config2.statusInstanceId,
56816
57151
  statusVersion: config2.statusVersion,
57152
+ getMeshPeerConnectionStatus: config2.getMeshPeerConnectionStatus,
56817
57153
  getCdpLogFn: config2.getCdpLogFn || ((ideType) => LOG.forComponent(`CDP:${ideType}`).asLogFn())
56818
57154
  });
56819
57155
  poller = new AgentStreamPoller({
@@ -57115,6 +57451,7 @@ __export(src_exports, {
57115
57451
  prepareSessionChatTailUpdate: () => prepareSessionChatTailUpdate,
57116
57452
  prepareSessionModalUpdate: () => prepareSessionModalUpdate,
57117
57453
  probeCdpPort: () => probeCdpPort,
57454
+ queuePendingMeshCoordinatorEvent: () => queuePendingMeshCoordinatorEvent,
57118
57455
  readChatHistory: () => readChatHistory,
57119
57456
  readLedgerEntries: () => readLedgerEntries,
57120
57457
  readLedgerSlice: () => readLedgerSlice,
@@ -97091,11 +97428,30 @@ var init_daemon_mesh_manager = __esm({
97091
97428
  nodeDatachannel = null;
97092
97429
  peers = /* @__PURE__ */ new Map();
97093
97430
  // Map<targetDaemonId, PeerEntry>
97431
+ peerSnapshots = /* @__PURE__ */ new Map();
97094
97432
  pendingRequests = /* @__PURE__ */ new Map();
97095
97433
  commandCallback;
97096
97434
  p2pFailure(message, command, targetDaemonId) {
97097
97435
  return new P2pRelayFailureError(message, { command, targetDaemonId });
97098
97436
  }
97437
+ updatePeerSnapshot(targetDaemonId, state, patch = {}) {
97438
+ const previous = this.peerSnapshots.get(targetDaemonId);
97439
+ const now = (/* @__PURE__ */ new Date()).toISOString();
97440
+ this.peerSnapshots.set(targetDaemonId, {
97441
+ perspective: "selected_coordinator",
97442
+ source: "mesh_peer_status",
97443
+ reported: true,
97444
+ state,
97445
+ transport: patch.transport ?? previous?.transport ?? "unknown",
97446
+ reason: patch.reason ?? previous?.reason,
97447
+ lastStateChangeAt: now,
97448
+ lastConnectedAt: patch.lastConnectedAt ?? previous?.lastConnectedAt,
97449
+ lastCommandAt: patch.lastCommandAt ?? previous?.lastCommandAt
97450
+ });
97451
+ }
97452
+ getPeerConnectionStatus(targetDaemonId) {
97453
+ return this.peerSnapshots.get(targetDaemonId) ?? null;
97454
+ }
97099
97455
  invalidatePeer(targetDaemonId, reason, options = {}) {
97100
97456
  const peer = this.peers.get(targetDaemonId);
97101
97457
  if (peer?.commandQueue) {
@@ -97110,6 +97466,11 @@ var init_daemon_mesh_manager = __esm({
97110
97466
  pending.reject(this.p2pFailure(reason, pending.command, targetDaemonId));
97111
97467
  }
97112
97468
  }
97469
+ const snapshotState = peer?.state === "closed" ? "closed" : peer?.state === "disconnected" ? "disconnected" : "failed";
97470
+ this.updatePeerSnapshot(targetDaemonId, snapshotState, {
97471
+ reason,
97472
+ transport: peer?.isRelay === true ? "relay" : peer?.isRelay === false ? "direct" : "unknown"
97473
+ });
97113
97474
  if (options.closeResources !== false && peer) {
97114
97475
  try {
97115
97476
  peer.dataChannel?.close?.();
@@ -97142,6 +97503,7 @@ var init_daemon_mesh_manager = __esm({
97142
97503
  "send_chat",
97143
97504
  "read_chat",
97144
97505
  "get_chat_debug_bundle",
97506
+ "get_pending_mesh_events",
97145
97507
  "git_status",
97146
97508
  "git_diff_summary",
97147
97509
  "launch_cli",
@@ -97229,6 +97591,20 @@ var init_daemon_mesh_manager = __esm({
97229
97591
  if (!peer) {
97230
97592
  throw this.p2pFailure("Failed to initiate P2P connection entry", command, targetDaemonId);
97231
97593
  }
97594
+ const lastCommandAt = (/* @__PURE__ */ new Date()).toISOString();
97595
+ if (peer.state === "connected") {
97596
+ this.updatePeerSnapshot(targetDaemonId, "connected", {
97597
+ transport: peer.isRelay === true ? "relay" : peer.isRelay === false ? "direct" : "unknown",
97598
+ lastConnectedAt: this.peerSnapshots.get(targetDaemonId)?.lastConnectedAt,
97599
+ lastCommandAt
97600
+ });
97601
+ } else {
97602
+ this.updatePeerSnapshot(targetDaemonId, "connecting", {
97603
+ transport: peer.isRelay === true ? "relay" : peer.isRelay === false ? "direct" : "unknown",
97604
+ reason: "Waiting for mesh DataChannel to open.",
97605
+ lastCommandAt
97606
+ });
97607
+ }
97232
97608
  return new Promise((resolve23, reject) => {
97233
97609
  const requestId = `req_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
97234
97610
  const timer = setTimeout(() => {
@@ -97372,6 +97748,9 @@ var init_daemon_mesh_manager = __esm({
97372
97748
  remoteDescriptionSet: false
97373
97749
  };
97374
97750
  this.peers.set(targetDaemonId, entry);
97751
+ this.updatePeerSnapshot(targetDaemonId, "connecting", {
97752
+ reason: isInitiator ? "P2P mesh connection initiated by the selected coordinator." : "Waiting for the remote daemon to finish the mesh DataChannel handshake."
97753
+ });
97375
97754
  pc.onLocalDescription((sdp, type2) => {
97376
97755
  this.serverConn.sendMeshCommand(targetDaemonId, type2 === "offer" ? "mesh_p2p_offer" : "mesh_p2p_answer", { sdp, type: type2 });
97377
97756
  });
@@ -97382,7 +97761,26 @@ var init_daemon_mesh_manager = __esm({
97382
97761
  LOG.info("Mesh", `[Mesh] P2P state with ${targetDaemonId.slice(0, 12)}: ${state}`);
97383
97762
  if (state === "connected") {
97384
97763
  entry.state = "connected";
97764
+ let transport = "unknown";
97765
+ try {
97766
+ const pair = pc.getSelectedCandidatePair?.();
97767
+ if (pair) {
97768
+ const localType = pair.local?.type || "unknown";
97769
+ const remoteType = pair.remote?.type || "unknown";
97770
+ entry.isRelay = localType === "relay" || remoteType === "relay";
97771
+ transport = entry.isRelay ? "relay" : "direct";
97772
+ LOG.info("Mesh", `[Mesh] Candidate pair with ${targetDaemonId.slice(0, 12)}: local=${localType} remote=${remoteType} \u2192 ${transport}`);
97773
+ }
97774
+ } catch {
97775
+ transport = entry.isRelay === true ? "relay" : entry.isRelay === false ? "direct" : "unknown";
97776
+ }
97777
+ this.updatePeerSnapshot(targetDaemonId, "connected", {
97778
+ transport,
97779
+ reason: transport === "relay" ? "Connected over TURN relay." : transport === "direct" ? "Connected directly peer-to-peer." : "Connected, but selected candidate pair details are unavailable.",
97780
+ lastConnectedAt: (/* @__PURE__ */ new Date()).toISOString()
97781
+ });
97385
97782
  } else if (state === "failed" || state === "closed" || state === "disconnected") {
97783
+ entry.state = state;
97386
97784
  this.invalidatePeer(targetDaemonId, `P2P state changed to ${state}`, { rejectPending: true, closeResources: false });
97387
97785
  }
97388
97786
  });
@@ -97400,6 +97798,11 @@ var init_daemon_mesh_manager = __esm({
97400
97798
  dc.onOpen(() => {
97401
97799
  LOG.info("Mesh", `[Mesh] DataChannel OPEN with ${targetDaemonId.slice(0, 12)}`);
97402
97800
  entry.state = "connected";
97801
+ this.updatePeerSnapshot(targetDaemonId, "connected", {
97802
+ transport: entry.isRelay === true ? "relay" : entry.isRelay === false ? "direct" : "unknown",
97803
+ reason: entry.isRelay === true ? "Connected over TURN relay." : entry.isRelay === false ? "Connected directly peer-to-peer." : "DataChannel open; transport details not reported yet.",
97804
+ lastConnectedAt: (/* @__PURE__ */ new Date()).toISOString()
97805
+ });
97403
97806
  if (entry.commandQueue) {
97404
97807
  const queue = entry.commandQueue;
97405
97808
  entry.commandQueue = [];
@@ -97679,6 +98082,7 @@ var init_adhdev_daemon = __esm({
97679
98082
  "use strict";
97680
98083
  init_server_connection();
97681
98084
  init_src();
98085
+ init_mesh_events();
97682
98086
  init_daemon_p2p2();
97683
98087
  init_screenshot_controller();
97684
98088
  init_session_host();
@@ -97695,7 +98099,7 @@ var init_adhdev_daemon = __esm({
97695
98099
  init_version();
97696
98100
  init_src();
97697
98101
  init_runtime_defaults();
97698
- pkgVersion = resolvePackageVersion({ injectedVersion: "0.9.82-rc.1" });
98102
+ pkgVersion = resolvePackageVersion({ injectedVersion: "0.9.82-rc.11" });
97699
98103
  AdhdevDaemon = class _AdhdevDaemon {
97700
98104
  localHttpServer = null;
97701
98105
  localWss = null;
@@ -98219,6 +98623,7 @@ ${err?.stack || ""}`);
98219
98623
  if (!this.meshManager) throw new Error("Mesh manager not initialized");
98220
98624
  return this.meshManager.sendCommand(daemonId, command, args);
98221
98625
  },
98626
+ getMeshPeerConnectionStatus: (daemonId) => this.meshManager?.getPeerConnectionStatus(daemonId) ?? null,
98222
98627
  onStatusChange: () => {
98223
98628
  this.invalidateHotChatSnapshotCache();
98224
98629
  this.statusReporter?.onStatusChange();
@@ -98611,6 +99016,21 @@ ${err?.stack || ""}`);
98611
99016
  await this.meshManager.sendCommand(coordinatorDaemonId, "mesh_forward_event", payload);
98612
99017
  LOG.info("MeshEvents", `Relayed ${payload.event} for mesh ${meshId} to coordinator daemon ${coordinatorDaemonId.slice(0, 12)}\u2026`);
98613
99018
  } catch (error48) {
99019
+ queuePendingMeshCoordinatorEvent({
99020
+ event: payload.event,
99021
+ meshId,
99022
+ nodeLabel: payload.nodeId ? `Node '${payload.nodeId}'` : payload.workspace ? `Agent at ${payload.workspace}` : "Remote agent",
99023
+ nodeId: payload.nodeId || void 0,
99024
+ workspace: payload.workspace || void 0,
99025
+ metadataEvent: {
99026
+ targetSessionId: payload.targetSessionId,
99027
+ providerType: payload.providerType,
99028
+ providerSessionId: payload.providerSessionId,
99029
+ finalSummary: payload.finalSummary,
99030
+ workspace: payload.workspace
99031
+ },
99032
+ queuedAt: Date.now()
99033
+ });
98614
99034
  LOG.warn("MeshEvents", `Failed to relay ${payload.event} for mesh ${meshId}: ${error48?.message || error48}`);
98615
99035
  }
98616
99036
  }
@@ -99517,6 +99937,420 @@ var init_runtime_target_trace = __esm({
99517
99937
  }
99518
99938
  });
99519
99939
 
99940
+ // src/cli/service-commands.ts
99941
+ var service_commands_exports = {};
99942
+ __export(service_commands_exports, {
99943
+ buildPlist: () => buildPlist,
99944
+ installAutoStartServiceForCurrentProcess: () => installAutoStartServiceForCurrentProcess,
99945
+ isAutoStartServiceInstalled: () => isAutoStartServiceInstalled,
99946
+ registerServiceCommands: () => registerServiceCommands
99947
+ });
99948
+ function getDarwinPlistPath() {
99949
+ return import_node_path5.default.join(import_node_os4.default.homedir(), "Library", "LaunchAgents", `${LAUNCHD_LABEL}.plist`);
99950
+ }
99951
+ function getWindowsStartupDir() {
99952
+ const appData = process.env.APPDATA || import_node_path5.default.join(import_node_os4.default.homedir(), "AppData", "Roaming");
99953
+ return import_node_path5.default.join(appData, "Microsoft", "Windows", "Start Menu", "Programs", "Startup");
99954
+ }
99955
+ function getWindowsVbsPath() {
99956
+ return import_node_path5.default.join(getWindowsStartupDir(), "adhdev-daemon.vbs");
99957
+ }
99958
+ function resolveCliPath() {
99959
+ return import_node_fs4.default.realpathSync(process.argv[1]);
99960
+ }
99961
+ function ensureDir(dir) {
99962
+ if (!import_node_fs4.default.existsSync(dir)) import_node_fs4.default.mkdirSync(dir, { recursive: true });
99963
+ }
99964
+ async function fetchHealth() {
99965
+ const controller = new AbortController();
99966
+ const timer = setTimeout(() => controller.abort(), DEFAULT_LOCAL_DAEMON_HEALTH_TIMEOUT_MS2);
99967
+ try {
99968
+ const res = await fetch(`http://127.0.0.1:${DEFAULT_DAEMON_PORT}/health`, { signal: controller.signal });
99969
+ if (!res.ok) return null;
99970
+ return await res.json();
99971
+ } catch {
99972
+ return null;
99973
+ } finally {
99974
+ clearTimeout(timer);
99975
+ }
99976
+ }
99977
+ function getProcessInfo(pid) {
99978
+ try {
99979
+ if (process.platform === "win32") {
99980
+ const out = (0, import_node_child_process4.execSync)(`tasklist /FI "PID eq ${pid}" /FO CSV /NH`, { encoding: "utf-8" });
99981
+ const match = out.match(/"(\d[\d,]+)\sK"/);
99982
+ const memKB = match ? parseInt(match[1].replace(/,/g, ""), 10) : 0;
99983
+ return { uptime: "-", memMB: Math.round(memKB / 1024) };
99984
+ } else {
99985
+ const out = (0, import_node_child_process4.execSync)(`ps -o etime=,rss= -p ${pid}`, { encoding: "utf-8" }).trim();
99986
+ const parts = out.split(/\s+/);
99987
+ const etime = parts[0] || "-";
99988
+ const rssKB = parseInt(parts[1] || "0", 10);
99989
+ return { uptime: formatElapsed(etime), memMB: Math.round(rssKB / 1024) };
99990
+ }
99991
+ } catch {
99992
+ return null;
99993
+ }
99994
+ }
99995
+ function formatElapsed(etime) {
99996
+ const parts = etime.replace("-", ":").split(":").map(Number);
99997
+ if (parts.length === 4) return `${parts[0]}d ${parts[1]}h ${parts[2]}m`;
99998
+ if (parts.length === 3) return `${parts[0]}h ${parts[1]}m`;
99999
+ if (parts.length === 2) return `${parts[0]}m ${parts[1]}s`;
100000
+ return etime;
100001
+ }
100002
+ function rotateLogIfNeeded(logPath) {
100003
+ try {
100004
+ if (!import_node_fs4.default.existsSync(logPath)) return;
100005
+ const stat5 = import_node_fs4.default.statSync(logPath);
100006
+ if (stat5.size > MAX_LOG_SIZE2) {
100007
+ const rotated = logPath + ".old";
100008
+ if (import_node_fs4.default.existsSync(rotated)) import_node_fs4.default.unlinkSync(rotated);
100009
+ import_node_fs4.default.renameSync(logPath, rotated);
100010
+ import_node_fs4.default.writeFileSync(logPath, `[log rotated at ${(/* @__PURE__ */ new Date()).toISOString()}]
100011
+ `, "utf-8");
100012
+ }
100013
+ } catch {
100014
+ }
100015
+ }
100016
+ function rotateLogs() {
100017
+ rotateLogIfNeeded(LOG_OUT);
100018
+ rotateLogIfNeeded(LOG_ERR);
100019
+ }
100020
+ function normalizeLaunchdPathEntry(entry) {
100021
+ const trimmed = String(entry || "").trim();
100022
+ if (!trimmed) return null;
100023
+ if (trimmed.startsWith("~")) {
100024
+ return import_node_path5.default.join(import_node_os4.default.homedir(), trimmed.slice(1));
100025
+ }
100026
+ return import_node_path5.default.isAbsolute(trimmed) ? trimmed : null;
100027
+ }
100028
+ function buildLaunchdPath(nodeExe, currentPath = process.env.PATH || "") {
100029
+ const brewPrefix = import_node_fs4.default.existsSync("/opt/homebrew/bin") ? "/opt/homebrew/bin" : "/usr/local/bin";
100030
+ const entries = [];
100031
+ const seen = /* @__PURE__ */ new Set();
100032
+ const addEntry = (value) => {
100033
+ if (!value) return;
100034
+ const normalized = normalizeLaunchdPathEntry(value);
100035
+ if (!normalized || seen.has(normalized)) return;
100036
+ seen.add(normalized);
100037
+ entries.push(normalized);
100038
+ };
100039
+ addEntry(import_node_path5.default.dirname(nodeExe));
100040
+ for (const entry of String(currentPath || "").split(import_node_path5.default.delimiter)) {
100041
+ addEntry(entry);
100042
+ }
100043
+ for (const entry of [brewPrefix, "/usr/local/bin", "/usr/bin", "/bin", "/usr/sbin", "/sbin"]) {
100044
+ addEntry(entry);
100045
+ }
100046
+ return entries.join(":");
100047
+ }
100048
+ function buildPlist(nodeExe, cliExe, currentPath = process.env.PATH || "") {
100049
+ const pathValue = buildLaunchdPath(nodeExe, currentPath);
100050
+ return `<?xml version="1.0" encoding="UTF-8"?>
100051
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
100052
+ <plist version="1.0">
100053
+ <dict>
100054
+ <key>Label</key>
100055
+ <string>${LAUNCHD_LABEL}</string>
100056
+ <key>ProgramArguments</key>
100057
+ <array>
100058
+ <string>${nodeExe}</string>
100059
+ <string>${cliExe}</string>
100060
+ <string>daemon</string>
100061
+ </array>
100062
+ <key>RunAtLoad</key>
100063
+ <true/>
100064
+ <key>KeepAlive</key>
100065
+ <dict>
100066
+ <key>SuccessfulExit</key>
100067
+ <false/>
100068
+ </dict>
100069
+ <key>ThrottleInterval</key>
100070
+ <integer>30</integer>
100071
+ <key>StandardOutPath</key>
100072
+ <string>${LOG_OUT}</string>
100073
+ <key>StandardErrorPath</key>
100074
+ <string>${LOG_ERR}</string>
100075
+ <key>EnvironmentVariables</key>
100076
+ <dict>
100077
+ <key>PATH</key>
100078
+ <string>${pathValue}</string>
100079
+ </dict>
100080
+ </dict>
100081
+ </plist>`;
100082
+ }
100083
+ function installDarwin(nodeExe, cliExe) {
100084
+ const plistPath = getDarwinPlistPath();
100085
+ ensureDir(ADHDEV_DIR);
100086
+ ensureDir(import_node_path5.default.dirname(plistPath));
100087
+ import_node_fs4.default.writeFileSync(plistPath, buildPlist(nodeExe, cliExe), "utf-8");
100088
+ console.log(source_default.gray(` Plist: ${plistPath}`));
100089
+ try {
100090
+ (0, import_node_child_process4.execSync)(`launchctl unload "${plistPath}" 2>/dev/null`, { stdio: "ignore" });
100091
+ } catch {
100092
+ }
100093
+ try {
100094
+ (0, import_node_child_process4.execSync)(`launchctl load -w "${plistPath}"`, { stdio: "ignore" });
100095
+ console.log(source_default.green("\n \u2713 Registered as LaunchAgent \u2014 daemon will start on login."));
100096
+ console.log(source_default.gray(` Logs: ~/.adhdev/daemon-launchd.{out,err}`));
100097
+ } catch (e) {
100098
+ console.log(source_default.red(`
100099
+ \u2717 launchctl load failed: ${e.message}`));
100100
+ }
100101
+ }
100102
+ function uninstallDarwin() {
100103
+ const plistPath = getDarwinPlistPath();
100104
+ if (!import_node_fs4.default.existsSync(plistPath)) {
100105
+ console.log(source_default.yellow("\n \u26A0 Service is not installed."));
100106
+ return;
100107
+ }
100108
+ try {
100109
+ (0, import_node_child_process4.execSync)(`launchctl unload "${plistPath}" 2>/dev/null`, { stdio: "ignore" });
100110
+ } catch {
100111
+ }
100112
+ import_node_fs4.default.unlinkSync(plistPath);
100113
+ console.log(source_default.green("\n \u2713 Removed LaunchAgent. Daemon will no longer auto-start."));
100114
+ }
100115
+ function isInstalledDarwin() {
100116
+ return import_node_fs4.default.existsSync(getDarwinPlistPath());
100117
+ }
100118
+ function buildVbs(nodeExe, cliExe) {
100119
+ const logFile = import_node_path5.default.join(ADHDEV_DIR, "daemon-service.log").replace(/\\/g, "\\\\");
100120
+ const escapedNodeExe = nodeExe.replace(/\\/g, "\\\\");
100121
+ const escapedCliExe = cliExe.replace(/\\/g, "\\\\");
100122
+ return `' ADHDev Daemon Auto-Start (generated by adhdev service install)
100123
+ Set WshShell = CreateObject("WScript.Shell")
100124
+ WshShell.Run "cmd.exe /c """"${escapedNodeExe}"""" """"${escapedCliExe}"""" daemon >> """"${logFile}"""" 2>&1", 0, False
100125
+ `;
100126
+ }
100127
+ function installWindows(nodeExe, cliExe) {
100128
+ const vbsPath = getWindowsVbsPath();
100129
+ ensureDir(ADHDEV_DIR);
100130
+ ensureDir(import_node_path5.default.dirname(vbsPath));
100131
+ import_node_fs4.default.writeFileSync(vbsPath, buildVbs(nodeExe, cliExe), "utf-8");
100132
+ console.log(source_default.gray(` Startup script: ${vbsPath}`));
100133
+ console.log(source_default.green("\n \u2713 Registered in Startup folder \u2014 daemon will start on login (hidden)."));
100134
+ console.log(source_default.gray(` Logs: ${import_node_path5.default.join(ADHDEV_DIR, "daemon-service.log")}`));
100135
+ console.log(source_default.gray(" To start now without rebooting, run: adhdev daemon"));
100136
+ }
100137
+ function uninstallWindows() {
100138
+ const vbsPath = getWindowsVbsPath();
100139
+ if (!import_node_fs4.default.existsSync(vbsPath)) {
100140
+ console.log(source_default.yellow("\n \u26A0 Service is not installed."));
100141
+ return;
100142
+ }
100143
+ import_node_fs4.default.unlinkSync(vbsPath);
100144
+ console.log(source_default.green("\n \u2713 Removed Startup script. Daemon will no longer auto-start."));
100145
+ console.log(source_default.gray(" Note: a currently running daemon is not affected. Stop with: adhdev daemon:stop"));
100146
+ }
100147
+ function isInstalledWindows() {
100148
+ return import_node_fs4.default.existsSync(getWindowsVbsPath());
100149
+ }
100150
+ function isAutoStartServiceInstalled(platform12 = import_node_os4.default.platform()) {
100151
+ if (platform12 === "darwin") return isInstalledDarwin();
100152
+ if (platform12 === "win32") return isInstalledWindows();
100153
+ return false;
100154
+ }
100155
+ function installAutoStartServiceForCurrentProcess(platform12 = import_node_os4.default.platform()) {
100156
+ const nodeExe = process.execPath;
100157
+ const cliExe = resolveCliPath();
100158
+ if (platform12 === "darwin") {
100159
+ installDarwin(nodeExe, cliExe);
100160
+ return true;
100161
+ }
100162
+ if (platform12 === "win32") {
100163
+ installWindows(nodeExe, cliExe);
100164
+ return true;
100165
+ }
100166
+ return false;
100167
+ }
100168
+ function registerServiceCommands(program2) {
100169
+ const svc = program2.command("service").description("\u{1F50C} Manage ADHDev as an OS background auto-start service");
100170
+ svc.command("install").description("Register ADHDev daemon to start automatically on login").action(async () => {
100171
+ console.log(source_default.bold("\n \u{1F680} Installing ADHDev Background Service"));
100172
+ const platform12 = import_node_os4.default.platform();
100173
+ const nodeExe = process.execPath;
100174
+ const cliExe = resolveCliPath();
100175
+ console.log(source_default.gray(` Node: ${nodeExe}`));
100176
+ console.log(source_default.gray(` CLI: ${cliExe}`));
100177
+ console.log(source_default.gray(` Platform: ${platform12}`));
100178
+ if (!installAutoStartServiceForCurrentProcess(platform12)) {
100179
+ console.log(source_default.yellow("\n \u26A0 Auto-start service install is not supported on this platform."));
100180
+ console.log(source_default.gray(" On Linux, create a systemd user unit manually:"));
100181
+ console.log(source_default.gray(" ~/.config/systemd/user/adhdev-daemon.service"));
100182
+ }
100183
+ console.log();
100184
+ });
100185
+ svc.command("uninstall").description("Remove the OS background service").action(async () => {
100186
+ console.log(source_default.bold("\n \u{1F5D1}\uFE0F Removing ADHDev Background Service"));
100187
+ const platform12 = import_node_os4.default.platform();
100188
+ if (platform12 === "darwin") {
100189
+ uninstallDarwin();
100190
+ } else if (platform12 === "win32") {
100191
+ uninstallWindows();
100192
+ } else {
100193
+ console.log(source_default.yellow("\n \u26A0 Not supported on this platform."));
100194
+ }
100195
+ console.log();
100196
+ });
100197
+ svc.command("status").description("Show service installation state and live daemon health").action(async () => {
100198
+ const platform12 = import_node_os4.default.platform();
100199
+ const installed = isAutoStartServiceInstalled(platform12);
100200
+ if (installed) {
100201
+ console.log(source_default.green("\n \u2713 Service is installed."));
100202
+ if (platform12 === "darwin") console.log(source_default.gray(` Plist: ${getDarwinPlistPath()}`));
100203
+ else console.log(source_default.gray(` Script: ${getWindowsVbsPath()}`));
100204
+ } else {
100205
+ console.log(source_default.gray("\n \u2717 Service is not installed. Run: adhdev service install"));
100206
+ }
100207
+ const health = await fetchHealth();
100208
+ if (health?.ok && health.pid) {
100209
+ const info = getProcessInfo(health.pid);
100210
+ if (info) {
100211
+ console.log(source_default.green(` \u2713 Daemon running \u2014 PID ${health.pid}, uptime ${info.uptime}, ${info.memMB} MB`));
100212
+ } else {
100213
+ console.log(source_default.green(` \u2713 Daemon running \u2014 PID ${health.pid}`));
100214
+ }
100215
+ } else {
100216
+ console.log(source_default.yellow(" \u2717 Daemon is not running."));
100217
+ }
100218
+ const outSize = import_node_fs4.default.existsSync(LOG_OUT) ? import_node_fs4.default.statSync(LOG_OUT).size : 0;
100219
+ const errSize = import_node_fs4.default.existsSync(LOG_ERR) ? import_node_fs4.default.statSync(LOG_ERR).size : 0;
100220
+ if (outSize > 0 || errSize > 0) {
100221
+ console.log(source_default.gray(` Logs: stdout ${formatBytes(outSize)}, stderr ${formatBytes(errSize)}`));
100222
+ }
100223
+ console.log();
100224
+ });
100225
+ svc.command("logs").description("View daemon service logs").option("--err", "Show stderr log instead of stdout").option("--clear", "Truncate all log files").option("-n, --lines <count>", "Number of lines to show", "30").action(async (options) => {
100226
+ if (options.clear) {
100227
+ for (const f of [LOG_OUT, LOG_ERR]) {
100228
+ if (import_node_fs4.default.existsSync(f)) import_node_fs4.default.writeFileSync(f, "", "utf-8");
100229
+ }
100230
+ console.log(source_default.green("\n \u2713 Logs cleared.\n"));
100231
+ return;
100232
+ }
100233
+ const logFile = options.err ? LOG_ERR : LOG_OUT;
100234
+ if (!import_node_fs4.default.existsSync(logFile)) {
100235
+ console.log(source_default.gray(`
100236
+ No log file found: ${logFile}
100237
+ `));
100238
+ return;
100239
+ }
100240
+ const lines = parseInt(options.lines, 10) || 30;
100241
+ console.log(source_default.gray(`
100242
+ \u2500\u2500 ${options.err ? "stderr" : "stdout"}: ${logFile} (last ${lines} lines) \u2500\u2500
100243
+ `));
100244
+ const content = import_node_fs4.default.readFileSync(logFile, "utf-8");
100245
+ const allLines = content.split("\n");
100246
+ const lastLines = allLines.slice(-lines).join("\n");
100247
+ if (lastLines.trim()) console.log(lastLines);
100248
+ console.log(source_default.gray("\n (watching for new output, Ctrl+C to stop)\n"));
100249
+ let offset = Buffer.byteLength(content, "utf-8");
100250
+ const watcher = import_node_fs4.default.watchFile(logFile, { interval: 500 }, () => {
100251
+ try {
100252
+ const stat5 = import_node_fs4.default.statSync(logFile);
100253
+ if (stat5.size > offset) {
100254
+ const fd = import_node_fs4.default.openSync(logFile, "r");
100255
+ const buf = Buffer.alloc(stat5.size - offset);
100256
+ import_node_fs4.default.readSync(fd, buf, 0, buf.length, offset);
100257
+ import_node_fs4.default.closeSync(fd);
100258
+ process.stdout.write(buf.toString("utf-8"));
100259
+ offset = stat5.size;
100260
+ } else if (stat5.size < offset) {
100261
+ offset = 0;
100262
+ }
100263
+ } catch {
100264
+ }
100265
+ });
100266
+ const cleanup = () => {
100267
+ import_node_fs4.default.unwatchFile(logFile);
100268
+ process.exit(0);
100269
+ };
100270
+ process.on("SIGINT", cleanup);
100271
+ process.on("SIGTERM", cleanup);
100272
+ });
100273
+ svc.command("restart").description("Restart the daemon process (service will auto-relaunch)").action(async () => {
100274
+ const platform12 = import_node_os4.default.platform();
100275
+ const installed = isAutoStartServiceInstalled(platform12);
100276
+ if (!installed) {
100277
+ console.log(source_default.yellow("\n \u26A0 Service is not installed. Use `adhdev daemon:restart` for manual restart."));
100278
+ console.log(source_default.gray(" Or install the service first: adhdev service install\n"));
100279
+ return;
100280
+ }
100281
+ rotateLogs();
100282
+ if (platform12 === "darwin") {
100283
+ console.log(source_default.cyan("\n Refreshing LaunchAgent definition and reloading service..."));
100284
+ installAutoStartServiceForCurrentProcess(platform12);
100285
+ console.log();
100286
+ return;
100287
+ }
100288
+ const health = await fetchHealth();
100289
+ if (!health?.pid) {
100290
+ console.log(source_default.yellow("\n \u26A0 Daemon is not currently running."));
100291
+ console.log(source_default.gray(" Start with: adhdev daemon\n"));
100292
+ return;
100293
+ }
100294
+ console.log(source_default.cyan(`
100295
+ Stopping daemon (PID ${health.pid})...`));
100296
+ try {
100297
+ process.kill(health.pid, "SIGTERM");
100298
+ } catch {
100299
+ console.log(source_default.yellow(" Could not send SIGTERM. Process may have already exited."));
100300
+ }
100301
+ await new Promise((r) => setTimeout(r, 2e3));
100302
+ if (platform12 === "win32") {
100303
+ const vbsPath = getWindowsVbsPath();
100304
+ if (import_node_fs4.default.existsSync(vbsPath)) {
100305
+ try {
100306
+ (0, import_node_child_process4.execSync)(`wscript.exe "${vbsPath}"`, { stdio: "ignore", windowsHide: true });
100307
+ } catch {
100308
+ }
100309
+ }
100310
+ }
100311
+ let restarted = false;
100312
+ for (let i = 0; i < 8; i++) {
100313
+ await new Promise((r) => setTimeout(r, 1e3));
100314
+ const newHealth = await fetchHealth();
100315
+ if (newHealth?.ok && newHealth.pid !== health.pid) {
100316
+ restarted = true;
100317
+ const info = getProcessInfo(newHealth.pid);
100318
+ console.log(source_default.green(` \u2713 Daemon restarted \u2014 new PID ${newHealth.pid}${info ? `, ${info.memMB} MB` : ""}`));
100319
+ break;
100320
+ }
100321
+ }
100322
+ if (!restarted) {
100323
+ console.log(source_default.yellow(" \u26A0 Daemon did not restart within 10s."));
100324
+ console.log(source_default.gray(" Check: adhdev service logs --err"));
100325
+ }
100326
+ console.log();
100327
+ });
100328
+ }
100329
+ function formatBytes(bytes) {
100330
+ if (bytes === 0) return "0 B";
100331
+ if (bytes < 1024) return `${bytes} B`;
100332
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
100333
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
100334
+ }
100335
+ var import_node_fs4, import_node_path5, import_node_os4, import_node_child_process4, DEFAULT_LOCAL_DAEMON_HEALTH_TIMEOUT_MS2, LAUNCHD_LABEL, ADHDEV_DIR, LOG_OUT, LOG_ERR, MAX_LOG_SIZE2;
100336
+ var init_service_commands = __esm({
100337
+ "src/cli/service-commands.ts"() {
100338
+ "use strict";
100339
+ import_node_fs4 = __toESM(require("fs"));
100340
+ import_node_path5 = __toESM(require("path"));
100341
+ import_node_os4 = __toESM(require("os"));
100342
+ import_node_child_process4 = require("child_process");
100343
+ init_source();
100344
+ init_src();
100345
+ DEFAULT_LOCAL_DAEMON_HEALTH_TIMEOUT_MS2 = 1500;
100346
+ LAUNCHD_LABEL = "dev.adhf.daemon";
100347
+ ADHDEV_DIR = import_node_path5.default.join(import_node_os4.default.homedir(), ".adhdev");
100348
+ LOG_OUT = import_node_path5.default.join(ADHDEV_DIR, "daemon-launchd.out");
100349
+ LOG_ERR = import_node_path5.default.join(ADHDEV_DIR, "daemon-launchd.err");
100350
+ MAX_LOG_SIZE2 = 10 * 1024 * 1024;
100351
+ }
100352
+ });
100353
+
99520
100354
  // ../../oss/packages/web-core/src/constants/supported.ts
99521
100355
  var supported_exports = {};
99522
100356
  __export(supported_exports, {
@@ -101490,7 +102324,7 @@ function formatDebugTraceEntryLine(entry) {
101490
102324
  }
101491
102325
 
101492
102326
  // src/cli/daemon-commands.ts
101493
- var DEFAULT_LOCAL_DAEMON_HEALTH_TIMEOUT_MS2 = 1500;
102327
+ var DEFAULT_LOCAL_DAEMON_HEALTH_TIMEOUT_MS3 = 1500;
101494
102328
  var DEFAULT_TRACE_FOLLOW_INTERVAL_MS = 1500;
101495
102329
  var DEFAULT_DAEMON_PORT_TEXT = String(DEFAULT_DAEMON_PORT);
101496
102330
  var DEV_SERVER_PORT2 = 19280;
@@ -101518,6 +102352,15 @@ async function resolveConfiguredUpdateChannel() {
101518
102352
  function releaseChannelLabel(channel) {
101519
102353
  return `${channel} (${CHANNEL_NPM_TAG3[channel]})`;
101520
102354
  }
102355
+ function buildDaemonRestartCommandArgv(options = {}) {
102356
+ const cliPath = options.cliPath || process.argv[1];
102357
+ const daemonPort = options.daemonPort || DEFAULT_DAEMON_PORT_TEXT;
102358
+ const platform12 = options.platform || process.platform;
102359
+ if (platform12 === "darwin" && options.serviceInstalled) {
102360
+ return [cliPath, "service", "install"];
102361
+ }
102362
+ return [cliPath, "daemon", "-p", daemonPort];
102363
+ }
101521
102364
  async function persistReleaseChannel(channel) {
101522
102365
  const { updateConfig: updateConfig2 } = await Promise.resolve().then(() => (init_src(), src_exports));
101523
102366
  updateConfig2({ updateChannel: channel, serverUrl: CHANNEL_SERVER_URL3[channel] });
@@ -101528,7 +102371,7 @@ function hideCommand(command) {
101528
102371
  }
101529
102372
  async function fetchLocalDaemonHealth(port) {
101530
102373
  const controller = new AbortController();
101531
- const timer = setTimeout(() => controller.abort(), DEFAULT_LOCAL_DAEMON_HEALTH_TIMEOUT_MS2);
102374
+ const timer = setTimeout(() => controller.abort(), DEFAULT_LOCAL_DAEMON_HEALTH_TIMEOUT_MS3);
101532
102375
  try {
101533
102376
  const res = await fetch(`http://127.0.0.1:${port}/health`, { signal: controller.signal });
101534
102377
  if (!res.ok) return null;
@@ -101894,6 +102737,9 @@ async function runDaemonUpgrade(options, pkgVersion3) {
101894
102737
  } else {
101895
102738
  console.log(source_default.cyan(`
101896
102739
  Upgrading v${currentVersion} \u2192 v${latest}...`));
102740
+ const { isAutoStartServiceInstalled: isAutoStartServiceInstalled2 } = await Promise.resolve().then(() => (init_service_commands(), service_commands_exports));
102741
+ const serviceInstalled = isAutoStartServiceInstalled2();
102742
+ const shouldRefreshInstalledService = options.restart !== false && process.platform === "darwin" && serviceInstalled;
101897
102743
  const daemonWasRunning = options.restart !== false && isDaemonRunning2();
101898
102744
  if (daemonWasRunning) {
101899
102745
  stopDaemon2();
@@ -101905,10 +102751,22 @@ async function runDaemonUpgrade(options, pkgVersion3) {
101905
102751
  packageName: "adhdev",
101906
102752
  targetVersion: latest,
101907
102753
  parentPid: process.pid,
101908
- restartArgv: daemonWasRunning ? [process.argv[1], "daemon", "-p", DEFAULT_DAEMON_PORT_TEXT] : [],
102754
+ restartArgv: shouldRefreshInstalledService ? buildDaemonRestartCommandArgv({
102755
+ cliPath: process.argv[1],
102756
+ daemonPort: DEFAULT_DAEMON_PORT_TEXT,
102757
+ platform: process.platform,
102758
+ serviceInstalled
102759
+ }) : daemonWasRunning ? buildDaemonRestartCommandArgv({
102760
+ cliPath: process.argv[1],
102761
+ daemonPort: DEFAULT_DAEMON_PORT_TEXT,
102762
+ platform: process.platform,
102763
+ serviceInstalled
102764
+ }) : [],
101909
102765
  cwd: process.cwd()
101910
102766
  });
101911
- if (daemonWasRunning) {
102767
+ if (shouldRefreshInstalledService) {
102768
+ console.log(source_default.cyan(" Upgrading and refreshing background service in background..."));
102769
+ } else if (daemonWasRunning) {
101912
102770
  console.log(source_default.cyan(" Upgrading and restarting daemon in background..."));
101913
102771
  } else {
101914
102772
  console.log(source_default.cyan(" Upgrading in background..."));
@@ -101920,29 +102778,44 @@ async function runDaemonUpgrade(options, pkgVersion3) {
101920
102778
  return;
101921
102779
  }
101922
102780
  }
101923
- if (options.restart !== false && isDaemonRunning2()) {
101924
- console.log(source_default.yellow("\n Restarting daemon..."));
101925
- stopDaemon2();
101926
- await new Promise((r) => setTimeout(r, 2e3));
101927
- stopManagedSessionHostProcess2();
101928
- await new Promise((r) => setTimeout(r, 500));
101929
- const child = spawn7(process.execPath, [process.argv[1], "daemon", "-p", DEFAULT_DAEMON_PORT_TEXT], {
101930
- detached: true,
101931
- stdio: "ignore",
101932
- windowsHide: true,
101933
- env: { ...process.env }
101934
- });
101935
- child.unref();
101936
- await new Promise((r) => setTimeout(r, 3e3));
102781
+ if (options.restart !== false) {
102782
+ const { installAutoStartServiceForCurrentProcess: installAutoStartServiceForCurrentProcess2, isAutoStartServiceInstalled: isAutoStartServiceInstalled2 } = await Promise.resolve().then(() => (init_service_commands(), service_commands_exports));
102783
+ const serviceInstalled = isAutoStartServiceInstalled2();
102784
+ if (process.platform === "darwin" && serviceInstalled) {
102785
+ console.log(source_default.yellow("\n Refreshing LaunchAgent definition..."));
102786
+ installAutoStartServiceForCurrentProcess2(process.platform);
102787
+ console.log();
102788
+ return;
102789
+ }
101937
102790
  if (isDaemonRunning2()) {
101938
- console.log(source_default.green(` \u2713 Daemon restarted with new version
102791
+ console.log(source_default.yellow("\n Restarting daemon..."));
102792
+ stopDaemon2();
102793
+ await new Promise((r) => setTimeout(r, 2e3));
102794
+ stopManagedSessionHostProcess2();
102795
+ await new Promise((r) => setTimeout(r, 500));
102796
+ const child = spawn7(process.execPath, buildDaemonRestartCommandArgv({
102797
+ cliPath: process.argv[1],
102798
+ daemonPort: DEFAULT_DAEMON_PORT_TEXT,
102799
+ platform: process.platform,
102800
+ serviceInstalled
102801
+ }), {
102802
+ detached: true,
102803
+ stdio: "ignore",
102804
+ windowsHide: true,
102805
+ env: { ...process.env }
102806
+ });
102807
+ child.unref();
102808
+ await new Promise((r) => setTimeout(r, 3e3));
102809
+ if (isDaemonRunning2()) {
102810
+ console.log(source_default.green(` \u2713 Daemon restarted with new version
101939
102811
  `));
101940
- } else {
101941
- console.log(source_default.yellow(` \u26A0 Daemon not detected. Start manually: adhdev daemon
102812
+ } else {
102813
+ console.log(source_default.yellow(` \u26A0 Daemon not detected. Start manually: adhdev daemon
101942
102814
  `));
102815
+ }
102816
+ } else {
102817
+ console.log(source_default.gray("\n Daemon was not running. Start with: adhdev daemon\n"));
101943
102818
  }
101944
- } else if (options.restart !== false) {
101945
- console.log(source_default.gray("\n Daemon was not running. Start with: adhdev daemon\n"));
101946
102819
  } else {
101947
102820
  console.log(source_default.green("\n \u2713 Upgrade complete (daemon not restarted)\n"));
101948
102821
  }
@@ -102113,7 +102986,7 @@ function registerDaemonCommands(program2, pkgVersion3) {
102113
102986
  }
102114
102987
  try {
102115
102988
  const controller = new AbortController();
102116
- const timer = setTimeout(() => controller.abort(), DEFAULT_LOCAL_DAEMON_HEALTH_TIMEOUT_MS2);
102989
+ const timer = setTimeout(() => controller.abort(), DEFAULT_LOCAL_DAEMON_HEALTH_TIMEOUT_MS3);
102117
102990
  const res = await fetch(`${DEV_SERVER_BASE_URL}/api/status`, { signal: controller.signal });
102118
102991
  clearTimeout(timer);
102119
102992
  if (res.ok) {
@@ -102660,373 +103533,8 @@ function buildDoctorAdvice(input) {
102660
103533
  return advice;
102661
103534
  }
102662
103535
 
102663
- // src/cli/service-commands.ts
102664
- var import_node_fs4 = __toESM(require("fs"));
102665
- var import_node_path5 = __toESM(require("path"));
102666
- var import_node_os4 = __toESM(require("os"));
102667
- var import_node_child_process4 = require("child_process");
102668
- init_source();
102669
- init_src();
102670
- var DEFAULT_LOCAL_DAEMON_HEALTH_TIMEOUT_MS3 = 1500;
102671
- var LAUNCHD_LABEL = "dev.adhf.daemon";
102672
- var ADHDEV_DIR = import_node_path5.default.join(import_node_os4.default.homedir(), ".adhdev");
102673
- var LOG_OUT = import_node_path5.default.join(ADHDEV_DIR, "daemon-launchd.out");
102674
- var LOG_ERR = import_node_path5.default.join(ADHDEV_DIR, "daemon-launchd.err");
102675
- var MAX_LOG_SIZE2 = 10 * 1024 * 1024;
102676
- function getDarwinPlistPath() {
102677
- return import_node_path5.default.join(import_node_os4.default.homedir(), "Library", "LaunchAgents", `${LAUNCHD_LABEL}.plist`);
102678
- }
102679
- function getWindowsStartupDir() {
102680
- const appData = process.env.APPDATA || import_node_path5.default.join(import_node_os4.default.homedir(), "AppData", "Roaming");
102681
- return import_node_path5.default.join(appData, "Microsoft", "Windows", "Start Menu", "Programs", "Startup");
102682
- }
102683
- function getWindowsVbsPath() {
102684
- return import_node_path5.default.join(getWindowsStartupDir(), "adhdev-daemon.vbs");
102685
- }
102686
- function resolveCliPath() {
102687
- return import_node_fs4.default.realpathSync(process.argv[1]);
102688
- }
102689
- function ensureDir(dir) {
102690
- if (!import_node_fs4.default.existsSync(dir)) import_node_fs4.default.mkdirSync(dir, { recursive: true });
102691
- }
102692
- async function fetchHealth() {
102693
- const controller = new AbortController();
102694
- const timer = setTimeout(() => controller.abort(), DEFAULT_LOCAL_DAEMON_HEALTH_TIMEOUT_MS3);
102695
- try {
102696
- const res = await fetch(`http://127.0.0.1:${DEFAULT_DAEMON_PORT}/health`, { signal: controller.signal });
102697
- if (!res.ok) return null;
102698
- return await res.json();
102699
- } catch {
102700
- return null;
102701
- } finally {
102702
- clearTimeout(timer);
102703
- }
102704
- }
102705
- function getProcessInfo(pid) {
102706
- try {
102707
- if (process.platform === "win32") {
102708
- const out = (0, import_node_child_process4.execSync)(`tasklist /FI "PID eq ${pid}" /FO CSV /NH`, { encoding: "utf-8" });
102709
- const match = out.match(/"(\d[\d,]+)\sK"/);
102710
- const memKB = match ? parseInt(match[1].replace(/,/g, ""), 10) : 0;
102711
- return { uptime: "-", memMB: Math.round(memKB / 1024) };
102712
- } else {
102713
- const out = (0, import_node_child_process4.execSync)(`ps -o etime=,rss= -p ${pid}`, { encoding: "utf-8" }).trim();
102714
- const parts = out.split(/\s+/);
102715
- const etime = parts[0] || "-";
102716
- const rssKB = parseInt(parts[1] || "0", 10);
102717
- return { uptime: formatElapsed(etime), memMB: Math.round(rssKB / 1024) };
102718
- }
102719
- } catch {
102720
- return null;
102721
- }
102722
- }
102723
- function formatElapsed(etime) {
102724
- const parts = etime.replace("-", ":").split(":").map(Number);
102725
- if (parts.length === 4) return `${parts[0]}d ${parts[1]}h ${parts[2]}m`;
102726
- if (parts.length === 3) return `${parts[0]}h ${parts[1]}m`;
102727
- if (parts.length === 2) return `${parts[0]}m ${parts[1]}s`;
102728
- return etime;
102729
- }
102730
- function rotateLogIfNeeded(logPath) {
102731
- try {
102732
- if (!import_node_fs4.default.existsSync(logPath)) return;
102733
- const stat5 = import_node_fs4.default.statSync(logPath);
102734
- if (stat5.size > MAX_LOG_SIZE2) {
102735
- const rotated = logPath + ".old";
102736
- if (import_node_fs4.default.existsSync(rotated)) import_node_fs4.default.unlinkSync(rotated);
102737
- import_node_fs4.default.renameSync(logPath, rotated);
102738
- import_node_fs4.default.writeFileSync(logPath, `[log rotated at ${(/* @__PURE__ */ new Date()).toISOString()}]
102739
- `, "utf-8");
102740
- }
102741
- } catch {
102742
- }
102743
- }
102744
- function rotateLogs() {
102745
- rotateLogIfNeeded(LOG_OUT);
102746
- rotateLogIfNeeded(LOG_ERR);
102747
- }
102748
- function buildPlist(nodeExe, cliExe) {
102749
- const brewPrefix = import_node_fs4.default.existsSync("/opt/homebrew/bin") ? "/opt/homebrew/bin" : "/usr/local/bin";
102750
- const nodeDir = import_node_path5.default.dirname(nodeExe);
102751
- const pathEntries = /* @__PURE__ */ new Set([nodeDir, brewPrefix, "/usr/local/bin", "/usr/bin", "/bin", "/usr/sbin", "/sbin"]);
102752
- const pathValue = Array.from(pathEntries).join(":");
102753
- return `<?xml version="1.0" encoding="UTF-8"?>
102754
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
102755
- <plist version="1.0">
102756
- <dict>
102757
- <key>Label</key>
102758
- <string>${LAUNCHD_LABEL}</string>
102759
- <key>ProgramArguments</key>
102760
- <array>
102761
- <string>${nodeExe}</string>
102762
- <string>${cliExe}</string>
102763
- <string>daemon</string>
102764
- </array>
102765
- <key>RunAtLoad</key>
102766
- <true/>
102767
- <key>KeepAlive</key>
102768
- <dict>
102769
- <key>SuccessfulExit</key>
102770
- <false/>
102771
- </dict>
102772
- <key>ThrottleInterval</key>
102773
- <integer>30</integer>
102774
- <key>StandardOutPath</key>
102775
- <string>${LOG_OUT}</string>
102776
- <key>StandardErrorPath</key>
102777
- <string>${LOG_ERR}</string>
102778
- <key>EnvironmentVariables</key>
102779
- <dict>
102780
- <key>PATH</key>
102781
- <string>${pathValue}</string>
102782
- </dict>
102783
- </dict>
102784
- </plist>`;
102785
- }
102786
- function installDarwin(nodeExe, cliExe) {
102787
- const plistPath = getDarwinPlistPath();
102788
- ensureDir(ADHDEV_DIR);
102789
- ensureDir(import_node_path5.default.dirname(plistPath));
102790
- import_node_fs4.default.writeFileSync(plistPath, buildPlist(nodeExe, cliExe), "utf-8");
102791
- console.log(source_default.gray(` Plist: ${plistPath}`));
102792
- try {
102793
- (0, import_node_child_process4.execSync)(`launchctl unload "${plistPath}" 2>/dev/null`, { stdio: "ignore" });
102794
- } catch {
102795
- }
102796
- try {
102797
- (0, import_node_child_process4.execSync)(`launchctl load -w "${plistPath}"`, { stdio: "ignore" });
102798
- console.log(source_default.green("\n \u2713 Registered as LaunchAgent \u2014 daemon will start on login."));
102799
- console.log(source_default.gray(` Logs: ~/.adhdev/daemon-launchd.{out,err}`));
102800
- } catch (e) {
102801
- console.log(source_default.red(`
102802
- \u2717 launchctl load failed: ${e.message}`));
102803
- }
102804
- }
102805
- function uninstallDarwin() {
102806
- const plistPath = getDarwinPlistPath();
102807
- if (!import_node_fs4.default.existsSync(plistPath)) {
102808
- console.log(source_default.yellow("\n \u26A0 Service is not installed."));
102809
- return;
102810
- }
102811
- try {
102812
- (0, import_node_child_process4.execSync)(`launchctl unload "${plistPath}" 2>/dev/null`, { stdio: "ignore" });
102813
- } catch {
102814
- }
102815
- import_node_fs4.default.unlinkSync(plistPath);
102816
- console.log(source_default.green("\n \u2713 Removed LaunchAgent. Daemon will no longer auto-start."));
102817
- }
102818
- function isInstalledDarwin() {
102819
- return import_node_fs4.default.existsSync(getDarwinPlistPath());
102820
- }
102821
- function buildVbs(nodeExe, cliExe) {
102822
- const logFile = import_node_path5.default.join(ADHDEV_DIR, "daemon-service.log").replace(/\\/g, "\\\\");
102823
- const escapedNodeExe = nodeExe.replace(/\\/g, "\\\\");
102824
- const escapedCliExe = cliExe.replace(/\\/g, "\\\\");
102825
- return `' ADHDev Daemon Auto-Start (generated by adhdev service install)
102826
- Set WshShell = CreateObject("WScript.Shell")
102827
- WshShell.Run "cmd.exe /c """"${escapedNodeExe}"""" """"${escapedCliExe}"""" daemon >> """"${logFile}"""" 2>&1", 0, False
102828
- `;
102829
- }
102830
- function installWindows(nodeExe, cliExe) {
102831
- const vbsPath = getWindowsVbsPath();
102832
- ensureDir(ADHDEV_DIR);
102833
- ensureDir(import_node_path5.default.dirname(vbsPath));
102834
- import_node_fs4.default.writeFileSync(vbsPath, buildVbs(nodeExe, cliExe), "utf-8");
102835
- console.log(source_default.gray(` Startup script: ${vbsPath}`));
102836
- console.log(source_default.green("\n \u2713 Registered in Startup folder \u2014 daemon will start on login (hidden)."));
102837
- console.log(source_default.gray(` Logs: ${import_node_path5.default.join(ADHDEV_DIR, "daemon-service.log")}`));
102838
- console.log(source_default.gray(" To start now without rebooting, run: adhdev daemon"));
102839
- }
102840
- function uninstallWindows() {
102841
- const vbsPath = getWindowsVbsPath();
102842
- if (!import_node_fs4.default.existsSync(vbsPath)) {
102843
- console.log(source_default.yellow("\n \u26A0 Service is not installed."));
102844
- return;
102845
- }
102846
- import_node_fs4.default.unlinkSync(vbsPath);
102847
- console.log(source_default.green("\n \u2713 Removed Startup script. Daemon will no longer auto-start."));
102848
- console.log(source_default.gray(" Note: a currently running daemon is not affected. Stop with: adhdev daemon:stop"));
102849
- }
102850
- function isInstalledWindows() {
102851
- return import_node_fs4.default.existsSync(getWindowsVbsPath());
102852
- }
102853
- function registerServiceCommands(program2) {
102854
- const svc = program2.command("service").description("\u{1F50C} Manage ADHDev as an OS background auto-start service");
102855
- svc.command("install").description("Register ADHDev daemon to start automatically on login").action(async () => {
102856
- console.log(source_default.bold("\n \u{1F680} Installing ADHDev Background Service"));
102857
- const platform12 = import_node_os4.default.platform();
102858
- const nodeExe = process.execPath;
102859
- const cliExe = resolveCliPath();
102860
- console.log(source_default.gray(` Node: ${nodeExe}`));
102861
- console.log(source_default.gray(` CLI: ${cliExe}`));
102862
- console.log(source_default.gray(` Platform: ${platform12}`));
102863
- if (platform12 === "darwin") {
102864
- installDarwin(nodeExe, cliExe);
102865
- } else if (platform12 === "win32") {
102866
- installWindows(nodeExe, cliExe);
102867
- } else {
102868
- console.log(source_default.yellow("\n \u26A0 Auto-start service install is not supported on this platform."));
102869
- console.log(source_default.gray(" On Linux, create a systemd user unit manually:"));
102870
- console.log(source_default.gray(" ~/.config/systemd/user/adhdev-daemon.service"));
102871
- }
102872
- console.log();
102873
- });
102874
- svc.command("uninstall").description("Remove the OS background service").action(async () => {
102875
- console.log(source_default.bold("\n \u{1F5D1}\uFE0F Removing ADHDev Background Service"));
102876
- const platform12 = import_node_os4.default.platform();
102877
- if (platform12 === "darwin") {
102878
- uninstallDarwin();
102879
- } else if (platform12 === "win32") {
102880
- uninstallWindows();
102881
- } else {
102882
- console.log(source_default.yellow("\n \u26A0 Not supported on this platform."));
102883
- }
102884
- console.log();
102885
- });
102886
- svc.command("status").description("Show service installation state and live daemon health").action(async () => {
102887
- const platform12 = import_node_os4.default.platform();
102888
- const installed = platform12 === "darwin" ? isInstalledDarwin() : platform12 === "win32" ? isInstalledWindows() : false;
102889
- if (installed) {
102890
- console.log(source_default.green("\n \u2713 Service is installed."));
102891
- if (platform12 === "darwin") console.log(source_default.gray(` Plist: ${getDarwinPlistPath()}`));
102892
- else console.log(source_default.gray(` Script: ${getWindowsVbsPath()}`));
102893
- } else {
102894
- console.log(source_default.gray("\n \u2717 Service is not installed. Run: adhdev service install"));
102895
- }
102896
- const health = await fetchHealth();
102897
- if (health?.ok && health.pid) {
102898
- const info = getProcessInfo(health.pid);
102899
- if (info) {
102900
- console.log(source_default.green(` \u2713 Daemon running \u2014 PID ${health.pid}, uptime ${info.uptime}, ${info.memMB} MB`));
102901
- } else {
102902
- console.log(source_default.green(` \u2713 Daemon running \u2014 PID ${health.pid}`));
102903
- }
102904
- } else {
102905
- console.log(source_default.yellow(" \u2717 Daemon is not running."));
102906
- }
102907
- const outSize = import_node_fs4.default.existsSync(LOG_OUT) ? import_node_fs4.default.statSync(LOG_OUT).size : 0;
102908
- const errSize = import_node_fs4.default.existsSync(LOG_ERR) ? import_node_fs4.default.statSync(LOG_ERR).size : 0;
102909
- if (outSize > 0 || errSize > 0) {
102910
- console.log(source_default.gray(` Logs: stdout ${formatBytes(outSize)}, stderr ${formatBytes(errSize)}`));
102911
- }
102912
- console.log();
102913
- });
102914
- svc.command("logs").description("View daemon service logs").option("--err", "Show stderr log instead of stdout").option("--clear", "Truncate all log files").option("-n, --lines <count>", "Number of lines to show", "30").action(async (options) => {
102915
- if (options.clear) {
102916
- for (const f of [LOG_OUT, LOG_ERR]) {
102917
- if (import_node_fs4.default.existsSync(f)) import_node_fs4.default.writeFileSync(f, "", "utf-8");
102918
- }
102919
- console.log(source_default.green("\n \u2713 Logs cleared.\n"));
102920
- return;
102921
- }
102922
- const logFile = options.err ? LOG_ERR : LOG_OUT;
102923
- if (!import_node_fs4.default.existsSync(logFile)) {
102924
- console.log(source_default.gray(`
102925
- No log file found: ${logFile}
102926
- `));
102927
- return;
102928
- }
102929
- const lines = parseInt(options.lines, 10) || 30;
102930
- console.log(source_default.gray(`
102931
- \u2500\u2500 ${options.err ? "stderr" : "stdout"}: ${logFile} (last ${lines} lines) \u2500\u2500
102932
- `));
102933
- const content = import_node_fs4.default.readFileSync(logFile, "utf-8");
102934
- const allLines = content.split("\n");
102935
- const lastLines = allLines.slice(-lines).join("\n");
102936
- if (lastLines.trim()) console.log(lastLines);
102937
- console.log(source_default.gray("\n (watching for new output, Ctrl+C to stop)\n"));
102938
- let offset = Buffer.byteLength(content, "utf-8");
102939
- const watcher = import_node_fs4.default.watchFile(logFile, { interval: 500 }, () => {
102940
- try {
102941
- const stat5 = import_node_fs4.default.statSync(logFile);
102942
- if (stat5.size > offset) {
102943
- const fd = import_node_fs4.default.openSync(logFile, "r");
102944
- const buf = Buffer.alloc(stat5.size - offset);
102945
- import_node_fs4.default.readSync(fd, buf, 0, buf.length, offset);
102946
- import_node_fs4.default.closeSync(fd);
102947
- process.stdout.write(buf.toString("utf-8"));
102948
- offset = stat5.size;
102949
- } else if (stat5.size < offset) {
102950
- offset = 0;
102951
- }
102952
- } catch {
102953
- }
102954
- });
102955
- const cleanup = () => {
102956
- import_node_fs4.default.unwatchFile(logFile);
102957
- process.exit(0);
102958
- };
102959
- process.on("SIGINT", cleanup);
102960
- process.on("SIGTERM", cleanup);
102961
- });
102962
- svc.command("restart").description("Restart the daemon process (service will auto-relaunch)").action(async () => {
102963
- const platform12 = import_node_os4.default.platform();
102964
- const installed = platform12 === "darwin" ? isInstalledDarwin() : platform12 === "win32" ? isInstalledWindows() : false;
102965
- if (!installed) {
102966
- console.log(source_default.yellow("\n \u26A0 Service is not installed. Use `adhdev daemon:restart` for manual restart."));
102967
- console.log(source_default.gray(" Or install the service first: adhdev service install\n"));
102968
- return;
102969
- }
102970
- rotateLogs();
102971
- const health = await fetchHealth();
102972
- if (!health?.pid) {
102973
- console.log(source_default.yellow("\n \u26A0 Daemon is not currently running."));
102974
- if (platform12 === "darwin") {
102975
- console.log(source_default.gray(" Starting via launchctl..."));
102976
- try {
102977
- (0, import_node_child_process4.execSync)(`launchctl start ${LAUNCHD_LABEL}`, { stdio: "ignore" });
102978
- console.log(source_default.green(" \u2713 Started.\n"));
102979
- } catch {
102980
- console.log(source_default.red(" \u2717 Failed to start. Check: adhdev service logs --err\n"));
102981
- }
102982
- } else {
102983
- console.log(source_default.gray(" Start with: adhdev daemon\n"));
102984
- }
102985
- return;
102986
- }
102987
- console.log(source_default.cyan(`
102988
- Stopping daemon (PID ${health.pid})...`));
102989
- try {
102990
- process.kill(health.pid, "SIGTERM");
102991
- } catch {
102992
- console.log(source_default.yellow(" Could not send SIGTERM. Process may have already exited."));
102993
- }
102994
- await new Promise((r) => setTimeout(r, 2e3));
102995
- if (platform12 === "win32") {
102996
- const vbsPath = getWindowsVbsPath();
102997
- if (import_node_fs4.default.existsSync(vbsPath)) {
102998
- try {
102999
- (0, import_node_child_process4.execSync)(`wscript.exe "${vbsPath}"`, { stdio: "ignore", windowsHide: true });
103000
- } catch {
103001
- }
103002
- }
103003
- }
103004
- let restarted = false;
103005
- for (let i = 0; i < 8; i++) {
103006
- await new Promise((r) => setTimeout(r, 1e3));
103007
- const newHealth = await fetchHealth();
103008
- if (newHealth?.ok && newHealth.pid !== health.pid) {
103009
- restarted = true;
103010
- const info = getProcessInfo(newHealth.pid);
103011
- console.log(source_default.green(` \u2713 Daemon restarted \u2014 new PID ${newHealth.pid}${info ? `, ${info.memMB} MB` : ""}`));
103012
- break;
103013
- }
103014
- }
103015
- if (!restarted) {
103016
- console.log(source_default.yellow(" \u26A0 Daemon did not restart within 10s."));
103017
- console.log(source_default.gray(" Check: adhdev service logs --err"));
103018
- }
103019
- console.log();
103020
- });
103021
- }
103022
- function formatBytes(bytes) {
103023
- if (bytes === 0) return "0 B";
103024
- if (bytes < 1024) return `${bytes} B`;
103025
- if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
103026
- return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
103027
- }
103028
-
103029
103536
  // src/cli/doctor-commands.ts
103537
+ init_service_commands();
103030
103538
  function resolvePackageRoot() {
103031
103539
  return path39.resolve(__dirname, "..", "..");
103032
103540
  }
@@ -104518,6 +105026,9 @@ function registerCdpCommands(program2) {
104518
105026
  });
104519
105027
  }
104520
105028
 
105029
+ // src/cli/index.ts
105030
+ init_service_commands();
105031
+
104521
105032
  // src/cli/mcp-commands.ts
104522
105033
  var import_node_child_process5 = require("child_process");
104523
105034
  var fs23 = __toESM(require("fs"));