@adhdev/daemon-core 0.9.82-rc.7 → 0.9.82-rc.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -5676,8 +5676,14 @@ async function getGitRepoStatus(workspace, options = {}) {
5676
5676
  const includeSubmodules = options.includeSubmodules !== false;
5677
5677
  try {
5678
5678
  const repo = await resolveGitRepository(workspace, options);
5679
- const statusOutput = await runGit(repo, ["status", "--porcelain=v2", "--branch"], options);
5680
- const parsed = parsePorcelainV2Status(statusOutput.stdout);
5679
+ let parsed = await readPorcelainStatus(repo, options);
5680
+ let upstreamProbe = getInitialUpstreamProbe(parsed);
5681
+ if (options.refreshUpstream) {
5682
+ upstreamProbe = await refreshTrackedUpstream(repo, parsed, options);
5683
+ if (upstreamProbe.upstreamStatus === "fresh") {
5684
+ parsed = await readPorcelainStatus(repo, options);
5685
+ }
5686
+ }
5681
5687
  const head = await readHead(repo, options);
5682
5688
  const stashCount = await readStashCount(repo, options);
5683
5689
  let submodules;
@@ -5692,6 +5698,9 @@ async function getGitRepoStatus(workspace, options = {}) {
5692
5698
  headCommit: head.commit,
5693
5699
  headMessage: head.message,
5694
5700
  upstream: parsed.upstream,
5701
+ upstreamStatus: parsed.upstream ? upstreamProbe.upstreamStatus : "no_upstream",
5702
+ upstreamFetchedAt: upstreamProbe.upstreamFetchedAt,
5703
+ upstreamFetchError: upstreamProbe.upstreamFetchError,
5695
5704
  ahead: parsed.ahead,
5696
5705
  behind: parsed.behind,
5697
5706
  staged: parsed.staged,
@@ -5716,6 +5725,60 @@ async function getGitRepoStatus(workspace, options = {}) {
5716
5725
  );
5717
5726
  }
5718
5727
  }
5728
+ async function readPorcelainStatus(repo, options) {
5729
+ const statusOutput = await runGit(repo, ["status", "--porcelain=v2", "--branch"], options);
5730
+ return parsePorcelainV2Status(statusOutput.stdout);
5731
+ }
5732
+ function getInitialUpstreamProbe(parsed) {
5733
+ return {
5734
+ upstreamStatus: parsed.upstream ? "unchecked" : "no_upstream"
5735
+ };
5736
+ }
5737
+ async function refreshTrackedUpstream(repo, parsed, options) {
5738
+ if (!parsed.upstream || !parsed.branch) {
5739
+ return { upstreamStatus: "no_upstream" };
5740
+ }
5741
+ const remoteName = await readBranchRemote(repo, parsed.branch, options) ?? inferRemoteName(parsed.upstream);
5742
+ if (!remoteName) {
5743
+ return {
5744
+ upstreamStatus: "stale",
5745
+ upstreamFetchError: `Unable to resolve remote for upstream '${parsed.upstream}'`
5746
+ };
5747
+ }
5748
+ try {
5749
+ await runGit(repo, ["fetch", "--quiet", "--prune", "--no-tags", remoteName], options);
5750
+ return {
5751
+ upstreamStatus: "fresh",
5752
+ upstreamFetchedAt: Date.now()
5753
+ };
5754
+ } catch (error) {
5755
+ return {
5756
+ upstreamStatus: "stale",
5757
+ upstreamFetchError: formatGitError(error)
5758
+ };
5759
+ }
5760
+ }
5761
+ async function readBranchRemote(repo, branch, options) {
5762
+ try {
5763
+ const result = await runGit(repo, ["config", "--get", `branch.${branch}.remote`], options);
5764
+ return result.stdout.trim() || null;
5765
+ } catch {
5766
+ return null;
5767
+ }
5768
+ }
5769
+ function inferRemoteName(upstream) {
5770
+ const [remoteName] = upstream.split("/");
5771
+ return remoteName?.trim() || null;
5772
+ }
5773
+ function formatGitError(error) {
5774
+ if (error instanceof GitCommandError) {
5775
+ return error.stderr || error.message;
5776
+ }
5777
+ if (error instanceof Error) {
5778
+ return error.message;
5779
+ }
5780
+ return String(error);
5781
+ }
5719
5782
  function parsePorcelainV2Status(output) {
5720
5783
  const parsed = {
5721
5784
  branch: null,
@@ -5810,6 +5873,7 @@ function emptyStatus(workspace, lastCheckedAt, error) {
5810
5873
  headCommit: null,
5811
5874
  headMessage: null,
5812
5875
  upstream: null,
5876
+ upstreamStatus: "unavailable",
5813
5877
  ahead: 0,
5814
5878
  behind: 0,
5815
5879
  staged: 0,
@@ -6090,6 +6154,9 @@ function createGitCompactSummary(status, diffSummary) {
6090
6154
  isGitRepo: status.isGitRepo,
6091
6155
  repoRoot: status.repoRoot,
6092
6156
  branch: status.branch,
6157
+ upstreamStatus: status.upstreamStatus,
6158
+ upstreamFetchedAt: status.upstreamFetchedAt,
6159
+ upstreamFetchError: status.upstreamFetchError,
6093
6160
  dirty: status.staged > 0 || status.modified > 0 || status.untracked > 0 || status.deleted > 0 || status.renamed > 0 || conflictCount > 0 || changedFiles > 0,
6094
6161
  changedFiles,
6095
6162
  ahead: status.ahead,
@@ -6434,7 +6501,7 @@ var defaultSnapshotStore = createGitSnapshotStore({
6434
6501
  });
6435
6502
  function createDefaultGitCommandServices() {
6436
6503
  return {
6437
- getStatus: ({ workspace }) => getGitRepoStatus(workspace),
6504
+ getStatus: ({ workspace, refreshUpstream }) => getGitRepoStatus(workspace, { refreshUpstream }),
6438
6505
  getDiffSummary: ({ workspace }) => getGitDiffSummary(workspace),
6439
6506
  getDiffFile: ({ workspace, path: filePath }) => getGitFileDiff(workspace, filePath),
6440
6507
  createSnapshot: ({ workspace, reason, sessionId, turnId }) => defaultSnapshotStore.create({
@@ -6520,7 +6587,7 @@ async function handleGitCommand(command, args, services = defaultGitCommandServi
6520
6587
  switch (command) {
6521
6588
  case "git_status": {
6522
6589
  if (!services.getStatus) return serviceNotImplemented(command);
6523
- const status = await runService(() => services.getStatus({ workspace }));
6590
+ const status = await runService(() => services.getStatus({ workspace, refreshUpstream: optionalBoolean(args?.refreshUpstream) }));
6524
6591
  return "success" in status ? status : { success: true, status };
6525
6592
  }
6526
6593
  case "git_diff_summary": {
@@ -23725,17 +23792,87 @@ function readCachedInlineMeshActiveSessions(node) {
23725
23792
  const sessionId = readStringValue(fallbackSession.id, fallbackSession.sessionId, fallbackSession.session_id, node?.activeSessionId, node?.active_session_id, node?.sessionId, node?.session_id);
23726
23793
  return sessionId ? [sessionId] : [];
23727
23794
  }
23795
+ function readCachedInlineMeshActiveSessionDetails(node) {
23796
+ const cachedStatus = readObjectRecord(node?.cachedStatus);
23797
+ const activeSession = readObjectRecord(cachedStatus.activeSession);
23798
+ const fallbackSession = Object.keys(activeSession).length ? activeSession : readObjectRecord(node?.activeSession ?? node?.active_session);
23799
+ const sessionId = readStringValue(
23800
+ fallbackSession.id,
23801
+ fallbackSession.sessionId,
23802
+ fallbackSession.session_id,
23803
+ node?.activeSessionId,
23804
+ node?.active_session_id,
23805
+ node?.sessionId,
23806
+ node?.session_id
23807
+ );
23808
+ if (!sessionId) return [];
23809
+ return [{
23810
+ sessionId,
23811
+ providerType: readStringValue(
23812
+ fallbackSession.providerType,
23813
+ fallbackSession.provider_type,
23814
+ fallbackSession.cliType,
23815
+ fallbackSession.cli_type,
23816
+ fallbackSession.provider,
23817
+ node?.providerType,
23818
+ node?.provider_type
23819
+ ),
23820
+ state: readStringValue(fallbackSession.status, fallbackSession.state, fallbackSession.lifecycle),
23821
+ lifecycle: readStringValue(fallbackSession.lifecycle),
23822
+ title: readStringValue(fallbackSession.title, fallbackSession.displayName, fallbackSession.display_name) ?? null,
23823
+ workspace: readStringValue(fallbackSession.workspace, node?.workspace) ?? null,
23824
+ lastActivityAt: readStringValue(fallbackSession.lastActivityAt, fallbackSession.last_activity_at) ?? null,
23825
+ recoveryState: readStringValue(fallbackSession.recoveryState, fallbackSession.recovery_state) ?? null,
23826
+ isCached: true
23827
+ }];
23828
+ }
23829
+ function readLiveMeshSessionState(record) {
23830
+ return readStringValue(
23831
+ record?.meta?.sessionStatus,
23832
+ record?.meta?.status,
23833
+ record?.meta?.providerStatus,
23834
+ record?.status,
23835
+ record?.state,
23836
+ record?.lifecycle
23837
+ );
23838
+ }
23839
+ function toIsoTimestamp(value) {
23840
+ if (typeof value === "number" && Number.isFinite(value)) return new Date(value).toISOString();
23841
+ const stringValue = readStringValue(value);
23842
+ return stringValue || null;
23843
+ }
23844
+ function summarizeMeshSessionRecord(record) {
23845
+ return {
23846
+ sessionId: readStringValue(record?.sessionId) || "unknown",
23847
+ providerType: readStringValue(record?.providerType),
23848
+ state: readLiveMeshSessionState(record),
23849
+ lifecycle: readStringValue(record?.lifecycle),
23850
+ surfaceKind: getSessionHostSurfaceKind(record),
23851
+ recoveryState: readStringValue(record?.meta?.runtimeRecoveryState) ?? null,
23852
+ workspace: readStringValue(record?.workspace) ?? null,
23853
+ title: readStringValue(record?.displayName, record?.workspaceLabel) ?? null,
23854
+ lastActivityAt: toIsoTimestamp(record?.updatedAt ?? record?.lastActivityAt ?? record?.last_activity_at),
23855
+ isCached: false
23856
+ };
23857
+ }
23728
23858
  function applyCachedInlineMeshNodeStatus(status, node) {
23729
23859
  const cachedStatus = readObjectRecord(node?.cachedStatus);
23730
23860
  const git = buildCachedInlineMeshGitStatus(node);
23731
23861
  const error = readStringValue(cachedStatus.error, node?.error);
23732
23862
  const health = readStringValue(cachedStatus.health, node?.health);
23733
23863
  const machineStatus = readStringValue(cachedStatus.machineStatus, node?.machineStatus);
23864
+ const lastSeenAt = toIsoTimestamp(cachedStatus.lastSeenAt ?? cachedStatus.last_seen_at ?? node?.lastSeenAt ?? node?.last_seen_at);
23865
+ const updatedAt = toIsoTimestamp(cachedStatus.updatedAt ?? cachedStatus.updated_at ?? node?.updatedAt ?? node?.updated_at);
23734
23866
  const activeSessions = readCachedInlineMeshActiveSessions(node);
23735
- if (!git && !error && !health && !machineStatus && activeSessions.length === 0) return false;
23867
+ const activeSessionDetails = readCachedInlineMeshActiveSessionDetails(node);
23868
+ if (!git && !error && !health && !machineStatus && !lastSeenAt && !updatedAt && activeSessions.length === 0) return false;
23736
23869
  if (git) status.git = git;
23737
23870
  if (error) status.error = error;
23871
+ if (machineStatus) status.machineStatus = machineStatus;
23872
+ if (lastSeenAt) status.lastSeenAt = lastSeenAt;
23873
+ if (updatedAt) status.updatedAt = updatedAt;
23738
23874
  if (activeSessions.length > 0) status.activeSessions = activeSessions;
23875
+ if (activeSessionDetails.length > 0) status.activeSessionDetails = activeSessionDetails;
23739
23876
  if (health) {
23740
23877
  status.health = health;
23741
23878
  return true;
@@ -23744,7 +23881,7 @@ function applyCachedInlineMeshNodeStatus(status, node) {
23744
23881
  status.health = deriveMeshNodeHealthFromGit(git);
23745
23882
  return true;
23746
23883
  }
23747
- return activeSessions.length > 0 || !!machineStatus;
23884
+ return activeSessions.length > 0 || !!machineStatus || !!lastSeenAt || !!updatedAt;
23748
23885
  }
23749
23886
  async function resolveProviderTypeFromPriority(args) {
23750
23887
  if (!args.providerPriority.length) {
@@ -25986,33 +26123,84 @@ ${block}`);
25986
26123
  const ledgerSummary = getLedgerSummary2(meshId);
25987
26124
  const sessionHostRecords = this.deps.sessionHostControl?.listSessions ? await this.deps.sessionHostControl.listSessions().catch(() => []) : [];
25988
26125
  const liveMeshSessions = partitionSessionHostRecords(Array.isArray(sessionHostRecords) ? sessionHostRecords : []).liveRuntimes;
26126
+ const localMachineId = loadConfig().machineId || "";
26127
+ const inlineCoordinatorNodeId = meshRecord?.inline && Array.isArray(mesh.nodes) ? readStringValue(mesh.nodes[0]?.id, mesh.nodes[0]?.nodeId) : void 0;
26128
+ const refreshedAt = (/* @__PURE__ */ new Date()).toISOString();
25989
26129
  const nodeStatuses = [];
25990
- for (const node of mesh.nodes || []) {
26130
+ for (const [nodeIndex, node] of (mesh.nodes || []).entries()) {
26131
+ const nodeId = String(node.id || node.nodeId || "");
26132
+ const daemonId = readStringValue(node.daemonId);
26133
+ const providerPriority = readProviderPriorityFromPolicy(node.policy);
26134
+ const isSelfNode = Boolean(
26135
+ nodeId && inlineCoordinatorNodeId && nodeId === inlineCoordinatorNodeId
26136
+ ) || Boolean(
26137
+ daemonId && (daemonId === localMachineId || daemonId === this.deps.statusInstanceId)
26138
+ ) || Boolean(meshRecord?.inline && nodeIndex === 0);
25991
26139
  const status = {
25992
- nodeId: node.id || node.nodeId,
26140
+ nodeId,
25993
26141
  machineLabel: node.machineLabel || node.id || node.nodeId,
25994
26142
  workspace: node.workspace,
25995
26143
  repoRoot: node.repoRoot,
25996
26144
  isLocalWorktree: node.isLocalWorktree,
25997
26145
  worktreeBranch: node.worktreeBranch,
25998
- daemonId: node.daemonId,
26146
+ daemonId,
25999
26147
  machineId: node.machineId,
26148
+ machineStatus: node.machineStatus,
26000
26149
  health: "unknown",
26001
26150
  providers: node.providers || [],
26002
- activeSessions: []
26151
+ providerPriority,
26152
+ activeSessions: [],
26153
+ activeSessionDetails: [],
26154
+ launchReady: false
26003
26155
  };
26004
- const nodeId = String(node.id || node.nodeId || "");
26005
- const matchedLiveSessions = liveMeshSessions.filter((record) => this.sessionMatchesMeshNode(record, node, nodeId)).map((record) => typeof record?.sessionId === "string" ? record.sessionId : "").filter(Boolean);
26006
- if (matchedLiveSessions.length > 0) {
26007
- status.activeSessions = matchedLiveSessions;
26156
+ if (isSelfNode) {
26157
+ status.connection = {
26158
+ perspective: "selected_coordinator",
26159
+ source: "mesh_peer_status",
26160
+ state: "self",
26161
+ transport: "local",
26162
+ reported: true,
26163
+ reason: "Selected coordinator daemon",
26164
+ lastStateChangeAt: refreshedAt
26165
+ };
26166
+ } else if (daemonId) {
26167
+ const connection = this.deps.getMeshPeerConnectionStatus?.(daemonId);
26168
+ status.connection = connection ?? {
26169
+ perspective: "selected_coordinator",
26170
+ source: "not_reported",
26171
+ state: "unknown",
26172
+ transport: "unknown",
26173
+ reported: false,
26174
+ reason: "No live mesh peer telemetry reported by the selected coordinator yet."
26175
+ };
26176
+ } else {
26177
+ status.connection = {
26178
+ perspective: "selected_coordinator",
26179
+ source: "not_reported",
26180
+ state: "unknown",
26181
+ transport: "unknown",
26182
+ reported: false,
26183
+ reason: "Node has no daemon id, so mesh transport cannot be reported from the selected coordinator."
26184
+ };
26185
+ }
26186
+ const matchedLiveSessionRecords = liveMeshSessions.filter((record) => this.sessionMatchesMeshNode(record, node, nodeId));
26187
+ if (matchedLiveSessionRecords.length > 0) {
26188
+ const sessionIds = matchedLiveSessionRecords.map((record) => typeof record?.sessionId === "string" ? record.sessionId : "").filter(Boolean);
26189
+ const providerTypes = matchedLiveSessionRecords.map((record) => readStringValue(record?.providerType)).filter(Boolean);
26190
+ status.activeSessions = sessionIds;
26191
+ status.activeSessionDetails = matchedLiveSessionRecords.map(summarizeMeshSessionRecord);
26192
+ if (providerTypes.length > 0) {
26193
+ status.providers = Array.from(/* @__PURE__ */ new Set([...Array.isArray(status.providers) ? status.providers : [], ...providerTypes]));
26194
+ }
26008
26195
  }
26009
26196
  if (node.workspace && typeof node.workspace === "string") {
26010
26197
  if (!fs10.existsSync(node.workspace) && applyCachedInlineMeshNodeStatus(status, node)) {
26198
+ status.launchReady = !!daemonId && (readStringValue(status.machineStatus) === "online" || isSelfNode);
26011
26199
  nodeStatuses.push(status);
26012
26200
  continue;
26013
26201
  }
26014
26202
  try {
26015
- const gitStatus = await getGitRepoStatus(node.workspace, { timeoutMs: 1e4 });
26203
+ const gitStatus = await getGitRepoStatus(node.workspace, { timeoutMs: 1e4, refreshUpstream: true });
26016
26204
  status.git = gitStatus;
26017
26205
  if (gitStatus.isGitRepo) {
26018
26206
  status.health = deriveMeshNodeHealthFromGit(gitStatus);
@@ -26028,6 +26216,7 @@ ${block}`);
26028
26216
  } else {
26029
26217
  applyCachedInlineMeshNodeStatus(status, node);
26030
26218
  }
26219
+ status.launchReady = !!daemonId && (readStringValue(status.machineStatus) === "online" || isSelfNode);
26031
26220
  nodeStatuses.push(status);
26032
26221
  }
26033
26222
  return {
@@ -26036,6 +26225,7 @@ ${block}`);
26036
26225
  meshName: mesh.name,
26037
26226
  repoIdentity: mesh.repoIdentity,
26038
26227
  defaultBranch: mesh.defaultBranch,
26228
+ refreshedAt: (/* @__PURE__ */ new Date()).toISOString(),
26039
26229
  nodes: nodeStatuses,
26040
26230
  queue: { tasks: queue, summary: queueSummary },
26041
26231
  ledger: { entries: ledgerEntries, summary: ledgerSummary }
@@ -33970,6 +34160,7 @@ async function initDaemonComponents(config) {
33970
34160
  sessionHostControl: config.sessionHostControl,
33971
34161
  statusInstanceId: config.statusInstanceId,
33972
34162
  statusVersion: config.statusVersion,
34163
+ getMeshPeerConnectionStatus: config.getMeshPeerConnectionStatus,
33973
34164
  getCdpLogFn: config.getCdpLogFn || ((ideType) => LOG.forComponent(`CDP:${ideType}`).asLogFn())
33974
34165
  });
33975
34166
  poller = new AgentStreamPoller({