@adhdev/daemon-core 0.8.29 → 0.8.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/dist/agent-stream/manager.d.ts +1 -0
  2. package/dist/agent-stream/provider-adapter.d.ts +1 -0
  3. package/dist/agent-stream/types.d.ts +3 -0
  4. package/dist/boot/daemon-lifecycle.d.ts +2 -1
  5. package/dist/cdp/manager.d.ts +2 -0
  6. package/dist/cli-adapter-types.d.ts +34 -5
  7. package/dist/cli-adapters/provider-cli-adapter.d.ts +4 -158
  8. package/dist/cli-adapters/provider-cli-config.d.ts +30 -0
  9. package/dist/cli-adapters/provider-cli-parse.d.ts +42 -0
  10. package/dist/cli-adapters/provider-cli-runtime.d.ts +29 -0
  11. package/dist/cli-adapters/provider-cli-shared.d.ts +158 -0
  12. package/dist/commands/handler.d.ts +4 -3
  13. package/dist/config/config.d.ts +4 -3
  14. package/dist/index.js +1033 -621
  15. package/dist/index.js.map +1 -1
  16. package/dist/index.mjs +1035 -624
  17. package/dist/index.mjs.map +1 -1
  18. package/dist/providers/acp-provider-instance.d.ts +1 -0
  19. package/dist/providers/approval-utils.d.ts +7 -0
  20. package/dist/providers/cli-provider-instance.d.ts +2 -0
  21. package/dist/providers/contracts.d.ts +12 -1
  22. package/dist/providers/ide-provider-instance.d.ts +1 -0
  23. package/dist/providers/provider-loader.d.ts +3 -0
  24. package/dist/status/reporter.d.ts +2 -3
  25. package/dist/status/snapshot.d.ts +2 -1
  26. package/node_modules/@adhdev/session-host-core/package.json +1 -1
  27. package/package.json +3 -1
  28. package/src/agent-stream/manager.ts +8 -2
  29. package/src/agent-stream/poller.ts +57 -6
  30. package/src/agent-stream/provider-adapter.ts +11 -7
  31. package/src/agent-stream/types.ts +3 -0
  32. package/src/boot/daemon-lifecycle.ts +7 -6
  33. package/src/cdp/initializer.ts +2 -2
  34. package/src/cdp/manager.ts +5 -0
  35. package/src/cdp/setup.ts +1 -1
  36. package/src/cli-adapter-types.ts +37 -5
  37. package/src/cli-adapters/provider-cli-adapter.ts +212 -795
  38. package/src/cli-adapters/provider-cli-config.ts +66 -0
  39. package/src/cli-adapters/provider-cli-parse.ts +202 -0
  40. package/src/cli-adapters/provider-cli-runtime.ts +142 -0
  41. package/src/cli-adapters/provider-cli-shared.ts +439 -0
  42. package/src/cli-adapters/terminal-backends/ghostty-vt-backend.ts +1 -1
  43. package/src/commands/cdp-commands.ts +6 -1
  44. package/src/commands/chat-commands.ts +45 -29
  45. package/src/commands/cli-manager.ts +28 -9
  46. package/src/commands/handler.ts +14 -10
  47. package/src/commands/router.ts +23 -10
  48. package/src/commands/stream-commands.ts +11 -5
  49. package/src/config/config.ts +4 -10
  50. package/src/daemon/dev-auto-implement.ts +22 -18
  51. package/src/daemon/dev-cli-debug.ts +59 -16
  52. package/src/daemon/dev-server.ts +67 -43
  53. package/src/providers/acp-provider-instance.ts +18 -3
  54. package/src/providers/approval-utils.ts +66 -0
  55. package/src/providers/cli-provider-instance.ts +32 -6
  56. package/src/providers/contracts.d.ts +1 -0
  57. package/src/providers/contracts.ts +15 -2
  58. package/src/providers/extension-provider-instance.ts +1 -1
  59. package/src/providers/ide-provider-instance.ts +67 -41
  60. package/src/providers/provider-loader.ts +110 -55
  61. package/src/providers/version-archive.ts +23 -5
  62. package/src/status/reporter.ts +18 -14
  63. package/src/status/snapshot.ts +5 -4
@@ -10,6 +10,7 @@ import * as path from 'path';
10
10
  import * as crypto from 'crypto';
11
11
  import chalk from 'chalk';
12
12
  import { ProviderCliAdapter } from '../cli-adapters/provider-cli-adapter.js';
13
+ import type { CliProviderModule } from '../cli-adapters/provider-cli-adapter.js';
13
14
  import { detectCLI } from '../detection/cli-detector.js';
14
15
  import { loadConfig } from '../config/config.js';
15
16
  import { loadState, saveState } from '../config/state-store.js';
@@ -24,6 +25,7 @@ import type { ProviderModule, ProviderResumeCapability } from '../providers/cont
24
25
  import type { CliAdapter } from '../cli-adapter-types.js';
25
26
  import type { PtyTransportFactory } from '../cli-adapters/pty-transport.js';
26
27
  import type { SessionRegistry } from '../sessions/registry.js';
28
+ import type { ProviderInstance } from '../providers/provider-instance.js';
27
29
  import { LOG } from '../logging/logger.js';
28
30
 
29
31
  // ─── external dependency interface ──────────────────────────
@@ -67,9 +69,17 @@ export interface HostedCliRuntimeDescriptor {
67
69
  providerSessionId?: string;
68
70
  }
69
71
 
70
- const chalkApi: any = (chalk as any)?.yellow
71
- ? (chalk as any)
72
- : (chalk as any)?.default || null;
72
+ type CliPresentationInstance = ProviderInstance & {
73
+ getPresentationMode?(): 'terminal' | 'chat';
74
+ };
75
+
76
+ type ChalkColorFn = (text: string) => string;
77
+ type ChalkLike = Partial<Record<'red' | 'green' | 'yellow' | 'cyan', ChalkColorFn>>;
78
+
79
+ const chalkModule = chalk as unknown as ChalkLike & { default?: ChalkLike };
80
+ const chalkApi: ChalkLike | null = typeof chalkModule.yellow === 'function'
81
+ ? chalkModule
82
+ : chalkModule.default || null;
73
83
 
74
84
  function colorize(color: 'red' | 'green' | 'yellow' | 'cyan', text: string): string {
75
85
  const fn = chalkApi?.[color];
@@ -84,6 +94,10 @@ type CliSessionBinding = {
84
94
  launchMode: CliLaunchMode;
85
95
  };
86
96
 
97
+ type CliAdapterWithExtraArgs = CliAdapter & {
98
+ extraArgs?: string[];
99
+ };
100
+
87
101
  function isUuid(value: string): boolean {
88
102
  return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value);
89
103
  }
@@ -239,7 +253,7 @@ export class DaemonCliManager {
239
253
 
240
254
  getSessionPresentationMode(sessionId: string): 'terminal' | 'chat' | null {
241
255
  if (!sessionId) return null;
242
- const instance = this.deps.getInstanceManager()?.getInstance(sessionId) as any;
256
+ const instance = this.deps.getInstanceManager()?.getInstance(sessionId) as CliPresentationInstance | undefined;
243
257
  const mode = instance?.category === 'cli'
244
258
  ? instance.getPresentationMode?.()
245
259
  : null;
@@ -321,7 +335,7 @@ export class DaemonCliManager {
321
335
  providerSessionId,
322
336
  attachExisting,
323
337
  );
324
- return new ProviderCliAdapter(resolvedProvider as any, workingDir, cliArgs, transportFactory);
338
+ return new ProviderCliAdapter(resolvedProvider as CliProviderModule, workingDir, cliArgs, transportFactory);
325
339
  }
326
340
 
327
341
  throw new Error(`No CLI provider found for '${cliType}'. Create a provider.js in providers/cli/${cliType}/`);
@@ -408,7 +422,7 @@ export class DaemonCliManager {
408
422
  throw new Error(`Failed to start ${provider.displayName || provider.name || cliType}: ${spawnErr?.message}`);
409
423
  }
410
424
 
411
- this.adapters.set(key, cliInstance.getAdapter() as any);
425
+ this.adapters.set(key, cliInstance.getAdapter());
412
426
  this.startCliExitMonitor(key, cliType);
413
427
  }
414
428
 
@@ -475,6 +489,7 @@ export class DaemonCliManager {
475
489
  // Register ACP entry in adapter map (getStatus queries from acpInstance in real-time)
476
490
  this.adapters.set(key, {
477
491
  cliType: normalizedType,
492
+ cliName: provider.name,
478
493
  workingDir: resolvedDir,
479
494
  _acpInstance: acpInstance,
480
495
  spawn: async () => {},
@@ -488,9 +503,13 @@ export class DaemonCliManager {
488
503
  activeModal: state.activeChat?.activeModal || null,
489
504
  };
490
505
  },
506
+ getPartialResponse: () => '',
507
+ cancel: () => { instanceManager.removeInstance(key); },
508
+ isProcessing: () => false,
509
+ isReady: () => true,
491
510
  setOnStatusChange: () => {},
492
511
  setOnPtyData: () => {},
493
- } as any);
512
+ });
494
513
 
495
514
  console.log(colorize('green', ` ✓ ACP agent started: ${provider.name} in ${resolvedDir}`));
496
515
 
@@ -893,7 +912,7 @@ export class DaemonCliManager {
893
912
  const dir = rdir.path;
894
913
  if (!cliType) throw new Error('cliType required');
895
914
  const found = this.findAdapter(cliType, { instanceKey: args?.targetSessionId, dir });
896
- const prevCliArgs = found ? (found.adapter as any).extraArgs : undefined;
915
+ const prevCliArgs = found ? (found.adapter as CliAdapterWithExtraArgs).extraArgs : undefined;
897
916
  if (found) await this.stopSession(found.key);
898
917
  await this.startSession(cliType, dir, args?.cliArgs || prevCliArgs, args?.initialModel);
899
918
  return { success: true, restarted: true };
@@ -916,7 +935,7 @@ export class DaemonCliManager {
916
935
  await adapter.sendMessage(message);
917
936
  return { success: true, status: 'generating' };
918
937
  } else if (action === 'clear_history') {
919
- if (typeof (adapter as any).clearHistory === 'function') (adapter as any).clearHistory();
938
+ if (typeof adapter.clearHistory === 'function') adapter.clearHistory();
920
939
  return { success: true, cleared: true };
921
940
  } else if (action === 'stop') {
922
941
  await this.stopSession(key);
@@ -16,8 +16,9 @@ import { CdpDomHandlers } from '../cdp/devtools.js';
16
16
  import { findCdpManager } from '../status/builders.js';
17
17
  import { ProviderLoader } from '../providers/provider-loader.js';
18
18
  import type { ProviderInstanceManager } from '../providers/provider-instance-manager.js';
19
- import type { ProviderModule } from '../providers/contracts.js';
19
+ import type { ProviderModule, ProviderScripts } from '../providers/contracts.js';
20
20
  import type { DaemonAgentStreamManager } from '../agent-stream/index.js';
21
+ import type { CliAdapter } from '../cli-adapter-types.js';
21
22
  import { loadConfig } from '../config/config.js';
22
23
  import { ChatHistoryWriter } from '../config/chat-history.js';
23
24
  import type { SessionRegistry, SessionRuntimeTarget } from '../sessions/registry.js';
@@ -39,7 +40,7 @@ export interface CommandResult {
39
40
  export interface CommandContext {
40
41
  cdpManagers: Map<string, DaemonCdpManager>;
41
42
  ideType: string;
42
- adapters: Map<string, any>;
43
+ adapters: Map<string, CliAdapter>;
43
44
  providerLoader?: ProviderLoader;
44
45
  /** ProviderInstanceManager — for runtime settings propagation */
45
46
  instanceManager?: ProviderInstanceManager;
@@ -56,7 +57,7 @@ export interface CommandHelpers {
56
57
  getProvider(overrideType?: string): ProviderModule | undefined;
57
58
  getProviderScript(scriptName: string, params?: Record<string, string>, ideType?: string): string | null;
58
59
  evaluateProviderScript(scriptName: string, params?: Record<string, string>, timeout?: number): Promise<{ result: any; category: string } | null>;
59
- getCliAdapter(type?: string): any | null;
60
+ getCliAdapter(type?: string): CliAdapter | null;
60
61
  readonly currentManagerKey: string | undefined;
61
62
  readonly currentIdeType: string | undefined;
62
63
  readonly currentProviderType: string | undefined;
@@ -66,6 +67,8 @@ export interface CommandHelpers {
66
67
  readonly historyWriter: ChatHistoryWriter;
67
68
  }
68
69
 
70
+ type LegacyStringScript = (params?: Record<string, unknown> | string) => string;
71
+
69
72
  const COMMAND_DEBUG_LEVELS = new Set([
70
73
  'pty_input',
71
74
  'pty_resize',
@@ -214,15 +217,16 @@ export class DaemonCommandHandler implements CommandHelpers {
214
217
  getProviderScript(scriptName: string, params?: Record<string, string>, ideType?: string): string | null {
215
218
  const provider = this.getProvider(ideType);
216
219
  if (provider?.scripts) {
217
- const fn = (provider.scripts as any)[scriptName];
220
+ const fn = provider.scripts[scriptName];
218
221
  if (typeof fn === 'function') {
222
+ const callScript = fn as LegacyStringScript;
219
223
  if (params && Object.keys(params).length > 0) {
220
224
  const firstVal = Object.values(params)[0];
221
225
  if (scriptName === 'sendMessage' && typeof firstVal === 'string') {
222
- const legacyScript = fn(firstVal);
226
+ const legacyScript = callScript(firstVal);
223
227
  if (legacyScript) return legacyScript;
224
228
  }
225
- const script = fn(params);
229
+ const script = callScript(params);
226
230
  if (script) {
227
231
  const likelyLegacyObjectLeak =
228
232
  typeof script === 'string'
@@ -232,13 +236,13 @@ export class DaemonCommandHandler implements CommandHelpers {
232
236
  }
233
237
 
234
238
  if (firstVal !== undefined) {
235
- const legacyScript = fn(firstVal);
239
+ const legacyScript = callScript(firstVal);
236
240
  if (legacyScript) return legacyScript;
237
241
  }
238
242
 
239
243
  if (script) return script;
240
244
  } else {
241
- const script = fn();
245
+ const script = callScript();
242
246
  if (script) return script;
243
247
  }
244
248
  }
@@ -290,7 +294,7 @@ export class DaemonCommandHandler implements CommandHelpers {
290
294
  }
291
295
 
292
296
  /** CLI adapter search */
293
- getCliAdapter(type?: string): any | null {
297
+ getCliAdapter(type?: string): CliAdapter | null {
294
298
  const target = type || this._currentRoute.session?.sessionId || this._currentRoute.providerType || this._currentRoute.managerKey;
295
299
  if (!target || !this._ctx.adapters) return null;
296
300
  const session = this._ctx.sessionRegistry?.get(target);
@@ -313,7 +317,7 @@ export class DaemonCommandHandler implements CommandHelpers {
313
317
  const targetSessionId = typeof args?.targetSessionId === 'string' ? args.targetSessionId.trim() : '';
314
318
  let session = targetSessionId ? this._ctx.sessionRegistry?.get(targetSessionId) : undefined;
315
319
  if (targetSessionId && !session) {
316
- reconcileIdeRuntimeSessions(this._ctx.instanceManager as any, this._ctx.sessionRegistry);
320
+ reconcileIdeRuntimeSessions(this._ctx.instanceManager, this._ctx.sessionRegistry);
317
321
  session = this._ctx.sessionRegistry?.get(targetSessionId);
318
322
  }
319
323
  const sessionLookupFailed = !!targetSessionId && !session;
@@ -28,6 +28,7 @@ import { detectIDEs } from '../detection/ide-detector.js';
28
28
  import { SessionRegistry } from '../sessions/registry.js';
29
29
  import { LOG } from '../logging/logger.js';
30
30
  import { logCommand } from '../logging/command-log.js';
31
+ import type { CommandLogEntry } from '../logging/command-log.js';
31
32
  import { getRecentLogs, LOG_PATH } from '../logging/logger.js';
32
33
  import { buildSessionEntries } from '../status/builders.js';
33
34
  import { getSessionCompletionMarker } from '../status/snapshot.js';
@@ -86,6 +87,19 @@ const CHAT_COMMANDS = [
86
87
  ];
87
88
  const READ_DEBUG_ENABLED = process.argv.includes('--dev') || process.env.ADHDEV_READ_DEBUG === '1';
88
89
 
90
+ function normalizeCommandSource(source: string): CommandLogEntry['source'] {
91
+ switch (source) {
92
+ case 'ws':
93
+ case 'p2p':
94
+ case 'ext':
95
+ case 'api':
96
+ case 'standalone':
97
+ return source;
98
+ default:
99
+ return 'unknown';
100
+ }
101
+ }
102
+
89
103
  function toHostedCliRuntimeDescriptor(record: any): HostedCliRuntimeDescriptor | null {
90
104
  if (!record || typeof record !== 'object') return null;
91
105
  const runtimeId = typeof record.sessionId === 'string' ? record.sessionId : '';
@@ -130,18 +144,19 @@ export class DaemonCommandRouter {
130
144
  */
131
145
  async execute(cmd: string, args: any, source: string = 'unknown'): Promise<CommandRouterResult> {
132
146
  const cmdStart = Date.now();
147
+ const logSource = normalizeCommandSource(source);
133
148
 
134
149
  try {
135
150
  // 1. Try daemon-level command
136
151
  const daemonResult = await this.executeDaemonCommand(cmd, args);
137
152
  if (daemonResult) {
138
- logCommand({ ts: new Date().toISOString(), cmd, source: source as any, args, success: daemonResult.success, durationMs: Date.now() - cmdStart });
153
+ logCommand({ ts: new Date().toISOString(), cmd, source: logSource, args, success: daemonResult.success, durationMs: Date.now() - cmdStart });
139
154
  return daemonResult;
140
155
  }
141
156
 
142
157
  // 2. Delegate to DaemonCommandHandler
143
158
  const handlerResult = await this.deps.commandHandler.handle(cmd, args);
144
- logCommand({ ts: new Date().toISOString(), cmd, source: source as any, args, success: handlerResult.success, durationMs: Date.now() - cmdStart });
159
+ logCommand({ ts: new Date().toISOString(), cmd, source: logSource, args, success: handlerResult.success, durationMs: Date.now() - cmdStart });
145
160
 
146
161
  // 3. Post-chat command callback
147
162
  if (CHAT_COMMANDS.includes(cmd) && this.deps.onPostChatCommand) {
@@ -150,7 +165,7 @@ export class DaemonCommandRouter {
150
165
 
151
166
  return handlerResult;
152
167
  } catch (e: any) {
153
- logCommand({ ts: new Date().toISOString(), cmd, source: source as any, args, success: false, error: e.message, durationMs: Date.now() - cmdStart });
168
+ logCommand({ ts: new Date().toISOString(), cmd, source: logSource, args, success: false, error: e.message, durationMs: Date.now() - cmdStart });
154
169
  throw e;
155
170
  }
156
171
  }
@@ -417,7 +432,7 @@ export class DaemonCommandRouter {
417
432
  ? this.deps.getCdpLogFn(result.ideId)
418
433
  : LOG.forComponent(`CDP:${result.ideId}`).asLogFn();
419
434
  const provider = this.deps.providerLoader.getMeta(result.ideId);
420
- const manager = new DaemonCdpManager(result.port, logFn, undefined, (provider as any)?.targetFilter);
435
+ const manager = new DaemonCdpManager(result.port, logFn, undefined, provider?.targetFilter);
421
436
  const connected = await manager.connect();
422
437
  if (connected) {
423
438
  // Register active extension providers for this IDE in CDP manager
@@ -457,7 +472,7 @@ export class DaemonCommandRouter {
457
472
  }));
458
473
  } catch { /* ignore activity persist errors */ }
459
474
  }
460
- return { success: result.success, ...result as any };
475
+ return { ...result };
461
476
  }
462
477
 
463
478
  // ─── Detect IDEs ───
@@ -485,7 +500,7 @@ export class DaemonCommandRouter {
485
500
  const prevSeenAt = currentState.sessionReads?.[sessionId] || 0;
486
501
  const sessionEntries = buildSessionEntries(
487
502
  this.deps.instanceManager.collectAllStates(),
488
- this.deps.cdpManagers as Map<string, any>,
503
+ this.deps.cdpManagers,
489
504
  );
490
505
  const targetSession = sessionEntries.find((entry) => entry.id === sessionId);
491
506
  const completionMarker = targetSession ? getSessionCompletionMarker(targetSession) : '';
@@ -606,8 +621,7 @@ export class DaemonCommandRouter {
606
621
  }
607
622
  }
608
623
  for (const instanceKey of keysToRemove) {
609
- const ideInstance = this.deps.instanceManager.getInstance(instanceKey) as any;
610
- if (ideInstance) {
624
+ if (this.deps.instanceManager.getInstance(instanceKey)) {
611
625
  this.deps.instanceManager.removeInstance(instanceKey);
612
626
  LOG.info('StopIDE', `Instance removed: ${instanceKey}`);
613
627
  }
@@ -615,8 +629,7 @@ export class DaemonCommandRouter {
615
629
  // Fallback: single instance key
616
630
  if (keysToRemove.length === 0) {
617
631
  const instanceKey = `ide:${ideType}`;
618
- const ideInstance = this.deps.instanceManager.getInstance(instanceKey) as any;
619
- if (ideInstance) {
632
+ if (this.deps.instanceManager.getInstance(instanceKey)) {
620
633
  this.deps.instanceManager.removeInstance(instanceKey);
621
634
  LOG.info('StopIDE', `Instance removed: ${instanceKey}`);
622
635
  }
@@ -5,11 +5,16 @@
5
5
 
6
6
  import type { CommandResult, CommandHelpers } from './handler.js';
7
7
  import type { ProviderLoader } from '../providers/provider-loader.js';
8
+ import type { ProviderInstance } from '../providers/provider-instance.js';
8
9
  import { LOG } from '../logging/logger.js';
9
10
 
11
+ interface CliPresentationInstance extends ProviderInstance {
12
+ getPresentationMode?(): 'terminal' | 'chat';
13
+ }
14
+
10
15
  function getCliPresentationMode(h: CommandHelpers, targetSessionId?: string): 'terminal' | 'chat' | null {
11
16
  if (!targetSessionId) return null;
12
- const instance = h.ctx.instanceManager?.getInstance(targetSessionId) as any;
17
+ const instance = h.ctx.instanceManager?.getInstance(targetSessionId) as CliPresentationInstance | undefined;
13
18
  if (instance?.category !== 'cli') return null;
14
19
  const mode = instance.getPresentationMode?.();
15
20
  return mode === 'chat' || mode === 'terminal' ? mode : null;
@@ -49,11 +54,12 @@ export function handlePtyResize(h: CommandHelpers, args: any): CommandResult {
49
54
  if (!adapter || typeof adapter.resize !== 'function') {
50
55
  return { success: false, error: `CLI adapter not found: ${targetSessionId || cliType || 'unknown'}` };
51
56
  }
57
+ const resize = adapter.resize;
52
58
  if (force) {
53
- adapter.resize(cols - 1, rows);
54
- setTimeout(() => adapter.resize(cols, rows), 50);
59
+ resize(cols - 1, rows);
60
+ setTimeout(() => resize(cols, rows), 50);
55
61
  } else {
56
- adapter.resize(cols, rows);
62
+ resize(cols, rows);
57
63
  }
58
64
  return { success: true };
59
65
  }
@@ -119,7 +125,7 @@ function parseScriptResult(result: unknown): { success: boolean; payload: any }
119
125
  return { success: true, payload: { result } };
120
126
  }
121
127
  }
122
- if (result && typeof result === 'object' && (result as any).success === false) {
128
+ if (result && typeof result === 'object' && 'success' in result && result.success === false) {
123
129
  return { success: false, payload: result };
124
130
  }
125
131
  return { success: true, payload: result };
@@ -57,10 +57,11 @@ export interface ADHDevConfig {
57
57
 
58
58
  /**
59
59
  * Server-side D1 `machines.id` — the row ID assigned when daemon registers via
60
- * `POST /cli/complete`. Used as fallback for machine lookup on re-auth.
60
+ * `POST /cli/complete`. This remains useful for account-side machine actions
61
+ * that target the registered machine row directly (for example cloud rename).
61
62
  *
62
- * @deprecated Legacy bridge field will be removed after 2026-05-01.
63
- * Modern auth flow uses `machineSecret` (adm_) to identify machines.
63
+ * Machine auth itself uses `machineSecret` (adm_) and no longer falls back
64
+ * to `registeredMachineId`.
64
65
  */
65
66
  registeredMachineId?: string;
66
67
 
@@ -174,17 +175,10 @@ function ensureMachineId(config: ADHDevConfig): { config: ADHDevConfig; changed:
174
175
  return { config, changed: false };
175
176
  }
176
177
 
177
- // TODO(2026-05-01): Remove this legacy bridge after cloud clients have had
178
- // time to persist registeredMachineId from the upgraded setup/login flow.
179
- const legacyRegisteredMachineId = (!config.registeredMachineId && config.machineSecret && config.machineId)
180
- ? config.machineId
181
- : config.registeredMachineId;
182
-
183
178
  return {
184
179
  config: {
185
180
  ...config,
186
181
  machineId: generateMachineId(),
187
- registeredMachineId: legacyRegisteredMachineId,
188
182
  },
189
183
  changed: true,
190
184
  };
@@ -10,6 +10,7 @@ import * as fs from 'fs';
10
10
  import * as path from 'path';
11
11
  import * as os from 'os';
12
12
  import type * as http from 'http';
13
+ import type { ChildProcess } from 'child_process';
13
14
  import type { DevServerContext, ProviderCategory } from './dev-server-types.js';
14
15
  import { DEV_SERVER_PORT } from './dev-server.js';
15
16
  import { LOG } from '../logging/logger.js';
@@ -33,8 +34,8 @@ type CliExerciseVerification = {
33
34
  };
34
35
 
35
36
  function getAutoImplPid(ctx: DevServerContext): number | null {
36
- const proc: any = ctx.autoImplProcess;
37
- return proc && typeof proc.pid === 'number' && proc.pid > 0 ? proc.pid : null;
37
+ const pid = ctx.autoImplProcess?.pid;
38
+ return typeof pid === 'number' && pid > 0 ? pid : null;
38
39
  }
39
40
 
40
41
  function isPidAlive(pid: number): boolean {
@@ -57,6 +58,15 @@ function clearStaleAutoImplState(ctx: DevServerContext, reason: string): void {
57
58
  ctx.autoImplStatus.running = false;
58
59
  }
59
60
 
61
+ function tryKillAutoImplProcess(processRef: ChildProcess | null, signal: NodeJS.Signals): void {
62
+ if (!processRef) return;
63
+ try {
64
+ processRef.kill(signal);
65
+ } catch {
66
+ // ignore
67
+ }
68
+ }
69
+
60
70
  export function getDefaultAutoImplReference(ctx: DevServerContext, category: string, type: string): string {
61
71
  if (category === 'cli') {
62
72
  return type === 'codex-cli' ? 'claude-cli' : 'codex-cli';
@@ -283,14 +293,14 @@ export async function handleAutoImplement(ctx: DevServerContext, type: string, r
283
293
 
284
294
  // 5. Determine agent command from provider spawn config
285
295
  const agentProvider = ctx.providerLoader.resolve(agent) || ctx.providerLoader.getMeta(agent);
286
- const spawn = (agentProvider as any)?.spawn;
296
+ const spawn = agentProvider?.spawn;
287
297
  if (!spawn?.command) {
288
298
  try { fs.unlinkSync(promptFile); } catch { /* ignore */ }
289
299
  ctx.json(res, 400, { error: `Agent '${agent}' has no spawn config. Select a CLI provider with a spawn configuration.` });
290
300
  return;
291
301
  }
292
302
 
293
- const agentCategory = (agentProvider as any)?.category;
303
+ const agentCategory = agentProvider?.category;
294
304
 
295
305
  // ─── ACP Agent: use ACP SDK (JSON-RPC protocol) ───
296
306
  if (agentCategory === 'acp') {
@@ -521,10 +531,12 @@ export async function handleAutoImplement(ctx: DevServerContext, type: string, r
521
531
  let autoStopIssued = false;
522
532
 
523
533
  try {
524
- const { normalizeCliProviderForRuntime } = await import('../cli-adapters/provider-cli-adapter.js');
525
- const normalized = normalizeCliProviderForRuntime(agentProvider);
526
- approvalPatterns = normalized.patterns.approval;
527
- approvalKeys = (agentProvider as any)?.approvalKeys || { 0: 'y\r', 1: 'a\r' };
534
+ if (agentProvider?.category === 'cli') {
535
+ const { normalizeCliProviderForRuntime } = await import('../cli-adapters/provider-cli-adapter.js');
536
+ const normalized = normalizeCliProviderForRuntime(agentProvider);
537
+ approvalPatterns = normalized.patterns.approval;
538
+ approvalKeys = agentProvider.approvalKeys || { 0: 'y\r', 1: 'a\r' };
539
+ }
528
540
  } catch (err: any) {
529
541
  ctx.log(`Failed to load approval patterns: ${err.message}`);
530
542
  }
@@ -547,11 +559,7 @@ export async function handleAutoImplement(ctx: DevServerContext, type: string, r
547
559
  sendAutoImplSSE(ctx, { event: 'output', data: { chunk: `\n[🤖 ADHDev Pipeline] Completion token detected. Proceeding...\n`, stream: 'stdout' } });
548
560
  approvalBuffer = '';
549
561
 
550
- try {
551
- (ctx.autoImplProcess as any).kill('SIGINT');
552
- } catch {
553
- // ignore
554
- }
562
+ tryKillAutoImplProcess(ctx.autoImplProcess, 'SIGINT');
555
563
  return;
556
564
  }
557
565
 
@@ -592,11 +600,7 @@ export async function handleAutoImplement(ctx: DevServerContext, type: string, r
592
600
  stream: 'stdout',
593
601
  },
594
602
  });
595
- try {
596
- (ctx.autoImplProcess as any).kill('SIGINT');
597
- } catch {
598
- // ignore
599
- }
603
+ tryKillAutoImplProcess(ctx.autoImplProcess, 'SIGINT');
600
604
  }, 30000);
601
605
  };
602
606
 
@@ -9,6 +9,8 @@ import * as fs from 'fs';
9
9
  import * as path from 'path';
10
10
  import type * as http from 'http';
11
11
  import type { DevServerContext } from './dev-server-types.js';
12
+ import type { CliAdapter } from '../cli-adapter-types.js';
13
+ import type { AcpProviderState, CliProviderState, ProviderInstance, ProviderState } from '../providers/provider-instance.js';
12
14
 
13
15
  // ─── Helpers ──────────────────────────────────────
14
16
 
@@ -56,6 +58,36 @@ type CliExerciseFixture = {
56
58
  notes?: string;
57
59
  };
58
60
 
61
+ type CliTargetState = CliProviderState | AcpProviderState;
62
+ type CliDebugState = {
63
+ status?: string;
64
+ activeModal?: { message?: string; buttons?: string[] } | null;
65
+ startupParseGate?: boolean;
66
+ ready?: boolean;
67
+ currentTurnScope?: unknown;
68
+ providerResolution?: Record<string, any> | null;
69
+ messages?: Array<{ role?: string; content?: string }>;
70
+ partialResponse?: string;
71
+ [key: string]: unknown;
72
+ };
73
+ type CliTraceState = {
74
+ entryCount?: number;
75
+ activeModal?: { message?: string; buttons?: string[] } | null;
76
+ entries?: Array<{ type?: string; [key: string]: unknown }>;
77
+ messages?: Array<{ role?: string; content?: string }>;
78
+ responseBuffer?: string;
79
+ [key: string]: unknown;
80
+ };
81
+ type CliDebugAdapter = CliAdapter & {
82
+ getDebugState?: () => CliDebugState | null;
83
+ getTraceState?: (limit?: number) => CliTraceState | null;
84
+ getProviderResolutionMeta?: () => Record<string, any> | null;
85
+ };
86
+ type CliAdapterBackedInstance = ProviderInstance & {
87
+ getAdapter?: () => CliDebugAdapter;
88
+ adapter?: CliDebugAdapter;
89
+ };
90
+
59
91
  function slugifyFixtureName(value: string): string {
60
92
  const normalized = String(value || '')
61
93
  .trim()
@@ -223,7 +255,18 @@ export function validateCliFixtureResult(result: any, assertions: CliFixtureAsse
223
255
  return failures;
224
256
  }
225
257
 
226
- function getCliProviderResolutionMeta(ctx: DevServerContext, type: string, adapter?: any): Record<string, any> | null {
258
+ function isCliTargetState(state: ProviderState): state is CliTargetState {
259
+ return state.category === 'cli' || state.category === 'acp';
260
+ }
261
+
262
+ function getCliAdapterFromInstance(instance: ProviderInstance | undefined): CliDebugAdapter | null {
263
+ if (!instance) return null;
264
+ const candidate = instance as CliAdapterBackedInstance;
265
+ if (typeof candidate.getAdapter === 'function') return candidate.getAdapter();
266
+ return candidate.adapter || null;
267
+ }
268
+
269
+ function getCliProviderResolutionMeta(ctx: DevServerContext, type: string, adapter?: CliDebugAdapter | null): Record<string, any> | null {
227
270
  const adapterMeta = typeof adapter?.getProviderResolutionMeta === 'function'
228
271
  ? adapter.getProviderResolutionMeta()
229
272
  : (adapter?.getDebugState?.()?.providerResolution || null);
@@ -241,11 +284,11 @@ function getCliProviderResolutionMeta(ctx: DevServerContext, type: string, adapt
241
284
  };
242
285
  }
243
286
 
244
- function findCliTarget(ctx: DevServerContext, type?: string, instanceId?: string): any | null {
287
+ function findCliTarget(ctx: DevServerContext, type?: string, instanceId?: string): CliTargetState | null {
245
288
  if (!ctx.instanceManager) return null;
246
289
  const cliStates = ctx.instanceManager
247
290
  .collectAllStates()
248
- .filter(s => s.category === 'cli' || s.category === 'acp');
291
+ .filter(isCliTargetState);
249
292
  if (instanceId) return cliStates.find(s => s.instanceId === instanceId) || null;
250
293
  if (!type) return cliStates[cliStates.length - 1] || null;
251
294
  const matches = cliStates.filter(s => s.type === type);
@@ -253,16 +296,16 @@ function findCliTarget(ctx: DevServerContext, type?: string, instanceId?: string
253
296
  }
254
297
 
255
298
  function getCliTargetBundle(ctx: DevServerContext, type?: string, instanceId?: string): {
256
- target: any;
257
- instance: any;
258
- adapter: any;
299
+ target: CliTargetState;
300
+ instance: ProviderInstance;
301
+ adapter: CliDebugAdapter;
259
302
  } | null {
260
303
  if (!ctx.instanceManager) return null;
261
304
  const target = findCliTarget(ctx, type, instanceId);
262
305
  if (!target) return null;
263
- const instance = ctx.instanceManager.getInstance(target.instanceId) as any;
306
+ const instance = ctx.instanceManager.getInstance(target.instanceId);
264
307
  if (!instance) return null;
265
- const adapter = instance.getAdapter?.() || instance.adapter;
308
+ const adapter = getCliAdapterFromInstance(instance);
266
309
  if (!adapter) return null;
267
310
  return { target, instance, adapter };
268
311
  }
@@ -838,14 +881,14 @@ export async function handleCliDebug(ctx: DevServerContext, type: string, _req:
838
881
  }
839
882
 
840
883
  // Get the ProviderInstance and access adapter debug state
841
- const instance = ctx.instanceManager.getInstance(target.instanceId) as any;
884
+ const instance = ctx.instanceManager.getInstance(target.instanceId);
842
885
  if (!instance) {
843
886
  ctx.json(res, 404, { error: `Instance not found: ${target.instanceId}` });
844
887
  return;
845
888
  }
846
889
 
847
890
  try {
848
- const adapter = instance.getAdapter?.() || instance.adapter;
891
+ const adapter = getCliAdapterFromInstance(instance);
849
892
  if (adapter && typeof adapter.getDebugState === 'function') {
850
893
  const debugState = adapter.getDebugState();
851
894
  ctx.json(res, 200, {
@@ -891,14 +934,14 @@ export async function handleCliTrace(ctx: DevServerContext, type: string, req: h
891
934
  return;
892
935
  }
893
936
 
894
- const instance = ctx.instanceManager.getInstance(target.instanceId) as any;
937
+ const instance = ctx.instanceManager.getInstance(target.instanceId);
895
938
  if (!instance) {
896
939
  ctx.json(res, 404, { error: `Instance not found: ${target.instanceId}` });
897
940
  return;
898
941
  }
899
942
 
900
943
  try {
901
- const adapter = instance.getAdapter?.() || instance.adapter;
944
+ const adapter = getCliAdapterFromInstance(instance);
902
945
  const url = new URL(req.url || '/', 'http://127.0.0.1');
903
946
  const limit = parseInt(url.searchParams.get('limit') || '120', 10);
904
947
  if (adapter && typeof adapter.getTraceState === 'function') {
@@ -1101,8 +1144,8 @@ export async function handleCliResolve(ctx: DevServerContext, req: http.Incoming
1101
1144
  return;
1102
1145
  }
1103
1146
 
1104
- const instance = ctx.instanceManager.getInstance(target.instanceId) as any;
1105
- const adapter = instance?.getAdapter?.() || instance?.adapter;
1147
+ const instance = ctx.instanceManager.getInstance(target.instanceId);
1148
+ const adapter = getCliAdapterFromInstance(instance);
1106
1149
  if (!adapter) {
1107
1150
  ctx.json(res, 404, { error: `Adapter not found for instance: ${target.instanceId}` });
1108
1151
  return;
@@ -1144,8 +1187,8 @@ export async function handleCliRaw(ctx: DevServerContext, req: http.IncomingMess
1144
1187
  return;
1145
1188
  }
1146
1189
 
1147
- const instance = ctx.instanceManager.getInstance(target.instanceId) as any;
1148
- const adapter = instance?.getAdapter?.() || instance?.adapter;
1190
+ const instance = ctx.instanceManager.getInstance(target.instanceId);
1191
+ const adapter = getCliAdapterFromInstance(instance);
1149
1192
  if (!adapter) {
1150
1193
  ctx.json(res, 404, { error: `Adapter not found for instance: ${target.instanceId}` });
1151
1194
  return;