@saifymatteo/pi-x-ide 0.0.0-stage → 1.20.1

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.
Files changed (81) hide show
  1. package/CHANGELOG.md +328 -0
  2. package/CONTRIBUTING.md +119 -0
  3. package/CONTRIBUTING.zh-CN.md +106 -0
  4. package/LICENSE +201 -0
  5. package/README.md +33 -2
  6. package/README.zh-CN.md +34 -0
  7. package/RELEASE.md +213 -0
  8. package/config.example.json +9 -0
  9. package/dist/src/pi/chunks/chunk-4RHJAL4S.js +200 -0
  10. package/dist/src/pi/chunks/chunk-UUXVCTOS.js +819 -0
  11. package/dist/src/pi/chunks/config-ui-LO3DVQFC.js +8073 -0
  12. package/dist/src/pi/chunks/runtime-services-TUOTPMCH.js +19569 -0
  13. package/dist/src/pi/commands.js +126 -0
  14. package/dist/src/pi/config-ui.js +127 -0
  15. package/dist/src/pi/connection.js +237 -0
  16. package/dist/src/pi/context.js +30 -0
  17. package/dist/src/pi/diagnostic-renderer.js +326 -0
  18. package/dist/src/pi/diagnostic-types.js +1 -0
  19. package/dist/src/pi/diagnostics.js +104 -0
  20. package/dist/src/pi/discovery.js +135 -0
  21. package/dist/src/pi/effect-boundary.js +5 -0
  22. package/dist/src/pi/ide-host.js +68 -0
  23. package/dist/src/pi/index.js +636 -0
  24. package/dist/src/pi/install.js +308 -0
  25. package/dist/src/pi/reconnect.js +57 -0
  26. package/dist/src/pi/runtime-loader.js +38 -0
  27. package/dist/src/pi/runtime-services.js +356 -0
  28. package/dist/src/pi/safety.js +61 -0
  29. package/dist/src/pi/selection.js +18 -0
  30. package/dist/src/pi/state.js +13 -0
  31. package/dist/src/pi/ui.js +304 -0
  32. package/dist/src/pi/zed.js +409 -0
  33. package/dist/src/shared/config-options.js +45 -0
  34. package/dist/src/shared/config.js +183 -0
  35. package/dist/src/shared/display-width.js +99 -0
  36. package/dist/src/shared/effect-errors.js +36 -0
  37. package/dist/src/shared/effect-runtime.js +36 -0
  38. package/dist/src/shared/effect-schema.js +120 -0
  39. package/dist/src/shared/errors.js +48 -0
  40. package/dist/src/shared/format.js +92 -0
  41. package/dist/src/shared/ide-server.js +167 -0
  42. package/dist/src/shared/jsonrpc-guard.js +12 -0
  43. package/dist/src/shared/lock-file-heartbeat.js +58 -0
  44. package/dist/src/shared/lock-file.js +50 -0
  45. package/dist/src/shared/paths.js +79 -0
  46. package/dist/src/shared/platform.js +57 -0
  47. package/dist/src/shared/protocol.js +3 -0
  48. package/dist/src/shared/schema.js +37 -0
  49. package/dist/src/shared/version.js +1 -0
  50. package/dist/src/shared/ws.js +8 -0
  51. package/docs/explanation/architecture.md +123 -0
  52. package/docs/explanation/discovery.md +113 -0
  53. package/docs/explanation/effect.md +127 -0
  54. package/docs/how-to/install-jetbrains.md +58 -0
  55. package/docs/how-to/install-neovim.md +138 -0
  56. package/docs/how-to/install-vscode.md +75 -0
  57. package/docs/how-to/install-zed.md +70 -0
  58. package/docs/how-to/troubleshoot-connection.md +103 -0
  59. package/docs/how-to/use-wsl2.md +90 -0
  60. package/docs/reference/commands.md +59 -0
  61. package/docs/reference/configuration.md +101 -0
  62. package/docs/reference/feature-parity.md +26 -0
  63. package/docs/reference/protocol.md +71 -0
  64. package/docs/specs/ide-protocol.md +215 -0
  65. package/docs/tutorials/get-started.md +133 -0
  66. package/docs/zh-CN/explanation/architecture.md +93 -0
  67. package/docs/zh-CN/explanation/discovery.md +71 -0
  68. package/docs/zh-CN/explanation/effect.md +90 -0
  69. package/docs/zh-CN/how-to/install-jetbrains.md +49 -0
  70. package/docs/zh-CN/how-to/install-neovim.md +126 -0
  71. package/docs/zh-CN/how-to/install-vscode.md +67 -0
  72. package/docs/zh-CN/how-to/install-zed.md +56 -0
  73. package/docs/zh-CN/how-to/troubleshoot-connection.md +85 -0
  74. package/docs/zh-CN/how-to/use-wsl2.md +75 -0
  75. package/docs/zh-CN/reference/commands.md +54 -0
  76. package/docs/zh-CN/reference/configuration.md +94 -0
  77. package/docs/zh-CN/reference/feature-parity.md +21 -0
  78. package/docs/zh-CN/reference/protocol.md +54 -0
  79. package/docs/zh-CN/tutorials/get-started.md +101 -0
  80. package/package.json +86 -4
  81. package/schemas/config.json +77 -0
@@ -0,0 +1,636 @@
1
+ import { createRequire as __piCreateRequire } from "node:module";const require = __piCreateRequire(import.meta.url);
2
+ import {
3
+ DIAGNOSTIC_CONTEXT_MARKER,
4
+ DIAGNOSTIC_FIX_CUSTOM_TYPE,
5
+ bindPiUiContext,
6
+ formatDiagnosticCode,
7
+ formatRange,
8
+ installPiErrorReporter,
9
+ runPiBoundary,
10
+ runPiBoundaryAsync
11
+ } from "./chunks/chunk-4RHJAL4S.js";
12
+ import {
13
+ buildWidget,
14
+ clearIdeUi,
15
+ formatEditorContextMessage,
16
+ formatRangeMention,
17
+ logExtensionError,
18
+ resolvePiConfigEnv,
19
+ toRelativeDisplayPath,
20
+ updateIdeUi,
21
+ visibleWidth
22
+ } from "./chunks/chunk-UUXVCTOS.js";
23
+
24
+ // src/pi/commands.ts
25
+ var PI_X_IDE_ATTACH_SHORTCUT_ENV = "PI_X_IDE_ATTACH_SHORTCUT";
26
+ var DEFAULT_ATTACH_SHORTCUT = "ctrl+alt+k";
27
+ var DISABLED_ATTACH_SHORTCUT_VALUES = /* @__PURE__ */ new Set(["", "0", "false", "off", "none", "disabled"]);
28
+ function registerIdeCommand(pi, runtime, actions, options = {}) {
29
+ const attachShortcut = resolveAttachShortcut(options.env);
30
+ if (attachShortcut) {
31
+ pi.registerShortcut(attachShortcut, {
32
+ description: "Attach latest IDE selection to the prompt",
33
+ handler: (ctx) => {
34
+ runPiBoundary(
35
+ "IDE attach shortcut",
36
+ runtime,
37
+ () => {
38
+ runtime.ctx = ctx;
39
+ attachLatest(runtime, ctx);
40
+ },
41
+ ctx
42
+ );
43
+ }
44
+ });
45
+ }
46
+ pi.registerCommand("ide", {
47
+ description: "Manage IDE connection and editor selection context",
48
+ getArgumentCompletions: (argumentPrefix) => {
49
+ const subcommands = [
50
+ { value: "status", label: "status", description: "Show IDE connection status" },
51
+ { value: "list", label: "list", description: "List available IDE connections" },
52
+ { value: "auto", label: "auto", description: "Auto-connect to the most recent IDE" },
53
+ { value: "off", label: "off", description: "Disable IDE integration" },
54
+ { value: "attach", label: "attach", description: "Attach latest IDE selection to the prompt" },
55
+ { value: "install", label: "install", description: "Install or update the IDE extension" },
56
+ { value: "settings", label: "settings", description: "Open IDE settings (Display, AutoInstall, ...)" }
57
+ ];
58
+ const filtered = subcommands.filter((s) => s.value.startsWith(argumentPrefix));
59
+ return filtered.length > 0 ? filtered : null;
60
+ },
61
+ handler: (args, ctx) => runPiBoundaryAsync(
62
+ "/ide command",
63
+ runtime,
64
+ async () => {
65
+ runtime.ctx = ctx;
66
+ const [subcommand] = args.trim().split(/\s+/, 1);
67
+ switch (subcommand || "") {
68
+ case "":
69
+ await showPicker(runtime, actions, ctx);
70
+ return;
71
+ case "status":
72
+ showStatus(runtime, ctx);
73
+ return;
74
+ case "list":
75
+ await listCandidates(actions, ctx);
76
+ return;
77
+ case "auto":
78
+ runtime.enabled = true;
79
+ await actions.connectAuto(ctx);
80
+ return;
81
+ case "off":
82
+ await actions.disconnect(ctx, true);
83
+ return;
84
+ case "attach":
85
+ attachLatest(runtime, ctx);
86
+ return;
87
+ case "install":
88
+ await actions.installExtension(ctx);
89
+ return;
90
+ case "settings": {
91
+ const { showIdeSettings } = await import("./chunks/config-ui-LO3DVQFC.js");
92
+ await showIdeSettings(runtime, ctx);
93
+ return;
94
+ }
95
+ default:
96
+ ctx.ui.notify("Usage: /ide [status|list|auto|off|attach|install|settings]", "warning");
97
+ }
98
+ },
99
+ ctx
100
+ )
101
+ });
102
+ }
103
+ async function showPicker(runtime, actions, ctx) {
104
+ const candidates = await actions.refreshCandidates(ctx);
105
+ if (candidates.length === 0) {
106
+ ctx.ui.notify("No matching IDE connections found.", "warning");
107
+ return;
108
+ }
109
+ const labels = candidates.map(
110
+ (candidate2, index2) => `${index2 + 1}. ${candidate2.lock.name} \u2014 ${candidate2.workspaceFolder}`
111
+ );
112
+ labels.push("Disable IDE integration");
113
+ const choice = await ctx.ui.select("Select IDE connection", labels);
114
+ if (!choice) return;
115
+ if (choice === "Disable IDE integration") {
116
+ await actions.disconnect(ctx, true);
117
+ return;
118
+ }
119
+ const index = labels.indexOf(choice);
120
+ const candidate = candidates[index];
121
+ if (candidate) {
122
+ runtime.enabled = true;
123
+ await actions.connectCandidate(candidate, ctx);
124
+ }
125
+ }
126
+ function showStatus(runtime, ctx) {
127
+ const lines = buildWidget(runtime, ctx.cwd) ?? ["IDE: disconnected"];
128
+ ctx.ui.notify(lines.join("\n"), runtime.connectionStatus === "error" ? "error" : "info");
129
+ }
130
+ async function listCandidates(actions, ctx) {
131
+ const candidates = await actions.refreshCandidates(ctx);
132
+ if (candidates.length === 0) {
133
+ ctx.ui.notify("No matching IDE lock files found.", "info");
134
+ return;
135
+ }
136
+ ctx.ui.notify(
137
+ candidates.map(
138
+ (candidate, index) => `${index + 1}. ${candidate.lock.name} ${candidate.lock.host}:${candidate.lock.port}
139
+ ${candidate.workspaceFolder}
140
+ ${candidate.path}`
141
+ ).join("\n"),
142
+ "info"
143
+ );
144
+ }
145
+ function resolveAttachShortcut(env = process.env) {
146
+ const value = resolvePiConfigEnv(env)[PI_X_IDE_ATTACH_SHORTCUT_ENV] ?? DEFAULT_ATTACH_SHORTCUT;
147
+ const normalized = value.trim().toLowerCase();
148
+ if (DISABLED_ATTACH_SHORTCUT_VALUES.has(normalized)) return void 0;
149
+ return normalized;
150
+ }
151
+ function attachLatest(runtime, ctx) {
152
+ if (!runtime.latestSelection) {
153
+ ctx.ui.notify("No IDE selection is available.", "warning");
154
+ return;
155
+ }
156
+ const mention = formatRangeMention(runtime.latestSelection, { cwd: ctx.cwd });
157
+ ctx.ui.pasteToEditor(mention + "\n");
158
+ runtime.attachState = "pending";
159
+ updateIdeUi(runtime, ctx);
160
+ ctx.ui.notify(`Attached ${mention}`, "info");
161
+ }
162
+
163
+ // src/pi/context.ts
164
+ function registerContextHandlers(pi, runtime) {
165
+ pi.on(
166
+ "before_agent_start",
167
+ (event, ctx) => runPiBoundary(
168
+ "Pi before_agent_start",
169
+ runtime,
170
+ () => {
171
+ runtime.ctx = ctx;
172
+ if (!runtime.enabled || !runtime.latestSelection || runtime.attachState !== "pending") return;
173
+ const snapshot = runtime.latestSelection;
174
+ runtime.attachState = "sent";
175
+ updateIdeUi(runtime, ctx);
176
+ if (promptContainsContextMarker(event.prompt, snapshot)) return;
177
+ return {
178
+ message: {
179
+ customType: IDE_CONTEXT_MESSAGE_TYPE,
180
+ content: formatEditorContextMessage(snapshot),
181
+ display: true
182
+ }
183
+ };
184
+ },
185
+ ctx
186
+ )
187
+ );
188
+ }
189
+ var IDE_CONTEXT_MESSAGE_TYPE = "pi-x-ide/context";
190
+ function promptContainsContextMarker(prompt, snapshot) {
191
+ return prompt.includes(DIAGNOSTIC_CONTEXT_MARKER) || prompt.includes("<system-reminder><selected-context>") && (prompt.includes(snapshot.filePath) || !!snapshot.workspaceFolder && prompt.includes(snapshot.workspaceFolder));
192
+ }
193
+
194
+ // src/pi/diagnostic-renderer.ts
195
+ var DIAGNOSTIC_BOX_PADDING_X = 1;
196
+ var DIAGNOSTIC_BOX_PADDING_Y = 1;
197
+ var MIN_CONTENT_WIDTH = 1;
198
+ var TAB_REPLACEMENT = " ";
199
+ var ESCAPE_CHARACTER = String.fromCharCode(27);
200
+ var ANSI_SEQUENCE_AT_START = new RegExp(`^${ESCAPE_CHARACTER}\\[[0-?]*[ -/]*[@-~]`);
201
+ var GRAPHEME_SEGMENTER = typeof Intl.Segmenter === "function" ? new Intl.Segmenter(void 0, { granularity: "grapheme" }) : void 0;
202
+ var SGR_CODES = {
203
+ reset: 0,
204
+ bold: 1,
205
+ dim: 2,
206
+ italic: 3,
207
+ underline: 4,
208
+ slowBlink: 5,
209
+ rapidBlink: 6,
210
+ inverse: 7,
211
+ conceal: 8,
212
+ strikethrough: 9,
213
+ doubleUnderline: 21,
214
+ intensityReset: 22,
215
+ italicReset: 23,
216
+ underlineReset: 24,
217
+ blinkReset: 25,
218
+ inverseReset: 27,
219
+ concealReset: 28,
220
+ strikethroughReset: 29,
221
+ foregroundStart: 30,
222
+ foregroundEnd: 37,
223
+ extendedForeground: 38,
224
+ foregroundReset: 39,
225
+ backgroundStart: 40,
226
+ backgroundEnd: 47,
227
+ extendedBackground: 48,
228
+ backgroundReset: 49,
229
+ overline: 53,
230
+ overlineReset: 55,
231
+ extendedUnderlineColor: 58,
232
+ underlineColorReset: 59,
233
+ brightForegroundStart: 90,
234
+ brightForegroundEnd: 97,
235
+ brightBackgroundStart: 100,
236
+ brightBackgroundEnd: 107
237
+ };
238
+ var SGR_INDEXED_COLOR_MODE = 5;
239
+ var SGR_TRUE_COLOR_MODE = 2;
240
+ var SGR_INDEXED_COLOR_PARAMETER_COUNT = 2;
241
+ var SGR_TRUE_COLOR_PARAMETER_COUNT = 4;
242
+ var SGR_STYLE_GROUPS = /* @__PURE__ */ new Map([
243
+ [SGR_CODES.bold, "bold"],
244
+ [SGR_CODES.dim, "dim"],
245
+ [SGR_CODES.italic, "italic"],
246
+ [SGR_CODES.underline, "underline"],
247
+ [SGR_CODES.slowBlink, "blink"],
248
+ [SGR_CODES.rapidBlink, "blink"],
249
+ [SGR_CODES.inverse, "inverse"],
250
+ [SGR_CODES.conceal, "conceal"],
251
+ [SGR_CODES.strikethrough, "strikethrough"],
252
+ [SGR_CODES.doubleUnderline, "underline"],
253
+ [SGR_CODES.overline, "overline"]
254
+ ]);
255
+ var SGR_STYLE_RESETS = /* @__PURE__ */ new Map([
256
+ [SGR_CODES.intensityReset, ["bold", "dim"]],
257
+ [SGR_CODES.italicReset, ["italic"]],
258
+ [SGR_CODES.underlineReset, ["underline"]],
259
+ [SGR_CODES.blinkReset, ["blink"]],
260
+ [SGR_CODES.inverseReset, ["inverse"]],
261
+ [SGR_CODES.concealReset, ["conceal"]],
262
+ [SGR_CODES.strikethroughReset, ["strikethrough"]],
263
+ [SGR_CODES.overlineReset, ["overline"]]
264
+ ]);
265
+ function registerDiagnosticRenderer(pi) {
266
+ pi.registerMessageRenderer(DIAGNOSTIC_FIX_CUSTOM_TYPE, (message, { expanded }, theme) => {
267
+ const details = message.details;
268
+ if (!details) return void 0;
269
+ return createDiagnosticFixComponent(details, theme, expanded);
270
+ });
271
+ }
272
+ function createDiagnosticFixComponent(details, theme, expanded) {
273
+ return new DiagnosticMessageComponent(
274
+ buildText(details, theme, expanded),
275
+ (text) => theme.bg("customMessageBg", text)
276
+ );
277
+ }
278
+ var DiagnosticMessageComponent = class {
279
+ constructor(text, bgFn) {
280
+ this.text = text;
281
+ this.bgFn = bgFn;
282
+ }
283
+ text;
284
+ bgFn;
285
+ cache;
286
+ invalidate() {
287
+ this.cache = void 0;
288
+ }
289
+ render(width) {
290
+ if (this.cache?.width === width) return this.cache.lines;
291
+ const contentWidth = Math.max(MIN_CONTENT_WIDTH, width - DIAGNOSTIC_BOX_PADDING_X * 2);
292
+ const leftPad = " ".repeat(DIAGNOSTIC_BOX_PADDING_X);
293
+ const lines = [];
294
+ for (let index = 0; index < DIAGNOSTIC_BOX_PADDING_Y; index += 1) {
295
+ lines.push(this.padAndApplyBackground("", width));
296
+ }
297
+ for (const wrappedLine of wrapAnsiText(this.text, contentWidth)) {
298
+ lines.push(this.padAndApplyBackground(leftPad + wrappedLine, width));
299
+ }
300
+ for (let index = 0; index < DIAGNOSTIC_BOX_PADDING_Y; index += 1) {
301
+ lines.push(this.padAndApplyBackground("", width));
302
+ }
303
+ this.cache = { width, lines };
304
+ return lines;
305
+ }
306
+ padAndApplyBackground(line, width) {
307
+ const padNeeded = Math.max(0, width - visibleWidth(line));
308
+ return this.bgFn(line + " ".repeat(padNeeded));
309
+ }
310
+ };
311
+ function wrapAnsiText(text, width) {
312
+ const normalizedText = text.replaceAll(" ", TAB_REPLACEMENT);
313
+ const lines = [];
314
+ const sgrState = new SgrState();
315
+ for (const logicalLine of normalizedText.split("\n")) {
316
+ lines.push(...wrapAnsiLine(logicalLine, width, sgrState));
317
+ }
318
+ return lines.length > 0 ? lines : [""];
319
+ }
320
+ function wrapAnsiLine(line, width, sgrState) {
321
+ const lines = [];
322
+ let currentLine = sgrState.toAnsi();
323
+ let currentWidth = 0;
324
+ let index = 0;
325
+ while (index < line.length) {
326
+ const ansiSequence = readAnsiSequence(line, index);
327
+ if (ansiSequence) {
328
+ currentLine += ansiSequence;
329
+ sgrState.process(ansiSequence);
330
+ index += ansiSequence.length;
331
+ continue;
332
+ }
333
+ if (line[index] === ESCAPE_CHARACTER) {
334
+ currentLine += ESCAPE_CHARACTER;
335
+ index += 1;
336
+ continue;
337
+ }
338
+ const nextEscape = line.indexOf(ESCAPE_CHARACTER, index);
339
+ const textEnd = nextEscape === -1 ? line.length : nextEscape;
340
+ const textChunk = line.slice(index, textEnd);
341
+ for (const grapheme of segmentGraphemes(textChunk)) {
342
+ const graphemeWidth = visibleWidth(grapheme);
343
+ if (currentWidth > 0 && currentWidth + graphemeWidth > width) {
344
+ lines.push(currentLine + sgrState.lineEndReset());
345
+ currentLine = sgrState.toAnsi();
346
+ currentWidth = 0;
347
+ }
348
+ currentLine += grapheme;
349
+ currentWidth += graphemeWidth;
350
+ }
351
+ index = textEnd;
352
+ }
353
+ lines.push(currentLine + sgrState.lineEndReset());
354
+ return lines;
355
+ }
356
+ function readAnsiSequence(text, index) {
357
+ if (text[index] !== ESCAPE_CHARACTER) return void 0;
358
+ return ANSI_SEQUENCE_AT_START.exec(text.slice(index))?.[0];
359
+ }
360
+ var SgrState = class {
361
+ activeCodes = /* @__PURE__ */ new Map();
362
+ process(sequence) {
363
+ if (!sequence.endsWith("m")) return;
364
+ const rawParameters = sequence.slice(2, -1);
365
+ const parameters = rawParameters === "" ? [SGR_CODES.reset] : rawParameters.split(";").map(Number);
366
+ for (let index = 0; index < parameters.length; index += 1) {
367
+ const code = parameters[index];
368
+ if (!Number.isInteger(code)) continue;
369
+ if (code === SGR_CODES.reset) {
370
+ this.activeCodes.clear();
371
+ continue;
372
+ }
373
+ const styleGroup = SGR_STYLE_GROUPS.get(code);
374
+ if (styleGroup) {
375
+ this.activeCodes.set(styleGroup, formatSgrSequence([code]));
376
+ continue;
377
+ }
378
+ const resetGroups = SGR_STYLE_RESETS.get(code);
379
+ if (resetGroups) {
380
+ for (const resetGroup of resetGroups) this.activeCodes.delete(resetGroup);
381
+ continue;
382
+ }
383
+ if (isStandardForegroundCode(code)) {
384
+ this.activeCodes.set("foreground", formatSgrSequence([code]));
385
+ continue;
386
+ }
387
+ if (code === SGR_CODES.foregroundReset) {
388
+ this.activeCodes.delete("foreground");
389
+ continue;
390
+ }
391
+ if (isStandardBackgroundCode(code)) {
392
+ this.activeCodes.set("background", formatSgrSequence([code]));
393
+ continue;
394
+ }
395
+ if (code === SGR_CODES.backgroundReset) {
396
+ this.activeCodes.delete("background");
397
+ continue;
398
+ }
399
+ if (code === SGR_CODES.underlineColorReset) {
400
+ this.activeCodes.delete("underline-color");
401
+ continue;
402
+ }
403
+ const extendedGroup = getExtendedColorGroup(code);
404
+ if (extendedGroup) {
405
+ const parameterCount = getExtendedColorParameterCount(parameters[index + 1]);
406
+ if (parameterCount === 0 || index + parameterCount >= parameters.length) continue;
407
+ const colorParameters = parameters.slice(index, index + parameterCount + 1);
408
+ this.activeCodes.set(extendedGroup, formatSgrSequence(colorParameters));
409
+ index += parameterCount;
410
+ }
411
+ }
412
+ }
413
+ toAnsi() {
414
+ return [...this.activeCodes.values()].join("");
415
+ }
416
+ lineEndReset() {
417
+ return this.activeCodes.has("underline") ? formatSgrSequence([SGR_CODES.underlineReset]) : "";
418
+ }
419
+ };
420
+ function isStandardForegroundCode(code) {
421
+ return code >= SGR_CODES.foregroundStart && code <= SGR_CODES.foregroundEnd || code >= SGR_CODES.brightForegroundStart && code <= SGR_CODES.brightForegroundEnd;
422
+ }
423
+ function isStandardBackgroundCode(code) {
424
+ return code >= SGR_CODES.backgroundStart && code <= SGR_CODES.backgroundEnd || code >= SGR_CODES.brightBackgroundStart && code <= SGR_CODES.brightBackgroundEnd;
425
+ }
426
+ function getExtendedColorGroup(code) {
427
+ if (code === SGR_CODES.extendedForeground) return "foreground";
428
+ if (code === SGR_CODES.extendedBackground) return "background";
429
+ if (code === SGR_CODES.extendedUnderlineColor) return "underline-color";
430
+ return void 0;
431
+ }
432
+ function getExtendedColorParameterCount(mode) {
433
+ if (mode === SGR_INDEXED_COLOR_MODE) return SGR_INDEXED_COLOR_PARAMETER_COUNT;
434
+ if (mode === SGR_TRUE_COLOR_MODE) return SGR_TRUE_COLOR_PARAMETER_COUNT;
435
+ return 0;
436
+ }
437
+ function formatSgrSequence(parameters) {
438
+ return `${ESCAPE_CHARACTER}[${parameters.join(";")}m`;
439
+ }
440
+ function* segmentGraphemes(text) {
441
+ if (GRAPHEME_SEGMENTER) {
442
+ for (const segment of GRAPHEME_SEGMENTER.segment(text)) yield segment.segment;
443
+ return;
444
+ }
445
+ yield* text;
446
+ }
447
+ function buildText(details, theme, expanded) {
448
+ const severityColor = pickSeverityColor(details.diagnostics);
449
+ const label = theme.fg(severityColor, theme.bold("[DIAGNOSTIC]"));
450
+ const sourceLabel = describeSource(details.source);
451
+ const relPath = toRelativeDisplayPath(details.filePath, details.workspaceFolder, details.cwd);
452
+ const location = theme.fg("dim", `${relPath}:${formatRange(details.triggerRange)}`);
453
+ const count = details.diagnostics.length;
454
+ const noun = count === 1 ? "diagnostic" : "diagnostics";
455
+ const header = `${label} Fix ${count} ${noun} from ${sourceLabel} \u2014 ${location}`;
456
+ if (!expanded) {
457
+ return `${header}
458
+ ${theme.fg("dim", "ctrl+o to expand")}`;
459
+ }
460
+ const lines = [header];
461
+ for (const [index, diagnostic] of details.diagnostics.entries()) {
462
+ lines.push("");
463
+ lines.push(formatDiagnostic(diagnostic, index, details, theme));
464
+ }
465
+ return lines.join("\n");
466
+ }
467
+ function formatDiagnostic(diagnostic, index, details, theme) {
468
+ const color = diagnostic.severity === "error" ? "error" : "warning";
469
+ const headerText = `${diagnostic.severity.toUpperCase()} #${index + 1}`;
470
+ const lines = [`${theme.fg(color, headerText)} ${theme.fg("dim", formatRange(diagnostic.range))}`];
471
+ if (diagnostic.code !== void 0) {
472
+ lines.push(theme.fg("dim", ` code: ${formatDiagnosticCode(diagnostic.code)}`));
473
+ }
474
+ if (diagnostic.source) {
475
+ lines.push(theme.fg("dim", ` source: ${diagnostic.source}`));
476
+ }
477
+ lines.push(` ${diagnostic.message}`);
478
+ if (diagnostic.contextLines.length > 0) {
479
+ for (const contextLine of diagnostic.contextLines) {
480
+ const marker = contextLine.isPrimary ? theme.fg(color, ">") : " ";
481
+ const lineNumber = theme.fg("dim", `${contextLine.line + 1}:`.padStart(4, " "));
482
+ lines.push(` ${marker} ${lineNumber} ${contextLine.text}`);
483
+ }
484
+ }
485
+ if (diagnostic.relatedInformation && diagnostic.relatedInformation.length > 0) {
486
+ lines.push(theme.fg("dim", " related:"));
487
+ for (const related of diagnostic.relatedInformation) {
488
+ const relatedPath = toRelativeDisplayPath(related.filePath, details.workspaceFolder, details.cwd);
489
+ lines.push(theme.fg("dim", ` ${relatedPath} ${formatRange(related.range)}: ${related.message}`));
490
+ }
491
+ }
492
+ return lines.join("\n");
493
+ }
494
+ function pickSeverityColor(diagnostics) {
495
+ return diagnostics.some((diagnostic) => diagnostic.severity === "error") ? "error" : "warning";
496
+ }
497
+ function describeSource(source) {
498
+ if (source === "vscode") return "VS Code";
499
+ return source;
500
+ }
501
+
502
+ // src/pi/runtime-loader.ts
503
+ var defaultImporter = () => import("./chunks/runtime-services-TUOTPMCH.js");
504
+ var importer = defaultImporter;
505
+ var cachedPromise;
506
+ function preloadRuntimeServices() {
507
+ return loadRuntimeServices();
508
+ }
509
+ function loadRuntimeServices() {
510
+ if (!cachedPromise) {
511
+ cachedPromise = importer().then(
512
+ (module) => module,
513
+ (error) => {
514
+ cachedPromise = void 0;
515
+ throw error;
516
+ }
517
+ );
518
+ }
519
+ return cachedPromise;
520
+ }
521
+
522
+ // src/pi/state.ts
523
+ function createRuntime() {
524
+ return {
525
+ enabled: true,
526
+ candidates: [],
527
+ connectionStatus: "idle",
528
+ attachState: "idle",
529
+ reconnectAttempts: 0,
530
+ installingIdeIds: /* @__PURE__ */ new Set(),
531
+ sessionGeneration: 0,
532
+ sessionStarting: false,
533
+ pendingExtensionErrors: []
534
+ };
535
+ }
536
+
537
+ // src/pi/index.ts
538
+ function index_default(pi) {
539
+ registerPiIdeExtension(pi);
540
+ }
541
+ function registerPiIdeExtension(pi, options = {}) {
542
+ const runtime = createRuntime();
543
+ const loadRuntimeServices2 = options.runtimeLoader?.loadRuntimeServices ?? loadRuntimeServices;
544
+ const preloadRuntimeServices2 = options.runtimeLoader?.preloadRuntimeServices ?? preloadRuntimeServices;
545
+ installPiErrorReporter(runtime);
546
+ registerContextHandlers(pi, runtime);
547
+ registerDiagnosticRenderer(pi);
548
+ registerIdeCommand(pi, runtime, {
549
+ refreshCandidates: (ctx) => withRuntimeServices(loadRuntimeServices2, runtime, ctx, (services) => services.refreshCandidates(runtime, ctx)),
550
+ connectAuto: (ctx) => withRuntimeServices(loadRuntimeServices2, runtime, ctx, (services) => services.connectAuto(runtime, ctx, pi)),
551
+ connectCandidate: (candidate, ctx) => withRuntimeServices(
552
+ loadRuntimeServices2,
553
+ runtime,
554
+ ctx,
555
+ (services) => services.connectCandidate(runtime, candidate, ctx, {}, pi)
556
+ ),
557
+ disconnect: (ctx, disabled) => withRuntimeServices(loadRuntimeServices2, runtime, ctx, (services) => services.disconnect(runtime, ctx, disabled)),
558
+ installExtension: (ctx) => withRuntimeServices(loadRuntimeServices2, runtime, ctx, (services) => services.installExtension(runtime, ctx))
559
+ });
560
+ void preloadRuntimeServices2().catch((error) => {
561
+ logExtensionError("Pi runtime preload", error);
562
+ });
563
+ pi.on(
564
+ "session_start",
565
+ (_event, ctx) => runPiBoundaryAsync(
566
+ "Pi session start",
567
+ runtime,
568
+ async () => {
569
+ runtime.sessionGeneration += 1;
570
+ const generation = runtime.sessionGeneration;
571
+ bindPiUiContext(runtime, ctx);
572
+ runtime.cwd = ctx.cwd;
573
+ runtime.sessionStarting = true;
574
+ const startupTask = (async () => {
575
+ const services = await loadRuntimeServices2();
576
+ if (runtime.sessionGeneration !== generation) return;
577
+ await services.startSession(pi, runtime, ctx);
578
+ })();
579
+ runtime.startupTask = startupTask;
580
+ try {
581
+ await startupTask;
582
+ } finally {
583
+ if (runtime.startupTask === startupTask) {
584
+ runtime.startupTask = void 0;
585
+ }
586
+ if (runtime.sessionGeneration === generation) {
587
+ runtime.sessionStarting = false;
588
+ }
589
+ }
590
+ },
591
+ ctx
592
+ )
593
+ );
594
+ pi.on(
595
+ "session_shutdown",
596
+ (_event, ctx) => runPiBoundaryAsync(
597
+ "Pi session shutdown",
598
+ runtime,
599
+ async () => {
600
+ runtime.sessionGeneration += 1;
601
+ runtime.sessionStarting = false;
602
+ bindPiUiContext(runtime, ctx);
603
+ const pendingStartup = runtime.startupTask;
604
+ if (pendingStartup) {
605
+ await pendingStartup.catch(() => void 0);
606
+ }
607
+ const shouldLoadRuntime = !!runtime.connection || !!runtime.reconnectFiber || !!runtime.zedPollFiber || !!pendingStartup;
608
+ if (shouldLoadRuntime) {
609
+ try {
610
+ const services = await loadRuntimeServices2();
611
+ await services.shutdownSession(runtime, ctx);
612
+ return;
613
+ } catch (error) {
614
+ logExtensionError("Pi session shutdown runtime load", error);
615
+ }
616
+ }
617
+ const connection = runtime.connection;
618
+ runtime.connection = void 0;
619
+ connection?.disconnect();
620
+ clearIdeUi(runtime, ctx);
621
+ runtime.ctx = void 0;
622
+ },
623
+ ctx
624
+ )
625
+ );
626
+ return runtime;
627
+ }
628
+ async function withRuntimeServices(loadRuntimeServices2, runtime, ctx, action) {
629
+ const services = await loadRuntimeServices2();
630
+ bindPiUiContext(runtime, ctx);
631
+ return action(services);
632
+ }
633
+ export {
634
+ index_default as default,
635
+ registerPiIdeExtension
636
+ };