@adhdev/daemon-core 0.9.28 → 0.9.30
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/config/config.d.ts +16 -0
- package/dist/index.js +374 -67
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +348 -41
- package/dist/index.mjs.map +1 -1
- package/dist/providers/provider-loader.d.ts +39 -8
- package/dist/shared-types.d.ts +35 -0
- package/dist/status/snapshot.d.ts +5 -1
- package/node_modules/@adhdev/session-host-core/package.json +1 -1
- package/package.json +1 -1
- package/src/boot/daemon-lifecycle.ts +4 -3
- package/src/commands/cli-manager.ts +45 -15
- package/src/commands/router.ts +38 -2
- package/src/config/config.ts +46 -0
- package/src/providers/provider-loader.d.ts +23 -0
- package/src/providers/provider-loader.ts +286 -18
- package/src/shared-types.d.ts +4 -0
- package/src/shared-types.ts +36 -0
- package/src/status/snapshot.ts +12 -0
|
@@ -16,6 +16,32 @@ import { VersionArchive } from './version-archive.js';
|
|
|
16
16
|
import type { ProviderModule, ProviderCategory, ProviderSettingSchema, ResolvedProvider } from './contracts.js';
|
|
17
17
|
import type { ProviderSourceMode } from '../config/config.js';
|
|
18
18
|
import type { ProviderSourceConfigSnapshot } from '../config/provider-source-config.js';
|
|
19
|
+
export type ProviderMachineStatus = 'disabled' | 'enabled_unchecked' | 'not_detected' | 'detected';
|
|
20
|
+
export interface MachineProviderCheckResult {
|
|
21
|
+
ok: boolean;
|
|
22
|
+
stage?: 'detection' | 'runnable' | 'verification';
|
|
23
|
+
checkedAt?: string;
|
|
24
|
+
message?: string;
|
|
25
|
+
command?: string;
|
|
26
|
+
path?: string | null;
|
|
27
|
+
}
|
|
28
|
+
export interface MachineProviderConfig {
|
|
29
|
+
enabled?: boolean;
|
|
30
|
+
executable?: string;
|
|
31
|
+
args?: string[];
|
|
32
|
+
lastDetection?: MachineProviderCheckResult;
|
|
33
|
+
lastVerification?: MachineProviderCheckResult;
|
|
34
|
+
}
|
|
35
|
+
type CliDetectionEntry = {
|
|
36
|
+
id: string;
|
|
37
|
+
displayName: string;
|
|
38
|
+
icon: string;
|
|
39
|
+
command: string;
|
|
40
|
+
args?: string[];
|
|
41
|
+
category: string;
|
|
42
|
+
enabled: boolean;
|
|
43
|
+
versionCommand?: string;
|
|
44
|
+
};
|
|
19
45
|
export declare class ProviderLoader {
|
|
20
46
|
private providers;
|
|
21
47
|
private providerAvailability;
|
|
@@ -132,14 +158,7 @@ export declare class ProviderLoader {
|
|
|
132
158
|
* Build CLI/ACP detection list (replaces cli-detector)
|
|
133
159
|
* Dynamically generated from provider.js spawn.command.
|
|
134
160
|
*/
|
|
135
|
-
getCliDetectionList():
|
|
136
|
-
id: string;
|
|
137
|
-
displayName: string;
|
|
138
|
-
icon: string;
|
|
139
|
-
command: string;
|
|
140
|
-
category: string;
|
|
141
|
-
versionCommand?: string;
|
|
142
|
-
}[];
|
|
161
|
+
getCliDetectionList(): CliDetectionEntry[];
|
|
143
162
|
/**
|
|
144
163
|
* List providers by category
|
|
145
164
|
*/
|
|
@@ -197,6 +216,13 @@ export declare class ProviderLoader {
|
|
|
197
216
|
getSpawnCommand(type: string, fallback?: string): string;
|
|
198
217
|
getIdeCliCommand(type: string, fallback?: string | null): string | null;
|
|
199
218
|
getIdePathCandidates(type: string, fallback?: string[]): string[];
|
|
219
|
+
isMachineProviderEnabled(type: string): boolean;
|
|
220
|
+
getMachineProviderConfig(type: string): MachineProviderConfig;
|
|
221
|
+
setMachineProviderConfig(type: string, patch: Partial<MachineProviderConfig>): boolean;
|
|
222
|
+
setMachineProviderEnabled(type: string, enabled: boolean): boolean;
|
|
223
|
+
getMachineProviderStatus(type: string): ProviderMachineStatus;
|
|
224
|
+
getSpawnArgs(type: string, fallback?: string[]): string[];
|
|
225
|
+
private parseArgsSetting;
|
|
200
226
|
setProviderAvailability(type: string, state: {
|
|
201
227
|
installed: boolean;
|
|
202
228
|
detectedPath?: string | null;
|
|
@@ -215,6 +241,10 @@ export declare class ProviderLoader {
|
|
|
215
241
|
getAvailableProviderInfos(): Array<ProviderModule & {
|
|
216
242
|
installed?: boolean;
|
|
217
243
|
detectedPath?: string | null;
|
|
244
|
+
enabled: boolean;
|
|
245
|
+
machineStatus: ProviderMachineStatus;
|
|
246
|
+
lastDetection?: MachineProviderCheckResult;
|
|
247
|
+
lastVerification?: MachineProviderCheckResult;
|
|
218
248
|
}>;
|
|
219
249
|
/**
|
|
220
250
|
* Register IDE providers to core/detector registry
|
|
@@ -327,3 +357,4 @@ export declare class ProviderLoader {
|
|
|
327
357
|
private matchesVersion;
|
|
328
358
|
private compareVersions;
|
|
329
359
|
}
|
|
360
|
+
export {};
|
package/dist/shared-types.d.ts
CHANGED
|
@@ -299,12 +299,31 @@ export interface CompactSessionEntry {
|
|
|
299
299
|
parentId: string | null;
|
|
300
300
|
providerType: string;
|
|
301
301
|
providerName: string;
|
|
302
|
+
providerSessionId?: string;
|
|
302
303
|
kind: SessionKind;
|
|
303
304
|
transport: SessionTransport;
|
|
304
305
|
status: SessionStatus;
|
|
305
306
|
title: string;
|
|
306
307
|
workspace: string | null;
|
|
307
308
|
cdpConnected?: boolean;
|
|
309
|
+
runtimeKey?: string;
|
|
310
|
+
runtimeDisplayName?: string;
|
|
311
|
+
runtimeWorkspaceLabel?: string;
|
|
312
|
+
runtimeWriteOwner?: RuntimeWriteOwner | null;
|
|
313
|
+
runtimeAttachedClients?: RuntimeAttachedClient[];
|
|
314
|
+
lastMessagePreview?: string;
|
|
315
|
+
lastMessageRole?: string;
|
|
316
|
+
lastMessageAt?: number;
|
|
317
|
+
lastMessageHash?: string;
|
|
318
|
+
lastUpdated?: number;
|
|
319
|
+
unread?: boolean;
|
|
320
|
+
lastSeenAt?: number;
|
|
321
|
+
inboxBucket?: RecentSessionBucket;
|
|
322
|
+
completionMarker?: string;
|
|
323
|
+
seenCompletionMarker?: string;
|
|
324
|
+
surfaceHidden?: boolean;
|
|
325
|
+
controlValues?: Record<string, string | number | boolean>;
|
|
326
|
+
providerControls?: ProviderControlSchema[];
|
|
308
327
|
summaryMetadata?: ProviderSummaryMetadata;
|
|
309
328
|
}
|
|
310
329
|
export type VersionUpdateReason = 'force_update_below' | 'major_minor_mismatch' | 'patch_mismatch' | 'daemon_ahead';
|
|
@@ -317,6 +336,22 @@ export interface AvailableProviderInfo {
|
|
|
317
336
|
icon: string;
|
|
318
337
|
installed?: boolean;
|
|
319
338
|
detectedPath?: string | null;
|
|
339
|
+
/** Machine-local opt-in activation state. Undefined means older daemon payload. */
|
|
340
|
+
enabled?: boolean;
|
|
341
|
+
/** Machine-local readiness state for opt-in providers. */
|
|
342
|
+
machineStatus?: 'disabled' | 'enabled_unchecked' | 'not_detected' | 'detected';
|
|
343
|
+
/** Last machine-local command detection/runnable check result. */
|
|
344
|
+
lastDetection?: MachineProviderCheckResult;
|
|
345
|
+
/** Last end-to-end ADHDev verification result, when available. */
|
|
346
|
+
lastVerification?: MachineProviderCheckResult;
|
|
347
|
+
}
|
|
348
|
+
export interface MachineProviderCheckResult {
|
|
349
|
+
ok: boolean;
|
|
350
|
+
stage?: 'detection' | 'runnable' | 'verification';
|
|
351
|
+
checkedAt?: string;
|
|
352
|
+
message?: string;
|
|
353
|
+
command?: string;
|
|
354
|
+
path?: string | null;
|
|
320
355
|
}
|
|
321
356
|
/** ACP config option (model/mode/thought_level selection) */
|
|
322
357
|
export interface AcpConfigOption {
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
import type { DaemonCdpManager } from '../cdp/manager.js';
|
|
9
9
|
import { type SessionEntryProfile } from './builders.js';
|
|
10
10
|
import type { ProviderState } from '../providers/provider-instance.js';
|
|
11
|
-
import type { MachineInfo, RecentSessionBucket, StatusReportPayload } from '../shared-types.js';
|
|
11
|
+
import type { AvailableProviderInfo, MachineInfo, RecentSessionBucket, StatusReportPayload } from '../shared-types.js';
|
|
12
12
|
export interface StatusSnapshotOptions {
|
|
13
13
|
allStates: ProviderState[];
|
|
14
14
|
cdpManagers: Map<string, DaemonCdpManager>;
|
|
@@ -26,6 +26,10 @@ export interface StatusSnapshotOptions {
|
|
|
26
26
|
category: 'ide' | 'extension' | 'cli' | 'acp';
|
|
27
27
|
installed?: boolean;
|
|
28
28
|
detectedPath?: string | null;
|
|
29
|
+
enabled?: boolean;
|
|
30
|
+
machineStatus?: 'disabled' | 'enabled_unchecked' | 'not_detected' | 'detected';
|
|
31
|
+
lastDetection?: AvailableProviderInfo['lastDetection'];
|
|
32
|
+
lastVerification?: AvailableProviderInfo['lastVerification'];
|
|
29
33
|
}>;
|
|
30
34
|
};
|
|
31
35
|
detectedIdes: Array<{
|
package/package.json
CHANGED
|
@@ -181,10 +181,11 @@ export async function initDaemonComponents(config: DaemonInitConfig): Promise<Da
|
|
|
181
181
|
if (!providerType || targetCategory === 'cli' || targetCategory === 'acp') {
|
|
182
182
|
if (providerType && targetProvider) {
|
|
183
183
|
const detected = await detectCLI(targetProvider.type, providerLoader, { includeVersion: false });
|
|
184
|
-
providerLoader.
|
|
184
|
+
providerLoader.setCliDetectionResults([{
|
|
185
|
+
id: targetProvider.type,
|
|
185
186
|
installed: !!detected,
|
|
186
|
-
|
|
187
|
-
});
|
|
187
|
+
path: detected?.path,
|
|
188
|
+
}], false);
|
|
188
189
|
} else {
|
|
189
190
|
providerLoader.setCliDetectionResults(await detectCLIs(providerLoader, { includeVersion: false }), true);
|
|
190
191
|
}
|
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
import * as os from 'os';
|
|
9
9
|
import * as path from 'path';
|
|
10
10
|
import * as crypto from 'crypto';
|
|
11
|
+
import { existsSync } from 'fs';
|
|
12
|
+
import { execFileSync } from 'child_process';
|
|
11
13
|
import chalk from 'chalk';
|
|
12
14
|
import { ProviderCliAdapter } from '../cli-adapters/provider-cli-adapter.js';
|
|
13
15
|
import type { CliProviderModule } from '../cli-adapters/provider-cli-adapter.js';
|
|
@@ -33,6 +35,30 @@ import { shouldRestoreHostedRuntime } from './hosted-runtime-restore.js';
|
|
|
33
35
|
|
|
34
36
|
// ─── external dependency interface ──────────────────────────
|
|
35
37
|
|
|
38
|
+
function isExplicitCommand(command: string): boolean {
|
|
39
|
+
const trimmed = command.trim();
|
|
40
|
+
return path.isAbsolute(trimmed) || trimmed.includes('/') || trimmed.includes('\\') || trimmed.startsWith('~');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function expandExecutable(command: string): string {
|
|
44
|
+
const trimmed = command.trim();
|
|
45
|
+
return trimmed.startsWith('~') ? path.join(os.homedir(), trimmed.slice(1)) : trimmed;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function commandExists(command: string): boolean {
|
|
49
|
+
const trimmed = command.trim();
|
|
50
|
+
if (!trimmed) return false;
|
|
51
|
+
if (isExplicitCommand(trimmed)) {
|
|
52
|
+
return existsSync(expandExecutable(trimmed));
|
|
53
|
+
}
|
|
54
|
+
try {
|
|
55
|
+
execFileSync(process.platform === 'win32' ? 'where' : 'which', [trimmed], { stdio: 'ignore' });
|
|
56
|
+
return true;
|
|
57
|
+
} catch {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
36
62
|
export interface CliManagerDeps {
|
|
37
63
|
/** Server connection — injected into adapter */
|
|
38
64
|
getServerConn(): any | null;
|
|
@@ -461,7 +487,15 @@ export class DaemonCliManager {
|
|
|
461
487
|
|
|
462
488
|
// cliType normalize (Resolve alias)
|
|
463
489
|
const normalizedType = this.providerLoader.resolveAlias(cliType);
|
|
464
|
-
const
|
|
490
|
+
const rawProvider = this.providerLoader.getByAlias(cliType);
|
|
491
|
+
const provider = rawProvider ? (this.providerLoader.resolve(normalizedType) || rawProvider) : undefined;
|
|
492
|
+
if (provider && (provider.category === 'cli' || provider.category === 'acp') && !this.providerLoader.isMachineProviderEnabled(normalizedType)) {
|
|
493
|
+
const displayName = provider.displayName || provider.name || normalizedType;
|
|
494
|
+
throw new Error(
|
|
495
|
+
`${displayName} is disabled on this machine.\n` +
|
|
496
|
+
`Enable and detect this provider from the Machine Providers page before starting a runtime.`
|
|
497
|
+
);
|
|
498
|
+
}
|
|
465
499
|
|
|
466
500
|
// Create UUID-based key (allows separate instances even for same type+dir)
|
|
467
501
|
const key = crypto.randomUUID();
|
|
@@ -471,26 +505,22 @@ export class DaemonCliManager {
|
|
|
471
505
|
if (provider && provider.category === 'acp') {
|
|
472
506
|
const instanceManager = this.deps.getInstanceManager();
|
|
473
507
|
if (!instanceManager) throw new Error('InstanceManager not available');
|
|
508
|
+
const resolvedProvider = this.providerLoader.resolve(normalizedType) || provider;
|
|
474
509
|
|
|
475
510
|
// Check if command is installed
|
|
476
|
-
const spawnCmd =
|
|
477
|
-
if (spawnCmd) {
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
`${provider.displayName || provider.name} is not installed.\n` +
|
|
485
|
-
`Command '${spawnCmd}' not found in PATH.\n\n` +
|
|
486
|
-
`${installInfo}`
|
|
487
|
-
);
|
|
488
|
-
}
|
|
511
|
+
const spawnCmd = resolvedProvider.spawn?.command;
|
|
512
|
+
if (spawnCmd && !commandExists(spawnCmd)) {
|
|
513
|
+
const installInfo = provider.install || `Install: check ${provider.displayName || provider.name} documentation`;
|
|
514
|
+
throw new Error(
|
|
515
|
+
`${provider.displayName || provider.name} is not installed.\n` +
|
|
516
|
+
`Command '${spawnCmd}' not found.\n\n` +
|
|
517
|
+
`${installInfo}`
|
|
518
|
+
);
|
|
489
519
|
}
|
|
490
520
|
|
|
491
521
|
console.log(colorize('cyan', ` 🔌 Starting ACP agent: ${provider.name} (${provider.type}) in ${resolvedDir}`));
|
|
492
522
|
|
|
493
|
-
const acpInstance = new AcpProviderInstance(
|
|
523
|
+
const acpInstance = new AcpProviderInstance(resolvedProvider, resolvedDir, cliArgs);
|
|
494
524
|
await instanceManager.addInstance(key, acpInstance, {
|
|
495
525
|
settings: this.providerLoader.getSettings(normalizedType),
|
|
496
526
|
});
|
package/src/commands/router.ts
CHANGED
|
@@ -25,6 +25,7 @@ import { appendRecentActivity, getRecentActivity, markSessionSeen, dismissSessio
|
|
|
25
25
|
import { getSavedProviderSessions } from '../config/saved-sessions.js';
|
|
26
26
|
import { listSavedHistorySessions } from '../config/chat-history.js';
|
|
27
27
|
import { detectIDEs } from '../detection/ide-detector.js';
|
|
28
|
+
import { detectCLI } from '../detection/cli-detector.js';
|
|
28
29
|
import { SessionRegistry } from '../sessions/registry.js';
|
|
29
30
|
import { LOG } from '../logging/logger.js';
|
|
30
31
|
import { logCommand } from '../logging/command-log.js';
|
|
@@ -669,6 +670,34 @@ export class DaemonCommandRouter {
|
|
|
669
670
|
return { ...result };
|
|
670
671
|
}
|
|
671
672
|
|
|
673
|
+
// ─── Detect providers ───
|
|
674
|
+
case 'detect_provider': {
|
|
675
|
+
const providerType = typeof args?.providerType === 'string' ? args.providerType.trim() : '';
|
|
676
|
+
if (!providerType) return { success: false, error: 'providerType is required' };
|
|
677
|
+
const normalizedType = this.deps.providerLoader.resolveAlias(providerType);
|
|
678
|
+
const provider = this.deps.providerLoader.getByAlias(providerType);
|
|
679
|
+
if (!provider) return { success: false, error: `Provider not found: ${providerType}` };
|
|
680
|
+
if (provider.category !== 'cli' && provider.category !== 'acp') {
|
|
681
|
+
return { success: false, error: `Provider detection is only supported for CLI/ACP providers: ${providerType}` };
|
|
682
|
+
}
|
|
683
|
+
if (!this.deps.providerLoader.isMachineProviderEnabled(normalizedType)) {
|
|
684
|
+
return { success: false, error: `Provider is disabled on this machine: ${providerType}` };
|
|
685
|
+
}
|
|
686
|
+
const detected = await detectCLI(normalizedType, this.deps.providerLoader, { includeVersion: false });
|
|
687
|
+
this.deps.providerLoader.setCliDetectionResults([{
|
|
688
|
+
id: normalizedType,
|
|
689
|
+
installed: !!detected,
|
|
690
|
+
path: detected?.path,
|
|
691
|
+
}], false);
|
|
692
|
+
this.deps.onStatusChange?.();
|
|
693
|
+
return {
|
|
694
|
+
success: true,
|
|
695
|
+
providerType: normalizedType,
|
|
696
|
+
detected: !!detected,
|
|
697
|
+
path: detected?.path || null,
|
|
698
|
+
};
|
|
699
|
+
}
|
|
700
|
+
|
|
672
701
|
// ─── Detect IDEs ───
|
|
673
702
|
case 'detect_ides': {
|
|
674
703
|
const results = await detectIDEs(this.deps.providerLoader);
|
|
@@ -718,13 +747,20 @@ export class DaemonCommandRouter {
|
|
|
718
747
|
this.deps.cdpManagers,
|
|
719
748
|
);
|
|
720
749
|
const targetSession = sessionEntries.find((entry) => entry.id === sessionId);
|
|
721
|
-
const
|
|
750
|
+
const requestedCompletionMarker = typeof args?.completionMarker === 'string'
|
|
751
|
+
? args.completionMarker.trim()
|
|
752
|
+
: '';
|
|
753
|
+
const completionMarker = requestedCompletionMarker || (targetSession ? getSessionCompletionMarker(targetSession) : '');
|
|
754
|
+
const requestedProviderSessionId = typeof args?.providerSessionId === 'string'
|
|
755
|
+
? args.providerSessionId.trim()
|
|
756
|
+
: '';
|
|
757
|
+
const providerSessionId = requestedProviderSessionId || targetSession?.providerSessionId;
|
|
722
758
|
const next = markSessionSeen(
|
|
723
759
|
currentState,
|
|
724
760
|
sessionId,
|
|
725
761
|
typeof args?.seenAt === 'number' ? args.seenAt : Date.now(),
|
|
726
762
|
completionMarker,
|
|
727
|
-
|
|
763
|
+
providerSessionId,
|
|
728
764
|
);
|
|
729
765
|
if (READ_DEBUG_ENABLED) {
|
|
730
766
|
LOG.info('RecentRead', `mark_session_seen sessionId=${sessionId} seenAt=${String(args?.seenAt || '')} prevSeenAt=${String(prevSeenAt)} nextSeenAt=${String(next.sessionReads?.[sessionId] || 0)} marker=${completionMarker || '-'}`);
|
package/src/config/config.ts
CHANGED
|
@@ -26,6 +26,23 @@ export function resolveProviderSourceMode(
|
|
|
26
26
|
return legacyDisableUpstream === true ? 'no-upstream' : 'normal';
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
export interface MachineProviderCheckResult {
|
|
30
|
+
ok: boolean;
|
|
31
|
+
stage?: 'detection' | 'runnable' | 'verification';
|
|
32
|
+
checkedAt?: string;
|
|
33
|
+
message?: string;
|
|
34
|
+
command?: string;
|
|
35
|
+
path?: string | null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface MachineProviderConfig {
|
|
39
|
+
enabled?: boolean;
|
|
40
|
+
executable?: string;
|
|
41
|
+
args?: string[];
|
|
42
|
+
lastDetection?: MachineProviderCheckResult;
|
|
43
|
+
lastVerification?: MachineProviderCheckResult;
|
|
44
|
+
}
|
|
45
|
+
|
|
29
46
|
export interface ADHDevConfig {
|
|
30
47
|
// Server connection
|
|
31
48
|
serverUrl: string;
|
|
@@ -86,6 +103,9 @@ export interface ADHDevConfig {
|
|
|
86
103
|
// Per-provider user config (public setting values)
|
|
87
104
|
providerSettings: Record<string, Record<string, any>>;
|
|
88
105
|
|
|
106
|
+
// Machine-local provider activation/config. Providers default disabled until explicitly enabled.
|
|
107
|
+
machineProviders: Record<string, MachineProviderConfig>;
|
|
108
|
+
|
|
89
109
|
// Per-IDE extension config (per-IDE on/off control)
|
|
90
110
|
ideSettings: Record<string, {
|
|
91
111
|
extensions?: Record<string, { enabled: boolean }>;
|
|
@@ -128,6 +148,7 @@ const DEFAULT_CONFIG: ADHDevConfig = {
|
|
|
128
148
|
machineSecret: null,
|
|
129
149
|
registeredMachineId: undefined,
|
|
130
150
|
providerSettings: {},
|
|
151
|
+
machineProviders: {},
|
|
131
152
|
ideSettings: {},
|
|
132
153
|
providerSourceMode: 'normal',
|
|
133
154
|
terminalSizingMode: 'measured',
|
|
@@ -156,6 +177,30 @@ function asBoolean(value: unknown, fallback: boolean): boolean {
|
|
|
156
177
|
return typeof value === 'boolean' ? value : fallback;
|
|
157
178
|
}
|
|
158
179
|
|
|
180
|
+
function normalizeMachineProviders(value: unknown): Record<string, MachineProviderConfig> {
|
|
181
|
+
if (!isPlainObject(value)) return {};
|
|
182
|
+
const result: Record<string, MachineProviderConfig> = {};
|
|
183
|
+
for (const [providerType, raw] of Object.entries(value)) {
|
|
184
|
+
if (!isPlainObject(raw)) continue;
|
|
185
|
+
const entry: MachineProviderConfig = {};
|
|
186
|
+
if (raw.enabled === true) entry.enabled = true;
|
|
187
|
+
if (typeof raw.executable === 'string' && raw.executable.trim()) {
|
|
188
|
+
entry.executable = raw.executable.trim();
|
|
189
|
+
}
|
|
190
|
+
if (Array.isArray(raw.args)) {
|
|
191
|
+
entry.args = raw.args.filter((arg): arg is string => typeof arg === 'string');
|
|
192
|
+
}
|
|
193
|
+
if (isPlainObject(raw.lastDetection)) {
|
|
194
|
+
entry.lastDetection = raw.lastDetection as MachineProviderCheckResult;
|
|
195
|
+
}
|
|
196
|
+
if (isPlainObject(raw.lastVerification)) {
|
|
197
|
+
entry.lastVerification = raw.lastVerification as MachineProviderCheckResult;
|
|
198
|
+
}
|
|
199
|
+
result[providerType] = entry;
|
|
200
|
+
}
|
|
201
|
+
return result;
|
|
202
|
+
}
|
|
203
|
+
|
|
159
204
|
function normalizeConfig(raw: unknown): ADHDevConfig & { activeWorkspaceId?: string | null } {
|
|
160
205
|
const parsed = isPlainObject(raw) ? raw : {};
|
|
161
206
|
|
|
@@ -179,6 +224,7 @@ function normalizeConfig(raw: unknown): ADHDevConfig & { activeWorkspaceId?: str
|
|
|
179
224
|
machineSecret: parsed.machineSecret === null ? null : asOptionalString(parsed.machineSecret),
|
|
180
225
|
registeredMachineId: asOptionalString(parsed.registeredMachineId),
|
|
181
226
|
providerSettings: isPlainObject(parsed.providerSettings) ? parsed.providerSettings : {},
|
|
227
|
+
machineProviders: normalizeMachineProviders(parsed.machineProviders),
|
|
182
228
|
ideSettings: isPlainObject(parsed.ideSettings) ? parsed.ideSettings : {},
|
|
183
229
|
providerSourceMode: resolveProviderSourceMode(parsed.providerSourceMode, parsed.disableUpstream),
|
|
184
230
|
providerDir: asOptionalString(parsed.providerDir),
|
|
@@ -15,6 +15,22 @@
|
|
|
15
15
|
import { VersionArchive } from './version-archive.js';
|
|
16
16
|
import type { ProviderModule, ProviderCategory, ProviderSettingSchema, ResolvedProvider } from './contracts.js';
|
|
17
17
|
import type { ProviderSourceMode } from '../config/config.js';
|
|
18
|
+
export type ProviderMachineStatus = 'disabled' | 'enabled_unchecked' | 'not_detected' | 'detected';
|
|
19
|
+
export interface MachineProviderCheckResult {
|
|
20
|
+
ok: boolean;
|
|
21
|
+
stage?: 'detection' | 'runnable' | 'verification';
|
|
22
|
+
checkedAt?: string;
|
|
23
|
+
message?: string;
|
|
24
|
+
command?: string;
|
|
25
|
+
path?: string | null;
|
|
26
|
+
}
|
|
27
|
+
export interface MachineProviderConfig {
|
|
28
|
+
enabled?: boolean;
|
|
29
|
+
executable?: string;
|
|
30
|
+
args?: string[];
|
|
31
|
+
lastDetection?: MachineProviderCheckResult;
|
|
32
|
+
lastVerification?: MachineProviderCheckResult;
|
|
33
|
+
}
|
|
18
34
|
export declare class ProviderLoader {
|
|
19
35
|
private providers;
|
|
20
36
|
private providerAvailability;
|
|
@@ -110,7 +126,9 @@ export declare class ProviderLoader {
|
|
|
110
126
|
displayName: string;
|
|
111
127
|
icon: string;
|
|
112
128
|
command: string;
|
|
129
|
+
args?: string[];
|
|
113
130
|
category: string;
|
|
131
|
+
enabled: boolean;
|
|
114
132
|
versionCommand?: string;
|
|
115
133
|
}[];
|
|
116
134
|
/**
|
|
@@ -168,6 +186,7 @@ export declare class ProviderLoader {
|
|
|
168
186
|
*/
|
|
169
187
|
getAvailableIdeTypes(): string[];
|
|
170
188
|
getSpawnCommand(type: string, fallback?: string): string;
|
|
189
|
+
getSpawnArgs(type: string, fallback?: string[]): string[];
|
|
171
190
|
getIdeCliCommand(type: string, fallback?: string | null): string | null;
|
|
172
191
|
getIdePathCandidates(type: string, fallback?: string[]): string[];
|
|
173
192
|
setProviderAvailability(type: string, state: {
|
|
@@ -188,6 +207,10 @@ export declare class ProviderLoader {
|
|
|
188
207
|
getAvailableProviderInfos(): Array<ProviderModule & {
|
|
189
208
|
installed?: boolean;
|
|
190
209
|
detectedPath?: string | null;
|
|
210
|
+
enabled: boolean;
|
|
211
|
+
machineStatus: ProviderMachineStatus;
|
|
212
|
+
lastDetection?: MachineProviderCheckResult;
|
|
213
|
+
lastVerification?: MachineProviderCheckResult;
|
|
191
214
|
}>;
|
|
192
215
|
/**
|
|
193
216
|
* Register IDE providers to core/detector registry
|