

























@@ -4,16 +4,20 @@ import path from "node:path";
44import {
55clearRuntimeAuthProfileStoreSnapshots,
66ensureAuthProfileStore,
7+upsertAuthProfile,
78} from "openclaw/plugin-sdk/agent-runtime";
89import { createTestPluginApi } from "openclaw/plugin-sdk/plugin-test-api";
910import { afterEach, describe, expect, it, vi } from "vitest";
101111-const resolveCopilotApiTokenMock = vi.hoisted(() => vi.fn());
12+const mocks = vi.hoisted(() => ({
13+githubCopilotLoginCommand: vi.fn(),
14+resolveCopilotApiToken: vi.fn(),
15+}));
12161317vi.mock("./register.runtime.js", () => ({
1418DEFAULT_COPILOT_API_BASE_URL: "https://api.githubcopilot.test",
15-resolveCopilotApiToken: resolveCopilotApiTokenMock,
16-githubCopilotLoginCommand: vi.fn(),
19+resolveCopilotApiToken: mocks.resolveCopilotApiToken,
20+githubCopilotLoginCommand: mocks.githubCopilotLoginCommand,
1721fetchCopilotUsage: vi.fn(),
1822}));
1923@@ -22,6 +26,7 @@ import plugin from "./index.js";
2226const tempDirs: string[] = [];
23272428afterEach(async () => {
29+vi.clearAllMocks();
2530clearRuntimeAuthProfileStoreSnapshots();
2631await Promise.all(tempDirs.splice(0).map((dir) => fs.rm(dir, { recursive: true, force: true })));
2732});
@@ -98,11 +103,11 @@ describe("github-copilot plugin", () => {
98103} as never);
99104100105expect(result).toBeNull();
101-expect(resolveCopilotApiTokenMock).not.toHaveBeenCalled();
106+expect(mocks.resolveCopilotApiToken).not.toHaveBeenCalled();
102107});
103108104109it("uses live plugin config to re-enable discovery after startup disable", async () => {
105-resolveCopilotApiTokenMock.mockResolvedValueOnce({
110+mocks.resolveCopilotApiToken.mockResolvedValueOnce({
106111token: "copilot_api_token",
107112baseUrl: "https://api.githubcopilot.live",
108113});
@@ -125,7 +130,7 @@ describe("github-copilot plugin", () => {
125130resolveProviderApiKey: () => ({ apiKey: "gh_test_token" }),
126131} as never);
127132128-expect(resolveCopilotApiTokenMock).toHaveBeenCalledWith({
133+expect(mocks.resolveCopilotApiToken).toHaveBeenCalledWith({
129134githubToken: "gh_test_token",
130135env: { GH_TOKEN: "gh_test_token" },
131136});
@@ -137,6 +142,135 @@ describe("github-copilot plugin", () => {
137142});
138143});
139144145+it("offers to reuse an existing token profile during interactive onboarding", async () => {
146+const provider = registerProviderWithPluginConfig({});
147+const method = provider.auth[0];
148+const agentDir = await createAgentDir();
149+await fs.writeFile(
150+path.join(agentDir, "auth-profiles.json"),
151+JSON.stringify({
152+version: 1,
153+profiles: {
154+"github-copilot:github": {
155+type: "token",
156+provider: "github-copilot",
157+token: "existing-token",
158+},
159+},
160+}),
161+);
162+const prompter = {
163+confirm: vi.fn(async () => false),
164+note: vi.fn(),
165+};
166+167+const result = await method.run({
168+config: {},
169+env: {},
170+ agentDir,
171+workspaceDir: "/tmp/workspace",
172+ prompter,
173+runtime: { log: vi.fn(), error: vi.fn(), exit: vi.fn() },
174+opts: {},
175+secretInputMode: "plaintext",
176+allowSecretRefPrompt: false,
177+isRemote: false,
178+openUrl: vi.fn(),
179+oauth: { createVpsAwareHandlers: vi.fn() },
180+} as never);
181+182+expect(prompter.confirm).toHaveBeenCalledWith({
183+message: "GitHub Copilot auth already exists. Re-run login?",
184+initialValue: false,
185+});
186+expect(mocks.githubCopilotLoginCommand).not.toHaveBeenCalled();
187+expect(result).toEqual({
188+profiles: [
189+{
190+profileId: "github-copilot:github",
191+credential: {
192+type: "token",
193+provider: "github-copilot",
194+token: "existing-token",
195+},
196+},
197+],
198+defaultModel: "github-copilot/claude-opus-4.7",
199+});
200+});
201+202+it("can refresh an existing token profile during interactive onboarding", async () => {
203+const provider = registerProviderWithPluginConfig({});
204+const method = provider.auth[0];
205+const agentDir = await createAgentDir();
206+await fs.writeFile(
207+path.join(agentDir, "auth-profiles.json"),
208+JSON.stringify({
209+version: 1,
210+profiles: {
211+"github-copilot:github": {
212+type: "token",
213+provider: "github-copilot",
214+token: "existing-token",
215+},
216+},
217+}),
218+);
219+mocks.githubCopilotLoginCommand.mockImplementationOnce(async (opts: { agentDir?: string }) => {
220+upsertAuthProfile({
221+profileId: "github-copilot:github",
222+credential: {
223+type: "token",
224+provider: "github-copilot",
225+token: "refreshed-token",
226+},
227+agentDir: opts.agentDir,
228+});
229+});
230+const prompter = {
231+confirm: vi.fn(async () => true),
232+note: vi.fn(),
233+};
234+const isTtyDescriptor = Object.getOwnPropertyDescriptor(process.stdin, "isTTY");
235+Object.defineProperty(process.stdin, "isTTY", {
236+configurable: true,
237+value: true,
238+});
239+240+try {
241+const result = await method.run({
242+config: {},
243+env: {},
244+ agentDir,
245+workspaceDir: "/tmp/workspace",
246+ prompter,
247+runtime: { log: vi.fn(), error: vi.fn(), exit: vi.fn() },
248+opts: {},
249+secretInputMode: "plaintext",
250+allowSecretRefPrompt: false,
251+isRemote: false,
252+openUrl: vi.fn(),
253+oauth: { createVpsAwareHandlers: vi.fn() },
254+} as never);
255+256+expect(mocks.githubCopilotLoginCommand).toHaveBeenCalledWith(
257+{ yes: true, profileId: "github-copilot:github", agentDir },
258+expect.any(Object),
259+);
260+expect(result.profiles[0]?.credential).toEqual({
261+type: "token",
262+provider: "github-copilot",
263+token: "refreshed-token",
264+});
265+} finally {
266+if (isTtyDescriptor) {
267+Object.defineProperty(process.stdin, "isTTY", isTtyDescriptor);
268+} else {
269+delete (process.stdin as { isTTY?: boolean }).isTTY;
270+}
271+}
272+});
273+140274it("stores GitHub Copilot token from non-interactive onboarding", async () => {
141275const provider = registerProviderWithPluginConfig({});
142276const method = provider.auth[0];
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。