@qodalis/vue-cli 2.0.0-beta.3 → 2.0.0-beta.5

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/dist/index.mjs ADDED
@@ -0,0 +1,1116 @@
1
+ // src/Cli.ts
2
+ import {
3
+ defineComponent as defineComponent2,
4
+ ref,
5
+ onMounted,
6
+ onBeforeUnmount,
7
+ h,
8
+ inject
9
+ } from "vue";
10
+ import { CliEngine } from "@qodalis/cli";
11
+
12
+ // src/cliInjection.ts
13
+ var CliInjectionKey = /* @__PURE__ */ Symbol("qodalis-cli");
14
+
15
+ // src/CliConfigProvider.ts
16
+ import { defineComponent, provide } from "vue";
17
+ var CliConfigKey = /* @__PURE__ */ Symbol("qodalis-cli-config");
18
+ var CliConfigProvider = defineComponent({
19
+ name: "CliConfigProvider",
20
+ props: {
21
+ modules: {
22
+ type: Array,
23
+ default: void 0
24
+ },
25
+ processors: {
26
+ type: Array,
27
+ default: void 0
28
+ },
29
+ options: {
30
+ type: Object,
31
+ default: void 0
32
+ },
33
+ services: {
34
+ type: Object,
35
+ default: void 0
36
+ }
37
+ },
38
+ setup(props, { slots }) {
39
+ provide(CliConfigKey, {
40
+ modules: props.modules,
41
+ processors: props.processors,
42
+ options: props.options,
43
+ services: props.services
44
+ });
45
+ return () => slots.default?.();
46
+ }
47
+ });
48
+
49
+ // src/Cli.ts
50
+ var Cli = defineComponent2({
51
+ name: "Cli",
52
+ props: {
53
+ modules: {
54
+ type: Array,
55
+ default: void 0
56
+ },
57
+ processors: {
58
+ type: Array,
59
+ default: void 0
60
+ },
61
+ options: {
62
+ type: Object,
63
+ default: void 0
64
+ },
65
+ services: {
66
+ type: Object,
67
+ default: void 0
68
+ },
69
+ snapshot: {
70
+ type: Object,
71
+ default: void 0
72
+ },
73
+ style: {
74
+ type: Object,
75
+ default: void 0
76
+ },
77
+ class: {
78
+ type: String,
79
+ default: void 0
80
+ }
81
+ },
82
+ emits: ["ready"],
83
+ setup(props, { emit }) {
84
+ const containerRef = ref(null);
85
+ const ctx = inject(CliInjectionKey, null);
86
+ const config = inject(CliConfigKey, null);
87
+ let engine = null;
88
+ if (ctx) {
89
+ return () => null;
90
+ }
91
+ const modules = props.modules ?? config?.modules;
92
+ const processors = props.processors ?? config?.processors;
93
+ const options = props.options ?? config?.options;
94
+ const services = props.services ?? config?.services;
95
+ onMounted(async () => {
96
+ if (!containerRef.value) return;
97
+ const engineOptions = props.snapshot ? { ...options, snapshot: props.snapshot } : options;
98
+ engine = new CliEngine(containerRef.value, engineOptions);
99
+ engine.registerService("cli-framework", "Vue");
100
+ if (services) {
101
+ for (const [token, value] of Object.entries(services)) {
102
+ engine.registerService(token, value);
103
+ }
104
+ }
105
+ if (modules) {
106
+ engine.registerModules(modules);
107
+ }
108
+ if (processors) {
109
+ engine.registerProcessors(processors);
110
+ }
111
+ await engine.start();
112
+ emit("ready", engine);
113
+ });
114
+ onBeforeUnmount(() => {
115
+ engine?.destroy();
116
+ engine = null;
117
+ });
118
+ return () => h("div", {
119
+ ref: containerRef,
120
+ style: { height: "100%", ...props.style },
121
+ class: props.class
122
+ });
123
+ }
124
+ });
125
+
126
+ // src/CliPanel.ts
127
+ import {
128
+ defineComponent as defineComponent3,
129
+ ref as ref2,
130
+ computed,
131
+ inject as inject2,
132
+ h as h2,
133
+ onMounted as onMounted2,
134
+ onBeforeUnmount as onBeforeUnmount2
135
+ } from "vue";
136
+ import { derivePanelThemeStyles, loadPanelPosition, savePanelPosition } from "@qodalis/cli-core";
137
+ var MIN_PANE_WIDTH_PERCENT = 10;
138
+ function normalizePanes(panes) {
139
+ const total = panes.reduce((s, p) => s + p.widthPercent, 0);
140
+ if (total === 0) return;
141
+ const scale = 100 / total;
142
+ panes.forEach((p) => {
143
+ p.widthPercent *= scale;
144
+ });
145
+ }
146
+ var svgAttrs = {
147
+ width: "20",
148
+ height: "20",
149
+ viewBox: "0 0 24 24",
150
+ fill: "none",
151
+ stroke: "currentColor",
152
+ "stroke-width": "1.8",
153
+ "stroke-linecap": "round",
154
+ "stroke-linejoin": "round"
155
+ };
156
+ var terminalIcon = () => h2("svg", { ...svgAttrs, width: "22", height: "22", "stroke-width": "2" }, [
157
+ h2("polyline", { points: "4 17 10 11 4 5" }),
158
+ h2("line", { x1: "12", y1: "19", x2: "20", y2: "19" })
159
+ ]);
160
+ var maximizeIcon = () => h2("svg", svgAttrs, [
161
+ h2("polyline", { points: "15 3 21 3 21 9" }),
162
+ h2("polyline", { points: "9 21 3 21 3 15" }),
163
+ h2("line", { x1: "21", y1: "3", x2: "14", y2: "10" }),
164
+ h2("line", { x1: "3", y1: "21", x2: "10", y2: "14" })
165
+ ]);
166
+ var restoreIcon = () => h2("svg", svgAttrs, [
167
+ h2("polyline", { points: "4 14 10 14 10 20" }),
168
+ h2("polyline", { points: "20 10 14 10 14 4" }),
169
+ h2("line", { x1: "14", y1: "10", x2: "21", y2: "3" }),
170
+ h2("line", { x1: "3", y1: "21", x2: "10", y2: "14" })
171
+ ]);
172
+ var closeIcon = () => h2("svg", svgAttrs, [
173
+ h2("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
174
+ h2("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
175
+ ]);
176
+ var hideIcon = () => h2("svg", svgAttrs, [
177
+ h2("line", { x1: "5", y1: "18", x2: "19", y2: "18" }),
178
+ h2("polyline", { points: "9 14 12 17 15 14" })
179
+ ]);
180
+ function collapseChevron(position, isCollapsed) {
181
+ let points;
182
+ switch (position) {
183
+ case "top":
184
+ points = isCollapsed ? "6 9 12 15 18 9" : "18 15 12 9 6 15";
185
+ break;
186
+ case "left":
187
+ points = isCollapsed ? "9 18 15 12 9 6" : "15 6 9 12 15 18";
188
+ break;
189
+ case "right":
190
+ points = isCollapsed ? "15 6 9 12 15 18" : "9 18 15 12 9 6";
191
+ break;
192
+ default:
193
+ points = isCollapsed ? "18 15 12 9 6 15" : "6 9 12 15 18 9";
194
+ break;
195
+ }
196
+ return h2("svg", svgAttrs, [h2("polyline", { points })]);
197
+ }
198
+ function hideTabChevron(position) {
199
+ let points;
200
+ switch (position) {
201
+ case "top":
202
+ points = "6 9 12 15 18 9";
203
+ break;
204
+ case "left":
205
+ points = "9 18 15 12 9 6";
206
+ break;
207
+ case "right":
208
+ points = "15 6 9 12 15 18";
209
+ break;
210
+ default:
211
+ points = "18 15 12 9 6 15";
212
+ break;
213
+ }
214
+ return h2("svg", { class: "cli-panel-hide-tab-arrow", ...svgAttrs, width: "14", height: "14", "stroke-width": "2.5" }, [
215
+ h2("polyline", { points })
216
+ ]);
217
+ }
218
+ function positionIcon(pos, size = 20) {
219
+ let fillRect;
220
+ switch (pos) {
221
+ case "top":
222
+ fillRect = h2("rect", { x: "4", y: "4", width: "16", height: "5", rx: "1", fill: "currentColor", stroke: "none", opacity: "0.5" });
223
+ break;
224
+ case "left":
225
+ fillRect = h2("rect", { x: "4", y: "4", width: "5", height: "16", rx: "1", fill: "currentColor", stroke: "none", opacity: "0.5" });
226
+ break;
227
+ case "right":
228
+ fillRect = h2("rect", { x: "15", y: "4", width: "5", height: "16", rx: "1", fill: "currentColor", stroke: "none", opacity: "0.5" });
229
+ break;
230
+ default:
231
+ fillRect = h2("rect", { x: "4", y: "15", width: "16", height: "5", rx: "1", fill: "currentColor", stroke: "none", opacity: "0.5" });
232
+ break;
233
+ }
234
+ return h2("svg", { ...svgAttrs, width: String(size), height: String(size) }, [
235
+ h2("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2" }),
236
+ fillRect
237
+ ]);
238
+ }
239
+ var CliPanel = defineComponent3({
240
+ name: "CliPanel",
241
+ props: {
242
+ options: {
243
+ type: Object,
244
+ default: void 0
245
+ },
246
+ modules: { type: Array, default: void 0 },
247
+ processors: {
248
+ type: Array,
249
+ default: void 0
250
+ },
251
+ services: {
252
+ type: Object,
253
+ default: void 0
254
+ },
255
+ onClose: {
256
+ type: Function,
257
+ default: void 0
258
+ },
259
+ style: {
260
+ type: Object,
261
+ default: void 0
262
+ },
263
+ class: { type: String, default: void 0 }
264
+ },
265
+ setup(props) {
266
+ const config = inject2(CliConfigKey, null);
267
+ const mergedOptions = computed(() => props.options ?? config?.options);
268
+ const mergedModules = computed(() => props.modules ?? config?.modules);
269
+ const mergedProcessors = computed(() => props.processors ?? config?.processors);
270
+ const mergedServices = computed(() => props.services ?? config?.services);
271
+ const visible = ref2(true);
272
+ const collapsed = ref2(mergedOptions.value?.isCollapsed ?? true);
273
+ const maximized = ref2(false);
274
+ const panelHeight = ref2(600);
275
+ const panelWidth = ref2(400);
276
+ const prevHeight = ref2(600);
277
+ const prevWidth = ref2(400);
278
+ const initialized = ref2(false);
279
+ const hidden = ref2(props.options?.isHidden ?? false);
280
+ let preHideCollapsed = true;
281
+ const position = ref2(loadPanelPosition() ?? mergedOptions.value?.position ?? "bottom");
282
+ const closable = computed(() => mergedOptions.value?.closable ?? true);
283
+ const resizable = computed(() => mergedOptions.value?.resizable ?? true);
284
+ const isHorizontal = computed(() => position.value === "left" || position.value === "right");
285
+ const hideable = computed(() => mergedOptions.value?.hideable ?? true);
286
+ const hideAlignment = computed(() => mergedOptions.value?.hideAlignment ?? "center");
287
+ const syncTheme = computed(() => mergedOptions.value?.syncTheme ?? false);
288
+ const themeStyles = ref2({});
289
+ const tabs = ref2([]);
290
+ const activeTabId = ref2(0);
291
+ const activePaneId = ref2(0);
292
+ let nextTabId = 1;
293
+ let nextPaneId = 1;
294
+ const contextMenu = ref2({
295
+ visible: false,
296
+ x: 0,
297
+ y: 0,
298
+ tabId: 0
299
+ });
300
+ const engineMap = /* @__PURE__ */ new Map();
301
+ const paneResizing = ref2(false);
302
+ let paneResizeState = {
303
+ tabId: 0,
304
+ dividerIndex: 0,
305
+ startX: 0,
306
+ startWidths: [],
307
+ containerWidth: 0
308
+ };
309
+ const panelResizing = ref2(false);
310
+ let panelResizeState = { startY: 0, startHeight: 0, startX: 0, startWidth: 0 };
311
+ function addTab() {
312
+ const paneId = nextPaneId++;
313
+ const tabId = nextTabId++;
314
+ const pane = { id: paneId, widthPercent: 100 };
315
+ const tab = {
316
+ id: tabId,
317
+ title: `Terminal ${tabId}`,
318
+ isEditing: false,
319
+ panes: [pane]
320
+ };
321
+ tabs.value.push(tab);
322
+ activeTabId.value = tabId;
323
+ activePaneId.value = paneId;
324
+ }
325
+ let themeObserver;
326
+ function syncThemeFromEngine() {
327
+ const engine = engineMap.values().next().value;
328
+ if (!engine) return;
329
+ const theme = engine.getTerminal().options.theme;
330
+ if (theme) themeStyles.value = derivePanelThemeStyles(theme);
331
+ }
332
+ function setupThemeSync() {
333
+ if (!syncTheme.value) return;
334
+ setTimeout(() => {
335
+ syncThemeFromEngine();
336
+ const container = document.querySelector(".cli-panel-wrapper .terminal-container");
337
+ if (!container) return;
338
+ themeObserver?.disconnect();
339
+ themeObserver = new MutationObserver(syncThemeFromEngine);
340
+ themeObserver.observe(container, { attributes: true, attributeFilter: ["style"] });
341
+ }, 200);
342
+ }
343
+ onMounted2(() => {
344
+ document.addEventListener("click", closePositionDropdown);
345
+ });
346
+ onBeforeUnmount2(() => {
347
+ themeObserver?.disconnect();
348
+ document.removeEventListener("click", closePositionDropdown);
349
+ });
350
+ function toggle() {
351
+ collapsed.value = !collapsed.value;
352
+ if (!collapsed.value && !initialized.value) {
353
+ initialized.value = true;
354
+ addTab();
355
+ setupThemeSync();
356
+ }
357
+ }
358
+ function closeTab(id) {
359
+ const idx = tabs.value.findIndex((t) => t.id === id);
360
+ if (idx === -1) return;
361
+ tabs.value.splice(idx, 1);
362
+ if (tabs.value.length === 0) {
363
+ initialized.value = false;
364
+ collapsed.value = true;
365
+ return;
366
+ }
367
+ if (activeTabId.value === id) {
368
+ const newIdx = Math.min(idx, tabs.value.length - 1);
369
+ selectTab(tabs.value[newIdx].id);
370
+ }
371
+ }
372
+ function selectTab(id) {
373
+ activeTabId.value = id;
374
+ const tab = tabs.value.find((t) => t.id === id);
375
+ if (tab && tab.panes.length > 0) {
376
+ activePaneId.value = tab.panes[0].id;
377
+ }
378
+ }
379
+ function splitRight(tabId) {
380
+ const tab = tabs.value.find(
381
+ (t) => t.id === (tabId ?? activeTabId.value)
382
+ );
383
+ if (!tab) return;
384
+ const idx = tab.panes.findIndex((p) => p.id === activePaneId.value);
385
+ const insertIdx = idx === -1 ? tab.panes.length : idx + 1;
386
+ const newPaneId = nextPaneId++;
387
+ tab.panes.splice(insertIdx, 0, { id: newPaneId, widthPercent: 0 });
388
+ const evenWidth = 100 / tab.panes.length;
389
+ tab.panes.forEach((p) => {
390
+ p.widthPercent = evenWidth;
391
+ });
392
+ normalizePanes(tab.panes);
393
+ activePaneId.value = newPaneId;
394
+ }
395
+ function closePane(tabId, paneId) {
396
+ const tab = tabs.value.find((t) => t.id === tabId);
397
+ if (!tab) return;
398
+ if (tab.panes.length <= 1) {
399
+ closeTab(tabId);
400
+ return;
401
+ }
402
+ const idx = tab.panes.findIndex((p) => p.id === paneId);
403
+ if (idx === -1) return;
404
+ tab.panes.splice(idx, 1);
405
+ const total = tab.panes.reduce((s, p) => s + p.widthPercent, 0);
406
+ if (total > 0)
407
+ tab.panes.forEach((p) => {
408
+ p.widthPercent = p.widthPercent / total * 100;
409
+ });
410
+ normalizePanes(tab.panes);
411
+ if (activePaneId.value === paneId) {
412
+ activePaneId.value = tab.panes[Math.min(idx, tab.panes.length - 1)].id;
413
+ }
414
+ }
415
+ function startRename(tabId) {
416
+ tabs.value.forEach((t) => {
417
+ t.isEditing = t.id === tabId;
418
+ });
419
+ }
420
+ function commitRename(tabId, value) {
421
+ const trimmed = value.trim();
422
+ const tab = tabs.value.find((t) => t.id === tabId);
423
+ if (tab) {
424
+ if (trimmed) tab.title = trimmed;
425
+ tab.isEditing = false;
426
+ }
427
+ }
428
+ function closeContextMenu() {
429
+ contextMenu.value = { ...contextMenu.value, visible: false };
430
+ }
431
+ function onDocClick() {
432
+ if (contextMenu.value.visible) closeContextMenu();
433
+ }
434
+ onMounted2(() => document.addEventListener("click", onDocClick));
435
+ onBeforeUnmount2(
436
+ () => document.removeEventListener("click", onDocClick)
437
+ );
438
+ function onPanelResizeStart(e) {
439
+ if (!resizable.value) return;
440
+ e.preventDefault();
441
+ if (collapsed.value) toggle();
442
+ panelResizing.value = true;
443
+ panelResizeState = {
444
+ startY: e.clientY,
445
+ startHeight: panelHeight.value,
446
+ startX: e.clientX,
447
+ startWidth: panelWidth.value
448
+ };
449
+ }
450
+ function onPanelResizeMove(e) {
451
+ if (!panelResizing.value) return;
452
+ if (isHorizontal.value) {
453
+ const deltaX = position.value === "left" ? e.clientX - panelResizeState.startX : panelResizeState.startX - e.clientX;
454
+ let next = Math.max(100, panelResizeState.startWidth + deltaX);
455
+ if (next > window.innerWidth) next = window.innerWidth;
456
+ panelWidth.value = next;
457
+ } else {
458
+ const deltaY = position.value === "top" ? e.clientY - panelResizeState.startY : panelResizeState.startY - e.clientY;
459
+ let next = Math.max(100, panelResizeState.startHeight + deltaY);
460
+ if (next > window.innerHeight) next = window.innerHeight;
461
+ panelHeight.value = next;
462
+ }
463
+ }
464
+ function onPanelResizeEnd() {
465
+ panelResizing.value = false;
466
+ }
467
+ onMounted2(() => {
468
+ document.addEventListener("mousemove", onPanelResizeMove);
469
+ document.addEventListener("mouseup", onPanelResizeEnd);
470
+ });
471
+ onBeforeUnmount2(() => {
472
+ document.removeEventListener("mousemove", onPanelResizeMove);
473
+ document.removeEventListener("mouseup", onPanelResizeEnd);
474
+ });
475
+ function onPaneResizeStart(e, tabId, dividerIndex) {
476
+ e.preventDefault();
477
+ const tab = tabs.value.find((t) => t.id === tabId);
478
+ if (!tab) return;
479
+ paneResizing.value = true;
480
+ const container = e.target.closest(
481
+ ".cli-panel-panes-container"
482
+ );
483
+ paneResizeState = {
484
+ tabId,
485
+ dividerIndex,
486
+ startX: e.clientX,
487
+ startWidths: tab.panes.map((p) => p.widthPercent),
488
+ containerWidth: container ? container.clientWidth : 1
489
+ };
490
+ document.body.classList.add("cli-pane-resizing");
491
+ }
492
+ function onPaneResizeMove(e) {
493
+ if (!paneResizing.value) return;
494
+ const s = paneResizeState;
495
+ const deltaPct = (e.clientX - s.startX) / s.containerWidth * 100;
496
+ const i = s.dividerIndex;
497
+ let leftW = s.startWidths[i] + deltaPct;
498
+ let rightW = s.startWidths[i + 1] - deltaPct;
499
+ if (leftW < MIN_PANE_WIDTH_PERCENT) {
500
+ leftW = MIN_PANE_WIDTH_PERCENT;
501
+ rightW = s.startWidths[i] + s.startWidths[i + 1] - MIN_PANE_WIDTH_PERCENT;
502
+ }
503
+ if (rightW < MIN_PANE_WIDTH_PERCENT) {
504
+ rightW = MIN_PANE_WIDTH_PERCENT;
505
+ leftW = s.startWidths[i] + s.startWidths[i + 1] - MIN_PANE_WIDTH_PERCENT;
506
+ }
507
+ const tab = tabs.value.find((t) => t.id === s.tabId);
508
+ if (tab) {
509
+ tab.panes[i].widthPercent = leftW;
510
+ tab.panes[i + 1].widthPercent = rightW;
511
+ }
512
+ }
513
+ function onPaneResizeEnd() {
514
+ if (!paneResizing.value) return;
515
+ paneResizing.value = false;
516
+ document.body.classList.remove("cli-pane-resizing");
517
+ }
518
+ onMounted2(() => {
519
+ document.addEventListener("mousemove", onPaneResizeMove);
520
+ document.addEventListener("mouseup", onPaneResizeEnd);
521
+ });
522
+ onBeforeUnmount2(() => {
523
+ document.removeEventListener("mousemove", onPaneResizeMove);
524
+ document.removeEventListener("mouseup", onPaneResizeEnd);
525
+ });
526
+ function toggleMaximize() {
527
+ if (!maximized.value) {
528
+ if (isHorizontal.value) {
529
+ prevWidth.value = panelWidth.value;
530
+ panelWidth.value = window.innerWidth;
531
+ } else {
532
+ prevHeight.value = panelHeight.value;
533
+ panelHeight.value = window.innerHeight;
534
+ }
535
+ } else {
536
+ if (isHorizontal.value) {
537
+ panelWidth.value = prevWidth.value;
538
+ } else {
539
+ panelHeight.value = prevHeight.value;
540
+ }
541
+ }
542
+ maximized.value = !maximized.value;
543
+ }
544
+ function handleClose() {
545
+ visible.value = false;
546
+ props.onClose?.();
547
+ }
548
+ function handleHide() {
549
+ preHideCollapsed = collapsed.value;
550
+ hidden.value = true;
551
+ }
552
+ function handleUnhide() {
553
+ hidden.value = false;
554
+ collapsed.value = preHideCollapsed;
555
+ }
556
+ const positionDropdownOpen = ref2(false);
557
+ function closePositionDropdown() {
558
+ positionDropdownOpen.value = false;
559
+ }
560
+ function togglePositionDropdown(e) {
561
+ e.stopPropagation();
562
+ positionDropdownOpen.value = !positionDropdownOpen.value;
563
+ }
564
+ function selectPosition(pos) {
565
+ positionDropdownOpen.value = false;
566
+ position.value = pos;
567
+ savePanelPosition(pos);
568
+ }
569
+ return () => {
570
+ if (!visible.value) return null;
571
+ const wrapperClass = [
572
+ "cli-panel-wrapper",
573
+ collapsed.value && "collapsed",
574
+ maximized.value && "maximized",
575
+ panelResizing.value && "resizing",
576
+ props.class
577
+ ].filter(Boolean).join(" ");
578
+ const wrapperStyle = {
579
+ ...isHorizontal.value ? { width: `${panelWidth.value}px` } : { height: `${panelHeight.value}px` },
580
+ ...hidden.value ? { display: "none" } : {},
581
+ ...themeStyles.value,
582
+ ...props.style
583
+ };
584
+ const headerEl = h2("div", { class: "cli-panel-header" }, [
585
+ h2(
586
+ "div",
587
+ {
588
+ class: "cli-panel-resize-bar",
589
+ onMousedown: onPanelResizeStart
590
+ },
591
+ [h2("div", { class: "cli-panel-resize-grip" })]
592
+ ),
593
+ h2("div", { class: "cli-panel-header-content" }, [
594
+ h2("p", { class: "cli-panel-title" }, [
595
+ h2("span", { class: "cli-panel-title-icon" }, [
596
+ terminalIcon()
597
+ ]),
598
+ "CLI"
599
+ ]),
600
+ h2("div", { class: "cli-panel-action-buttons" }, [
601
+ h2("div", {
602
+ class: "cli-panel-btn-position-wrapper",
603
+ onClick: (e) => e.stopPropagation()
604
+ }, [
605
+ h2("button", {
606
+ class: "cli-panel-btn cli-panel-btn-position",
607
+ title: "Move panel",
608
+ onClick: togglePositionDropdown
609
+ }, [positionIcon(position.value)]),
610
+ positionDropdownOpen.value ? h2(
611
+ "div",
612
+ { class: "cli-panel-position-dropdown" },
613
+ ["bottom", "top", "left", "right"].map(
614
+ (pos) => h2("button", {
615
+ class: ["cli-panel-position-dropdown-item", position.value === pos ? "active" : ""].filter(Boolean).join(" "),
616
+ onClick: () => selectPosition(pos)
617
+ }, [
618
+ positionIcon(pos, 16),
619
+ pos.charAt(0).toUpperCase() + pos.slice(1)
620
+ ])
621
+ )
622
+ ) : null
623
+ ]),
624
+ hideable.value ? h2("button", {
625
+ class: "cli-panel-btn cli-panel-btn-hide",
626
+ title: "Hide",
627
+ onClick: handleHide
628
+ }, [hideIcon()]) : null,
629
+ h2(
630
+ "button",
631
+ {
632
+ class: "cli-panel-btn",
633
+ title: maximized.value ? "Restore" : "Maximize",
634
+ disabled: collapsed.value,
635
+ onClick: toggleMaximize
636
+ },
637
+ [maximized.value ? restoreIcon() : maximizeIcon()]
638
+ ),
639
+ h2(
640
+ "button",
641
+ {
642
+ class: "cli-panel-btn",
643
+ title: collapsed.value ? "Expand" : "Collapse",
644
+ onClick: toggle
645
+ },
646
+ [collapseChevron(position.value, collapsed.value)]
647
+ ),
648
+ closable.value ? h2(
649
+ "button",
650
+ {
651
+ class: "cli-panel-btn cli-panel-btn-close",
652
+ title: "Close",
653
+ onClick: handleClose
654
+ },
655
+ [closeIcon()]
656
+ ) : null
657
+ ])
658
+ ])
659
+ ]);
660
+ const contentEl = initialized.value ? h2("div", { class: "cli-panel-content", style: collapsed.value ? { display: "none" } : void 0 }, [
661
+ // Tab bar
662
+ h2("div", { class: "cli-panel-tabs" }, [
663
+ h2(
664
+ "ul",
665
+ { class: "cli-panel-tab-list" },
666
+ tabs.value.map(
667
+ (tab) => h2(
668
+ "li",
669
+ {
670
+ key: tab.id,
671
+ class: [
672
+ "cli-panel-tab",
673
+ tab.id === activeTabId.value && "active"
674
+ ].filter(Boolean).join(" "),
675
+ onClick: () => selectTab(tab.id),
676
+ onDblclick: () => startRename(tab.id),
677
+ onContextmenu: (e) => {
678
+ e.preventDefault();
679
+ e.stopPropagation();
680
+ contextMenu.value = {
681
+ visible: true,
682
+ x: e.clientX,
683
+ y: e.clientY,
684
+ tabId: tab.id
685
+ };
686
+ }
687
+ },
688
+ tab.isEditing ? [
689
+ h2("input", {
690
+ class: "cli-panel-tab-rename-input",
691
+ type: "text",
692
+ value: tab.title,
693
+ onKeydown: (e) => {
694
+ if (e.key === "Enter")
695
+ commitRename(
696
+ tab.id,
697
+ e.target.value
698
+ );
699
+ else if (e.key === "Escape") {
700
+ tab.isEditing = false;
701
+ }
702
+ },
703
+ onBlur: (e) => commitRename(
704
+ tab.id,
705
+ e.target.value
706
+ ),
707
+ onClick: (e) => e.stopPropagation(),
708
+ onDblclick: (e) => e.stopPropagation()
709
+ })
710
+ ] : [
711
+ h2(
712
+ "span",
713
+ {
714
+ class: "cli-panel-tab-title"
715
+ },
716
+ tab.title
717
+ ),
718
+ h2(
719
+ "button",
720
+ {
721
+ class: "cli-panel-tab-close-btn",
722
+ title: "Close tab",
723
+ onClick: (e) => {
724
+ e.stopPropagation();
725
+ closeTab(
726
+ tab.id
727
+ );
728
+ }
729
+ },
730
+ "\xD7"
731
+ )
732
+ ]
733
+ )
734
+ )
735
+ ),
736
+ h2(
737
+ "button",
738
+ {
739
+ class: "cli-panel-add-tab",
740
+ title: "New terminal",
741
+ onClick: addTab
742
+ },
743
+ "+"
744
+ )
745
+ ]),
746
+ // Terminal instances
747
+ h2(
748
+ "div",
749
+ { class: "cli-panel-instances" },
750
+ tabs.value.map(
751
+ (tab) => h2(
752
+ "div",
753
+ {
754
+ key: tab.id,
755
+ class: "cli-panel-instance",
756
+ style: {
757
+ display: tab.id === activeTabId.value ? void 0 : "none"
758
+ }
759
+ },
760
+ [
761
+ h2(
762
+ "div",
763
+ {
764
+ class: [
765
+ "cli-panel-panes-container",
766
+ paneResizing.value && "resizing"
767
+ ].filter(Boolean).join(" ")
768
+ },
769
+ tab.panes.flatMap((pane, i) => {
770
+ const nodes = [];
771
+ if (i > 0) {
772
+ nodes.push(
773
+ h2(
774
+ "div",
775
+ {
776
+ class: "cli-panel-pane-divider",
777
+ onMousedown: (e) => onPaneResizeStart(
778
+ e,
779
+ tab.id,
780
+ i - 1
781
+ )
782
+ },
783
+ [
784
+ h2("div", {
785
+ class: "cli-panel-pane-divider-grip"
786
+ })
787
+ ]
788
+ )
789
+ );
790
+ }
791
+ nodes.push(
792
+ h2(
793
+ "div",
794
+ {
795
+ class: [
796
+ "cli-panel-pane",
797
+ pane.id === activePaneId.value && tab.id === activeTabId.value && "active-pane"
798
+ ].filter(
799
+ Boolean
800
+ ).join(" "),
801
+ style: {
802
+ flex: `${pane.widthPercent} 1 0`
803
+ },
804
+ onClick: () => {
805
+ activePaneId.value = pane.id;
806
+ activeTabId.value = tab.id;
807
+ }
808
+ },
809
+ [
810
+ tab.panes.length > 1 ? h2(
811
+ "button",
812
+ {
813
+ class: "cli-panel-pane-close-btn",
814
+ title: "Close pane",
815
+ onClick: (e) => {
816
+ e.stopPropagation();
817
+ closePane(
818
+ tab.id,
819
+ pane.id
820
+ );
821
+ }
822
+ },
823
+ "\xD7"
824
+ ) : null,
825
+ h2(Cli, {
826
+ options: mergedOptions.value,
827
+ modules: mergedModules.value,
828
+ processors: mergedProcessors.value,
829
+ services: mergedServices.value,
830
+ snapshot: pane.snapshot,
831
+ style: {
832
+ height: "100%"
833
+ },
834
+ onReady: (engine) => {
835
+ engineMap.set(pane.id, engine);
836
+ }
837
+ })
838
+ ]
839
+ )
840
+ );
841
+ return nodes;
842
+ })
843
+ )
844
+ ]
845
+ )
846
+ )
847
+ )
848
+ ]) : null;
849
+ const contextMenuEl = contextMenu.value.visible ? h2(
850
+ "div",
851
+ {
852
+ class: "cli-panel-context-menu",
853
+ style: {
854
+ left: `${contextMenu.value.x}px`,
855
+ top: `${contextMenu.value.y}px`
856
+ },
857
+ onClick: (e) => e.stopPropagation()
858
+ },
859
+ [
860
+ h2(
861
+ "button",
862
+ {
863
+ class: "cli-panel-context-menu-item",
864
+ onClick: () => {
865
+ closeContextMenu();
866
+ startRename(contextMenu.value.tabId);
867
+ }
868
+ },
869
+ "Rename"
870
+ ),
871
+ h2(
872
+ "button",
873
+ {
874
+ class: "cli-panel-context-menu-item",
875
+ onClick: () => {
876
+ const tab = tabs.value.find(
877
+ (t) => t.id === contextMenu.value.tabId
878
+ );
879
+ closeContextMenu();
880
+ if (!tab) return;
881
+ const sourceEngine = engineMap.get(tab.panes[0]?.id);
882
+ const snapshot = sourceEngine?.snapshot();
883
+ const paneId = nextPaneId++;
884
+ const tabId = nextTabId++;
885
+ const idx = tabs.value.indexOf(tab);
886
+ tabs.value.splice(idx + 1, 0, {
887
+ id: tabId,
888
+ title: `${tab.title} (copy)`,
889
+ isEditing: false,
890
+ panes: [
891
+ { id: paneId, widthPercent: 100, snapshot }
892
+ ]
893
+ });
894
+ activeTabId.value = tabId;
895
+ activePaneId.value = paneId;
896
+ }
897
+ },
898
+ "Duplicate"
899
+ ),
900
+ h2(
901
+ "button",
902
+ {
903
+ class: "cli-panel-context-menu-item",
904
+ onClick: () => {
905
+ closeContextMenu();
906
+ splitRight(contextMenu.value.tabId);
907
+ }
908
+ },
909
+ "Split Right"
910
+ ),
911
+ h2("div", {
912
+ class: "cli-panel-context-menu-separator"
913
+ }),
914
+ h2(
915
+ "button",
916
+ {
917
+ class: "cli-panel-context-menu-item",
918
+ onClick: () => {
919
+ closeContextMenu();
920
+ closeTab(contextMenu.value.tabId);
921
+ }
922
+ },
923
+ "Close"
924
+ ),
925
+ h2(
926
+ "button",
927
+ {
928
+ class: "cli-panel-context-menu-item",
929
+ disabled: tabs.value.length <= 1,
930
+ onClick: () => {
931
+ const id = contextMenu.value.tabId;
932
+ closeContextMenu();
933
+ tabs.value = tabs.value.filter(
934
+ (t) => t.id === id
935
+ );
936
+ activeTabId.value = id;
937
+ }
938
+ },
939
+ "Close Others"
940
+ ),
941
+ h2(
942
+ "button",
943
+ {
944
+ class: "cli-panel-context-menu-item",
945
+ onClick: () => {
946
+ const id = contextMenu.value.tabId;
947
+ closeContextMenu();
948
+ const idx = tabs.value.findIndex(
949
+ (t) => t.id === id
950
+ );
951
+ if (idx !== -1)
952
+ tabs.value = tabs.value.slice(
953
+ 0,
954
+ idx + 1
955
+ );
956
+ }
957
+ },
958
+ "Close to the Right"
959
+ ),
960
+ h2("div", {
961
+ class: "cli-panel-context-menu-separator"
962
+ }),
963
+ h2(
964
+ "button",
965
+ {
966
+ class: "cli-panel-context-menu-item destructive",
967
+ onClick: () => {
968
+ closeContextMenu();
969
+ tabs.value = [];
970
+ initialized.value = false;
971
+ collapsed.value = true;
972
+ }
973
+ },
974
+ "Close All"
975
+ )
976
+ ]
977
+ ) : null;
978
+ const hideTabEl = hidden.value ? h2("button", {
979
+ class: "cli-panel-hide-tab",
980
+ "data-position": position.value,
981
+ "data-hide-align": hideAlignment.value,
982
+ style: themeStyles.value,
983
+ title: "Show CLI",
984
+ onClick: handleUnhide
985
+ }, [
986
+ h2("svg", { class: "cli-panel-hide-tab-icon", ...svgAttrs, width: "16", height: "16", "stroke-width": "2" }, [
987
+ h2("polyline", { points: "4 17 10 11 4 5" }),
988
+ h2("line", { x1: "12", y1: "19", x2: "20", y2: "19" })
989
+ ]),
990
+ h2("span", { class: "cli-panel-hide-tab-label" }, "CLI"),
991
+ hideTabChevron(position.value)
992
+ ]) : null;
993
+ return h2("div", {}, [
994
+ hideTabEl,
995
+ h2(
996
+ "div",
997
+ {
998
+ class: wrapperClass,
999
+ style: wrapperStyle,
1000
+ "data-position": position.value,
1001
+ "data-resizable": String(resizable.value),
1002
+ "data-closable": String(closable.value),
1003
+ "data-hideable": String(hideable.value)
1004
+ },
1005
+ [headerEl, contentEl]
1006
+ ),
1007
+ contextMenuEl
1008
+ ]);
1009
+ };
1010
+ }
1011
+ });
1012
+
1013
+ // src/CliProvider.ts
1014
+ import { defineComponent as defineComponent4, ref as ref4, h as h3, provide as provide2 } from "vue";
1015
+
1016
+ // src/useCliEngine.ts
1017
+ import { onMounted as onMounted3, onBeforeUnmount as onBeforeUnmount3, shallowRef } from "vue";
1018
+ import { CliEngine as CliEngine2 } from "@qodalis/cli";
1019
+ function useCliEngine(containerRef, config) {
1020
+ const engine = shallowRef(null);
1021
+ onMounted3(async () => {
1022
+ if (!containerRef.value) return;
1023
+ const e = new CliEngine2(containerRef.value, config?.options);
1024
+ e.registerService("cli-framework", "Vue");
1025
+ if (config?.services) {
1026
+ for (const [token, value] of Object.entries(config.services)) {
1027
+ e.registerService(token, value);
1028
+ }
1029
+ }
1030
+ if (config?.modules) {
1031
+ e.registerModules(config.modules);
1032
+ }
1033
+ if (config?.processors) {
1034
+ e.registerProcessors(config.processors);
1035
+ }
1036
+ await e.start();
1037
+ engine.value = e;
1038
+ });
1039
+ onBeforeUnmount3(() => {
1040
+ engine.value?.destroy();
1041
+ engine.value = null;
1042
+ });
1043
+ return engine;
1044
+ }
1045
+
1046
+ // src/CliProvider.ts
1047
+ var CliProvider = defineComponent4({
1048
+ name: "CliProvider",
1049
+ props: {
1050
+ modules: {
1051
+ type: Array,
1052
+ default: void 0
1053
+ },
1054
+ processors: {
1055
+ type: Array,
1056
+ default: void 0
1057
+ },
1058
+ options: {
1059
+ type: Object,
1060
+ default: void 0
1061
+ },
1062
+ services: {
1063
+ type: Object,
1064
+ default: void 0
1065
+ },
1066
+ style: {
1067
+ type: Object,
1068
+ default: void 0
1069
+ }
1070
+ },
1071
+ emits: ["ready"],
1072
+ setup(props, { slots, emit }) {
1073
+ const containerRef = ref4(null);
1074
+ const engine = useCliEngine(containerRef, {
1075
+ modules: props.modules,
1076
+ processors: props.processors,
1077
+ options: props.options,
1078
+ services: props.services
1079
+ });
1080
+ provide2(CliInjectionKey, { engine });
1081
+ return () => h3("div", { style: { height: "100%" } }, [
1082
+ h3("div", {
1083
+ ref: containerRef,
1084
+ style: { height: "100%", ...props.style }
1085
+ }),
1086
+ slots.default?.()
1087
+ ]);
1088
+ }
1089
+ });
1090
+
1091
+ // src/useCli.ts
1092
+ import { inject as inject3 } from "vue";
1093
+ function useCli() {
1094
+ const ctx = inject3(CliInjectionKey);
1095
+ if (!ctx) {
1096
+ throw new Error(
1097
+ "useCli() must be used inside a <CliProvider> component"
1098
+ );
1099
+ }
1100
+ return ctx;
1101
+ }
1102
+
1103
+ // src/index.ts
1104
+ import { CliEngine as CliEngine3 } from "@qodalis/cli";
1105
+ export {
1106
+ Cli,
1107
+ CliConfigKey,
1108
+ CliConfigProvider,
1109
+ CliEngine3 as CliEngine,
1110
+ CliInjectionKey,
1111
+ CliPanel,
1112
+ CliProvider,
1113
+ useCli,
1114
+ useCliEngine
1115
+ };
1116
+ //# sourceMappingURL=index.mjs.map