pi-x-ide 1.15.2 → 1.16.0

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.
@@ -1,34 +1,27 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.IDE_HOST_TCP_PROBE_TIMEOUT_MS = exports.PI_X_IDE_HOST_OVERRIDE_ENV = void 0;
4
- exports.resolveIdeHost = resolveIdeHost;
5
- exports.resolveWslDefaultGateway = resolveWslDefaultGateway;
6
- exports.parseDefaultGateway = parseDefaultGateway;
7
- exports.tcpReachable = tcpReachable;
8
- const node_child_process_1 = require("node:child_process");
9
- const node_net_1 = require("node:net");
10
- const node_util_1 = require("node:util");
11
- const config_1 = require("../shared/config");
12
- const platform_1 = require("../shared/platform");
13
- exports.PI_X_IDE_HOST_OVERRIDE_ENV = "PI_X_IDE_HOST_OVERRIDE";
14
- exports.IDE_HOST_TCP_PROBE_TIMEOUT_MS = 500;
15
- const execFileAsync = (0, node_util_1.promisify)(node_child_process_1.execFile);
16
- async function resolveIdeHost(lock, options = {}) {
17
- const env = (0, config_1.resolvePiConfigEnv)(options.env ?? process.env);
18
- const override = env[exports.PI_X_IDE_HOST_OVERRIDE_ENV]?.trim();
1
+ import { execFile } from "node:child_process";
2
+ import { createConnection } from "node:net";
3
+ import { promisify } from "node:util";
4
+ import { resolvePiConfigEnv } from "../shared/config.js";
5
+ import { isWsl } from "../shared/platform.js";
6
+ export const PI_X_IDE_HOST_OVERRIDE_ENV = "PI_X_IDE_HOST_OVERRIDE";
7
+ export const IDE_HOST_TCP_PROBE_TIMEOUT_MS = 500;
8
+ const execFileAsync = promisify(execFile);
9
+ export async function resolveIdeHost(lock, options = {}) {
10
+ const env = resolvePiConfigEnv(options.env ?? process.env);
11
+ const override = env[PI_X_IDE_HOST_OVERRIDE_ENV]?.trim();
19
12
  if (override)
20
13
  return override;
21
- if (lock.runningInWindows === true && (0, platform_1.isWsl)(env)) {
14
+ if (lock.runningInWindows === true && isWsl(env)) {
22
15
  const gateway = await resolveWslDefaultGateway(options.runCommand ?? defaultRunCommand);
23
16
  if (gateway) {
24
- const reachable = await (options.tcpProbe ?? tcpReachable)(gateway, lock.port, options.timeoutMs ?? exports.IDE_HOST_TCP_PROBE_TIMEOUT_MS);
17
+ const reachable = await (options.tcpProbe ?? tcpReachable)(gateway, lock.port, options.timeoutMs ?? IDE_HOST_TCP_PROBE_TIMEOUT_MS);
25
18
  if (reachable)
26
19
  return gateway;
27
20
  }
28
21
  }
29
22
  return lock.host || "127.0.0.1";
30
23
  }
31
- async function resolveWslDefaultGateway(runCommand = defaultRunCommand) {
24
+ export async function resolveWslDefaultGateway(runCommand = defaultRunCommand) {
32
25
  try {
33
26
  const { stdout } = await runCommand("ip", ["route", "show"]);
34
27
  return parseDefaultGateway(stdout);
@@ -37,7 +30,7 @@ async function resolveWslDefaultGateway(runCommand = defaultRunCommand) {
37
30
  return undefined;
38
31
  }
39
32
  }
40
- function parseDefaultGateway(output) {
33
+ export function parseDefaultGateway(output) {
41
34
  for (const line of output.split(/\r?\n/)) {
42
35
  const match = line.match(/^default\s+via\s+(\d{1,3}(?:\.\d{1,3}){3})(?:\s|$)/);
43
36
  if (match)
@@ -49,9 +42,9 @@ async function defaultRunCommand(command, args) {
49
42
  const { stdout } = await execFileAsync(command, args, { encoding: "utf8" });
50
43
  return { stdout };
51
44
  }
52
- function tcpReachable(host, port, timeoutMs = exports.IDE_HOST_TCP_PROBE_TIMEOUT_MS) {
45
+ export function tcpReachable(host, port, timeoutMs = IDE_HOST_TCP_PROBE_TIMEOUT_MS) {
53
46
  return new Promise((resolve) => {
54
- const socket = (0, node_net_1.createConnection)({ host, port });
47
+ const socket = createConnection({ host, port });
55
48
  let settled = false;
56
49
  const finish = (reachable) => {
57
50
  if (settled)
@@ -1,20 +1,18 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.default = default_1;
4
- const errors_1 = require("../shared/errors");
5
- const format_1 = require("../shared/format");
6
- const paths_1 = require("../shared/paths");
7
- const discovery_1 = require("./discovery");
8
- const connection_1 = require("./connection");
9
- const install_1 = require("./install");
10
- const commands_1 = require("./commands");
11
- const context_1 = require("./context");
12
- const diagnostics_1 = require("./diagnostics");
13
- const reconnect_1 = require("./reconnect");
14
- const safety_1 = require("./safety");
15
- const state_1 = require("./state");
16
- const ui_1 = require("./ui");
17
- const zed_1 = require("./zed");
1
+ import { logExtensionError } from "../shared/errors.js";
2
+ import { formatRangeMention } from "../shared/format.js";
3
+ import { hasDirectWorkspaceMatch } from "../shared/paths.js";
4
+ import { discoverIdeCandidates } from "./discovery.js";
5
+ import { IdeConnection, IdeConnectionTimeoutError } from "./connection.js";
6
+ import { discoverInstallCandidates, installIdeExtension, isAutoInstallEnabled, selectAutoInstallCandidate, } from "./install.js";
7
+ import { registerIdeCommand } from "./commands.js";
8
+ import { clearLatestSelection, registerContextHandlers, setLatestSelection } from "./context.js";
9
+ import { handleDiagnosticFixRequested } from "./diagnostics.js";
10
+ import { registerDiagnosticRenderer } from "./diagnostic-renderer.js";
11
+ import { formatReconnectLimitMessage, recordReconnectAttempt, resetReconnectState } from "./reconnect.js";
12
+ import { containPiError, runPiBoundary, runPiBoundaryAsync } from "./safety.js";
13
+ import { createRuntime } from "./state.js";
14
+ import { clearIdeUi, updateIdeUi } from "./ui.js";
15
+ import { startZedPolling, stopZedPolling } from "./zed.js";
18
16
  const RECONNECT_DELAY_MS = 2_000;
19
17
  const INSTALL_RECONNECT_RETRY_MS = 1_500;
20
18
  const INSTALL_RECONNECT_TIMEOUT_MS = 15_000;
@@ -22,51 +20,52 @@ let activePi;
22
20
  function formatConnectTimeoutMessage(error) {
23
21
  return `${error.message}.`;
24
22
  }
25
- function default_1(pi) {
23
+ export default function (pi) {
26
24
  activePi = pi;
27
- const runtime = (0, state_1.createRuntime)();
28
- (0, context_1.registerContextHandlers)(pi, runtime);
29
- (0, commands_1.registerIdeCommand)(pi, runtime, {
25
+ const runtime = createRuntime();
26
+ registerContextHandlers(pi, runtime);
27
+ registerDiagnosticRenderer(pi);
28
+ registerIdeCommand(pi, runtime, {
30
29
  refreshCandidates: (ctx) => refreshCandidates(runtime, ctx),
31
30
  connectAuto: (ctx) => connectAutoWithZedFallback(runtime, ctx),
32
31
  connectCandidate: (candidate, ctx) => connectCandidate(runtime, candidate, ctx),
33
32
  disconnect: (ctx, disabled) => disconnect(runtime, ctx, disabled),
34
33
  installExtension: (ctx) => installExtension(runtime, ctx),
35
34
  });
36
- pi.on("session_start", (_event, ctx) => (0, safety_1.runPiBoundaryAsync)("Pi session start", runtime, async () => {
35
+ pi.on("session_start", (_event, ctx) => runPiBoundaryAsync("Pi session start", runtime, async () => {
37
36
  runtime.sessionGeneration += 1;
38
37
  const generation = runtime.sessionGeneration;
39
38
  runtime.ctx = ctx;
40
39
  runtime.cwd = ctx.cwd;
41
- (0, zed_1.stopZedPolling)(runtime);
40
+ stopZedPolling(runtime);
42
41
  if (!runtime.enabled) {
43
42
  runtime.connectionStatus = "disabled";
44
- (0, ui_1.updateIdeUi)(runtime, ctx);
43
+ updateIdeUi(runtime, ctx);
45
44
  return;
46
45
  }
47
46
  void maybeAutoInstallAndReconnect(runtime, ctx, generation);
48
47
  await connectAutoWithZedFallback(runtime, ctx, generation);
49
48
  }, ctx));
50
- pi.on("session_shutdown", (_event, ctx) => (0, safety_1.runPiBoundary)("Pi session shutdown", runtime, () => {
49
+ pi.on("session_shutdown", (_event, ctx) => runPiBoundary("Pi session shutdown", runtime, () => {
51
50
  runtime.sessionGeneration += 1;
52
51
  runtime.ctx = ctx;
53
- (0, zed_1.stopZedPolling)(runtime);
52
+ stopZedPolling(runtime);
54
53
  if (runtime.reconnectTimer)
55
54
  clearTimeout(runtime.reconnectTimer);
56
55
  runtime.reconnectTimer = undefined;
57
56
  const connection = runtime.connection;
58
57
  runtime.connection = undefined;
59
58
  connection?.disconnect();
60
- (0, ui_1.clearIdeUi)(runtime, ctx);
59
+ clearIdeUi(runtime, ctx);
61
60
  runtime.ctx = undefined;
62
61
  }, ctx));
63
62
  }
64
63
  async function maybeAutoInstallAndReconnect(runtime, ctx, generation) {
65
64
  try {
66
- if (!(0, install_1.isAutoInstallEnabled)() || !isInstallSessionActive(runtime, generation))
65
+ if (!isAutoInstallEnabled() || !isInstallSessionActive(runtime, generation))
67
66
  return;
68
- const candidates = await (0, install_1.discoverInstallCandidates)();
69
- const candidate = (0, install_1.selectAutoInstallCandidate)(candidates);
67
+ const candidates = await discoverInstallCandidates();
68
+ const candidate = selectAutoInstallCandidate(candidates);
70
69
  if (!candidate)
71
70
  return;
72
71
  if (!isInstallSessionActive(runtime, generation))
@@ -74,7 +73,7 @@ async function maybeAutoInstallAndReconnect(runtime, ctx, generation) {
74
73
  if (!candidate.needsInstall)
75
74
  return;
76
75
  notifyInstall(ctx, `Installing Pi x IDE extension for ${candidate.label}...`, "info");
77
- const result = await (0, install_1.installIdeExtension)(candidate, runtime);
76
+ const result = await installIdeExtension(candidate, runtime);
78
77
  if (!isInstallSessionActive(runtime, generation))
79
78
  return;
80
79
  if (!result.success) {
@@ -104,7 +103,7 @@ async function maybeAutoInstallAndReconnect(runtime, ctx, generation) {
104
103
  async function installExtension(runtime, ctx) {
105
104
  runtime.ctx = ctx;
106
105
  runtime.cwd = ctx.cwd;
107
- const candidates = await (0, install_1.discoverInstallCandidates)({ includeLowConfidence: true });
106
+ const candidates = await discoverInstallCandidates({ includeLowConfidence: true });
108
107
  if (candidates.length === 0) {
109
108
  ctx.ui.notify("No supported VS Code-family IDE CLI found. Install VS Code, Cursor, or Windsurf CLI first.", "warning");
110
109
  return;
@@ -119,7 +118,7 @@ async function installExtension(runtime, ctx) {
119
118
  return;
120
119
  }
121
120
  ctx.ui.notify(`${installActionLabel(candidate)} Pi x IDE extension for ${candidate.label}...`, "info");
122
- const result = await (0, install_1.installIdeExtension)(candidate, runtime);
121
+ const result = await installIdeExtension(candidate, runtime);
123
122
  if (!result.success) {
124
123
  ctx.ui.notify(`Failed to install Pi x IDE extension for ${candidate.label}: ${describeInstallError(result.error, result.stderr)}`, "warning");
125
124
  return;
@@ -177,7 +176,7 @@ function notifyInstall(ctx, message, level) {
177
176
  ctx.ui.notify(message, level);
178
177
  }
179
178
  catch (error) {
180
- (0, errors_1.logExtensionError)("IDE install notification", error);
179
+ logExtensionError("IDE install notification", error);
181
180
  }
182
181
  }
183
182
  function describeInstallError(error, stderr) {
@@ -193,13 +192,13 @@ function sleep(ms) {
193
192
  async function refreshCandidates(runtime, ctx) {
194
193
  runtime.ctx = ctx;
195
194
  runtime.cwd = ctx.cwd;
196
- runtime.candidates = await (0, discovery_1.discoverIdeCandidates)({ cwd: ctx.cwd });
195
+ runtime.candidates = await discoverIdeCandidates({ cwd: ctx.cwd });
197
196
  return runtime.candidates;
198
197
  }
199
198
  async function connectAutoWithZedFallback(runtime, ctx, generation = runtime.sessionGeneration, options = {}) {
200
199
  await connectAuto(runtime, ctx, options);
201
200
  if (runtime.connectionStatus !== "connected") {
202
- (0, zed_1.startZedPolling)(runtime, ctx, { generation });
201
+ startZedPolling(runtime, ctx, { generation });
203
202
  }
204
203
  }
205
204
  async function connectAuto(runtime, ctx, options = {}) {
@@ -208,7 +207,7 @@ async function connectAuto(runtime, ctx, options = {}) {
208
207
  const candidate = candidates.find((candidate) => isAutoConnectCandidate(candidate, ctx.cwd));
209
208
  if (!candidate) {
210
209
  if (options.resetReconnectState !== false)
211
- (0, reconnect_1.resetReconnectState)(runtime);
210
+ resetReconnectState(runtime);
212
211
  runtime.connectionStatus = "disconnected";
213
212
  runtime.connectionMessage =
214
213
  candidates.length > 0
@@ -216,21 +215,21 @@ async function connectAuto(runtime, ctx, options = {}) {
216
215
  : "No matching IDE lock files found.";
217
216
  runtime.currentCandidate = undefined;
218
217
  runtime.connectedServer = undefined;
219
- (0, ui_1.updateIdeUi)(runtime, ctx);
218
+ updateIdeUi(runtime, ctx);
220
219
  return;
221
220
  }
222
221
  await connectCandidate(runtime, candidate, ctx, options);
223
222
  }
224
223
  function isAutoConnectCandidate(candidate, cwd) {
225
- return (0, paths_1.hasDirectWorkspaceMatch)(candidate.lock.workspaceFolders, cwd);
224
+ return hasDirectWorkspaceMatch(candidate.lock.workspaceFolders, cwd);
226
225
  }
227
226
  async function connectCandidate(runtime, candidate, ctx, options = {}) {
228
227
  if (options.resetReconnectState !== false)
229
- (0, reconnect_1.resetReconnectState)(runtime);
228
+ resetReconnectState(runtime);
230
229
  runtime.ctx = ctx;
231
230
  runtime.cwd = ctx.cwd;
232
231
  runtime.enabled = true;
233
- (0, zed_1.stopZedPolling)(runtime);
232
+ stopZedPolling(runtime);
234
233
  if (runtime.reconnectTimer)
235
234
  clearTimeout(runtime.reconnectTimer);
236
235
  runtime.reconnectTimer = undefined;
@@ -241,10 +240,10 @@ async function connectCandidate(runtime, candidate, ctx, options = {}) {
241
240
  runtime.connectedServer = undefined;
242
241
  runtime.connectionStatus = "connecting";
243
242
  runtime.connectionMessage = `Connecting to ${candidate.lock.name} at ${candidate.lock.host}:${candidate.lock.port}`;
244
- (0, ui_1.updateIdeUi)(runtime, ctx);
243
+ updateIdeUi(runtime, ctx);
245
244
  const generation = runtime.sessionGeneration;
246
245
  const connectionRef = {};
247
- const connection = new connection_1.IdeConnection(candidate, ctx.cwd, createConnectionCallbacks(activePi, runtime, () => connectionRef.current, generation));
246
+ const connection = new IdeConnection(candidate, ctx.cwd, createConnectionCallbacks(activePi, runtime, () => connectionRef.current, generation));
248
247
  connectionRef.current = connection;
249
248
  runtime.connection = connection;
250
249
  try {
@@ -252,8 +251,8 @@ async function connectCandidate(runtime, candidate, ctx, options = {}) {
252
251
  if (runtime.connection === connection && runtime.connectionStatus === "connecting") {
253
252
  runtime.connectionStatus = "connected";
254
253
  runtime.connectionMessage = undefined;
255
- (0, reconnect_1.resetReconnectState)(runtime);
256
- (0, ui_1.updateIdeUi)(runtime, ctx);
254
+ resetReconnectState(runtime);
255
+ updateIdeUi(runtime, ctx);
257
256
  }
258
257
  }
259
258
  catch (error) {
@@ -261,9 +260,9 @@ async function connectCandidate(runtime, candidate, ctx, options = {}) {
261
260
  runtime.connection = undefined;
262
261
  runtime.connectionStatus = "error";
263
262
  runtime.connectionMessage =
264
- error instanceof connection_1.IdeConnectionTimeoutError ? formatConnectTimeoutMessage(error) : errorMessage(error);
265
- (0, ui_1.updateIdeUi)(runtime, ctx);
266
- if (!(error instanceof connection_1.IdeConnectionTimeoutError))
263
+ error instanceof IdeConnectionTimeoutError ? formatConnectTimeoutMessage(error) : errorMessage(error);
264
+ updateIdeUi(runtime, ctx);
265
+ if (!(error instanceof IdeConnectionTimeoutError))
267
266
  scheduleReconnect(runtime);
268
267
  }
269
268
  }
@@ -276,8 +275,8 @@ function createConnectionCallbacks(pi, runtime, getConnection, generation) {
276
275
  runtime.connectedServer = server;
277
276
  runtime.connectionStatus = "connected";
278
277
  runtime.connectionMessage = undefined;
279
- (0, reconnect_1.resetReconnectState)(runtime);
280
- (0, ui_1.updateIdeUi)(runtime);
278
+ resetReconnectState(runtime);
279
+ updateIdeUi(runtime);
281
280
  },
282
281
  onDisconnected: (reason) => {
283
282
  if (!isCurrentConnection(runtime, getConnection(), generation))
@@ -286,19 +285,19 @@ function createConnectionCallbacks(pi, runtime, getConnection, generation) {
286
285
  runtime.connectedServer = undefined;
287
286
  runtime.connectionStatus = runtime.enabled ? "disconnected" : "disabled";
288
287
  runtime.connectionMessage = reason;
289
- (0, ui_1.updateIdeUi)(runtime);
288
+ updateIdeUi(runtime);
290
289
  if (runtime.enabled)
291
290
  scheduleReconnect(runtime);
292
291
  },
293
292
  onSelectionChanged: (snapshot) => {
294
293
  if (!isCurrentConnection(runtime, getConnection(), generation))
295
294
  return;
296
- (0, context_1.setLatestSelection)(runtime, snapshot);
295
+ setLatestSelection(runtime, snapshot);
297
296
  },
298
297
  onSelectionCleared: () => {
299
298
  if (!isCurrentConnection(runtime, getConnection(), generation))
300
299
  return;
301
- (0, context_1.clearLatestSelection)(runtime);
300
+ clearLatestSelection(runtime);
302
301
  },
303
302
  onAtMentioned: (params) => {
304
303
  if (!isCurrentConnection(runtime, getConnection(), generation))
@@ -308,12 +307,12 @@ function createConnectionCallbacks(pi, runtime, getConnection, generation) {
308
307
  onDiagnosticFixRequested: (params) => {
309
308
  if (!pi || !isCurrentConnection(runtime, getConnection(), generation))
310
309
  return;
311
- (0, diagnostics_1.handleDiagnosticFixRequested)(pi, runtime, params);
310
+ handleDiagnosticFixRequested(pi, runtime, params);
312
311
  },
313
312
  onError: (error) => {
314
313
  if (!isCurrentConnection(runtime, getConnection(), generation))
315
314
  return;
316
- (0, safety_1.containPiError)(runtime, "IDE connection error", error);
315
+ containPiError(runtime, "IDE connection error", error);
317
316
  },
318
317
  };
319
318
  }
@@ -322,14 +321,14 @@ function isCurrentConnection(runtime, connection, generation = runtime.sessionGe
322
321
  }
323
322
  function disconnect(runtime, ctx, disabled = false) {
324
323
  runtime.ctx = ctx;
325
- (0, zed_1.stopZedPolling)(runtime);
324
+ stopZedPolling(runtime);
326
325
  if (runtime.reconnectTimer)
327
326
  clearTimeout(runtime.reconnectTimer);
328
327
  runtime.reconnectTimer = undefined;
329
328
  const connection = runtime.connection;
330
329
  runtime.connection = undefined;
331
330
  connection?.disconnect();
332
- (0, reconnect_1.resetReconnectState)(runtime);
331
+ resetReconnectState(runtime);
333
332
  runtime.enabled = !disabled;
334
333
  runtime.connectedServer = undefined;
335
334
  runtime.connectionStatus = disabled ? "disabled" : "disconnected";
@@ -340,17 +339,17 @@ function disconnect(runtime, ctx, disabled = false) {
340
339
  runtime.turnSelection = undefined;
341
340
  runtime.attachState = "idle";
342
341
  }
343
- (0, ui_1.updateIdeUi)(runtime, ctx);
342
+ updateIdeUi(runtime, ctx);
344
343
  }
345
344
  function scheduleReconnect(runtime) {
346
345
  if (runtime.reconnectTimer || !runtime.enabled)
347
346
  return;
348
347
  const generation = runtime.sessionGeneration;
349
- const attempt = (0, reconnect_1.recordReconnectAttempt)(runtime, runtime.currentCandidate);
348
+ const attempt = recordReconnectAttempt(runtime, runtime.currentCandidate);
350
349
  if (attempt === undefined) {
351
350
  runtime.connectionStatus = "error";
352
- runtime.connectionMessage = (0, reconnect_1.formatReconnectLimitMessage)(runtime.currentCandidate);
353
- (0, ui_1.updateIdeUi)(runtime);
351
+ runtime.connectionMessage = formatReconnectLimitMessage(runtime.currentCandidate);
352
+ updateIdeUi(runtime);
354
353
  return;
355
354
  }
356
355
  runtime.reconnectTimer = setTimeout(() => {
@@ -358,15 +357,15 @@ function scheduleReconnect(runtime) {
358
357
  const ctx = runtime.ctx;
359
358
  if (!ctx || !runtime.enabled || runtime.sessionGeneration !== generation)
360
359
  return;
361
- connectAutoWithZedFallback(runtime, ctx, runtime.sessionGeneration, { resetReconnectState: false }).catch((error) => (0, safety_1.containPiError)(runtime, "IDE reconnect", error));
360
+ connectAutoWithZedFallback(runtime, ctx, runtime.sessionGeneration, { resetReconnectState: false }).catch((error) => containPiError(runtime, "IDE reconnect", error));
362
361
  }, RECONNECT_DELAY_MS);
363
362
  }
364
363
  function handleAtMentioned(runtime, params) {
365
- (0, context_1.setLatestSelection)(runtime, params);
364
+ setLatestSelection(runtime, params);
366
365
  const ctx = runtime.ctx;
367
366
  if (!ctx?.hasUI)
368
367
  return;
369
- const text = params.rangeText || (0, format_1.formatRangeMention)(params, { cwd: ctx.cwd });
368
+ const text = params.rangeText || formatRangeMention(params, { cwd: ctx.cwd });
370
369
  ctx.ui.pasteToEditor(text);
371
370
  ctx.ui.notify(`Attached ${text}`, "info");
372
371
  }
@@ -1,59 +1,26 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SUPPORTED_IDE_CLI_PROFILES = exports.PI_X_IDE_TARGET_VERSION = exports.PI_X_IDE_AUTO_INSTALL_ENV = exports.PI_X_IDE_EXTENSION_ID = void 0;
4
- exports.isAutoInstallEnabled = isAutoInstallEnabled;
5
- exports.parseInstalledExtensionVersion = parseInstalledExtensionVersion;
6
- exports.compareExtensionVersions = compareExtensionVersions;
7
- exports.inferCurrentIdeFromEnv = inferCurrentIdeFromEnv;
8
- exports.buildInstallArgs = buildInstallArgs;
9
- exports.findExecutable = findExecutable;
10
- exports.runCli = runCli;
11
- exports.discoverInstallCandidates = discoverInstallCandidates;
12
- exports.selectAutoInstallCandidate = selectAutoInstallCandidate;
13
- exports.installIdeExtension = installIdeExtension;
14
- const node_child_process_1 = require("node:child_process");
15
- const node_fs_1 = require("node:fs");
16
- const promises_1 = require("node:fs/promises");
17
- const node_path_1 = require("node:path");
18
- const node_util_1 = require("node:util");
19
- const config_1 = require("../shared/config");
20
- const execFileAsync = (0, node_util_1.promisify)(node_child_process_1.execFile);
21
- exports.PI_X_IDE_EXTENSION_ID = "balaenis.pi-x-ide";
22
- exports.PI_X_IDE_AUTO_INSTALL_ENV = "PI_X_IDE_AUTO_INSTALL";
23
- exports.PI_X_IDE_TARGET_VERSION = readPackageVersion();
24
- function readPackageVersion(startDir = __dirname) {
25
- let currentDir = startDir;
26
- while (true) {
27
- const packageJsonPath = (0, node_path_1.join)(currentDir, "package.json");
28
- try {
29
- const packageJson = JSON.parse((0, node_fs_1.readFileSync)(packageJsonPath, "utf8"));
30
- if (packageJson.name === "pi-x-ide" && typeof packageJson.version === "string") {
31
- return packageJson.version;
32
- }
33
- }
34
- catch (error) {
35
- if (error.code !== "ENOENT")
36
- throw error;
37
- }
38
- const parentDir = (0, node_path_1.dirname)(currentDir);
39
- if (parentDir === currentDir)
40
- throw new Error("Unable to locate pi-x-ide package.json");
41
- currentDir = parentDir;
42
- }
43
- }
44
- exports.SUPPORTED_IDE_CLI_PROFILES = [
1
+ import { execFile } from "node:child_process";
2
+ import { access } from "node:fs/promises";
3
+ import { delimiter, isAbsolute, join } from "node:path";
4
+ import { promisify } from "node:util";
5
+ import { resolvePiConfigEnv } from "../shared/config.js";
6
+ import { PI_X_IDE_VERSION } from "../shared/version.js";
7
+ const execFileAsync = promisify(execFile);
8
+ export const PI_X_IDE_EXTENSION_ID = "balaenis.pi-x-ide";
9
+ export const PI_X_IDE_AUTO_INSTALL_ENV = "PI_X_IDE_AUTO_INSTALL";
10
+ export const PI_X_IDE_TARGET_VERSION = PI_X_IDE_VERSION;
11
+ export const SUPPORTED_IDE_CLI_PROFILES = [
45
12
  { id: "vscode", label: "VS Code", command: "code" },
46
13
  { id: "cursor", label: "Cursor", command: "cursor" },
47
14
  { id: "windsurf", label: "Windsurf", command: "windsurf" },
48
15
  ];
49
- function isAutoInstallEnabled(env = process.env) {
50
- const configuredEnv = (0, config_1.resolvePiConfigEnv)(env);
51
- const value = configuredEnv[exports.PI_X_IDE_AUTO_INSTALL_ENV];
16
+ export function isAutoInstallEnabled(env = process.env) {
17
+ const configuredEnv = resolvePiConfigEnv(env);
18
+ const value = configuredEnv[PI_X_IDE_AUTO_INSTALL_ENV];
52
19
  if (value === undefined)
53
20
  return true;
54
21
  return !["0", "false", "off"].includes(value.trim().toLowerCase());
55
22
  }
56
- function parseInstalledExtensionVersion(output, extensionId = exports.PI_X_IDE_EXTENSION_ID) {
23
+ export function parseInstalledExtensionVersion(output, extensionId = PI_X_IDE_EXTENSION_ID) {
57
24
  const target = extensionId.toLowerCase();
58
25
  for (const rawLine of output.split(/\r?\n/)) {
59
26
  const line = rawLine.trim();
@@ -68,7 +35,7 @@ function parseInstalledExtensionVersion(output, extensionId = exports.PI_X_IDE_E
68
35
  }
69
36
  return undefined;
70
37
  }
71
- function compareExtensionVersions(installed, target) {
38
+ export function compareExtensionVersions(installed, target) {
72
39
  if (!installed)
73
40
  return "unknown";
74
41
  const installedParts = parseStableVersion(installed);
@@ -83,8 +50,8 @@ function compareExtensionVersions(installed, target) {
83
50
  }
84
51
  return "equal";
85
52
  }
86
- function inferCurrentIdeFromEnv(env = process.env) {
87
- const configuredEnv = (0, config_1.resolvePiConfigEnv)(env);
53
+ export function inferCurrentIdeFromEnv(env = process.env) {
54
+ const configuredEnv = resolvePiConfigEnv(env);
88
55
  const matches = new Set();
89
56
  const hasWindsurfMarker = hasWindsurfEnvMarker(configuredEnv);
90
57
  const hasCursorMarker = hasCursorEnvMarker(configuredEnv);
@@ -126,24 +93,24 @@ function envValueMatches(value, patterns) {
126
93
  const upperValue = value?.toUpperCase();
127
94
  return upperValue ? patterns.some((pattern) => pattern.test(upperValue)) : false;
128
95
  }
129
- function buildInstallArgs() {
130
- return ["--force", "--install-extension", exports.PI_X_IDE_EXTENSION_ID];
96
+ export function buildInstallArgs() {
97
+ return ["--force", "--install-extension", PI_X_IDE_EXTENSION_ID];
131
98
  }
132
- async function findExecutable(command, env = process.env) {
133
- const configuredEnv = (0, config_1.resolvePiConfigEnv)(env);
99
+ export async function findExecutable(command, env = process.env) {
100
+ const configuredEnv = resolvePiConfigEnv(env);
134
101
  const pathEnv = configuredEnv.PATH ?? configuredEnv.Path ?? configuredEnv.path;
135
102
  if (!pathEnv)
136
103
  return undefined;
137
104
  const extensions = process.platform === "win32" ? parsePathExt(configuredEnv) : [""];
138
- const candidates = (0, node_path_1.isAbsolute)(command)
105
+ const candidates = isAbsolute(command)
139
106
  ? [command]
140
107
  : pathEnv
141
- .split(node_path_1.delimiter)
108
+ .split(delimiter)
142
109
  .filter(Boolean)
143
- .flatMap((directory) => extensions.map((extension) => (0, node_path_1.join)(directory, withExtension(command, extension))));
110
+ .flatMap((directory) => extensions.map((extension) => join(directory, withExtension(command, extension))));
144
111
  for (const candidate of candidates) {
145
112
  try {
146
- await (0, promises_1.access)(candidate);
113
+ await access(candidate);
147
114
  return candidate;
148
115
  }
149
116
  catch {
@@ -151,7 +118,7 @@ async function findExecutable(command, env = process.env) {
151
118
  }
152
119
  return undefined;
153
120
  }
154
- async function runCli(cliPath, args, timeoutMs = 15_000) {
121
+ export async function runCli(cliPath, args, timeoutMs = 15_000) {
155
122
  if (process.platform === "win32" && isCmdOrBatFile(cliPath)) {
156
123
  const { stdout, stderr } = await execFileAsync(resolveCmdExe(), ["/d", "/c", cliPath, ...args], {
157
124
  timeout: timeoutMs,
@@ -167,13 +134,13 @@ async function runCli(cliPath, args, timeoutMs = 15_000) {
167
134
  });
168
135
  return { stdout: String(stdout), stderr: String(stderr) };
169
136
  }
170
- async function discoverInstallCandidates(options = {}) {
171
- const env = (0, config_1.resolvePiConfigEnv)(options.env ?? process.env);
137
+ export async function discoverInstallCandidates(options = {}) {
138
+ const env = resolvePiConfigEnv(options.env ?? process.env);
172
139
  const currentIde = inferCurrentIdeFromEnv(env);
173
140
  const includeLowConfidence = options.includeLowConfidence ?? false;
174
141
  const timeoutMs = options.timeoutMs ?? 15_000;
175
142
  const candidates = [];
176
- for (const profile of exports.SUPPORTED_IDE_CLI_PROFILES) {
143
+ for (const profile of SUPPORTED_IDE_CLI_PROFILES) {
177
144
  const cliPath = await findExecutable(profile.command, env);
178
145
  if (!cliPath)
179
146
  continue;
@@ -189,7 +156,7 @@ async function discoverInstallCandidates(options = {}) {
189
156
  catch (error) {
190
157
  listError = error instanceof Error ? error.message : String(error);
191
158
  }
192
- const reason = resolveInstallReason(installedVersion, exports.PI_X_IDE_TARGET_VERSION, listError);
159
+ const reason = resolveInstallReason(installedVersion, PI_X_IDE_TARGET_VERSION, listError);
193
160
  candidates.push({
194
161
  id: profile.id,
195
162
  label: profile.label,
@@ -197,7 +164,7 @@ async function discoverInstallCandidates(options = {}) {
197
164
  cliPath,
198
165
  confidence,
199
166
  installedVersion,
200
- targetVersion: exports.PI_X_IDE_TARGET_VERSION,
167
+ targetVersion: PI_X_IDE_TARGET_VERSION,
201
168
  needsInstall: reason === "missing" || reason === "outdated" || reason === "unknown",
202
169
  reason,
203
170
  listError,
@@ -205,15 +172,15 @@ async function discoverInstallCandidates(options = {}) {
205
172
  }
206
173
  return candidates;
207
174
  }
208
- function selectAutoInstallCandidate(candidates, env = process.env) {
209
- const configuredEnv = (0, config_1.resolvePiConfigEnv)(env);
175
+ export function selectAutoInstallCandidate(candidates, env = process.env) {
176
+ const configuredEnv = resolvePiConfigEnv(env);
210
177
  const currentIde = inferCurrentIdeFromEnv(configuredEnv);
211
178
  const highConfidence = candidates.filter((candidate) => candidate.confidence === "current-terminal" &&
212
179
  candidate.reason !== "unknown" &&
213
180
  (!currentIde || candidate.id === currentIde));
214
181
  return highConfidence.length === 1 ? highConfidence[0] : undefined;
215
182
  }
216
- async function installIdeExtension(candidate, runtime, options = {}) {
183
+ export async function installIdeExtension(candidate, runtime, options = {}) {
217
184
  if (!candidate.needsInstall) {
218
185
  return { candidate, skipped: true, success: true, stdout: "", stderr: "" };
219
186
  }
@@ -1,28 +1,22 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.MAX_RECONNECT_ATTEMPTS = void 0;
4
- exports.resetReconnectState = resetReconnectState;
5
- exports.recordReconnectAttempt = recordReconnectAttempt;
6
- exports.formatReconnectLimitMessage = formatReconnectLimitMessage;
7
- exports.MAX_RECONNECT_ATTEMPTS = 3;
8
- function resetReconnectState(runtime) {
1
+ export const MAX_RECONNECT_ATTEMPTS = 3;
2
+ export function resetReconnectState(runtime) {
9
3
  runtime.reconnectAttempts = 0;
10
4
  runtime.reconnectCandidateKey = undefined;
11
5
  }
12
- function recordReconnectAttempt(runtime, candidate) {
6
+ export function recordReconnectAttempt(runtime, candidate) {
13
7
  const key = candidate ? reconnectCandidateKey(candidate) : undefined;
14
8
  if (runtime.reconnectCandidateKey !== key) {
15
9
  runtime.reconnectCandidateKey = key;
16
10
  runtime.reconnectAttempts = 0;
17
11
  }
18
- if (runtime.reconnectAttempts >= exports.MAX_RECONNECT_ATTEMPTS)
12
+ if (runtime.reconnectAttempts >= MAX_RECONNECT_ATTEMPTS)
19
13
  return undefined;
20
14
  runtime.reconnectAttempts += 1;
21
15
  return runtime.reconnectAttempts;
22
16
  }
23
- function formatReconnectLimitMessage(candidate) {
17
+ export function formatReconnectLimitMessage(candidate) {
24
18
  const target = candidate ? `${candidate.lock.name} at ${candidate.lock.host}:${candidate.lock.port}` : "IDE";
25
- return `Stopped reconnecting to ${target} after ${exports.MAX_RECONNECT_ATTEMPTS} attempts.`;
19
+ return `Stopped reconnecting to ${target} after ${MAX_RECONNECT_ATTEMPTS} attempts.`;
26
20
  }
27
21
  function reconnectCandidateKey(candidate) {
28
22
  return `${candidate.path}:${candidate.lock.host}:${candidate.lock.port}:${candidate.mtimeMs}`;