File size: 4,235 Bytes
5710dd0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
const assert = require("node:assert/strict");
const { readFile, writeFile } = require("node:fs/promises");
const os = require("node:os");
const path = require("node:path");
const vscode = require("vscode");

const EXTENSION_ID = "moonshot-ai.kimi-code";
const EXPECTED_COMMANDS = [
  "kimi.clearAllState",
  "kimi.focusInput",
  "kimi.insertMention",
  "kimi.logout",
  "kimi.migrateLegacyData",
  "kimi.newConversation",
  "kimi.openInSideBar",
  "kimi.openInTab",
  "kimi.resetKimi",
  "kimi.showLogs",
];

exports.run = async function run() {
  const isolatedHome = process.env.KIMI_VSCODE_SMOKE_OS_HOME;
  assert.ok(isolatedHome, "isolated OS home must be provided");
  process.env.HOME = isolatedHome;
  process.env.USERPROFILE = isolatedHome;
  const root = path.parse(isolatedHome).root;
  process.env.HOMEDRIVE = process.platform === "win32" ? root.replace(/[\\/]+$/, "") : root;
  process.env.HOMEPATH = process.platform === "win32"
    ? `${path.sep}${isolatedHome.slice(root.length)}`
    : isolatedHome;

  const extension = vscode.extensions.getExtension(EXTENSION_ID);
  assert.ok(extension, `${EXTENSION_ID} is not installed in the isolated Extension Host`);
  const sourceManifest = JSON.parse(
    await readFile(path.join(__dirname, "..", "..", "package.json"), "utf8"),
  );
  assert.equal(extension.packageJSON.version, sourceManifest.version);
  assert.equal(extension.packageJSON.main, "./dist/extension.js");
  assert.ok(process.env.KIMI_CODE_HOME, "KIMI_CODE_HOME must point at the isolated test home");
  assert.equal(process.env.HOME, isolatedHome);
  assert.equal(process.env.USERPROFILE, isolatedHome);
  assert.equal(os.homedir(), isolatedHome);

  await extension.activate();
  assert.equal(extension.isActive, true, "extension activation did not complete");

  const commands = new Set(await vscode.commands.getCommands(true));
  for (const command of EXPECTED_COMMANDS) {
    assert.ok(commands.has(command), `missing registered command: ${command}`);
  }

  const config = vscode.workspace.getConfiguration("kimi");
  assert.equal(config.get("autosave"), true);
  assert.equal(config.get("executablePath"), undefined, "removed Python CLI setting is still contributed");
  assert.equal(config.get("environmentVariables"), undefined, "removed global CLI env setting is still contributed");

  await vscode.commands.executeCommand("kimi.openInTab");
  await waitFor(() => {
    return vscode.window.tabGroups.all.some((group) =>
      group.tabs.some((tab) =>
        tab.input instanceof vscode.TabInputWebview && isKimiPanelViewType(tab.input.viewType)));
  }, 5_000, () => `Kimi Webview tab did not open; tabs=${describeTabs()}`);

  await vscode.commands.executeCommand("kimi.showLogs");
  await vscode.commands.executeCommand("kimi.resetKimi");
  await vscode.commands.executeCommand("workbench.action.closeActiveEditor");

  console.log(
    JSON.stringify({
      extension: EXTENSION_ID,
      version: extension.packageJSON.version,
      vscode: vscode.version,
      remoteName: vscode.env.remoteName ?? null,
      commands: EXPECTED_COMMANDS.length,
      webview: "opened",
    }),
  );
  assert.ok(process.env.KIMI_VSCODE_SMOKE_REPORT, "Extension Host report path must be provided");
  await writeFile(
    process.env.KIMI_VSCODE_SMOKE_REPORT,
    JSON.stringify({ vscode: vscode.version }),
    "utf8",
  );
};

async function waitFor(predicate, timeoutMs, message) {
  const deadline = Date.now() + timeoutMs;
  while (Date.now() < deadline) {
    if (predicate()) return;
    await new Promise((resolve) => setTimeout(resolve, 50));
  }
  throw new Error(typeof message === "function" ? message() : message);
}

function describeTabs() {
  return JSON.stringify(vscode.window.tabGroups.all.map((group) =>
    group.tabs.map((tab) => ({
      label: tab.label,
      input: tab.input?.constructor?.name,
      viewType: tab.input instanceof vscode.TabInputWebview ? tab.input.viewType : undefined,
      active: tab.isActive,
    }))));
}

function isKimiPanelViewType(viewType) {
  // VS Code 1.100 exposes the internal `mainThreadWebview-` prefix here;
  // newer hosts expose the extension's original view type.
  return viewType === "kimiPanel" || viewType.endsWith("-kimiPanel");
}