@saifymatteo/pi-x-ide 0.0.0-stage → 1.20.2
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.
- package/CHANGELOG.md +328 -0
- package/CONTRIBUTING.md +119 -0
- package/CONTRIBUTING.zh-CN.md +106 -0
- package/LICENSE +201 -0
- package/README.md +33 -2
- package/README.zh-CN.md +34 -0
- package/RELEASE.md +213 -0
- package/config.example.json +9 -0
- package/dist/src/pi/chunks/chunk-4RHJAL4S.js +200 -0
- package/dist/src/pi/chunks/chunk-UUXVCTOS.js +819 -0
- package/dist/src/pi/chunks/config-ui-LO3DVQFC.js +8073 -0
- package/dist/src/pi/chunks/runtime-services-BVQBAAWT.js +19569 -0
- package/dist/src/pi/commands.js +126 -0
- package/dist/src/pi/config-ui.js +127 -0
- package/dist/src/pi/connection.js +237 -0
- package/dist/src/pi/context.js +30 -0
- package/dist/src/pi/diagnostic-renderer.js +326 -0
- package/dist/src/pi/diagnostic-types.js +1 -0
- package/dist/src/pi/diagnostics.js +104 -0
- package/dist/src/pi/discovery.js +135 -0
- package/dist/src/pi/effect-boundary.js +5 -0
- package/dist/src/pi/ide-host.js +68 -0
- package/dist/src/pi/index.js +636 -0
- package/dist/src/pi/install.js +308 -0
- package/dist/src/pi/reconnect.js +57 -0
- package/dist/src/pi/runtime-loader.js +38 -0
- package/dist/src/pi/runtime-services.js +356 -0
- package/dist/src/pi/safety.js +61 -0
- package/dist/src/pi/selection.js +18 -0
- package/dist/src/pi/state.js +13 -0
- package/dist/src/pi/ui.js +304 -0
- package/dist/src/pi/zed.js +409 -0
- package/dist/src/shared/config-options.js +45 -0
- package/dist/src/shared/config.js +183 -0
- package/dist/src/shared/display-width.js +99 -0
- package/dist/src/shared/effect-errors.js +36 -0
- package/dist/src/shared/effect-runtime.js +36 -0
- package/dist/src/shared/effect-schema.js +120 -0
- package/dist/src/shared/errors.js +48 -0
- package/dist/src/shared/format.js +92 -0
- package/dist/src/shared/ide-server.js +167 -0
- package/dist/src/shared/jsonrpc-guard.js +12 -0
- package/dist/src/shared/lock-file-heartbeat.js +58 -0
- package/dist/src/shared/lock-file.js +50 -0
- package/dist/src/shared/paths.js +79 -0
- package/dist/src/shared/platform.js +57 -0
- package/dist/src/shared/protocol.js +3 -0
- package/dist/src/shared/schema.js +37 -0
- package/dist/src/shared/version.js +1 -0
- package/dist/src/shared/ws.js +8 -0
- package/docs/explanation/architecture.md +123 -0
- package/docs/explanation/discovery.md +113 -0
- package/docs/explanation/effect.md +127 -0
- package/docs/how-to/install-jetbrains.md +58 -0
- package/docs/how-to/install-neovim.md +138 -0
- package/docs/how-to/install-vscode.md +75 -0
- package/docs/how-to/install-zed.md +70 -0
- package/docs/how-to/troubleshoot-connection.md +103 -0
- package/docs/how-to/use-wsl2.md +90 -0
- package/docs/reference/commands.md +59 -0
- package/docs/reference/configuration.md +101 -0
- package/docs/reference/feature-parity.md +26 -0
- package/docs/reference/protocol.md +71 -0
- package/docs/specs/ide-protocol.md +215 -0
- package/docs/tutorials/get-started.md +133 -0
- package/docs/zh-CN/explanation/architecture.md +93 -0
- package/docs/zh-CN/explanation/discovery.md +71 -0
- package/docs/zh-CN/explanation/effect.md +90 -0
- package/docs/zh-CN/how-to/install-jetbrains.md +49 -0
- package/docs/zh-CN/how-to/install-neovim.md +126 -0
- package/docs/zh-CN/how-to/install-vscode.md +67 -0
- package/docs/zh-CN/how-to/install-zed.md +56 -0
- package/docs/zh-CN/how-to/troubleshoot-connection.md +85 -0
- package/docs/zh-CN/how-to/use-wsl2.md +75 -0
- package/docs/zh-CN/reference/commands.md +54 -0
- package/docs/zh-CN/reference/configuration.md +94 -0
- package/docs/zh-CN/reference/feature-parity.md +21 -0
- package/docs/zh-CN/reference/protocol.md +54 -0
- package/docs/zh-CN/tutorials/get-started.md +101 -0
- package/package.json +86 -4
- package/schemas/config.json +77 -0
|
@@ -0,0 +1,819 @@
|
|
|
1
|
+
import { createRequire as __piCreateRequire } from "node:module";const require = __piCreateRequire(import.meta.url);
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
9
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
10
|
+
}) : x)(function(x) {
|
|
11
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
12
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
13
|
+
});
|
|
14
|
+
var __commonJS = (cb, mod) => function __require2() {
|
|
15
|
+
try {
|
|
16
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
17
|
+
} catch (e) {
|
|
18
|
+
throw mod = 0, e;
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
var __copyProps = (to, from, except, desc) => {
|
|
22
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
23
|
+
for (let key of __getOwnPropNames(from))
|
|
24
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
25
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
26
|
+
}
|
|
27
|
+
return to;
|
|
28
|
+
};
|
|
29
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
30
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
31
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
32
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
33
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
34
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
35
|
+
mod
|
|
36
|
+
));
|
|
37
|
+
|
|
38
|
+
// src/shared/errors.ts
|
|
39
|
+
var extensionErrorReporter;
|
|
40
|
+
function setExtensionErrorReporter(reporter) {
|
|
41
|
+
extensionErrorReporter = reporter;
|
|
42
|
+
}
|
|
43
|
+
function errorMessage(error) {
|
|
44
|
+
return error instanceof Error ? error.message : String(error);
|
|
45
|
+
}
|
|
46
|
+
function isStaleContextError(error) {
|
|
47
|
+
return errorMessage(error).includes("stale after session replacement or reload");
|
|
48
|
+
}
|
|
49
|
+
function toError(error, prefix) {
|
|
50
|
+
if (error instanceof Error) {
|
|
51
|
+
if (!prefix) return error;
|
|
52
|
+
return new Error(`${prefix}: ${error.message}`, { cause: error });
|
|
53
|
+
}
|
|
54
|
+
return new Error(prefix ? `${prefix}: ${String(error)}` : String(error));
|
|
55
|
+
}
|
|
56
|
+
function formatExtensionError(scope, error) {
|
|
57
|
+
return `[pi-x-ide] ${scope}: ${errorMessage(error)}`;
|
|
58
|
+
}
|
|
59
|
+
function logExtensionError(scope, error) {
|
|
60
|
+
extensionErrorReporter?.(scope, error);
|
|
61
|
+
}
|
|
62
|
+
function safeRun(scope, action, onError) {
|
|
63
|
+
try {
|
|
64
|
+
return action();
|
|
65
|
+
} catch (error) {
|
|
66
|
+
if (onError) onError(error);
|
|
67
|
+
else logExtensionError(scope, error);
|
|
68
|
+
return void 0;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
async function safeRunAsync(scope, action, onError) {
|
|
72
|
+
try {
|
|
73
|
+
return await action();
|
|
74
|
+
} catch (error) {
|
|
75
|
+
if (onError) onError(error);
|
|
76
|
+
else logExtensionError(scope, error);
|
|
77
|
+
return void 0;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// src/shared/config-options.ts
|
|
82
|
+
var CONFIG_ENV_VALUE_TYPES = ["string", "number", "boolean"];
|
|
83
|
+
function isConfigEnvValue(value) {
|
|
84
|
+
return CONFIG_ENV_VALUE_TYPES.some((type) => typeof value === type);
|
|
85
|
+
}
|
|
86
|
+
var STATUS_DISPLAY_VALUES = ["widget", "statusline"];
|
|
87
|
+
var DEFAULT_STATUS_DISPLAY = "widget";
|
|
88
|
+
|
|
89
|
+
// src/shared/config.ts
|
|
90
|
+
import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
91
|
+
import { homedir } from "node:os";
|
|
92
|
+
import { dirname, resolve } from "node:path";
|
|
93
|
+
var EXT_CONFIG_NAME = "pi-x-ide";
|
|
94
|
+
var CONFIG_DIR_NAME = ".pi";
|
|
95
|
+
var PI_CONFIG_FILE = "config.json";
|
|
96
|
+
var STATUS_DISPLAY_CONFIG_KEY = "status_display";
|
|
97
|
+
var AUTO_INSTALL_ENV_KEY = "PI_X_IDE_AUTO_INSTALL";
|
|
98
|
+
var processEnvOverlays = /* @__PURE__ */ new WeakSet();
|
|
99
|
+
var AUTO_INSTALL_DISABLED_VALUES = /* @__PURE__ */ new Set(["0", "false", "off"]);
|
|
100
|
+
function resolvePiConfigPath(home = homedir()) {
|
|
101
|
+
return resolvePiGlobalConfigPath(home);
|
|
102
|
+
}
|
|
103
|
+
function resolvePiGlobalConfigPath(home = homedir()) {
|
|
104
|
+
return resolve(home, CONFIG_DIR_NAME, EXT_CONFIG_NAME, PI_CONFIG_FILE);
|
|
105
|
+
}
|
|
106
|
+
function resolvePiProjectConfigPath(projectDir) {
|
|
107
|
+
return resolve(projectDir, CONFIG_DIR_NAME, EXT_CONFIG_NAME, PI_CONFIG_FILE);
|
|
108
|
+
}
|
|
109
|
+
function readPiConfigFile(configPath) {
|
|
110
|
+
let parsed;
|
|
111
|
+
try {
|
|
112
|
+
parsed = JSON.parse(readFileSync(configPath, "utf8"));
|
|
113
|
+
} catch {
|
|
114
|
+
return void 0;
|
|
115
|
+
}
|
|
116
|
+
return isRecord(parsed) ? parsed : void 0;
|
|
117
|
+
}
|
|
118
|
+
function writePiConfigFile(partial, configPath) {
|
|
119
|
+
const existing = readPiConfigFile(configPath) ?? {};
|
|
120
|
+
const merged = { ...existing, ...partial };
|
|
121
|
+
if (isRecord(existing.env) || isRecord(partial.env)) {
|
|
122
|
+
merged.env = {
|
|
123
|
+
...isRecord(existing.env) ? existing.env : {},
|
|
124
|
+
...isRecord(partial.env) ? partial.env : {}
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
mkdirSync(dirname(configPath), { recursive: true });
|
|
128
|
+
writeFileSync(configPath, `${JSON.stringify(merged, null, 2)}
|
|
129
|
+
`, "utf8");
|
|
130
|
+
}
|
|
131
|
+
function readPiConfigEnv(configPath = resolvePiConfigPath()) {
|
|
132
|
+
const parsed = readPiConfigFile(configPath);
|
|
133
|
+
if (!parsed || !isRecord(parsed.env)) return {};
|
|
134
|
+
return Object.fromEntries(
|
|
135
|
+
Object.entries(parsed.env).filter((entry) => {
|
|
136
|
+
const [key, value] = entry;
|
|
137
|
+
return key.length > 0 && isConfigEnvValue(value);
|
|
138
|
+
}).map(([key, value]) => [key, String(value)])
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
function resolvePiConfigEnv(env = process.env, options = {}) {
|
|
142
|
+
if (env !== process.env && !options.configPath && options.projectDir === void 0) {
|
|
143
|
+
return env;
|
|
144
|
+
}
|
|
145
|
+
const configEnv = options.configPath ? readPiConfigEnv(options.configPath) : {
|
|
146
|
+
...readPiConfigEnv(resolvePiGlobalConfigPath(options.home)),
|
|
147
|
+
...options.projectDir ? readPiConfigEnv(resolvePiProjectConfigPath(options.projectDir)) : {}
|
|
148
|
+
};
|
|
149
|
+
if (Object.keys(configEnv).length === 0) return env;
|
|
150
|
+
const merged = { ...configEnv, ...env };
|
|
151
|
+
if (env === process.env) processEnvOverlays.add(merged);
|
|
152
|
+
return merged;
|
|
153
|
+
}
|
|
154
|
+
function isProcessEnvOrPiConfigOverlay(env) {
|
|
155
|
+
return env === process.env || processEnvOverlays.has(env);
|
|
156
|
+
}
|
|
157
|
+
function readPiConfigFixPrompt(configPath = resolvePiConfigPath()) {
|
|
158
|
+
const parsed = readPiConfigFile(configPath);
|
|
159
|
+
if (!parsed) return void 0;
|
|
160
|
+
return typeof parsed.fixPrompt === "string" ? parsed.fixPrompt : void 0;
|
|
161
|
+
}
|
|
162
|
+
function readPiConfigStatusDisplay(configPathOrOptions = {}) {
|
|
163
|
+
return resolvePiConfigStatusDisplay(configPathOrOptions).value;
|
|
164
|
+
}
|
|
165
|
+
function resolvePiConfigStatusDisplay(configPathOrOptions = {}) {
|
|
166
|
+
if (typeof configPathOrOptions === "string") {
|
|
167
|
+
const value = readStatusDisplayFromFile(configPathOrOptions);
|
|
168
|
+
return value === void 0 ? { value: DEFAULT_STATUS_DISPLAY, scope: "default" } : { value, scope: "global", path: configPathOrOptions };
|
|
169
|
+
}
|
|
170
|
+
const projectDir = configPathOrOptions.projectDir;
|
|
171
|
+
if (projectDir) {
|
|
172
|
+
const projectPath = resolvePiProjectConfigPath(projectDir);
|
|
173
|
+
const projectValue = readStatusDisplayFromFile(projectPath);
|
|
174
|
+
if (projectValue !== void 0) {
|
|
175
|
+
return { value: projectValue, scope: "project", path: projectPath };
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
const globalPath = resolvePiGlobalConfigPath(configPathOrOptions.home);
|
|
179
|
+
const globalValue = readStatusDisplayFromFile(globalPath);
|
|
180
|
+
if (globalValue !== void 0) {
|
|
181
|
+
return { value: globalValue, scope: "global", path: globalPath };
|
|
182
|
+
}
|
|
183
|
+
return { value: DEFAULT_STATUS_DISPLAY, scope: "default" };
|
|
184
|
+
}
|
|
185
|
+
function resolvePiConfigAutoInstall(configPathOrOptions = {}) {
|
|
186
|
+
if (typeof configPathOrOptions === "string") {
|
|
187
|
+
const raw = readEnvValueFromFile(configPathOrOptions, AUTO_INSTALL_ENV_KEY);
|
|
188
|
+
return raw === void 0 ? { value: true, scope: "default" } : { value: parseAutoInstallValue(raw), scope: "global", path: configPathOrOptions };
|
|
189
|
+
}
|
|
190
|
+
const projectDir = configPathOrOptions.projectDir;
|
|
191
|
+
if (projectDir) {
|
|
192
|
+
const projectPath = resolvePiProjectConfigPath(projectDir);
|
|
193
|
+
const projectRaw = readEnvValueFromFile(projectPath, AUTO_INSTALL_ENV_KEY);
|
|
194
|
+
if (projectRaw !== void 0) {
|
|
195
|
+
return { value: parseAutoInstallValue(projectRaw), scope: "project", path: projectPath };
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
const globalPath = resolvePiGlobalConfigPath(configPathOrOptions.home);
|
|
199
|
+
const globalRaw = readEnvValueFromFile(globalPath, AUTO_INSTALL_ENV_KEY);
|
|
200
|
+
if (globalRaw !== void 0) {
|
|
201
|
+
return { value: parseAutoInstallValue(globalRaw), scope: "global", path: globalPath };
|
|
202
|
+
}
|
|
203
|
+
return { value: true, scope: "default" };
|
|
204
|
+
}
|
|
205
|
+
function resolveIdeConfigSettings(options = {}) {
|
|
206
|
+
const display = resolvePiConfigStatusDisplay(options);
|
|
207
|
+
const autoInstall = resolvePiConfigAutoInstall(options);
|
|
208
|
+
return {
|
|
209
|
+
settings: {
|
|
210
|
+
display: display.value,
|
|
211
|
+
autoInstall: autoInstall.value
|
|
212
|
+
},
|
|
213
|
+
display,
|
|
214
|
+
autoInstall
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
function writePiConfigSettings(settings, options) {
|
|
218
|
+
const path = options.scope === "project" ? resolvePiProjectConfigPath(requireProjectDir(options.projectDir)) : resolvePiGlobalConfigPath(options.home);
|
|
219
|
+
const partial = {};
|
|
220
|
+
if (settings.display !== void 0) {
|
|
221
|
+
partial[STATUS_DISPLAY_CONFIG_KEY] = settings.display;
|
|
222
|
+
}
|
|
223
|
+
if (settings.autoInstall !== void 0) {
|
|
224
|
+
partial.env = {
|
|
225
|
+
[AUTO_INSTALL_ENV_KEY]: settings.autoInstall ? "true" : "false"
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
writePiConfigFile(partial, path);
|
|
229
|
+
return { path, scope: options.scope };
|
|
230
|
+
}
|
|
231
|
+
function parseAutoInstallValue(value) {
|
|
232
|
+
return !AUTO_INSTALL_DISABLED_VALUES.has(value.trim().toLowerCase());
|
|
233
|
+
}
|
|
234
|
+
function requireProjectDir(projectDir) {
|
|
235
|
+
if (!projectDir) {
|
|
236
|
+
throw new Error("projectDir is required when saving project config");
|
|
237
|
+
}
|
|
238
|
+
return projectDir;
|
|
239
|
+
}
|
|
240
|
+
function readStatusDisplayFromFile(configPath) {
|
|
241
|
+
const parsed = readPiConfigFile(configPath);
|
|
242
|
+
if (!parsed || typeof parsed[STATUS_DISPLAY_CONFIG_KEY] !== "string") return void 0;
|
|
243
|
+
const value = parsed[STATUS_DISPLAY_CONFIG_KEY];
|
|
244
|
+
return isStatusDisplay(value) ? value : void 0;
|
|
245
|
+
}
|
|
246
|
+
function readEnvValueFromFile(configPath, key) {
|
|
247
|
+
const env = readPiConfigEnv(configPath);
|
|
248
|
+
return env[key];
|
|
249
|
+
}
|
|
250
|
+
function isStatusDisplay(value) {
|
|
251
|
+
return STATUS_DISPLAY_VALUES.includes(value);
|
|
252
|
+
}
|
|
253
|
+
function isRecord(value) {
|
|
254
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// src/shared/paths.ts
|
|
258
|
+
import { realpathSync } from "node:fs";
|
|
259
|
+
import { homedir as homedir2 } from "node:os";
|
|
260
|
+
import { isAbsolute, relative, resolve as resolve3, sep } from "node:path";
|
|
261
|
+
|
|
262
|
+
// src/shared/platform.ts
|
|
263
|
+
import { readdirSync, readFileSync as readFileSync2 } from "node:fs";
|
|
264
|
+
import { resolve as resolve2 } from "node:path";
|
|
265
|
+
var WINDOWS_SYSTEM_PROFILES = /* @__PURE__ */ new Set(["public", "default", "default user", "all users"]);
|
|
266
|
+
function isWsl(env = process.env) {
|
|
267
|
+
const configuredEnv = resolvePiConfigEnv(env);
|
|
268
|
+
if (configuredEnv.WSL_DISTRO_NAME || configuredEnv.WSL_INTEROP) return true;
|
|
269
|
+
if (!isProcessEnvOrPiConfigOverlay(configuredEnv)) return false;
|
|
270
|
+
try {
|
|
271
|
+
return /microsoft|wsl/i.test(readFileSync2("/proc/version", "utf8"));
|
|
272
|
+
} catch {
|
|
273
|
+
return false;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
function normalizePathForHost(input, env = process.env) {
|
|
277
|
+
const configuredEnv = resolvePiConfigEnv(env);
|
|
278
|
+
if (!input || !isWsl(configuredEnv)) return input;
|
|
279
|
+
const driveMatch = input.match(/^([a-zA-Z]):[\\/](.*)$/);
|
|
280
|
+
if (driveMatch) {
|
|
281
|
+
const drive = driveMatch[1].toLowerCase();
|
|
282
|
+
const rest = driveMatch[2].replaceAll("\\", "/");
|
|
283
|
+
return `/mnt/${drive}/${rest}`;
|
|
284
|
+
}
|
|
285
|
+
const uncMatch = input.match(/^[\\/]{2}(?:wsl\$|wsl\.localhost)[\\/]([^\\/]+)[\\/](.*)$/i);
|
|
286
|
+
if (uncMatch) {
|
|
287
|
+
const distro = uncMatch[1];
|
|
288
|
+
const rest = uncMatch[2].replaceAll("\\", "/");
|
|
289
|
+
const currentDistro = configuredEnv.WSL_DISTRO_NAME;
|
|
290
|
+
if (!currentDistro || distro.toLowerCase() === currentDistro.toLowerCase()) {
|
|
291
|
+
return `/${rest}`;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
return input;
|
|
295
|
+
}
|
|
296
|
+
function windowsUserProfileDirs(usersRoot = "/mnt/c/Users", env = process.env) {
|
|
297
|
+
if (!isWsl(env)) return [];
|
|
298
|
+
try {
|
|
299
|
+
return readdirSync(usersRoot, { withFileTypes: true }).filter(
|
|
300
|
+
(entry) => entry.isDirectory() && !entry.name.startsWith(".") && !WINDOWS_SYSTEM_PROFILES.has(entry.name.toLowerCase())
|
|
301
|
+
).map((entry) => resolve2(usersRoot, entry.name));
|
|
302
|
+
} catch {
|
|
303
|
+
return [];
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
function normalizeEditorSelectionSnapshotForHost(snapshot, env = process.env) {
|
|
307
|
+
return {
|
|
308
|
+
...snapshot,
|
|
309
|
+
filePath: normalizePathForHost(snapshot.filePath, env),
|
|
310
|
+
workspaceFolder: snapshot.workspaceFolder ? normalizePathForHost(snapshot.workspaceFolder, env) : void 0
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// src/shared/paths.ts
|
|
315
|
+
function resolveLockDir() {
|
|
316
|
+
return resolve3(homedir2(), CONFIG_DIR_NAME, EXT_CONFIG_NAME, "lock");
|
|
317
|
+
}
|
|
318
|
+
function resolveLockDirs(options = {}) {
|
|
319
|
+
if (options.lockDir) return [resolve3(options.lockDir)];
|
|
320
|
+
const dirs = [resolve3(options.homeLockDir ?? resolveLockDir())];
|
|
321
|
+
for (const profileDir of windowsUserProfileDirs(options.windowsUsersRoot, options.env)) {
|
|
322
|
+
dirs.push(resolve3(profileDir, CONFIG_DIR_NAME, EXT_CONFIG_NAME, "lock"));
|
|
323
|
+
}
|
|
324
|
+
return dedupePaths(dirs);
|
|
325
|
+
}
|
|
326
|
+
function dedupePaths(paths) {
|
|
327
|
+
const seen = /* @__PURE__ */ new Set();
|
|
328
|
+
const deduped = [];
|
|
329
|
+
for (const path of paths) {
|
|
330
|
+
const resolved = resolve3(path);
|
|
331
|
+
let key = resolved;
|
|
332
|
+
try {
|
|
333
|
+
key = realpathSync(resolved);
|
|
334
|
+
} catch {
|
|
335
|
+
}
|
|
336
|
+
if (seen.has(key)) continue;
|
|
337
|
+
seen.add(key);
|
|
338
|
+
deduped.push(resolved);
|
|
339
|
+
}
|
|
340
|
+
return deduped;
|
|
341
|
+
}
|
|
342
|
+
function normalizePath(input) {
|
|
343
|
+
const resolved = resolve3(input);
|
|
344
|
+
if (process.platform === "win32" && resolved.length >= 2 && resolved[1] === ":") {
|
|
345
|
+
return resolved[0].toUpperCase() + resolved.slice(1);
|
|
346
|
+
}
|
|
347
|
+
return resolved;
|
|
348
|
+
}
|
|
349
|
+
function normalizePathForComparison(input, env = process.env) {
|
|
350
|
+
return normalizePath(normalizePathForHost(input, env));
|
|
351
|
+
}
|
|
352
|
+
function isPathInsideOrEqual(parent, child) {
|
|
353
|
+
const normalizedParent = normalizePath(parent);
|
|
354
|
+
const normalizedChild = normalizePath(child);
|
|
355
|
+
if (normalizedParent === normalizedChild) return true;
|
|
356
|
+
const rel = relative(normalizedParent, normalizedChild);
|
|
357
|
+
return rel !== "" && !rel.startsWith("..") && !isAbsolute(rel);
|
|
358
|
+
}
|
|
359
|
+
function hasDirectWorkspaceMatch(workspaceFolders, cwd, env = process.env) {
|
|
360
|
+
const normalizedCwd = normalizePathForComparison(cwd, env);
|
|
361
|
+
return workspaceFolders.some(
|
|
362
|
+
(workspaceFolder) => isPathInsideOrEqual(normalizePathForComparison(workspaceFolder, env), normalizedCwd)
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
function relationshipMatchLength(workspaceFolder, cwd, env = process.env) {
|
|
366
|
+
const workspace = normalizePathForComparison(workspaceFolder, env);
|
|
367
|
+
const active = normalizePathForComparison(cwd, env);
|
|
368
|
+
if (isPathInsideOrEqual(workspace, active)) {
|
|
369
|
+
return workspace.length + 1e4;
|
|
370
|
+
}
|
|
371
|
+
if (isPathInsideOrEqual(active, workspace)) {
|
|
372
|
+
return active.length;
|
|
373
|
+
}
|
|
374
|
+
return 0;
|
|
375
|
+
}
|
|
376
|
+
function toRelativeDisplayPath(filePath, workspaceFolder, cwd, env = process.env) {
|
|
377
|
+
const base = workspaceFolder ?? cwd;
|
|
378
|
+
if (!base) return normalizePathForHost(filePath, env);
|
|
379
|
+
const normalizedFilePath = normalizePathForHost(filePath, env);
|
|
380
|
+
const normalizedBase = normalizePathForHost(base, env);
|
|
381
|
+
const rel = relative(normalizedBase, normalizedFilePath);
|
|
382
|
+
if (!rel || rel.startsWith("..") || isAbsolute(rel)) return normalizedFilePath;
|
|
383
|
+
return rel.split(sep).join("/");
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// src/shared/format.ts
|
|
387
|
+
function rangeToLineSpan(range) {
|
|
388
|
+
return {
|
|
389
|
+
startLine: range.selection.start.line + 1,
|
|
390
|
+
endLine: range.selection.end.line + 1
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
function formatLineRange(range) {
|
|
394
|
+
const { startLine, endLine } = rangeToLineSpan(range);
|
|
395
|
+
return startLine === endLine ? `L${startLine}` : `L${startLine}-L${endLine}`;
|
|
396
|
+
}
|
|
397
|
+
function formatLineSpan(range) {
|
|
398
|
+
return `#${formatLineRange(range)}`;
|
|
399
|
+
}
|
|
400
|
+
function formatRangeMention(snapshot, options = {}) {
|
|
401
|
+
const rel = toRelativeDisplayPath(snapshot.filePath, snapshot.workspaceFolder, options.cwd, options.env);
|
|
402
|
+
const first = snapshot.ranges[0];
|
|
403
|
+
return first ? `@${rel}${formatLineSpan(first)}` : `@${rel}`;
|
|
404
|
+
}
|
|
405
|
+
function describeRanges(ranges) {
|
|
406
|
+
if (ranges.length === 0) return "open file";
|
|
407
|
+
if (ranges.length === 1) return formatLineSpan(ranges[0]);
|
|
408
|
+
return ranges.map((range, index) => `${index + 1}:${formatLineSpan(range)}`).join(" ");
|
|
409
|
+
}
|
|
410
|
+
function snapshotKey(snapshot) {
|
|
411
|
+
return JSON.stringify({
|
|
412
|
+
source: snapshot.source,
|
|
413
|
+
filePath: snapshot.filePath,
|
|
414
|
+
workspaceFolder: snapshot.workspaceFolder,
|
|
415
|
+
ranges: snapshot.ranges.map((range) => ({
|
|
416
|
+
start: range.selection.start,
|
|
417
|
+
end: range.selection.end,
|
|
418
|
+
textLength: range.text.length
|
|
419
|
+
}))
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
function formatEditorContextMessage(snapshot, options = {}) {
|
|
423
|
+
const filePath = toRelativeDisplayPath(
|
|
424
|
+
snapshot.filePath,
|
|
425
|
+
snapshot.workspaceFolder,
|
|
426
|
+
void 0,
|
|
427
|
+
options.env
|
|
428
|
+
).replaceAll("`", "\\`");
|
|
429
|
+
const lines = ["### IDE Context", `- **IDE**: ${snapshot.source}`, `- **File**: \`${filePath}\``];
|
|
430
|
+
if (snapshot.ranges.length > 0) {
|
|
431
|
+
lines.push(`- **Selection**: ${snapshot.ranges.map(formatLineRange).join(", ")}`);
|
|
432
|
+
}
|
|
433
|
+
return lines.join("\n");
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// src/pi/ui.ts
|
|
437
|
+
import { basename } from "node:path";
|
|
438
|
+
|
|
439
|
+
// src/shared/display-width.ts
|
|
440
|
+
var ESC = String.fromCharCode(27);
|
|
441
|
+
var ANSI_PATTERN = new RegExp(`${ESC}\\[[0-?]*[ -/]*[@-~]`, "g");
|
|
442
|
+
var EMOJI_VARIATION_SELECTOR = 65039;
|
|
443
|
+
var COMBINING_ENCLOSING_KEYCAP = 8419;
|
|
444
|
+
var graphemeSegmenter = typeof Intl.Segmenter === "function" ? new Intl.Segmenter(void 0, { granularity: "grapheme" }) : void 0;
|
|
445
|
+
function visibleWidth(input) {
|
|
446
|
+
let width = 0;
|
|
447
|
+
for (const grapheme of graphemes(stripAnsi(input))) width += graphemeWidth(grapheme);
|
|
448
|
+
return width;
|
|
449
|
+
}
|
|
450
|
+
function truncateToWidth(input, maxWidth, ellipsis = "...", pad = false) {
|
|
451
|
+
if (maxWidth <= 0) return "";
|
|
452
|
+
const inputWidth = visibleWidth(input);
|
|
453
|
+
if (inputWidth <= maxWidth) return padToWidth(input, maxWidth, pad);
|
|
454
|
+
const suffix = fitSuffix(ellipsis, maxWidth);
|
|
455
|
+
const suffixWidth = visibleWidth(suffix);
|
|
456
|
+
const contentLimit = Math.max(0, maxWidth - suffixWidth);
|
|
457
|
+
let output = "";
|
|
458
|
+
let used = 0;
|
|
459
|
+
for (const grapheme of graphemes(stripAnsi(input))) {
|
|
460
|
+
const width = graphemeWidth(grapheme);
|
|
461
|
+
if (used + width > contentLimit) break;
|
|
462
|
+
output += grapheme;
|
|
463
|
+
used += width;
|
|
464
|
+
}
|
|
465
|
+
return padToWidth(output + suffix, maxWidth, pad);
|
|
466
|
+
}
|
|
467
|
+
function stripAnsi(input) {
|
|
468
|
+
return input.replace(ANSI_PATTERN, "");
|
|
469
|
+
}
|
|
470
|
+
function* graphemes(input) {
|
|
471
|
+
if (graphemeSegmenter) {
|
|
472
|
+
for (const segment of graphemeSegmenter.segment(input)) yield segment.segment;
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
475
|
+
yield* input;
|
|
476
|
+
}
|
|
477
|
+
function padToWidth(input, maxWidth, pad) {
|
|
478
|
+
if (!pad) return input;
|
|
479
|
+
return input + " ".repeat(Math.max(0, maxWidth - visibleWidth(input)));
|
|
480
|
+
}
|
|
481
|
+
function fitSuffix(ellipsis, maxWidth) {
|
|
482
|
+
if (visibleWidth(ellipsis) <= maxWidth) return ellipsis;
|
|
483
|
+
let output = "";
|
|
484
|
+
let used = 0;
|
|
485
|
+
for (const grapheme of graphemes(stripAnsi(ellipsis))) {
|
|
486
|
+
const width = graphemeWidth(grapheme);
|
|
487
|
+
if (used + width > maxWidth) break;
|
|
488
|
+
output += grapheme;
|
|
489
|
+
used += width;
|
|
490
|
+
}
|
|
491
|
+
return output;
|
|
492
|
+
}
|
|
493
|
+
function graphemeWidth(grapheme) {
|
|
494
|
+
if (grapheme.length === 0) return 0;
|
|
495
|
+
const codePoints = [...grapheme].map((char) => char.codePointAt(0)).filter((value) => value !== void 0);
|
|
496
|
+
if (codePoints.every(isZeroWidthCodePoint)) return 0;
|
|
497
|
+
if (codePoints.every(isControlCodePoint)) return 0;
|
|
498
|
+
if (codePoints.includes(EMOJI_VARIATION_SELECTOR) || codePoints.includes(COMBINING_ENCLOSING_KEYCAP)) return 2;
|
|
499
|
+
return codePoints.some(isWideCodePoint) ? 2 : 1;
|
|
500
|
+
}
|
|
501
|
+
function isZeroWidthCodePoint(codePoint) {
|
|
502
|
+
return codePoint >= 768 && codePoint <= 879 || codePoint >= 6832 && codePoint <= 6911 || codePoint >= 7616 && codePoint <= 7679 || codePoint >= 8400 && codePoint <= 8447 || codePoint >= 65056 && codePoint <= 65071 || codePoint === 8205 || codePoint === 65038 || codePoint === 65039;
|
|
503
|
+
}
|
|
504
|
+
function isControlCodePoint(codePoint) {
|
|
505
|
+
return codePoint <= 31 || codePoint >= 127 && codePoint <= 159;
|
|
506
|
+
}
|
|
507
|
+
function isWideCodePoint(codePoint) {
|
|
508
|
+
return codePoint >= 4352 && codePoint <= 4607 || codePoint >= 11904 && codePoint <= 42191 || codePoint >= 44032 && codePoint <= 55203 || codePoint >= 63744 && codePoint <= 64255 || codePoint >= 65040 && codePoint <= 65049 || codePoint >= 65072 && codePoint <= 65135 || codePoint >= 65280 && codePoint <= 65376 || codePoint >= 65504 && codePoint <= 65510 || codePoint >= 127462 && codePoint <= 127487 || codePoint >= 127744 && codePoint <= 129791 || codePoint >= 131072 && codePoint <= 262141;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
// src/pi/ui.ts
|
|
512
|
+
var IDE_ICON = "\u29C9";
|
|
513
|
+
var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
514
|
+
var SPINNER_INTERVAL_MS = 90;
|
|
515
|
+
var PI_THEME_KEYS = [
|
|
516
|
+
/* @__PURE__ */ Symbol.for("@earendil-works/pi-coding-agent:theme"),
|
|
517
|
+
/* @__PURE__ */ Symbol.for("@mariozechner/pi-coding-agent:theme")
|
|
518
|
+
];
|
|
519
|
+
var statuslineSpinner = { frame: 0 };
|
|
520
|
+
function getActiveUiContext(ctx) {
|
|
521
|
+
if (!ctx) return void 0;
|
|
522
|
+
try {
|
|
523
|
+
if (!ctx.hasUI) return void 0;
|
|
524
|
+
return { cwd: ctx.cwd, ui: ctx.ui };
|
|
525
|
+
} catch (error) {
|
|
526
|
+
if (!isStaleContextError(error)) logExtensionError("read active Pi UI context", error);
|
|
527
|
+
return void 0;
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
function runReportingUiFailure(scope, action) {
|
|
531
|
+
try {
|
|
532
|
+
action();
|
|
533
|
+
} catch (error) {
|
|
534
|
+
logExtensionError(scope, error);
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
function updateIdeUi(runtime, ctx = runtime.ctx, statusDisplay) {
|
|
538
|
+
const uiContext = getActiveUiContext(ctx);
|
|
539
|
+
if (!uiContext) return;
|
|
540
|
+
const display = statusDisplay ?? readPiConfigStatusDisplay({
|
|
541
|
+
projectDir: ctx?.cwd ?? runtime.cwd
|
|
542
|
+
});
|
|
543
|
+
if (display === "statusline") {
|
|
544
|
+
clearWidget(uiContext);
|
|
545
|
+
updateStatusline(runtime, uiContext);
|
|
546
|
+
return;
|
|
547
|
+
}
|
|
548
|
+
stopStatuslineSpinner();
|
|
549
|
+
clearStatusline(uiContext);
|
|
550
|
+
updateWidget(runtime, uiContext);
|
|
551
|
+
}
|
|
552
|
+
function clearIdeUi(runtime, ctx = runtime.ctx) {
|
|
553
|
+
const uiContext = getActiveUiContext(ctx);
|
|
554
|
+
stopStatuslineSpinner();
|
|
555
|
+
if (!uiContext) return;
|
|
556
|
+
clearWidget(uiContext);
|
|
557
|
+
clearStatusline(uiContext);
|
|
558
|
+
}
|
|
559
|
+
function updateWidget(runtime, uiContext) {
|
|
560
|
+
runReportingUiFailure(
|
|
561
|
+
"update IDE UI widget",
|
|
562
|
+
() => uiContext.ui.setWidget(
|
|
563
|
+
EXT_CONFIG_NAME,
|
|
564
|
+
(tui, theme) => {
|
|
565
|
+
let frame = 0;
|
|
566
|
+
let timer;
|
|
567
|
+
const animate = (active) => {
|
|
568
|
+
if (active && !timer) {
|
|
569
|
+
timer = setInterval(() => {
|
|
570
|
+
try {
|
|
571
|
+
frame = (frame + 1) % SPINNER_FRAMES.length;
|
|
572
|
+
tui.requestRender();
|
|
573
|
+
} catch (error) {
|
|
574
|
+
logExtensionError("animate IDE UI widget", error);
|
|
575
|
+
if (timer) {
|
|
576
|
+
clearInterval(timer);
|
|
577
|
+
timer = void 0;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
}, SPINNER_INTERVAL_MS);
|
|
581
|
+
timer.unref?.();
|
|
582
|
+
} else if (!active && timer) {
|
|
583
|
+
clearInterval(timer);
|
|
584
|
+
timer = void 0;
|
|
585
|
+
}
|
|
586
|
+
};
|
|
587
|
+
return {
|
|
588
|
+
render(width) {
|
|
589
|
+
try {
|
|
590
|
+
const connecting = runtime.enabled && runtime.connectionStatus === "connecting";
|
|
591
|
+
animate(connecting);
|
|
592
|
+
const segments = buildStatusSegments(runtime, SPINNER_FRAMES[frame]);
|
|
593
|
+
if (segments.length === 0 || width <= 0) return [];
|
|
594
|
+
const visible = truncateSegments(segments, width);
|
|
595
|
+
const plainWidth = visible.reduce((sum, segment) => sum + visibleWidth(segment.text), 0);
|
|
596
|
+
const pad = " ".repeat(Math.max(0, width - plainWidth));
|
|
597
|
+
return [pad + visible.map((segment) => theme.fg(segment.color, segment.text)).join("")];
|
|
598
|
+
} catch (error) {
|
|
599
|
+
logExtensionError("render IDE UI widget", error);
|
|
600
|
+
animate(false);
|
|
601
|
+
return [];
|
|
602
|
+
}
|
|
603
|
+
},
|
|
604
|
+
invalidate() {
|
|
605
|
+
},
|
|
606
|
+
dispose() {
|
|
607
|
+
animate(false);
|
|
608
|
+
}
|
|
609
|
+
};
|
|
610
|
+
},
|
|
611
|
+
{ placement: "aboveEditor" }
|
|
612
|
+
)
|
|
613
|
+
);
|
|
614
|
+
}
|
|
615
|
+
function updateStatusline(runtime, uiContext) {
|
|
616
|
+
statuslineSpinner.runtime = runtime;
|
|
617
|
+
statuslineSpinner.ui = uiContext;
|
|
618
|
+
const connecting = runtime.enabled && runtime.connectionStatus === "connecting";
|
|
619
|
+
if (connecting) {
|
|
620
|
+
startStatuslineSpinner();
|
|
621
|
+
} else {
|
|
622
|
+
stopStatuslineSpinner();
|
|
623
|
+
}
|
|
624
|
+
applyStatusline(runtime, uiContext, SPINNER_FRAMES[statuslineSpinner.frame]);
|
|
625
|
+
}
|
|
626
|
+
function applyStatusline(runtime, uiContext, spinnerFrame) {
|
|
627
|
+
runReportingUiFailure("update IDE statusline", () => {
|
|
628
|
+
const text = buildStatusText(runtime, spinnerFrame, getThemeColorizer());
|
|
629
|
+
uiContext.ui.setStatus(EXT_CONFIG_NAME, text);
|
|
630
|
+
});
|
|
631
|
+
}
|
|
632
|
+
function startStatuslineSpinner() {
|
|
633
|
+
if (statuslineSpinner.timer) return;
|
|
634
|
+
statuslineSpinner.timer = setInterval(() => {
|
|
635
|
+
try {
|
|
636
|
+
statuslineSpinner.frame = (statuslineSpinner.frame + 1) % SPINNER_FRAMES.length;
|
|
637
|
+
const runtime = statuslineSpinner.runtime;
|
|
638
|
+
const ui = statuslineSpinner.ui;
|
|
639
|
+
if (!runtime || !ui) return;
|
|
640
|
+
if (!(runtime.enabled && runtime.connectionStatus === "connecting")) {
|
|
641
|
+
stopStatuslineSpinner();
|
|
642
|
+
applyStatusline(runtime, ui, SPINNER_FRAMES[statuslineSpinner.frame]);
|
|
643
|
+
return;
|
|
644
|
+
}
|
|
645
|
+
applyStatusline(runtime, ui, SPINNER_FRAMES[statuslineSpinner.frame]);
|
|
646
|
+
} catch (error) {
|
|
647
|
+
logExtensionError("animate IDE statusline", error);
|
|
648
|
+
stopStatuslineSpinner();
|
|
649
|
+
}
|
|
650
|
+
}, SPINNER_INTERVAL_MS);
|
|
651
|
+
statuslineSpinner.timer.unref?.();
|
|
652
|
+
}
|
|
653
|
+
function stopStatuslineSpinner() {
|
|
654
|
+
if (!statuslineSpinner.timer) return;
|
|
655
|
+
clearInterval(statuslineSpinner.timer);
|
|
656
|
+
statuslineSpinner.timer = void 0;
|
|
657
|
+
}
|
|
658
|
+
function clearWidget(uiContext) {
|
|
659
|
+
runReportingUiFailure("clear IDE UI widget", () => uiContext.ui.setWidget(EXT_CONFIG_NAME, void 0));
|
|
660
|
+
}
|
|
661
|
+
function clearStatusline(uiContext) {
|
|
662
|
+
runReportingUiFailure("clear IDE statusline", () => uiContext.ui.setStatus(EXT_CONFIG_NAME, void 0));
|
|
663
|
+
}
|
|
664
|
+
function truncateSegments(segments, width) {
|
|
665
|
+
const total = segments.reduce((sum, segment) => sum + visibleWidth(segment.text), 0);
|
|
666
|
+
if (total <= width) return segments;
|
|
667
|
+
const fallbackColor = segments[0]?.color ?? "dim";
|
|
668
|
+
if (width <= 3) return [{ text: ".".repeat(width), color: fallbackColor }];
|
|
669
|
+
const shrinkIndex = segments.findIndex((segment) => segment.shrink);
|
|
670
|
+
if (shrinkIndex >= 0) {
|
|
671
|
+
const shrinkSegment = segments[shrinkIndex];
|
|
672
|
+
const shrinkWidth = visibleWidth(shrinkSegment.text);
|
|
673
|
+
const reservedWidth = total - shrinkWidth;
|
|
674
|
+
const room = width - reservedWidth;
|
|
675
|
+
if (room > 0) {
|
|
676
|
+
const preserved = segments.map(
|
|
677
|
+
(segment, index) => index === shrinkIndex ? { ...segment, text: truncateToWidth(segment.text, room) } : segment
|
|
678
|
+
);
|
|
679
|
+
const preservedWidth = preserved.reduce((sum, segment) => sum + visibleWidth(segment.text), 0);
|
|
680
|
+
if (preservedWidth <= width) return preserved;
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
const ellipsis = "...";
|
|
684
|
+
const limit = width - visibleWidth(ellipsis);
|
|
685
|
+
const visible = [];
|
|
686
|
+
let used = 0;
|
|
687
|
+
for (const segment of segments) {
|
|
688
|
+
if (used >= limit) break;
|
|
689
|
+
const room = limit - used;
|
|
690
|
+
const segmentWidth = visibleWidth(segment.text);
|
|
691
|
+
if (segmentWidth <= room) {
|
|
692
|
+
visible.push(segment);
|
|
693
|
+
used += segmentWidth;
|
|
694
|
+
} else {
|
|
695
|
+
const text = truncateToWidth(segment.text, room, "");
|
|
696
|
+
if (text) visible.push({ text, color: segment.color });
|
|
697
|
+
break;
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
visible.push({ text: ellipsis, color: visible[visible.length - 1]?.color ?? fallbackColor });
|
|
701
|
+
return visible;
|
|
702
|
+
}
|
|
703
|
+
function buildStatusSegments(runtime, spinnerFrame = SPINNER_FRAMES[0]) {
|
|
704
|
+
if (!runtime.enabled) return [];
|
|
705
|
+
switch (runtime.connectionStatus) {
|
|
706
|
+
case "connecting":
|
|
707
|
+
return [{ text: `${IDE_ICON} ${spinnerFrame}`, color: "dim" }];
|
|
708
|
+
case "error":
|
|
709
|
+
return [
|
|
710
|
+
{ text: `${IDE_ICON} `, color: "dim" },
|
|
711
|
+
{ text: "\u2715", color: "error" }
|
|
712
|
+
];
|
|
713
|
+
case "connected":
|
|
714
|
+
return buildConnectedSegments(runtime);
|
|
715
|
+
default:
|
|
716
|
+
return [];
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
function buildStatusText(runtime, spinnerFrame = SPINNER_FRAMES[0], colorize) {
|
|
720
|
+
const segments = buildStatusSegments(runtime, spinnerFrame);
|
|
721
|
+
if (segments.length === 0) return void 0;
|
|
722
|
+
return formatStatusSegments(segments, colorize);
|
|
723
|
+
}
|
|
724
|
+
function formatStatusSegments(segments, colorize) {
|
|
725
|
+
if (!colorize) return segments.map((segment) => segment.text).join("");
|
|
726
|
+
return segments.map((segment) => colorize(segment.color, segment.text)).join("");
|
|
727
|
+
}
|
|
728
|
+
function getThemeColorizer() {
|
|
729
|
+
const activeTheme = getActivePiTheme();
|
|
730
|
+
if (!activeTheme) return void 0;
|
|
731
|
+
return (color, text) => activeTheme.fg(color, text);
|
|
732
|
+
}
|
|
733
|
+
function getActivePiTheme() {
|
|
734
|
+
const globalStore = globalThis;
|
|
735
|
+
for (const key of PI_THEME_KEYS) {
|
|
736
|
+
const candidate = globalStore[key];
|
|
737
|
+
if (!isThemeLike(candidate)) continue;
|
|
738
|
+
return candidate;
|
|
739
|
+
}
|
|
740
|
+
return void 0;
|
|
741
|
+
}
|
|
742
|
+
function isThemeLike(value) {
|
|
743
|
+
if (!value || typeof value !== "object") return false;
|
|
744
|
+
return typeof value.fg === "function";
|
|
745
|
+
}
|
|
746
|
+
function buildConnectedSegments(runtime) {
|
|
747
|
+
const selection = runtime.latestSelection;
|
|
748
|
+
if (!selection) return [{ text: `${IDE_ICON} \u2713`, color: "dim" }];
|
|
749
|
+
const rel = basename(selection.filePath);
|
|
750
|
+
const range = describeRanges(selection.ranges);
|
|
751
|
+
const pending = runtime.attachState === "pending";
|
|
752
|
+
const marker = pending ? "\u21E1" : "\u2713";
|
|
753
|
+
const color = pending ? "success" : "dim";
|
|
754
|
+
const prefix = `${IDE_ICON} ${marker} `;
|
|
755
|
+
if (range === "open file") return [{ text: `${prefix}${rel}`, color, shrink: true }];
|
|
756
|
+
return [
|
|
757
|
+
{ text: prefix, color },
|
|
758
|
+
{ text: rel, color, shrink: true },
|
|
759
|
+
{ text: range, color }
|
|
760
|
+
];
|
|
761
|
+
}
|
|
762
|
+
function buildWidget(runtime, cwd) {
|
|
763
|
+
if (!runtime.enabled || runtime.connectionStatus === "disabled") return void 0;
|
|
764
|
+
if (runtime.connectionStatus !== "connected" && runtime.connectionStatus !== "connecting" && runtime.connectionStatus !== "error") {
|
|
765
|
+
return void 0;
|
|
766
|
+
}
|
|
767
|
+
const lines = [];
|
|
768
|
+
const ide = runtime.connectedServer?.name ?? runtime.currentCandidate?.lock.name ?? "IDE";
|
|
769
|
+
lines.push(`IDE: ${ide} (${runtime.connectionStatus})`);
|
|
770
|
+
if (runtime.currentCandidate) {
|
|
771
|
+
lines.push(`Workspace: ${runtime.currentCandidate.workspaceFolder}`);
|
|
772
|
+
}
|
|
773
|
+
if (runtime.latestSelection) {
|
|
774
|
+
const selection = runtime.latestSelection;
|
|
775
|
+
lines.push(`File: ${toRelativeDisplayPath(selection.filePath, selection.workspaceFolder, cwd)}`);
|
|
776
|
+
lines.push(`Range: ${describeRanges(selection.ranges)}`);
|
|
777
|
+
lines.push(`Attach: ${runtime.attachState}`);
|
|
778
|
+
if (selection.receivedAt) lines.push(`Updated: ${new Date(selection.receivedAt).toLocaleTimeString()}`);
|
|
779
|
+
} else if (runtime.connectionMessage) {
|
|
780
|
+
lines.push(runtime.connectionMessage);
|
|
781
|
+
}
|
|
782
|
+
return lines;
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
export {
|
|
786
|
+
__require,
|
|
787
|
+
__commonJS,
|
|
788
|
+
__toESM,
|
|
789
|
+
setExtensionErrorReporter,
|
|
790
|
+
errorMessage,
|
|
791
|
+
isStaleContextError,
|
|
792
|
+
toError,
|
|
793
|
+
formatExtensionError,
|
|
794
|
+
logExtensionError,
|
|
795
|
+
safeRun,
|
|
796
|
+
safeRunAsync,
|
|
797
|
+
STATUS_DISPLAY_VALUES,
|
|
798
|
+
DEFAULT_STATUS_DISPLAY,
|
|
799
|
+
EXT_CONFIG_NAME,
|
|
800
|
+
resolvePiConfigEnv,
|
|
801
|
+
readPiConfigFixPrompt,
|
|
802
|
+
resolveIdeConfigSettings,
|
|
803
|
+
writePiConfigSettings,
|
|
804
|
+
isWsl,
|
|
805
|
+
normalizePathForHost,
|
|
806
|
+
normalizeEditorSelectionSnapshotForHost,
|
|
807
|
+
resolveLockDirs,
|
|
808
|
+
isPathInsideOrEqual,
|
|
809
|
+
hasDirectWorkspaceMatch,
|
|
810
|
+
relationshipMatchLength,
|
|
811
|
+
toRelativeDisplayPath,
|
|
812
|
+
formatRangeMention,
|
|
813
|
+
snapshotKey,
|
|
814
|
+
formatEditorContextMessage,
|
|
815
|
+
visibleWidth,
|
|
816
|
+
updateIdeUi,
|
|
817
|
+
clearIdeUi,
|
|
818
|
+
buildWidget
|
|
819
|
+
};
|