@agent-link/agent 0.1.235 → 0.1.236

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.
@@ -42,6 +42,8 @@ export function createBackend(type, _opts) {
42
42
  return new ClaudeBackend(_opts);
43
43
  case 'codex':
44
44
  throw new BackendNotImplementedError('codex');
45
+ case 'copilot':
46
+ throw new BackendNotImplementedError('copilot'); // CopilotBackend uses copilot.ts directly, not through AgentBackend
45
47
  default: {
46
48
  // exhaustiveness guard
47
49
  const _exhaustive = type;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/backends/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,mBAAmB,EAAuD,MAAM,YAAY,CAAC;AACtG,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,MAAM,OAAO,mBAAoB,SAAQ,KAAK;IAC5C,YAAY,IAAY;QACtB,KAAK,CACH,0BAA0B,IAAI,mBAAmB,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CACnF,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;IACpC,CAAC;CACF;AAED,MAAM,OAAO,0BAA2B,SAAQ,KAAK;IACnD,YAAY,IAAiB;QAC3B,KAAK,CACH,YAAY,IAAI,0DAA0D,CAC3E,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,4BAA4B,CAAC;IAC3C,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CAAC,IAAY;IACjD,IAAI,CAAE,mBAAyC,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QAC/D,MAAM,IAAI,mBAAmB,CAAC,IAAI,CAAC,CAAC;IACtC,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,KAAiB;IAC3D,sBAAsB,CAAC,IAAI,CAAC,CAAC;IAC7B,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,QAAQ;YACX,OAAO,IAAI,aAAa,CAAC,KAAK,CAAC,CAAC;QAClC,KAAK,OAAO;YACV,MAAM,IAAI,0BAA0B,CAAC,OAAO,CAAC,CAAC;QAChD,OAAO,CAAC,CAAC,CAAC;YACR,uBAAuB;YACvB,MAAM,WAAW,GAAU,IAAI,CAAC;YAChC,MAAM,IAAI,mBAAmB,CAAC,WAAW,CAAC,CAAC;QAC7C,CAAC;IACH,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/backends/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,mBAAmB,EAAuD,MAAM,YAAY,CAAC;AACtG,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,MAAM,OAAO,mBAAoB,SAAQ,KAAK;IAC5C,YAAY,IAAY;QACtB,KAAK,CACH,0BAA0B,IAAI,mBAAmB,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CACnF,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;IACpC,CAAC;CACF;AAED,MAAM,OAAO,0BAA2B,SAAQ,KAAK;IACnD,YAAY,IAAiB;QAC3B,KAAK,CACH,YAAY,IAAI,0DAA0D,CAC3E,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,4BAA4B,CAAC;IAC3C,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CAAC,IAAY;IACjD,IAAI,CAAE,mBAAyC,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QAC/D,MAAM,IAAI,mBAAmB,CAAC,IAAI,CAAC,CAAC;IACtC,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,KAAiB;IAC3D,sBAAsB,CAAC,IAAI,CAAC,CAAC;IAC7B,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,QAAQ;YACX,OAAO,IAAI,aAAa,CAAC,KAAK,CAAC,CAAC;QAClC,KAAK,OAAO;YACV,MAAM,IAAI,0BAA0B,CAAC,OAAO,CAAC,CAAC;QAChD,KAAK,SAAS;YACZ,MAAM,IAAI,0BAA0B,CAAC,SAAS,CAAC,CAAC,CAAC,oEAAoE;QACvH,OAAO,CAAC,CAAC,CAAC;YACR,uBAAuB;YACvB,MAAM,WAAW,GAAU,IAAI,CAAC;YAChC,MAAM,IAAI,mBAAmB,CAAC,WAAW,CAAC,CAAC;QAC7C,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -4,7 +4,7 @@
4
4
  * Stage 1: defines the interface only. ClaudeBackend implementation lives in
5
5
  * agent/src/claude.ts (refactor to backends/claude/* is a follow-up PR).
6
6
  */
7
- export type BackendType = 'claude' | 'codex';
7
+ export type BackendType = 'claude' | 'codex' | 'copilot';
8
8
  export declare const KNOWN_BACKEND_TYPES: readonly BackendType[];
9
9
  /**
10
10
  * Backend-neutral file attachment for `UserTurnInput.files`.
@@ -319,3 +319,9 @@ export declare function emptyCapabilities(): BackendCapabilities;
319
319
  * yet, so both are reported as unsupported.
320
320
  */
321
321
  export declare function claudeCapabilities(): BackendCapabilities;
322
+ /**
323
+ * Capabilities declared by the CopilotBackend adapter.
324
+ * Copilot CLI uses `--output-format json` JSONL, per-turn process spawning,
325
+ * and `~/.copilot/session-state/` for session persistence.
326
+ */
327
+ export declare function copilotCapabilities(): BackendCapabilities;
@@ -4,7 +4,7 @@
4
4
  * Stage 1: defines the interface only. ClaudeBackend implementation lives in
5
5
  * agent/src/claude.ts (refactor to backends/claude/* is a follow-up PR).
6
6
  */
7
- export const KNOWN_BACKEND_TYPES = ['claude', 'codex'];
7
+ export const KNOWN_BACKEND_TYPES = ['claude', 'codex', 'copilot'];
8
8
  /** Helper: minimal capabilities object for a stub/unknown backend. */
9
9
  export function emptyCapabilities() {
10
10
  const cap = () => ({ supported: false });
@@ -101,4 +101,65 @@ export function claudeCapabilities() {
101
101
  sandboxModes: ['unrestricted'], // Claude runs with bypassPermissions
102
102
  };
103
103
  }
104
+ /**
105
+ * Capabilities declared by the CopilotBackend adapter.
106
+ * Copilot CLI uses `--output-format json` JSONL, per-turn process spawning,
107
+ * and `~/.copilot/session-state/` for session persistence.
108
+ */
109
+ export function copilotCapabilities() {
110
+ const yes = (details) => ({ supported: true, details });
111
+ const no = () => ({ supported: false });
112
+ return {
113
+ lifecycle: {
114
+ persistentProcess: false, // each turn = new process
115
+ resumableSessions: true, // --resume=<sessionId>
116
+ concurrentTurns: false,
117
+ backgroundTurns: false,
118
+ fork: no(),
119
+ compaction: no(), // /compact is interactive-only
120
+ },
121
+ approvals: {
122
+ command: no(), // --allow-all-tools bypasses
123
+ fileChange: no(),
124
+ permissions: no(),
125
+ genericTool: no(),
126
+ userInput: no(), // no stdin protocol for ask_user in -p mode
127
+ },
128
+ streaming: {
129
+ text: true, // assistant.message_delta
130
+ reasoning: yes(), // assistant.reasoning_delta
131
+ plan: no(),
132
+ usage: { supported: true, details: { incremental: false } },
133
+ processOutput: no(),
134
+ fsWatch: no(),
135
+ remoteControl: { supported: false },
136
+ },
137
+ history: {
138
+ list: true, // read workspace.yaml files
139
+ read: true, // parse events.jsonl
140
+ rename: true, // edit workspace.yaml name field
141
+ delete: true, // filesystem delete
142
+ search: false,
143
+ },
144
+ models: {
145
+ list: no(), // /model is interactive-only
146
+ switchPerSession: true, // --model flag
147
+ switchPerTurn: true, // new process per turn
148
+ },
149
+ tools: {
150
+ itemTypes: ['powershell', 'bash', 'create', 'edit', 'read', 'grep', 'glob'],
151
+ fallbackRenderer: true,
152
+ specializedRenderers: [],
153
+ },
154
+ integrations: {
155
+ accountInfo: no(),
156
+ codeReview: no(),
157
+ mcpManagement: no(),
158
+ hooks: no(),
159
+ personalitySwitch: no(),
160
+ skills: no(),
161
+ },
162
+ sandboxModes: ['unrestricted'], // --allow-all-tools
163
+ };
164
+ }
104
165
  //# sourceMappingURL=types.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/backends/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/backends/types.ts"],"names":[],"mappings":"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"}
@@ -16,7 +16,7 @@ import { listDevops, getDevopsDetail } from './devops.js';
16
16
  import { listProjects, getProjectDetail } from './project.js';
17
17
  import { brainSearch, getSearchIndexStats } from './search.js';
18
18
  import { listBrainSessions, loadBrainChatEntries, sendBrainChatMessage, getBrainSessionStatus, deleteBrainSession } from './brain-chat.js';
19
- import { listProviders, saveProvider, deleteProvider, getDefaultProviderId, setDefaultProviderId } from './providers.js';
19
+ import { listProviders, saveProvider, deleteProvider, getDefaultProviderId, setDefaultProviderId, getBackendTypeForProvider } from './providers.js';
20
20
  import { createTunnelHandler } from './tunnel.js';
21
21
  import { createTerminalManager } from './terminal.js';
22
22
  import { mkdirSync } from 'fs';
@@ -24,7 +24,7 @@ const require = createRequire(import.meta.url);
24
24
  const pkg = require('../package.json');
25
25
  const TEAM_SESSIONS_DIR = path.join(CONFIG_DIR, 'team-sessions');
26
26
  const LOOP_SESSIONS_DIR = path.join(CONFIG_DIR, 'loop-sessions');
27
- import { handleChat as claudeHandleChat, addSendFn, abort as abortClaude, abortAll as abortAllClaude, cancelExecution as claudeCancelExecution, handleUserAnswer, handleToolPermissionResponse, handleBtwQuestion, getConversation, getConversations, getIsCompacting, clearSessionId, evictByClaudeSessionId, rebindConversation, addOutputObserver, removeOutputObserver, addCloseObserver, removeCloseObserver, setOutputObserver, clearOutputObserver, setCloseObserver, clearCloseObserver, restartConversation, createPlaceholderConversation, getPendingQuestions, getPendingToolPermissions, setModel, addOnSessionStarted } from './runtime.js';
27
+ import { handleChat as claudeHandleChat, addSendFn, abort as abortClaude, abortAll as abortAllClaude, cancelExecution as claudeCancelExecution, handleUserAnswer, handleToolPermissionResponse, handleBtwQuestion, getConversation, getConversations, getIsCompacting, clearSessionId, evictByClaudeSessionId, rebindConversation, addOutputObserver, removeOutputObserver, addCloseObserver, removeCloseObserver, setOutputObserver, clearOutputObserver, setCloseObserver, clearCloseObserver, restartConversation, createPlaceholderConversation, getPendingQuestions, getPendingToolPermissions, setModel, addOnSessionStarted, getBackendType, setBackendType, isCopilotBackend, addCopilotSendFn, handleCopilotChat, cancelCopilotExecution, listCopilotSessions, listAllCopilotSessions, readCopilotSessionMessages, deleteCopilotSession, renameCopilotSession, getCopilotConversation, createCopilotPlaceholder, restartCopilotConversation, copilotCapabilities } from './runtime.js';
28
28
  import { listSessions, readSessionMessages, deleteSession, renameSession, listAllRecentSessions, getSessionCacheStats } from './history.js';
29
29
  import { searchSessions } from './search-sessions.js';
30
30
  import { listMemoryFiles, updateMemoryFile, deleteMemoryFile } from './memory.js';
@@ -52,6 +52,7 @@ const state = {
52
52
  entraToken: null,
53
53
  };
54
54
  let unsubscribeSend = null;
55
+ let unsubscribeCopilotSend = null;
55
56
  let unsubscribeSessionStarted = null;
56
57
  let heartbeatInterval = null;
57
58
  let heartbeatTimeout = null;
@@ -95,6 +96,14 @@ export function connect(config) {
95
96
  catch { /* ignore */ }
96
97
  }
97
98
  unsubscribeSend = addSendFn(send);
99
+ // Also wire up copilot module to send through same WebSocket
100
+ if (unsubscribeCopilotSend) {
101
+ try {
102
+ unsubscribeCopilotSend();
103
+ }
104
+ catch { /* ignore */ }
105
+ }
106
+ unsubscribeCopilotSend = addCopilotSendFn(send);
98
107
  // Wire up action item session linkage
99
108
  if (unsubscribeSessionStarted) {
100
109
  try {
@@ -567,24 +576,71 @@ function handleServerMessage(msg) {
567
576
  if (actionItemId && chatConvId) {
568
577
  pendingActionItems.set(chatConvId, actionItemId);
569
578
  }
570
- claudeHandleChat(chatConvId, msg.prompt, chatDir, chatOptions, msg.files);
579
+ // Auto-switch backend if chat message's providerId requires a different backend
580
+ if (effectiveProviderId) {
581
+ const requiredBt = getBackendTypeForProvider(effectiveProviderId);
582
+ if (requiredBt !== getBackendType()) {
583
+ setBackendType(requiredBt);
584
+ console.log(`[AgentLink] Backend auto-switched to ${requiredBt} (chat providerId=${effectiveProviderId})`);
585
+ const caps = requiredBt === 'copilot' ? copilotCapabilities() : undefined;
586
+ send({
587
+ type: 'backend_info',
588
+ backend: requiredBt,
589
+ ...(caps ? { capabilities: caps } : {}),
590
+ });
591
+ }
592
+ }
593
+ // Route to copilot or claude based on current backend
594
+ if (isCopilotBackend()) {
595
+ handleCopilotChat(chatConvId || '', msg.prompt, chatDir, { resumeSessionId: chatOptions.resumeSessionId });
596
+ }
597
+ else {
598
+ claudeHandleChat(chatConvId, msg.prompt, chatDir, chatOptions, msg.files);
599
+ }
571
600
  break;
572
601
  }
573
602
  case 'cancel_execution':
574
- claudeCancelExecution(msg.conversationId);
603
+ if (isCopilotBackend()) {
604
+ cancelCopilotExecution(msg.conversationId || '');
605
+ }
606
+ else {
607
+ claudeCancelExecution(msg.conversationId);
608
+ }
575
609
  break;
576
610
  case 'list_sessions': {
577
611
  const m = msg;
578
612
  const dir = m.workDir?.trim() ? path.resolve(m.workDir) : state.workDir;
579
- handleListSessions(dir);
613
+ // Use providerId from message to determine backend, falling back to global state
614
+ const sessionBackend = m.providerId
615
+ ? getBackendTypeForProvider(m.providerId)
616
+ : getBackendType();
617
+ if (sessionBackend === 'copilot') {
618
+ handleListCopilotSessionsFn(dir);
619
+ }
620
+ else {
621
+ handleListSessions(dir);
622
+ }
580
623
  break;
581
624
  }
582
625
  case 'list_brain_sessions':
583
626
  handleListBrainSessions();
584
627
  break;
585
- case 'list_recent_sessions':
586
- handleListRecentSessions(msg);
628
+ case 'list_recent_sessions': {
629
+ const m = msg;
630
+ const recentBackend = m.providerId
631
+ ? getBackendTypeForProvider(m.providerId)
632
+ : getBackendType();
633
+ if (recentBackend === 'copilot') {
634
+ const limit = m.limit && m.limit > 0 ? m.limit : 500;
635
+ const sessions = listAllCopilotSessions(limit);
636
+ console.log(`[AgentLink] → recent_sessions_list (${sessions.length} copilot sessions)`);
637
+ send({ type: 'recent_sessions_list', sessions });
638
+ }
639
+ else {
640
+ handleListRecentSessions(msg);
641
+ }
587
642
  break;
643
+ }
588
644
  case 'search_sessions': {
589
645
  const m = msg;
590
646
  const dir = m.workDir?.trim() ? path.resolve(m.workDir) : state.workDir;
@@ -677,6 +733,38 @@ function handleServerMessage(msg) {
677
733
  const convId = m.conversationId;
678
734
  // Explicit workDir from frontend (e.g. action-item resume) — normalize to absolute path
679
735
  const explicitWorkDir = m.workDir?.trim() ? path.resolve(m.workDir) : undefined;
736
+ // Determine backend: use providerId from message, fall back to global state
737
+ const resumeBackend = m.providerId
738
+ ? getBackendTypeForProvider(m.providerId)
739
+ : getBackendType();
740
+ // Route to copilot backend
741
+ if (resumeBackend === 'copilot') {
742
+ // Create a copilot placeholder so follow-up chats auto-resume
743
+ if (convId) {
744
+ createCopilotPlaceholder(convId, { providerId: 'copilot' });
745
+ const placeholder = getCopilotConversation(convId);
746
+ if (placeholder) {
747
+ placeholder.copilotSessionId = m.claudeSessionId;
748
+ placeholder.workDir = explicitWorkDir || state.workDir;
749
+ }
750
+ }
751
+ const resolvedWorkDir = explicitWorkDir || state.workDir;
752
+ const history = readCopilotSessionMessages(resolvedWorkDir, m.claudeSessionId);
753
+ console.log(`[AgentLink] → conversation_resumed (${history.length} copilot messages, session ${m.claudeSessionId.slice(0, 8)})`);
754
+ send({
755
+ type: 'conversation_resumed',
756
+ conversationId: convId,
757
+ claudeSessionId: m.claudeSessionId,
758
+ history,
759
+ isCompacting: false,
760
+ isProcessing: false,
761
+ planMode: false,
762
+ permissionMode: 'normal',
763
+ ...(typeof m.scrollToMessageIdx === 'number' ? { scrollToMessageIdx: m.scrollToMessageIdx } : {}),
764
+ ...(m.searchQuery ? { searchQuery: m.searchQuery } : {}),
765
+ });
766
+ break;
767
+ }
680
768
  if (!convId) {
681
769
  // Backward compat: single-session mode
682
770
  const conv = getConversation();
@@ -803,13 +891,27 @@ function handleServerMessage(msg) {
803
891
  case 'delete_session': {
804
892
  const m = msg;
805
893
  const dir = m.workDir?.trim() ? path.resolve(m.workDir) : state.workDir;
806
- handleDeleteSession(m.sessionId, dir);
894
+ if (isCopilotBackend()) {
895
+ const ok = deleteCopilotSession(dir, m.sessionId);
896
+ console.log(`[AgentLink] delete copilot session ${m.sessionId}: ${ok}`);
897
+ handleListCopilotSessionsFn(dir);
898
+ }
899
+ else {
900
+ handleDeleteSession(m.sessionId, dir);
901
+ }
807
902
  break;
808
903
  }
809
904
  case 'rename_session': {
810
905
  const m = msg;
811
906
  const dir = m.workDir?.trim() ? path.resolve(m.workDir) : state.workDir;
812
- handleRenameSession(m.sessionId, m.newTitle, dir);
907
+ if (isCopilotBackend()) {
908
+ const ok = renameCopilotSession(dir, m.sessionId, m.newTitle);
909
+ console.log(`[AgentLink] rename copilot session ${m.sessionId}: ${ok}`);
910
+ handleListCopilotSessionsFn(dir);
911
+ }
912
+ else {
913
+ handleRenameSession(m.sessionId, m.newTitle, dir);
914
+ }
813
915
  break;
814
916
  }
815
917
  case 'query_active_conversations': {
@@ -1076,23 +1178,85 @@ function handleServerMessage(msg) {
1076
1178
  case 'set_provider': {
1077
1179
  const { providerId, conversationId } = msg;
1078
1180
  console.log(`[AgentLink] set_provider: providerId=${providerId}, conversationId=${conversationId}`);
1079
- const conv = getConversation(conversationId);
1080
- if (conv) {
1081
- const result = restartConversation(conversationId, { providerId });
1082
- if (result.wasTurnActive) {
1083
- send({ type: 'execution_cancelled', conversationId });
1181
+ // Detect backend type change
1182
+ const newBackendType = getBackendTypeForProvider(providerId);
1183
+ const oldBackendType = getBackendType();
1184
+ const backendChanged = newBackendType !== oldBackendType;
1185
+ if (backendChanged) {
1186
+ // Cancel any in-flight work on the old backend
1187
+ if (oldBackendType === 'copilot' && conversationId) {
1188
+ cancelCopilotExecution(conversationId);
1189
+ }
1190
+ else if (conversationId) {
1191
+ const conv = getConversation(conversationId);
1192
+ if (conv) {
1193
+ const result = restartConversation(conversationId, { providerId });
1194
+ if (result.wasTurnActive) {
1195
+ send({ type: 'execution_cancelled', conversationId });
1196
+ }
1197
+ }
1198
+ }
1199
+ setBackendType(newBackendType);
1200
+ console.log(`[AgentLink] Backend switched: ${oldBackendType} → ${newBackendType}`);
1201
+ }
1202
+ else if (oldBackendType === 'copilot') {
1203
+ // Same backend (copilot), restart conversation
1204
+ if (conversationId && getCopilotConversation(conversationId)) {
1205
+ const result = restartCopilotConversation(conversationId, { providerId });
1206
+ if (result.wasTurnActive) {
1207
+ send({ type: 'execution_cancelled', conversationId });
1208
+ }
1209
+ }
1210
+ else if (conversationId) {
1211
+ createCopilotPlaceholder(conversationId, { providerId });
1084
1212
  }
1085
1213
  }
1086
1214
  else {
1087
- createPlaceholderConversation(conversationId, { providerId });
1215
+ // Same backend (claude), existing logic
1216
+ const conv = getConversation(conversationId);
1217
+ if (conv) {
1218
+ const result = restartConversation(conversationId, { providerId });
1219
+ if (result.wasTurnActive) {
1220
+ send({ type: 'execution_cancelled', conversationId });
1221
+ }
1222
+ }
1223
+ else {
1224
+ createPlaceholderConversation(conversationId, { providerId });
1225
+ }
1088
1226
  }
1089
1227
  send({ type: 'provider_changed', providerId, conversationId });
1228
+ // Send backend_info when backend type changed
1229
+ if (backendChanged) {
1230
+ const caps = newBackendType === 'copilot'
1231
+ ? copilotCapabilities()
1232
+ : undefined; // Claude doesn't send capabilities yet (Phase 2)
1233
+ send({
1234
+ type: 'backend_info',
1235
+ backend: newBackendType,
1236
+ ...(caps ? { capabilities: caps } : {}),
1237
+ });
1238
+ }
1090
1239
  break;
1091
1240
  }
1092
1241
  case 'list_providers': {
1093
1242
  const providers = listProviders();
1094
1243
  const defaultId = getDefaultProviderId();
1095
1244
  send({ type: 'providers_list', providers, default: defaultId });
1245
+ // On initial connect, sync backend type to match the default provider.
1246
+ // This handles agent restart: currentBackendType resets to 'claude' but
1247
+ // the user's saved default provider may be 'copilot'.
1248
+ const expectedBt = getBackendTypeForProvider(defaultId);
1249
+ if (expectedBt !== getBackendType()) {
1250
+ setBackendType(expectedBt);
1251
+ console.log(`[AgentLink] Backend synced to default provider: ${expectedBt}`);
1252
+ }
1253
+ if (getBackendType() === 'copilot') {
1254
+ send({
1255
+ type: 'backend_info',
1256
+ backend: 'copilot',
1257
+ capabilities: copilotCapabilities(),
1258
+ });
1259
+ }
1096
1260
  break;
1097
1261
  }
1098
1262
  case 'save_provider': {
@@ -1570,6 +1734,17 @@ function handleListSessions(dir) {
1570
1734
  send({ type: 'sessions_list', sessions: [], workDir: dir });
1571
1735
  }
1572
1736
  }
1737
+ function handleListCopilotSessionsFn(dir) {
1738
+ try {
1739
+ const sessions = listCopilotSessions(dir);
1740
+ console.log(`[AgentLink] → sessions_list (${sessions.length} copilot sessions for ${dir})`);
1741
+ send({ type: 'sessions_list', sessions, workDir: dir });
1742
+ }
1743
+ catch (err) {
1744
+ console.error(`[AgentLink] listCopilotSessions failed:`, err);
1745
+ send({ type: 'sessions_list', sessions: [], workDir: dir });
1746
+ }
1747
+ }
1573
1748
  function handleListBrainSessions() {
1574
1749
  try {
1575
1750
  const sessions = listSessions(BRAIN_DATA_DIR);