@agent-link/agent 0.1.235 → 0.1.237

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":"AAAA;;;;;GAKG;AAGH,MAAM,CAAC,MAAM,mBAAmB,GAA2B,CAAC,QAAQ,EAAE,OAAO,CAAU,CAAC;AA0PxF,sEAAsE;AACtE,MAAM,UAAU,iBAAiB;IAC/B,MAAM,GAAG,GAAG,GAAe,EAAE,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;IACrD,OAAO;QACL,SAAS,EAAE;YACT,iBAAiB,EAAE,KAAK;YACxB,iBAAiB,EAAE,KAAK;YACxB,eAAe,EAAE,KAAK;YACtB,eAAe,EAAE,KAAK;YACtB,IAAI,EAAE,GAAG,EAAE;YACX,UAAU,EAAE,GAAG,EAAE;SAClB;QACD,SAAS,EAAE;YACT,OAAO,EAAE,GAAG,EAAE;YACd,UAAU,EAAE,GAAG,EAAE;YACjB,WAAW,EAAE,GAAG,EAAE;YAClB,WAAW,EAAE,GAAG,EAAE;YAClB,SAAS,EAAE,GAAG,EAAE;SACjB;QACD,SAAS,EAAE;YACT,IAAI,EAAE,KAAK;YACX,SAAS,EAAE,GAAG,EAAE;YAChB,IAAI,EAAE,GAAG,EAAE;YACX,KAAK,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE;YAC3B,aAAa,EAAE,GAAG,EAAE;YACpB,OAAO,EAAE,GAAG,EAAE;YACd,aAAa,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE;SACpC;QACD,OAAO,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE;QAClF,MAAM,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,gBAAgB,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE;QACtE,KAAK,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,gBAAgB,EAAE,KAAK,EAAE,oBAAoB,EAAE,EAAE,EAAE;QAC3E,YAAY,EAAE;YACZ,WAAW,EAAE,GAAG,EAAE;YAClB,UAAU,EAAE,GAAG,EAAE;YACjB,aAAa,EAAE,GAAG,EAAE;YACpB,KAAK,EAAE,GAAG,EAAE;YACZ,iBAAiB,EAAE,GAAG,EAAE;YACxB,MAAM,EAAE,GAAG,EAAE;SACd;QACD,YAAY,EAAE,EAAE;KACjB,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB;IAChC,MAAM,GAAG,GAAG,CAAC,OAAiB,EAAc,EAAE,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;IAC9E,MAAM,EAAE,GAAG,GAAe,EAAE,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;IACpD,OAAO;QACL,SAAS,EAAE;YACT,iBAAiB,EAAE,IAAI;YACvB,iBAAiB,EAAE,IAAI;YACvB,eAAe,EAAE,IAAI,EAAE,8CAA8C;YACrE,eAAe,EAAE,KAAK;YACtB,IAAI,EAAE,EAAE,EAAE,EAAW,+EAA+E;YACpG,UAAU,EAAE,EAAE,EAAE,EAAK,4CAA4C;SAClE;QACD,SAAS,EAAE;YACT,OAAO,EAAE,EAAE,EAAE,EAAQ,yDAAyD;YAC9E,UAAU,EAAE,EAAE,EAAE;YAChB,WAAW,EAAE,EAAE,EAAE;YACjB,WAAW,EAAE,GAAG,EAAE,EAAG,mDAAmD;YACxE,SAAS,EAAE,GAAG,EAAE,EAAK,sCAAsC;SAC5D;QACD,SAAS,EAAE;YACT,IAAI,EAAE,IAAI;YACV,SAAS,EAAE,GAAG,EAAE,EAAK,kBAAkB;YACvC,IAAI,EAAE,GAAG,EAAE,EAAU,qBAAqB;YAC1C,KAAK,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,EAAE;YAC3D,aAAa,EAAE,EAAE,EAAE,EAAE,wDAAwD;YAC7E,OAAO,EAAE,EAAE,EAAE;YACb,aAAa,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE;SACpC;QACD,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE;QAC7E,MAAM,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,gBAAgB,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE;QACpE,KAAK,EAAE;YACL,SAAS,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,CAAC;YACnH,gBAAgB,EAAE,IAAI;YACtB,oBAAoB,EAAE,CAAC,MAAM,EAAE,eAAe,CAAC;SAChD;QACD,YAAY,EAAE;YACZ,WAAW,EAAE,EAAE,EAAE;YACjB,UAAU,EAAE,EAAE,EAAE;YAChB,aAAa,EAAE,EAAE,EAAE;YACnB,KAAK,EAAE,EAAE,EAAE;YACX,iBAAiB,EAAE,EAAE,EAAE;YACvB,MAAM,EAAE,EAAE,EAAE;SACb;QACD,YAAY,EAAE,CAAC,cAAc,CAAC,EAAE,qCAAqC;KACtE,CAAC;AACJ,CAAC"}
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, rebindCopilotConversation, 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,45 @@ 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
+ // Rebind running copilot process to new conversationId (handles page refresh)
743
+ if (convId) {
744
+ rebindCopilotConversation(m.claudeSessionId, convId);
745
+ }
746
+ // Create a copilot placeholder so follow-up chats auto-resume
747
+ if (convId) {
748
+ createCopilotPlaceholder(convId, { providerId: 'copilot' });
749
+ const placeholder = getCopilotConversation(convId);
750
+ if (placeholder) {
751
+ placeholder.copilotSessionId = m.claudeSessionId;
752
+ placeholder.workDir = explicitWorkDir || state.workDir;
753
+ }
754
+ }
755
+ const resolvedWorkDir = explicitWorkDir || state.workDir;
756
+ const history = readCopilotSessionMessages(resolvedWorkDir, m.claudeSessionId);
757
+ // Check if this session has an active copilot process running
758
+ const copilotState = getCopilotConversation(convId || '');
759
+ const isCopilotProcessing = !!(copilotState?.turnActive && copilotState?.child);
760
+ console.log(`[AgentLink] → conversation_resumed (${history.length} copilot messages, session ${m.claudeSessionId.slice(0, 8)})`);
761
+ send({
762
+ type: 'conversation_resumed',
763
+ conversationId: convId,
764
+ claudeSessionId: m.claudeSessionId,
765
+ history,
766
+ isCompacting: false,
767
+ isProcessing: isCopilotProcessing,
768
+ planMode: false,
769
+ permissionMode: 'normal',
770
+ ...(typeof m.scrollToMessageIdx === 'number' ? { scrollToMessageIdx: m.scrollToMessageIdx } : {}),
771
+ ...(m.searchQuery ? { searchQuery: m.searchQuery } : {}),
772
+ });
773
+ break;
774
+ }
680
775
  if (!convId) {
681
776
  // Backward compat: single-session mode
682
777
  const conv = getConversation();
@@ -803,13 +898,27 @@ function handleServerMessage(msg) {
803
898
  case 'delete_session': {
804
899
  const m = msg;
805
900
  const dir = m.workDir?.trim() ? path.resolve(m.workDir) : state.workDir;
806
- handleDeleteSession(m.sessionId, dir);
901
+ if (isCopilotBackend()) {
902
+ const ok = deleteCopilotSession(dir, m.sessionId);
903
+ console.log(`[AgentLink] delete copilot session ${m.sessionId}: ${ok}`);
904
+ handleListCopilotSessionsFn(dir);
905
+ }
906
+ else {
907
+ handleDeleteSession(m.sessionId, dir);
908
+ }
807
909
  break;
808
910
  }
809
911
  case 'rename_session': {
810
912
  const m = msg;
811
913
  const dir = m.workDir?.trim() ? path.resolve(m.workDir) : state.workDir;
812
- handleRenameSession(m.sessionId, m.newTitle, dir);
914
+ if (isCopilotBackend()) {
915
+ const ok = renameCopilotSession(dir, m.sessionId, m.newTitle);
916
+ console.log(`[AgentLink] rename copilot session ${m.sessionId}: ${ok}`);
917
+ handleListCopilotSessionsFn(dir);
918
+ }
919
+ else {
920
+ handleRenameSession(m.sessionId, m.newTitle, dir);
921
+ }
813
922
  break;
814
923
  }
815
924
  case 'query_active_conversations': {
@@ -1076,23 +1185,85 @@ function handleServerMessage(msg) {
1076
1185
  case 'set_provider': {
1077
1186
  const { providerId, conversationId } = msg;
1078
1187
  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 });
1188
+ // Detect backend type change
1189
+ const newBackendType = getBackendTypeForProvider(providerId);
1190
+ const oldBackendType = getBackendType();
1191
+ const backendChanged = newBackendType !== oldBackendType;
1192
+ if (backendChanged) {
1193
+ // Cancel any in-flight work on the old backend
1194
+ if (oldBackendType === 'copilot' && conversationId) {
1195
+ cancelCopilotExecution(conversationId);
1196
+ }
1197
+ else if (conversationId) {
1198
+ const conv = getConversation(conversationId);
1199
+ if (conv) {
1200
+ const result = restartConversation(conversationId, { providerId });
1201
+ if (result.wasTurnActive) {
1202
+ send({ type: 'execution_cancelled', conversationId });
1203
+ }
1204
+ }
1205
+ }
1206
+ setBackendType(newBackendType);
1207
+ console.log(`[AgentLink] Backend switched: ${oldBackendType} → ${newBackendType}`);
1208
+ }
1209
+ else if (oldBackendType === 'copilot') {
1210
+ // Same backend (copilot), restart conversation
1211
+ if (conversationId && getCopilotConversation(conversationId)) {
1212
+ const result = restartCopilotConversation(conversationId, { providerId });
1213
+ if (result.wasTurnActive) {
1214
+ send({ type: 'execution_cancelled', conversationId });
1215
+ }
1216
+ }
1217
+ else if (conversationId) {
1218
+ createCopilotPlaceholder(conversationId, { providerId });
1084
1219
  }
1085
1220
  }
1086
1221
  else {
1087
- createPlaceholderConversation(conversationId, { providerId });
1222
+ // Same backend (claude), existing logic
1223
+ const conv = getConversation(conversationId);
1224
+ if (conv) {
1225
+ const result = restartConversation(conversationId, { providerId });
1226
+ if (result.wasTurnActive) {
1227
+ send({ type: 'execution_cancelled', conversationId });
1228
+ }
1229
+ }
1230
+ else {
1231
+ createPlaceholderConversation(conversationId, { providerId });
1232
+ }
1088
1233
  }
1089
1234
  send({ type: 'provider_changed', providerId, conversationId });
1235
+ // Send backend_info when backend type changed
1236
+ if (backendChanged) {
1237
+ const caps = newBackendType === 'copilot'
1238
+ ? copilotCapabilities()
1239
+ : undefined; // Claude doesn't send capabilities yet (Phase 2)
1240
+ send({
1241
+ type: 'backend_info',
1242
+ backend: newBackendType,
1243
+ ...(caps ? { capabilities: caps } : {}),
1244
+ });
1245
+ }
1090
1246
  break;
1091
1247
  }
1092
1248
  case 'list_providers': {
1093
1249
  const providers = listProviders();
1094
1250
  const defaultId = getDefaultProviderId();
1095
1251
  send({ type: 'providers_list', providers, default: defaultId });
1252
+ // On initial connect, sync backend type to match the default provider.
1253
+ // This handles agent restart: currentBackendType resets to 'claude' but
1254
+ // the user's saved default provider may be 'copilot'.
1255
+ const expectedBt = getBackendTypeForProvider(defaultId);
1256
+ if (expectedBt !== getBackendType()) {
1257
+ setBackendType(expectedBt);
1258
+ console.log(`[AgentLink] Backend synced to default provider: ${expectedBt}`);
1259
+ }
1260
+ if (getBackendType() === 'copilot') {
1261
+ send({
1262
+ type: 'backend_info',
1263
+ backend: 'copilot',
1264
+ capabilities: copilotCapabilities(),
1265
+ });
1266
+ }
1096
1267
  break;
1097
1268
  }
1098
1269
  case 'save_provider': {
@@ -1570,6 +1741,17 @@ function handleListSessions(dir) {
1570
1741
  send({ type: 'sessions_list', sessions: [], workDir: dir });
1571
1742
  }
1572
1743
  }
1744
+ function handleListCopilotSessionsFn(dir) {
1745
+ try {
1746
+ const sessions = listCopilotSessions(dir);
1747
+ console.log(`[AgentLink] → sessions_list (${sessions.length} copilot sessions for ${dir})`);
1748
+ send({ type: 'sessions_list', sessions, workDir: dir });
1749
+ }
1750
+ catch (err) {
1751
+ console.error(`[AgentLink] listCopilotSessions failed:`, err);
1752
+ send({ type: 'sessions_list', sessions: [], workDir: dir });
1753
+ }
1754
+ }
1573
1755
  function handleListBrainSessions() {
1574
1756
  try {
1575
1757
  const sessions = listSessions(BRAIN_DATA_DIR);