@adhdev/daemon-core 0.9.81 → 0.9.82-rc.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adhdev/daemon-core",
3
- "version": "0.9.81",
3
+ "version": "0.9.82-rc.2",
4
4
  "description": "ADHDev daemon core — CDP, IDE detection, providers, command execution",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -85,6 +85,136 @@ function readProviderPriorityFromPolicy(policy: unknown): string[] {
85
85
  });
86
86
  }
87
87
 
88
+ function readObjectRecord(value: unknown): Record<string, any> {
89
+ return value && typeof value === 'object' && !Array.isArray(value)
90
+ ? value as Record<string, any>
91
+ : {};
92
+ }
93
+
94
+ function readStringValue(...values: unknown[]): string | undefined {
95
+ for (const value of values) {
96
+ if (typeof value === 'string' && value.trim()) return value.trim();
97
+ }
98
+ return undefined;
99
+ }
100
+
101
+ function readNumberValue(...values: unknown[]): number | undefined {
102
+ for (const value of values) {
103
+ if (typeof value === 'number' && Number.isFinite(value)) return value;
104
+ }
105
+ return undefined;
106
+ }
107
+
108
+ function readBooleanValue(...values: unknown[]): boolean | undefined {
109
+ for (const value of values) {
110
+ if (typeof value === 'boolean') return value;
111
+ }
112
+ return undefined;
113
+ }
114
+
115
+ function buildCachedInlineMeshGitStatus(node: any): Record<string, unknown> | undefined {
116
+ const cachedStatus = readObjectRecord(node?.cachedStatus);
117
+ const cachedGit = readObjectRecord(cachedStatus.git);
118
+ if (Object.keys(cachedGit).length) {
119
+ const conflictFiles = Array.isArray(cachedGit.conflictFiles)
120
+ ? cachedGit.conflictFiles.filter((value: unknown): value is string => typeof value === 'string')
121
+ : [];
122
+ const conflictCount = readNumberValue(cachedGit.conflicts) ?? conflictFiles.length;
123
+ const hasConflicts = readBooleanValue(cachedGit.hasConflicts) ?? conflictCount > 0;
124
+ const isGitRepo = readBooleanValue(cachedGit.isGitRepo);
125
+ if (isGitRepo !== undefined) {
126
+ return {
127
+ workspace: readStringValue(cachedGit.workspace, node?.workspace) || '',
128
+ repoRoot: readStringValue(cachedGit.repoRoot, node?.repoRoot, node?.workspace) || null,
129
+ isGitRepo,
130
+ branch: readStringValue(cachedGit.branch) ?? null,
131
+ headCommit: readStringValue(cachedGit.headCommit) ?? null,
132
+ headMessage: readStringValue(cachedGit.headMessage) ?? null,
133
+ upstream: readStringValue(cachedGit.upstream) ?? null,
134
+ ahead: readNumberValue(cachedGit.ahead) ?? 0,
135
+ behind: readNumberValue(cachedGit.behind) ?? 0,
136
+ staged: readNumberValue(cachedGit.staged) ?? 0,
137
+ modified: readNumberValue(cachedGit.modified) ?? 0,
138
+ untracked: readNumberValue(cachedGit.untracked) ?? 0,
139
+ deleted: readNumberValue(cachedGit.deleted) ?? 0,
140
+ renamed: readNumberValue(cachedGit.renamed) ?? 0,
141
+ hasConflicts,
142
+ conflictFiles,
143
+ stashCount: readNumberValue(cachedGit.stashCount) ?? 0,
144
+ lastCheckedAt: readNumberValue(cachedGit.lastCheckedAt) ?? Date.now(),
145
+ };
146
+ }
147
+ }
148
+
149
+ const rawGit = readObjectRecord(node?.lastGit ?? node?.last_git);
150
+ const gitResult = readObjectRecord(rawGit.result);
151
+ const directStatus = readObjectRecord(rawGit.status);
152
+ const nestedStatus = readObjectRecord(gitResult.status);
153
+ const rawProbe = readObjectRecord(node?.lastProbe ?? node?.last_probe);
154
+ const probeGit = readObjectRecord(rawProbe.git);
155
+ const probeGitResult = readObjectRecord(probeGit.result);
156
+ const probeDirectStatus = readObjectRecord(probeGit.status);
157
+ const probeNestedStatus = readObjectRecord(probeGitResult.status);
158
+ const status = Object.keys(directStatus).length
159
+ ? directStatus
160
+ : Object.keys(nestedStatus).length
161
+ ? nestedStatus
162
+ : Object.keys(probeDirectStatus).length
163
+ ? probeDirectStatus
164
+ : Object.keys(probeNestedStatus).length
165
+ ? probeNestedStatus
166
+ : {};
167
+ const isGitRepo = readBooleanValue(status.isGitRepo);
168
+ if (!Object.keys(status).length || isGitRepo === undefined) return undefined;
169
+ const conflictFiles = Array.isArray(status.conflictFiles)
170
+ ? status.conflictFiles.filter((value: unknown): value is string => typeof value === 'string')
171
+ : [];
172
+ const conflictCount = readNumberValue(status.conflicts) ?? conflictFiles.length;
173
+ const hasConflicts = readBooleanValue(status.hasConflicts) ?? conflictCount > 0;
174
+ return {
175
+ workspace: readStringValue(status.workspace, node?.workspace) || '',
176
+ repoRoot: readStringValue(status.repoRoot, node?.repoRoot, node?.workspace) || null,
177
+ isGitRepo,
178
+ branch: readStringValue(status.branch) ?? null,
179
+ headCommit: readStringValue(status.headCommit) ?? null,
180
+ headMessage: readStringValue(status.headMessage) ?? null,
181
+ upstream: readStringValue(status.upstream) ?? null,
182
+ ahead: readNumberValue(status.ahead) ?? 0,
183
+ behind: readNumberValue(status.behind) ?? 0,
184
+ staged: readNumberValue(status.staged) ?? 0,
185
+ modified: readNumberValue(status.modified) ?? 0,
186
+ untracked: readNumberValue(status.untracked) ?? 0,
187
+ deleted: readNumberValue(status.deleted) ?? 0,
188
+ renamed: readNumberValue(status.renamed) ?? 0,
189
+ hasConflicts,
190
+ conflictFiles,
191
+ stashCount: readNumberValue(status.stashCount) ?? 0,
192
+ lastCheckedAt: Date.now(),
193
+ };
194
+ }
195
+
196
+ function applyCachedInlineMeshNodeStatus(status: Record<string, unknown>, node: any): boolean {
197
+ const cachedStatus = readObjectRecord(node?.cachedStatus);
198
+ const git = buildCachedInlineMeshGitStatus(node);
199
+ const error = readStringValue(cachedStatus.error, node?.error);
200
+ const health = readStringValue(cachedStatus.health, node?.health);
201
+ const machineStatus = readStringValue(cachedStatus.machineStatus, node?.machineStatus);
202
+ if (!git && !error && !health) return false;
203
+ if (!machineStatus && !git && !error) return false;
204
+ if (git) status.git = git;
205
+ if (error) status.error = error;
206
+ if (health) {
207
+ status.health = health;
208
+ return true;
209
+ }
210
+ if (git) {
211
+ const dirty = Number(git.staged || 0) + Number(git.modified || 0) + Number(git.untracked || 0) + Number(git.deleted || 0) + Number(git.renamed || 0) > 0;
212
+ status.health = git.isGitRepo === false ? 'degraded' : dirty ? 'dirty' : 'online';
213
+ return true;
214
+ }
215
+ return false;
216
+ }
217
+
88
218
  async function resolveProviderTypeFromPriority(args: {
89
219
  nodeId: string;
90
220
  providerPriority: string[];
@@ -632,7 +762,16 @@ export class DaemonCommandRouter {
632
762
  return this.inlineMeshCache.get(meshId);
633
763
  }
634
764
 
635
- private async getMeshForCommand(meshId: string, inlineMesh?: unknown): Promise<{ mesh: any; inline: boolean } | null> {
765
+ private async getMeshForCommand(
766
+ meshId: string,
767
+ inlineMesh?: unknown,
768
+ options?: { preferInline?: boolean },
769
+ ): Promise<{ mesh: any; inline: boolean } | null> {
770
+ const preferInline = options?.preferInline === true;
771
+ if (preferInline) {
772
+ const cached = this.getCachedInlineMesh(meshId, inlineMesh);
773
+ if (cached) return { mesh: cached, inline: true };
774
+ }
636
775
  try {
637
776
  const { getMesh } = await import('../config/mesh-config.js');
638
777
  const mesh = getMesh(meshId);
@@ -2734,7 +2873,7 @@ export class DaemonCommandRouter {
2734
2873
  const meshId = typeof args?.meshId === 'string' ? args.meshId.trim() : '';
2735
2874
  if (!meshId) return { success: false, error: 'meshId required' };
2736
2875
  try {
2737
- const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
2876
+ const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
2738
2877
  const mesh = meshRecord?.mesh;
2739
2878
  if (!mesh) return { success: false, error: 'Mesh not found' };
2740
2879
 
@@ -2762,6 +2901,10 @@ export class DaemonCommandRouter {
2762
2901
  activeSessions: [],
2763
2902
  };
2764
2903
  if (node.workspace && typeof node.workspace === 'string') {
2904
+ if (!fs.existsSync(node.workspace as string) && applyCachedInlineMeshNodeStatus(status, node)) {
2905
+ nodeStatuses.push(status);
2906
+ continue;
2907
+ }
2765
2908
  try {
2766
2909
  const { execFile } = await import('node:child_process');
2767
2910
  const { promisify } = await import('node:util');
@@ -2826,8 +2969,12 @@ export class DaemonCommandRouter {
2826
2969
  };
2827
2970
  status.health = branch ? (dirty ? 'dirty' : 'online') : 'degraded';
2828
2971
  } catch {
2829
- status.health = 'degraded';
2972
+ if (!applyCachedInlineMeshNodeStatus(status, node)) {
2973
+ status.health = 'degraded';
2974
+ }
2830
2975
  }
2976
+ } else {
2977
+ applyCachedInlineMeshNodeStatus(status, node);
2831
2978
  }
2832
2979
  nodeStatuses.push(status);
2833
2980
  }