@ecmaos/kernel 0.10.2 → 0.10.4

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.
@@ -26,21 +26,21 @@ async function blank({ terminal }) {
26
26
  if (!ctx) return false;
27
27
  ctx.fillStyle = "black";
28
28
  ctx.fillRect(0, 0, canvas.width, canvas.height);
29
- canvas.addEventListener("click", () => exit$2(canvas, terminal));
30
- document.addEventListener("click", () => exit$2(canvas, terminal));
31
- document.addEventListener("mousemove", () => exit$2(canvas, terminal));
32
- document.addEventListener("keydown", () => exit$2(canvas, terminal));
29
+ canvas.addEventListener("click", () => exit$3(canvas, terminal));
30
+ document.addEventListener("click", () => exit$3(canvas, terminal));
31
+ document.addEventListener("mousemove", () => exit$3(canvas, terminal));
32
+ document.addEventListener("keydown", () => exit$3(canvas, terminal));
33
33
  }
34
34
  __name(blank, "blank");
35
- async function exit$2(canvas, terminal) {
35
+ async function exit$3(canvas, terminal) {
36
36
  canvas.remove();
37
37
  terminal.listen();
38
38
  }
39
- __name(exit$2, "exit$2");
39
+ __name(exit$3, "exit$3");
40
40
  const __vite_glob_0_0 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
41
41
  __proto__: null,
42
42
  default: blank,
43
- exit: exit$2
43
+ exit: exit$3
44
44
  }, Symbol.toStringTag, { value: "Module" }));
45
45
  async function matrix({ terminal }) {
46
46
  if (document.getElementById("screensaver")) return false;
@@ -74,20 +74,152 @@ async function matrix({ terminal }) {
74
74
  }, "animatrix");
75
75
  terminal.unlisten();
76
76
  const interval = setInterval(animatrix, 33);
77
+ document.addEventListener("click", () => exit$2(interval, canvas, terminal));
78
+ document.addEventListener("mousemove", () => exit$2(interval, canvas, terminal));
79
+ document.addEventListener("keydown", () => exit$2(interval, canvas, terminal));
80
+ }
81
+ __name(matrix, "matrix");
82
+ async function exit$2(interval, canvas, terminal) {
83
+ clearInterval(interval);
84
+ canvas.remove();
85
+ terminal.listen();
86
+ }
87
+ __name(exit$2, "exit$2");
88
+ const __vite_glob_0_1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
89
+ __proto__: null,
90
+ default: matrix,
91
+ exit: exit$2
92
+ }, Symbol.toStringTag, { value: "Module" }));
93
+ async function toasters({ terminal }) {
94
+ if (document.getElementById("screensaver")) return false;
95
+ const canvas = document.createElement("canvas");
96
+ canvas.id = "screensaver";
97
+ canvas.width = globalThis.innerWidth;
98
+ canvas.height = globalThis.innerHeight;
99
+ canvas.style.position = "absolute";
100
+ canvas.style.top = "0";
101
+ canvas.style.left = "0";
102
+ canvas.style.zIndex = Number.MAX_SAFE_INTEGER.toString();
103
+ document.body.appendChild(canvas);
104
+ const ctx = canvas.getContext("2d");
105
+ if (!ctx) return false;
106
+ ctx.fillStyle = "black";
107
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
108
+ const spritesheet = new Image();
109
+ spritesheet.src = "/toasters.png";
110
+ await new Promise((resolve2, reject) => {
111
+ spritesheet.onload = () => resolve2();
112
+ spritesheet.onerror = () => reject(new Error("Failed to load toasters spritesheet"));
113
+ });
114
+ if (spritesheet.width === 0 || spritesheet.height === 0) return false;
115
+ const toasterWidth = 65;
116
+ const toasterHeight = 58;
117
+ const toastWidth = 65;
118
+ const toastHeight = 39;
119
+ const toasterSpacing = spritesheet.width / 5;
120
+ const processSprite = /* @__PURE__ */ __name((sx, sy, width2, height) => {
121
+ const spriteCanvas = document.createElement("canvas");
122
+ spriteCanvas.width = width2;
123
+ spriteCanvas.height = height;
124
+ const spriteCtx = spriteCanvas.getContext("2d");
125
+ if (!spriteCtx) return spriteCanvas;
126
+ spriteCtx.drawImage(spritesheet, sx, sy, width2, height, 0, 0, width2, height);
127
+ const imageData = spriteCtx.getImageData(0, 0, width2, height);
128
+ const data = imageData.data;
129
+ for (let i2 = 0; i2 < data.length; i2 += 4) {
130
+ if (data[i2] === 17 && data[i2 + 1] === 17 && data[i2 + 2] === 17) {
131
+ data[i2 + 3] = 0;
132
+ }
133
+ }
134
+ spriteCtx.putImageData(imageData, 0, 0);
135
+ return spriteCanvas;
136
+ }, "processSprite");
137
+ const toasterSprites = [];
138
+ for (let i2 = 0; i2 < 5; i2++) {
139
+ toasterSprites.push(processSprite(i2 * toasterSpacing, 0, toasterWidth, toasterHeight));
140
+ }
141
+ const toastSprite = processSprite(0, toasterHeight, toastWidth, toastHeight);
142
+ const toasters2 = [];
143
+ const toasts = [];
144
+ const maxToasters = 5;
145
+ const maxToasts = 20;
146
+ const createToaster = /* @__PURE__ */ __name(() => {
147
+ const baseY = Math.random() * (canvas.height - toasterHeight * 2) + toasterHeight;
148
+ return {
149
+ x: canvas.width + toasterWidth,
150
+ y: baseY,
151
+ vx: -(2 + Math.random() * 2),
152
+ vy: Math.sin(Math.random() * Math.PI * 2) * 0.5,
153
+ frame: 0,
154
+ frameCounter: 0,
155
+ baseY
156
+ };
157
+ }, "createToaster");
158
+ for (let i2 = 0; i2 < maxToasters; i2++) {
159
+ const toaster = createToaster();
160
+ toaster.x = canvas.width + i2 * toasterWidth * 3;
161
+ toasters2.push(toaster);
162
+ }
163
+ const animate = /* @__PURE__ */ __name(() => {
164
+ ctx.fillStyle = "black";
165
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
166
+ for (let i2 = toasters2.length - 1; i2 >= 0; i2--) {
167
+ const toaster = toasters2[i2];
168
+ if (!toaster) continue;
169
+ toaster.frameCounter++;
170
+ if (toaster.frameCounter >= 5) {
171
+ toaster.frameCounter = 0;
172
+ toaster.frame = (toaster.frame + 1) % 5;
173
+ }
174
+ toaster.y = toaster.baseY + Math.sin(toaster.x * 0.01) * 20;
175
+ toaster.x += toaster.vx;
176
+ if (toaster.x < -toasterWidth) {
177
+ toasters2[i2] = createToaster();
178
+ toasters2[i2].x = canvas.width + toasterWidth;
179
+ }
180
+ const sprite = toasterSprites[toaster.frame];
181
+ if (sprite) ctx.drawImage(sprite, toaster.x, toaster.y);
182
+ if (Math.random() < 0.01 && toasts.length < maxToasts) {
183
+ toasts.push({
184
+ x: toaster.x + toasterWidth / 2,
185
+ y: toaster.y + toasterHeight,
186
+ vy: 1 + Math.random() * 2,
187
+ vx: (Math.random() - 0.5) * 0.5
188
+ });
189
+ }
190
+ }
191
+ for (let i2 = toasts.length - 1; i2 >= 0; i2--) {
192
+ const toast = toasts[i2];
193
+ if (!toast) continue;
194
+ toast.x += toast.vx;
195
+ toast.y += toast.vy;
196
+ if (toast.y > canvas.height) {
197
+ toasts.splice(i2, 1);
198
+ continue;
199
+ }
200
+ ctx.drawImage(
201
+ toastSprite,
202
+ toast.x - toastWidth / 2,
203
+ toast.y
204
+ );
205
+ }
206
+ }, "animate");
207
+ terminal.unlisten();
208
+ const interval = setInterval(animate, 33);
77
209
  document.addEventListener("click", () => exit$1(interval, canvas, terminal));
78
210
  document.addEventListener("mousemove", () => exit$1(interval, canvas, terminal));
79
211
  document.addEventListener("keydown", () => exit$1(interval, canvas, terminal));
80
212
  }
81
- __name(matrix, "matrix");
213
+ __name(toasters, "toasters");
82
214
  async function exit$1(interval, canvas, terminal) {
83
215
  clearInterval(interval);
84
216
  canvas.remove();
85
217
  terminal.listen();
86
218
  }
87
219
  __name(exit$1, "exit$1");
88
- const __vite_glob_0_1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
220
+ const __vite_glob_0_2 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
89
221
  __proto__: null,
90
- default: matrix,
222
+ default: toasters,
91
223
  exit: exit$1
92
224
  }, Symbol.toStringTag, { value: "Module" }));
93
225
  function getDefaultExportFromCjs$1(x2) {
@@ -24516,400 +24648,6 @@ const $pkg$1 = {
24516
24648
  version: version$2
24517
24649
  };
24518
24650
  globalThis.__zenfs__ = Object.assign(Object.create(fs$2), { _version: $pkg$1.version });
24519
- var __assign = /* @__PURE__ */ __name(function() {
24520
- __assign = Object.assign || /* @__PURE__ */ __name(function __assign2(t2) {
24521
- for (var s2, i2 = 1, n2 = arguments.length; i2 < n2; i2++) {
24522
- s2 = arguments[i2];
24523
- for (var p2 in s2) if (Object.prototype.hasOwnProperty.call(s2, p2)) t2[p2] = s2[p2];
24524
- }
24525
- return t2;
24526
- }, "__assign");
24527
- return __assign.apply(this, arguments);
24528
- }, "__assign");
24529
- var NotyfNotification = (
24530
- /** @class */
24531
- (function() {
24532
- function NotyfNotification2(options) {
24533
- this.options = options;
24534
- this.listeners = {};
24535
- }
24536
- __name(NotyfNotification2, "NotyfNotification");
24537
- NotyfNotification2.prototype.on = function(eventType, cb) {
24538
- var callbacks = this.listeners[eventType] || [];
24539
- this.listeners[eventType] = callbacks.concat([cb]);
24540
- };
24541
- NotyfNotification2.prototype.triggerEvent = function(eventType, event) {
24542
- var _this = this;
24543
- var callbacks = this.listeners[eventType] || [];
24544
- callbacks.forEach(function(cb) {
24545
- return cb({ target: _this, event });
24546
- });
24547
- };
24548
- return NotyfNotification2;
24549
- })()
24550
- );
24551
- var NotyfArrayEvent;
24552
- (function(NotyfArrayEvent2) {
24553
- NotyfArrayEvent2[NotyfArrayEvent2["Add"] = 0] = "Add";
24554
- NotyfArrayEvent2[NotyfArrayEvent2["Remove"] = 1] = "Remove";
24555
- })(NotyfArrayEvent || (NotyfArrayEvent = {}));
24556
- var NotyfArray = (
24557
- /** @class */
24558
- (function() {
24559
- function NotyfArray2() {
24560
- this.notifications = [];
24561
- }
24562
- __name(NotyfArray2, "NotyfArray");
24563
- NotyfArray2.prototype.push = function(elem) {
24564
- this.notifications.push(elem);
24565
- this.updateFn(elem, NotyfArrayEvent.Add, this.notifications);
24566
- };
24567
- NotyfArray2.prototype.splice = function(index2, num) {
24568
- var elem = this.notifications.splice(index2, num)[0];
24569
- this.updateFn(elem, NotyfArrayEvent.Remove, this.notifications);
24570
- return elem;
24571
- };
24572
- NotyfArray2.prototype.indexOf = function(elem) {
24573
- return this.notifications.indexOf(elem);
24574
- };
24575
- NotyfArray2.prototype.onUpdate = function(fn2) {
24576
- this.updateFn = fn2;
24577
- };
24578
- return NotyfArray2;
24579
- })()
24580
- );
24581
- var NotyfEvent;
24582
- (function(NotyfEvent2) {
24583
- NotyfEvent2["Dismiss"] = "dismiss";
24584
- NotyfEvent2["Click"] = "click";
24585
- })(NotyfEvent || (NotyfEvent = {}));
24586
- var DEFAULT_OPTIONS = {
24587
- types: [
24588
- {
24589
- type: "success",
24590
- className: "notyf__toast--success",
24591
- backgroundColor: "#3dc763",
24592
- icon: {
24593
- className: "notyf__icon--success",
24594
- tagName: "i"
24595
- }
24596
- },
24597
- {
24598
- type: "error",
24599
- className: "notyf__toast--error",
24600
- backgroundColor: "#ed3d3d",
24601
- icon: {
24602
- className: "notyf__icon--error",
24603
- tagName: "i"
24604
- }
24605
- }
24606
- ],
24607
- duration: 2e3,
24608
- ripple: true,
24609
- position: {
24610
- x: "right",
24611
- y: "bottom"
24612
- },
24613
- dismissible: false
24614
- };
24615
- var NotyfView = (
24616
- /** @class */
24617
- (function() {
24618
- function NotyfView2() {
24619
- this.notifications = [];
24620
- this.events = {};
24621
- this.X_POSITION_FLEX_MAP = {
24622
- left: "flex-start",
24623
- center: "center",
24624
- right: "flex-end"
24625
- };
24626
- this.Y_POSITION_FLEX_MAP = {
24627
- top: "flex-start",
24628
- center: "center",
24629
- bottom: "flex-end"
24630
- };
24631
- var docFrag = document.createDocumentFragment();
24632
- var notyfContainer = this._createHTMLElement({ tagName: "div", className: "notyf" });
24633
- docFrag.appendChild(notyfContainer);
24634
- document.body.appendChild(docFrag);
24635
- this.container = notyfContainer;
24636
- this.animationEndEventName = this._getAnimationEndEventName();
24637
- this._createA11yContainer();
24638
- }
24639
- __name(NotyfView2, "NotyfView");
24640
- NotyfView2.prototype.on = function(event, cb) {
24641
- var _a3;
24642
- this.events = __assign(__assign({}, this.events), (_a3 = {}, _a3[event] = cb, _a3));
24643
- };
24644
- NotyfView2.prototype.update = function(notification, type2) {
24645
- if (type2 === NotyfArrayEvent.Add) {
24646
- this.addNotification(notification);
24647
- } else if (type2 === NotyfArrayEvent.Remove) {
24648
- this.removeNotification(notification);
24649
- }
24650
- };
24651
- NotyfView2.prototype.removeNotification = function(notification) {
24652
- var _this = this;
24653
- var renderedNotification = this._popRenderedNotification(notification);
24654
- var node;
24655
- if (!renderedNotification) {
24656
- return;
24657
- }
24658
- node = renderedNotification.node;
24659
- node.classList.add("notyf__toast--disappear");
24660
- var handleEvent;
24661
- node.addEventListener(this.animationEndEventName, handleEvent = /* @__PURE__ */ __name(function(event) {
24662
- if (event.target === node) {
24663
- node.removeEventListener(_this.animationEndEventName, handleEvent);
24664
- _this.container.removeChild(node);
24665
- }
24666
- }, "handleEvent"));
24667
- };
24668
- NotyfView2.prototype.addNotification = function(notification) {
24669
- var node = this._renderNotification(notification);
24670
- this.notifications.push({ notification, node });
24671
- this._announce(notification.options.message || "Notification");
24672
- };
24673
- NotyfView2.prototype._renderNotification = function(notification) {
24674
- var _a3;
24675
- var card = this._buildNotificationCard(notification);
24676
- var className = notification.options.className;
24677
- if (className) {
24678
- (_a3 = card.classList).add.apply(_a3, className.split(" "));
24679
- }
24680
- this.container.appendChild(card);
24681
- return card;
24682
- };
24683
- NotyfView2.prototype._popRenderedNotification = function(notification) {
24684
- var idx = -1;
24685
- for (var i2 = 0; i2 < this.notifications.length && idx < 0; i2++) {
24686
- if (this.notifications[i2].notification === notification) {
24687
- idx = i2;
24688
- }
24689
- }
24690
- if (idx !== -1) {
24691
- return this.notifications.splice(idx, 1)[0];
24692
- }
24693
- return;
24694
- };
24695
- NotyfView2.prototype.getXPosition = function(options) {
24696
- var _a3;
24697
- return ((_a3 = options === null || options === void 0 ? void 0 : options.position) === null || _a3 === void 0 ? void 0 : _a3.x) || "right";
24698
- };
24699
- NotyfView2.prototype.getYPosition = function(options) {
24700
- var _a3;
24701
- return ((_a3 = options === null || options === void 0 ? void 0 : options.position) === null || _a3 === void 0 ? void 0 : _a3.y) || "bottom";
24702
- };
24703
- NotyfView2.prototype.adjustContainerAlignment = function(options) {
24704
- var align = this.X_POSITION_FLEX_MAP[this.getXPosition(options)];
24705
- var justify = this.Y_POSITION_FLEX_MAP[this.getYPosition(options)];
24706
- var style = this.container.style;
24707
- style.setProperty("justify-content", justify);
24708
- style.setProperty("align-items", align);
24709
- };
24710
- NotyfView2.prototype._buildNotificationCard = function(notification) {
24711
- var _this = this;
24712
- var options = notification.options;
24713
- var iconOpts = options.icon;
24714
- this.adjustContainerAlignment(options);
24715
- var notificationElem = this._createHTMLElement({ tagName: "div", className: "notyf__toast" });
24716
- var ripple = this._createHTMLElement({ tagName: "div", className: "notyf__ripple" });
24717
- var wrapper = this._createHTMLElement({ tagName: "div", className: "notyf__wrapper" });
24718
- var message = this._createHTMLElement({ tagName: "div", className: "notyf__message" });
24719
- message.innerHTML = options.message || "";
24720
- var mainColor = options.background || options.backgroundColor;
24721
- if (iconOpts) {
24722
- var iconContainer = this._createHTMLElement({ tagName: "div", className: "notyf__icon" });
24723
- if (typeof iconOpts === "string" || iconOpts instanceof String)
24724
- iconContainer.innerHTML = new String(iconOpts).valueOf();
24725
- if (typeof iconOpts === "object") {
24726
- var _a3 = iconOpts.tagName, tagName = _a3 === void 0 ? "i" : _a3, className_1 = iconOpts.className, text = iconOpts.text, _b3 = iconOpts.color, color = _b3 === void 0 ? mainColor : _b3;
24727
- var iconElement = this._createHTMLElement({ tagName, className: className_1, text });
24728
- if (color)
24729
- iconElement.style.color = color;
24730
- iconContainer.appendChild(iconElement);
24731
- }
24732
- wrapper.appendChild(iconContainer);
24733
- }
24734
- wrapper.appendChild(message);
24735
- notificationElem.appendChild(wrapper);
24736
- if (mainColor) {
24737
- if (options.ripple) {
24738
- ripple.style.background = mainColor;
24739
- notificationElem.appendChild(ripple);
24740
- } else {
24741
- notificationElem.style.background = mainColor;
24742
- }
24743
- }
24744
- if (options.dismissible) {
24745
- var dismissWrapper = this._createHTMLElement({ tagName: "div", className: "notyf__dismiss" });
24746
- var dismissButton = this._createHTMLElement({
24747
- tagName: "button",
24748
- className: "notyf__dismiss-btn"
24749
- });
24750
- dismissWrapper.appendChild(dismissButton);
24751
- wrapper.appendChild(dismissWrapper);
24752
- notificationElem.classList.add("notyf__toast--dismissible");
24753
- dismissButton.addEventListener("click", function(event) {
24754
- var _a4, _b4;
24755
- (_b4 = (_a4 = _this.events)[NotyfEvent.Dismiss]) === null || _b4 === void 0 ? void 0 : _b4.call(_a4, { target: notification, event });
24756
- event.stopPropagation();
24757
- });
24758
- }
24759
- notificationElem.addEventListener("click", function(event) {
24760
- var _a4, _b4;
24761
- return (_b4 = (_a4 = _this.events)[NotyfEvent.Click]) === null || _b4 === void 0 ? void 0 : _b4.call(_a4, { target: notification, event });
24762
- });
24763
- var className = this.getYPosition(options) === "top" ? "upper" : "lower";
24764
- notificationElem.classList.add("notyf__toast--" + className);
24765
- return notificationElem;
24766
- };
24767
- NotyfView2.prototype._createHTMLElement = function(_a3) {
24768
- var tagName = _a3.tagName, className = _a3.className, text = _a3.text;
24769
- var elem = document.createElement(tagName);
24770
- if (className) {
24771
- elem.className = className;
24772
- }
24773
- elem.textContent = text || null;
24774
- return elem;
24775
- };
24776
- NotyfView2.prototype._createA11yContainer = function() {
24777
- var a11yContainer = this._createHTMLElement({ tagName: "div", className: "notyf-announcer" });
24778
- a11yContainer.setAttribute("aria-atomic", "true");
24779
- a11yContainer.setAttribute("aria-live", "polite");
24780
- a11yContainer.style.border = "0";
24781
- a11yContainer.style.clip = "rect(0 0 0 0)";
24782
- a11yContainer.style.height = "1px";
24783
- a11yContainer.style.margin = "-1px";
24784
- a11yContainer.style.overflow = "hidden";
24785
- a11yContainer.style.padding = "0";
24786
- a11yContainer.style.position = "absolute";
24787
- a11yContainer.style.width = "1px";
24788
- a11yContainer.style.outline = "0";
24789
- document.body.appendChild(a11yContainer);
24790
- this.a11yContainer = a11yContainer;
24791
- };
24792
- NotyfView2.prototype._announce = function(message) {
24793
- var _this = this;
24794
- this.a11yContainer.textContent = "";
24795
- setTimeout(function() {
24796
- _this.a11yContainer.textContent = message;
24797
- }, 100);
24798
- };
24799
- NotyfView2.prototype._getAnimationEndEventName = function() {
24800
- var el2 = document.createElement("_fake");
24801
- var transitions = {
24802
- MozTransition: "animationend",
24803
- OTransition: "oAnimationEnd",
24804
- WebkitTransition: "webkitAnimationEnd",
24805
- transition: "animationend"
24806
- };
24807
- var t2;
24808
- for (t2 in transitions) {
24809
- if (el2.style[t2] !== void 0) {
24810
- return transitions[t2];
24811
- }
24812
- }
24813
- return "animationend";
24814
- };
24815
- return NotyfView2;
24816
- })()
24817
- );
24818
- var Notyf = (
24819
- /** @class */
24820
- (function() {
24821
- function Notyf2(opts) {
24822
- var _this = this;
24823
- this.dismiss = this._removeNotification;
24824
- this.notifications = new NotyfArray();
24825
- this.view = new NotyfView();
24826
- var types2 = this.registerTypes(opts);
24827
- this.options = __assign(__assign({}, DEFAULT_OPTIONS), opts);
24828
- this.options.types = types2;
24829
- this.notifications.onUpdate(function(elem, type2) {
24830
- return _this.view.update(elem, type2);
24831
- });
24832
- this.view.on(NotyfEvent.Dismiss, function(_a3) {
24833
- var target = _a3.target, event = _a3.event;
24834
- _this._removeNotification(target);
24835
- target["triggerEvent"](NotyfEvent.Dismiss, event);
24836
- });
24837
- this.view.on(NotyfEvent.Click, function(_a3) {
24838
- var target = _a3.target, event = _a3.event;
24839
- return target["triggerEvent"](NotyfEvent.Click, event);
24840
- });
24841
- }
24842
- __name(Notyf2, "Notyf");
24843
- Notyf2.prototype.error = function(payload) {
24844
- var options = this.normalizeOptions("error", payload);
24845
- return this.open(options);
24846
- };
24847
- Notyf2.prototype.success = function(payload) {
24848
- var options = this.normalizeOptions("success", payload);
24849
- return this.open(options);
24850
- };
24851
- Notyf2.prototype.open = function(options) {
24852
- var defaultOpts = this.options.types.find(function(_a3) {
24853
- var type2 = _a3.type;
24854
- return type2 === options.type;
24855
- }) || {};
24856
- var config2 = __assign(__assign({}, defaultOpts), options);
24857
- this.assignProps(["ripple", "position", "dismissible"], config2);
24858
- var notification = new NotyfNotification(config2);
24859
- this._pushNotification(notification);
24860
- return notification;
24861
- };
24862
- Notyf2.prototype.dismissAll = function() {
24863
- while (this.notifications.splice(0, 1))
24864
- ;
24865
- };
24866
- Notyf2.prototype.assignProps = function(props, config2) {
24867
- var _this = this;
24868
- props.forEach(function(prop) {
24869
- config2[prop] = config2[prop] == null ? _this.options[prop] : config2[prop];
24870
- });
24871
- };
24872
- Notyf2.prototype._pushNotification = function(notification) {
24873
- var _this = this;
24874
- this.notifications.push(notification);
24875
- var duration = notification.options.duration !== void 0 ? notification.options.duration : this.options.duration;
24876
- if (duration) {
24877
- setTimeout(function() {
24878
- return _this._removeNotification(notification);
24879
- }, duration);
24880
- }
24881
- };
24882
- Notyf2.prototype._removeNotification = function(notification) {
24883
- var index2 = this.notifications.indexOf(notification);
24884
- if (index2 !== -1) {
24885
- this.notifications.splice(index2, 1);
24886
- }
24887
- };
24888
- Notyf2.prototype.normalizeOptions = function(type2, payload) {
24889
- var options = { type: type2 };
24890
- if (typeof payload === "string") {
24891
- options.message = payload;
24892
- } else if (typeof payload === "object") {
24893
- options = __assign(__assign({}, options), payload);
24894
- }
24895
- return options;
24896
- };
24897
- Notyf2.prototype.registerTypes = function(opts) {
24898
- var incomingTypes = (opts && opts.types || []).slice();
24899
- var finalDefaultTypes = DEFAULT_OPTIONS.types.map(function(defaultType) {
24900
- var userTypeIdx = -1;
24901
- incomingTypes.forEach(function(t2, idx) {
24902
- if (t2.type === defaultType.type)
24903
- userTypeIdx = idx;
24904
- });
24905
- var userType = userTypeIdx !== -1 ? incomingTypes.splice(userTypeIdx, 1)[0] : {};
24906
- return __assign(__assign({}, defaultType), userType);
24907
- });
24908
- return finalDefaultTypes.concat(incomingTypes);
24909
- };
24910
- return Notyf2;
24911
- })()
24912
- );
24913
24651
  const global$1 = globalThis || void 0 || self;
24914
24652
  var _globalThis$1 = typeof globalThis === "object" ? globalThis : typeof self === "object" ? self : typeof window === "object" ? window : typeof global$1 === "object" ? global$1 : {};
24915
24653
  var VERSION$2 = "1.9.0";
@@ -29527,6 +29265,400 @@ function requireTopbar_min() {
29527
29265
  __name(requireTopbar_min, "requireTopbar_min");
29528
29266
  var topbar_minExports = requireTopbar_min();
29529
29267
  const topbar = /* @__PURE__ */ getDefaultExportFromCjs(topbar_minExports);
29268
+ var __assign = /* @__PURE__ */ __name(function() {
29269
+ __assign = Object.assign || /* @__PURE__ */ __name(function __assign2(t2) {
29270
+ for (var s2, i2 = 1, n2 = arguments.length; i2 < n2; i2++) {
29271
+ s2 = arguments[i2];
29272
+ for (var p2 in s2) if (Object.prototype.hasOwnProperty.call(s2, p2)) t2[p2] = s2[p2];
29273
+ }
29274
+ return t2;
29275
+ }, "__assign");
29276
+ return __assign.apply(this, arguments);
29277
+ }, "__assign");
29278
+ var NotyfNotification = (
29279
+ /** @class */
29280
+ (function() {
29281
+ function NotyfNotification2(options) {
29282
+ this.options = options;
29283
+ this.listeners = {};
29284
+ }
29285
+ __name(NotyfNotification2, "NotyfNotification");
29286
+ NotyfNotification2.prototype.on = function(eventType, cb) {
29287
+ var callbacks = this.listeners[eventType] || [];
29288
+ this.listeners[eventType] = callbacks.concat([cb]);
29289
+ };
29290
+ NotyfNotification2.prototype.triggerEvent = function(eventType, event) {
29291
+ var _this = this;
29292
+ var callbacks = this.listeners[eventType] || [];
29293
+ callbacks.forEach(function(cb) {
29294
+ return cb({ target: _this, event });
29295
+ });
29296
+ };
29297
+ return NotyfNotification2;
29298
+ })()
29299
+ );
29300
+ var NotyfArrayEvent;
29301
+ (function(NotyfArrayEvent2) {
29302
+ NotyfArrayEvent2[NotyfArrayEvent2["Add"] = 0] = "Add";
29303
+ NotyfArrayEvent2[NotyfArrayEvent2["Remove"] = 1] = "Remove";
29304
+ })(NotyfArrayEvent || (NotyfArrayEvent = {}));
29305
+ var NotyfArray = (
29306
+ /** @class */
29307
+ (function() {
29308
+ function NotyfArray2() {
29309
+ this.notifications = [];
29310
+ }
29311
+ __name(NotyfArray2, "NotyfArray");
29312
+ NotyfArray2.prototype.push = function(elem) {
29313
+ this.notifications.push(elem);
29314
+ this.updateFn(elem, NotyfArrayEvent.Add, this.notifications);
29315
+ };
29316
+ NotyfArray2.prototype.splice = function(index2, num) {
29317
+ var elem = this.notifications.splice(index2, num)[0];
29318
+ this.updateFn(elem, NotyfArrayEvent.Remove, this.notifications);
29319
+ return elem;
29320
+ };
29321
+ NotyfArray2.prototype.indexOf = function(elem) {
29322
+ return this.notifications.indexOf(elem);
29323
+ };
29324
+ NotyfArray2.prototype.onUpdate = function(fn2) {
29325
+ this.updateFn = fn2;
29326
+ };
29327
+ return NotyfArray2;
29328
+ })()
29329
+ );
29330
+ var NotyfEvent;
29331
+ (function(NotyfEvent2) {
29332
+ NotyfEvent2["Dismiss"] = "dismiss";
29333
+ NotyfEvent2["Click"] = "click";
29334
+ })(NotyfEvent || (NotyfEvent = {}));
29335
+ var DEFAULT_OPTIONS = {
29336
+ types: [
29337
+ {
29338
+ type: "success",
29339
+ className: "notyf__toast--success",
29340
+ backgroundColor: "#3dc763",
29341
+ icon: {
29342
+ className: "notyf__icon--success",
29343
+ tagName: "i"
29344
+ }
29345
+ },
29346
+ {
29347
+ type: "error",
29348
+ className: "notyf__toast--error",
29349
+ backgroundColor: "#ed3d3d",
29350
+ icon: {
29351
+ className: "notyf__icon--error",
29352
+ tagName: "i"
29353
+ }
29354
+ }
29355
+ ],
29356
+ duration: 2e3,
29357
+ ripple: true,
29358
+ position: {
29359
+ x: "right",
29360
+ y: "bottom"
29361
+ },
29362
+ dismissible: false
29363
+ };
29364
+ var NotyfView = (
29365
+ /** @class */
29366
+ (function() {
29367
+ function NotyfView2() {
29368
+ this.notifications = [];
29369
+ this.events = {};
29370
+ this.X_POSITION_FLEX_MAP = {
29371
+ left: "flex-start",
29372
+ center: "center",
29373
+ right: "flex-end"
29374
+ };
29375
+ this.Y_POSITION_FLEX_MAP = {
29376
+ top: "flex-start",
29377
+ center: "center",
29378
+ bottom: "flex-end"
29379
+ };
29380
+ var docFrag = document.createDocumentFragment();
29381
+ var notyfContainer = this._createHTMLElement({ tagName: "div", className: "notyf" });
29382
+ docFrag.appendChild(notyfContainer);
29383
+ document.body.appendChild(docFrag);
29384
+ this.container = notyfContainer;
29385
+ this.animationEndEventName = this._getAnimationEndEventName();
29386
+ this._createA11yContainer();
29387
+ }
29388
+ __name(NotyfView2, "NotyfView");
29389
+ NotyfView2.prototype.on = function(event, cb) {
29390
+ var _a3;
29391
+ this.events = __assign(__assign({}, this.events), (_a3 = {}, _a3[event] = cb, _a3));
29392
+ };
29393
+ NotyfView2.prototype.update = function(notification, type2) {
29394
+ if (type2 === NotyfArrayEvent.Add) {
29395
+ this.addNotification(notification);
29396
+ } else if (type2 === NotyfArrayEvent.Remove) {
29397
+ this.removeNotification(notification);
29398
+ }
29399
+ };
29400
+ NotyfView2.prototype.removeNotification = function(notification) {
29401
+ var _this = this;
29402
+ var renderedNotification = this._popRenderedNotification(notification);
29403
+ var node;
29404
+ if (!renderedNotification) {
29405
+ return;
29406
+ }
29407
+ node = renderedNotification.node;
29408
+ node.classList.add("notyf__toast--disappear");
29409
+ var handleEvent;
29410
+ node.addEventListener(this.animationEndEventName, handleEvent = /* @__PURE__ */ __name(function(event) {
29411
+ if (event.target === node) {
29412
+ node.removeEventListener(_this.animationEndEventName, handleEvent);
29413
+ _this.container.removeChild(node);
29414
+ }
29415
+ }, "handleEvent"));
29416
+ };
29417
+ NotyfView2.prototype.addNotification = function(notification) {
29418
+ var node = this._renderNotification(notification);
29419
+ this.notifications.push({ notification, node });
29420
+ this._announce(notification.options.message || "Notification");
29421
+ };
29422
+ NotyfView2.prototype._renderNotification = function(notification) {
29423
+ var _a3;
29424
+ var card = this._buildNotificationCard(notification);
29425
+ var className = notification.options.className;
29426
+ if (className) {
29427
+ (_a3 = card.classList).add.apply(_a3, className.split(" "));
29428
+ }
29429
+ this.container.appendChild(card);
29430
+ return card;
29431
+ };
29432
+ NotyfView2.prototype._popRenderedNotification = function(notification) {
29433
+ var idx = -1;
29434
+ for (var i2 = 0; i2 < this.notifications.length && idx < 0; i2++) {
29435
+ if (this.notifications[i2].notification === notification) {
29436
+ idx = i2;
29437
+ }
29438
+ }
29439
+ if (idx !== -1) {
29440
+ return this.notifications.splice(idx, 1)[0];
29441
+ }
29442
+ return;
29443
+ };
29444
+ NotyfView2.prototype.getXPosition = function(options) {
29445
+ var _a3;
29446
+ return ((_a3 = options === null || options === void 0 ? void 0 : options.position) === null || _a3 === void 0 ? void 0 : _a3.x) || "right";
29447
+ };
29448
+ NotyfView2.prototype.getYPosition = function(options) {
29449
+ var _a3;
29450
+ return ((_a3 = options === null || options === void 0 ? void 0 : options.position) === null || _a3 === void 0 ? void 0 : _a3.y) || "bottom";
29451
+ };
29452
+ NotyfView2.prototype.adjustContainerAlignment = function(options) {
29453
+ var align = this.X_POSITION_FLEX_MAP[this.getXPosition(options)];
29454
+ var justify = this.Y_POSITION_FLEX_MAP[this.getYPosition(options)];
29455
+ var style = this.container.style;
29456
+ style.setProperty("justify-content", justify);
29457
+ style.setProperty("align-items", align);
29458
+ };
29459
+ NotyfView2.prototype._buildNotificationCard = function(notification) {
29460
+ var _this = this;
29461
+ var options = notification.options;
29462
+ var iconOpts = options.icon;
29463
+ this.adjustContainerAlignment(options);
29464
+ var notificationElem = this._createHTMLElement({ tagName: "div", className: "notyf__toast" });
29465
+ var ripple = this._createHTMLElement({ tagName: "div", className: "notyf__ripple" });
29466
+ var wrapper = this._createHTMLElement({ tagName: "div", className: "notyf__wrapper" });
29467
+ var message = this._createHTMLElement({ tagName: "div", className: "notyf__message" });
29468
+ message.innerHTML = options.message || "";
29469
+ var mainColor = options.background || options.backgroundColor;
29470
+ if (iconOpts) {
29471
+ var iconContainer = this._createHTMLElement({ tagName: "div", className: "notyf__icon" });
29472
+ if (typeof iconOpts === "string" || iconOpts instanceof String)
29473
+ iconContainer.innerHTML = new String(iconOpts).valueOf();
29474
+ if (typeof iconOpts === "object") {
29475
+ var _a3 = iconOpts.tagName, tagName = _a3 === void 0 ? "i" : _a3, className_1 = iconOpts.className, text = iconOpts.text, _b3 = iconOpts.color, color = _b3 === void 0 ? mainColor : _b3;
29476
+ var iconElement = this._createHTMLElement({ tagName, className: className_1, text });
29477
+ if (color)
29478
+ iconElement.style.color = color;
29479
+ iconContainer.appendChild(iconElement);
29480
+ }
29481
+ wrapper.appendChild(iconContainer);
29482
+ }
29483
+ wrapper.appendChild(message);
29484
+ notificationElem.appendChild(wrapper);
29485
+ if (mainColor) {
29486
+ if (options.ripple) {
29487
+ ripple.style.background = mainColor;
29488
+ notificationElem.appendChild(ripple);
29489
+ } else {
29490
+ notificationElem.style.background = mainColor;
29491
+ }
29492
+ }
29493
+ if (options.dismissible) {
29494
+ var dismissWrapper = this._createHTMLElement({ tagName: "div", className: "notyf__dismiss" });
29495
+ var dismissButton = this._createHTMLElement({
29496
+ tagName: "button",
29497
+ className: "notyf__dismiss-btn"
29498
+ });
29499
+ dismissWrapper.appendChild(dismissButton);
29500
+ wrapper.appendChild(dismissWrapper);
29501
+ notificationElem.classList.add("notyf__toast--dismissible");
29502
+ dismissButton.addEventListener("click", function(event) {
29503
+ var _a4, _b4;
29504
+ (_b4 = (_a4 = _this.events)[NotyfEvent.Dismiss]) === null || _b4 === void 0 ? void 0 : _b4.call(_a4, { target: notification, event });
29505
+ event.stopPropagation();
29506
+ });
29507
+ }
29508
+ notificationElem.addEventListener("click", function(event) {
29509
+ var _a4, _b4;
29510
+ return (_b4 = (_a4 = _this.events)[NotyfEvent.Click]) === null || _b4 === void 0 ? void 0 : _b4.call(_a4, { target: notification, event });
29511
+ });
29512
+ var className = this.getYPosition(options) === "top" ? "upper" : "lower";
29513
+ notificationElem.classList.add("notyf__toast--" + className);
29514
+ return notificationElem;
29515
+ };
29516
+ NotyfView2.prototype._createHTMLElement = function(_a3) {
29517
+ var tagName = _a3.tagName, className = _a3.className, text = _a3.text;
29518
+ var elem = document.createElement(tagName);
29519
+ if (className) {
29520
+ elem.className = className;
29521
+ }
29522
+ elem.textContent = text || null;
29523
+ return elem;
29524
+ };
29525
+ NotyfView2.prototype._createA11yContainer = function() {
29526
+ var a11yContainer = this._createHTMLElement({ tagName: "div", className: "notyf-announcer" });
29527
+ a11yContainer.setAttribute("aria-atomic", "true");
29528
+ a11yContainer.setAttribute("aria-live", "polite");
29529
+ a11yContainer.style.border = "0";
29530
+ a11yContainer.style.clip = "rect(0 0 0 0)";
29531
+ a11yContainer.style.height = "1px";
29532
+ a11yContainer.style.margin = "-1px";
29533
+ a11yContainer.style.overflow = "hidden";
29534
+ a11yContainer.style.padding = "0";
29535
+ a11yContainer.style.position = "absolute";
29536
+ a11yContainer.style.width = "1px";
29537
+ a11yContainer.style.outline = "0";
29538
+ document.body.appendChild(a11yContainer);
29539
+ this.a11yContainer = a11yContainer;
29540
+ };
29541
+ NotyfView2.prototype._announce = function(message) {
29542
+ var _this = this;
29543
+ this.a11yContainer.textContent = "";
29544
+ setTimeout(function() {
29545
+ _this.a11yContainer.textContent = message;
29546
+ }, 100);
29547
+ };
29548
+ NotyfView2.prototype._getAnimationEndEventName = function() {
29549
+ var el2 = document.createElement("_fake");
29550
+ var transitions = {
29551
+ MozTransition: "animationend",
29552
+ OTransition: "oAnimationEnd",
29553
+ WebkitTransition: "webkitAnimationEnd",
29554
+ transition: "animationend"
29555
+ };
29556
+ var t2;
29557
+ for (t2 in transitions) {
29558
+ if (el2.style[t2] !== void 0) {
29559
+ return transitions[t2];
29560
+ }
29561
+ }
29562
+ return "animationend";
29563
+ };
29564
+ return NotyfView2;
29565
+ })()
29566
+ );
29567
+ var Notyf = (
29568
+ /** @class */
29569
+ (function() {
29570
+ function Notyf2(opts) {
29571
+ var _this = this;
29572
+ this.dismiss = this._removeNotification;
29573
+ this.notifications = new NotyfArray();
29574
+ this.view = new NotyfView();
29575
+ var types2 = this.registerTypes(opts);
29576
+ this.options = __assign(__assign({}, DEFAULT_OPTIONS), opts);
29577
+ this.options.types = types2;
29578
+ this.notifications.onUpdate(function(elem, type2) {
29579
+ return _this.view.update(elem, type2);
29580
+ });
29581
+ this.view.on(NotyfEvent.Dismiss, function(_a3) {
29582
+ var target = _a3.target, event = _a3.event;
29583
+ _this._removeNotification(target);
29584
+ target["triggerEvent"](NotyfEvent.Dismiss, event);
29585
+ });
29586
+ this.view.on(NotyfEvent.Click, function(_a3) {
29587
+ var target = _a3.target, event = _a3.event;
29588
+ return target["triggerEvent"](NotyfEvent.Click, event);
29589
+ });
29590
+ }
29591
+ __name(Notyf2, "Notyf");
29592
+ Notyf2.prototype.error = function(payload) {
29593
+ var options = this.normalizeOptions("error", payload);
29594
+ return this.open(options);
29595
+ };
29596
+ Notyf2.prototype.success = function(payload) {
29597
+ var options = this.normalizeOptions("success", payload);
29598
+ return this.open(options);
29599
+ };
29600
+ Notyf2.prototype.open = function(options) {
29601
+ var defaultOpts = this.options.types.find(function(_a3) {
29602
+ var type2 = _a3.type;
29603
+ return type2 === options.type;
29604
+ }) || {};
29605
+ var config2 = __assign(__assign({}, defaultOpts), options);
29606
+ this.assignProps(["ripple", "position", "dismissible"], config2);
29607
+ var notification = new NotyfNotification(config2);
29608
+ this._pushNotification(notification);
29609
+ return notification;
29610
+ };
29611
+ Notyf2.prototype.dismissAll = function() {
29612
+ while (this.notifications.splice(0, 1))
29613
+ ;
29614
+ };
29615
+ Notyf2.prototype.assignProps = function(props, config2) {
29616
+ var _this = this;
29617
+ props.forEach(function(prop) {
29618
+ config2[prop] = config2[prop] == null ? _this.options[prop] : config2[prop];
29619
+ });
29620
+ };
29621
+ Notyf2.prototype._pushNotification = function(notification) {
29622
+ var _this = this;
29623
+ this.notifications.push(notification);
29624
+ var duration = notification.options.duration !== void 0 ? notification.options.duration : this.options.duration;
29625
+ if (duration) {
29626
+ setTimeout(function() {
29627
+ return _this._removeNotification(notification);
29628
+ }, duration);
29629
+ }
29630
+ };
29631
+ Notyf2.prototype._removeNotification = function(notification) {
29632
+ var index2 = this.notifications.indexOf(notification);
29633
+ if (index2 !== -1) {
29634
+ this.notifications.splice(index2, 1);
29635
+ }
29636
+ };
29637
+ Notyf2.prototype.normalizeOptions = function(type2, payload) {
29638
+ var options = { type: type2 };
29639
+ if (typeof payload === "string") {
29640
+ options.message = payload;
29641
+ } else if (typeof payload === "object") {
29642
+ options = __assign(__assign({}, options), payload);
29643
+ }
29644
+ return options;
29645
+ };
29646
+ Notyf2.prototype.registerTypes = function(opts) {
29647
+ var incomingTypes = (opts && opts.types || []).slice();
29648
+ var finalDefaultTypes = DEFAULT_OPTIONS.types.map(function(defaultType) {
29649
+ var userTypeIdx = -1;
29650
+ incomingTypes.forEach(function(t2, idx) {
29651
+ if (t2.type === defaultType.type)
29652
+ userTypeIdx = idx;
29653
+ });
29654
+ var userType = userTypeIdx !== -1 ? incomingTypes.splice(userTypeIdx, 1)[0] : {};
29655
+ return __assign(__assign({}, defaultType), userType);
29656
+ });
29657
+ return finalDefaultTypes.concat(incomingTypes);
29658
+ };
29659
+ return Notyf2;
29660
+ })()
29661
+ );
29530
29662
  const DefaultDomOptions = { topbar: true };
29531
29663
  const _Dom = class _Dom {
29532
29664
  constructor(_options = DefaultDomOptions) {
@@ -29535,8 +29667,10 @@ const _Dom = class _Dom {
29535
29667
  __publicField(this, "_window", globalThis.window);
29536
29668
  __publicField(this, "_topbarEnabled", false);
29537
29669
  __publicField(this, "_topbarShow", false);
29670
+ __publicField(this, "_toast");
29538
29671
  const options = { ...DefaultDomOptions, ..._options };
29539
29672
  this._topbarEnabled = options.topbar ?? true;
29673
+ this._toast = new Notyf(options.toast);
29540
29674
  }
29541
29675
  get document() {
29542
29676
  return this._document;
@@ -29547,6 +29681,9 @@ const _Dom = class _Dom {
29547
29681
  get window() {
29548
29682
  return this._window;
29549
29683
  }
29684
+ get toast() {
29685
+ return this._toast;
29686
+ }
29550
29687
  async topbar(show) {
29551
29688
  if (!this._topbarEnabled) return;
29552
29689
  this._topbarShow = show ?? !this._topbarShow;
@@ -29561,6 +29698,26 @@ const _Dom = class _Dom {
29561
29698
  if (!this._topbarEnabled) return;
29562
29699
  topbar.progress(value);
29563
29700
  }
29701
+ /**
29702
+ * Shows a quick flash indicator for the TTY number in the top-right corner
29703
+ * @param ttyNumber - TTY number to display
29704
+ */
29705
+ showTtyIndicator(ttyNumber) {
29706
+ const existingIndicator = this._document.getElementById("tty-indicator");
29707
+ if (existingIndicator) existingIndicator.remove();
29708
+ const indicator = this._document.createElement("div");
29709
+ indicator.id = "tty-indicator";
29710
+ indicator.className = "tty-indicator";
29711
+ indicator.textContent = `TTY ${ttyNumber}`;
29712
+ this._document.body.appendChild(indicator);
29713
+ requestAnimationFrame(() => indicator.classList.add("show"));
29714
+ setTimeout(() => {
29715
+ indicator.classList.remove("show");
29716
+ setTimeout(() => {
29717
+ if (indicator.parentNode) indicator.remove();
29718
+ }, 300);
29719
+ }, 1500);
29720
+ }
29564
29721
  };
29565
29722
  __name(_Dom, "Dom");
29566
29723
  let Dom = _Dom;
@@ -59158,11 +59315,16 @@ function createCommand$1e(kernel, shell, terminal) {
59158
59315
  }, "getModeString");
59159
59316
  const getTimestampString = /* @__PURE__ */ __name((timestamp2) => {
59160
59317
  const diff = ((/* @__PURE__ */ new Date()).getTime() - timestamp2.getTime()) / 1e3;
59161
- if (diff < 24 * 60 * 60) return chalk$1.green(timestamp2.toISOString().slice(0, 19).replace("T", " "));
59162
- else if (diff < 7 * 24 * 60 * 60) return chalk$1.yellow(timestamp2.toISOString().slice(0, 19).replace("T", " "));
59163
- else if (diff < 30 * 24 * 60 * 60) return chalk$1.blue(timestamp2.toISOString().slice(0, 19).replace("T", " "));
59164
- else if (diff < 365 * 24 * 60 * 60) return chalk$1.magenta(timestamp2.toISOString().slice(0, 19).replace("T", " "));
59165
- else return chalk$1.gray(timestamp2.toISOString().slice(0, 19).replace("T", " "));
59318
+ if (diff < 24 * 60 * 60)
59319
+ return chalk$1.red(timestamp2.toISOString().slice(0, 19).replace("T", " "));
59320
+ else if (diff < 7 * 24 * 60 * 60)
59321
+ return chalk$1.yellow(timestamp2.toISOString().slice(0, 19).replace("T", " "));
59322
+ else if (diff < 30 * 24 * 60 * 60)
59323
+ return chalk$1.green(timestamp2.toISOString().slice(0, 19).replace("T", " "));
59324
+ else if (diff < 365 * 24 * 60 * 60)
59325
+ return chalk$1.cyan(timestamp2.toISOString().slice(0, 19).replace("T", " "));
59326
+ else
59327
+ return chalk$1.blue(timestamp2.toISOString().slice(0, 19).replace("T", " "));
59166
59328
  }, "getTimestampString");
59167
59329
  const getOwnerString = /* @__PURE__ */ __name((stats) => {
59168
59330
  const owner = kernel.users.all.get(Number(stats.uid)) || kernel.users.all.get(0);
@@ -81715,7 +81877,7 @@ function createCommand$1b(kernel, shell, terminal) {
81715
81877
  if (!clientConfig.accessToken) {
81716
81878
  throw new Error("client configuration must include accessToken");
81717
81879
  }
81718
- const dropboxModule = await import("./index-Dt0A0I3o.js");
81880
+ const dropboxModule = await import("./index-DXuNSaKe.js");
81719
81881
  const DropboxClient = dropboxModule.Dropbox;
81720
81882
  const client = new DropboxClient(clientConfig);
81721
81883
  const cacheTTL = mountOptions.cacheTTL ? parseInt(mountOptions.cacheTTL, 10) : void 0;
@@ -82055,7 +82217,7 @@ Mount summary: ${successCount} succeeded, ${failCount} failed`);
82055
82217
  await writelnStderr(process2, terminal, chalk$1.red("mount: client configuration must include accessToken"));
82056
82218
  return 1;
82057
82219
  }
82058
- const dropboxModule = await import("./index-Dt0A0I3o.js");
82220
+ const dropboxModule = await import("./index-DXuNSaKe.js");
82059
82221
  const DropboxClient = dropboxModule.Dropbox;
82060
82222
  const client = new DropboxClient(clientConfig);
82061
82223
  const cacheTTL = mountOptions.cacheTTL ? parseInt(mountOptions.cacheTTL, 10) : void 0;
@@ -96332,12 +96494,12 @@ function createCommand$E(kernel, shell, terminal) {
96332
96494
  }
96333
96495
  break;
96334
96496
  }
96335
- let data = buffer2.subarray(0, bytesRead);
96497
+ let data = buffer2.slice(0, bytesRead);
96336
96498
  if (skipBytes > 0) {
96337
96499
  const toSkip = Math.min(data.length, skipBytes - skipped);
96338
96500
  skipped += toSkip;
96339
96501
  if (toSkip < data.length) {
96340
- data = data.subarray(toSkip);
96502
+ data = data.slice(toSkip);
96341
96503
  } else {
96342
96504
  continue;
96343
96505
  }
@@ -104507,7 +104669,7 @@ customElements.define("json-viewer", JsonViewer);
104507
104669
  function detectFileType(filePath) {
104508
104670
  const ext = path$2.extname(filePath).toLowerCase();
104509
104671
  if (ext === ".pdf") return "pdf";
104510
- const markdownExts = [".md", ".markdown", ".mdown", ".mkd", ".mkdn"];
104672
+ const markdownExts = [".md", ".markdown", ".mdown", ".mkd", ".mkdn", ".txt"];
104511
104673
  if (markdownExts.includes(ext)) return "markdown";
104512
104674
  const jsonExts = [".json", ".jsonl", ".jsonc", ".jsonld"];
104513
104675
  if (jsonExts.includes(ext)) return "json";
@@ -125149,7 +125311,7 @@ const TerminalCommands = /* @__PURE__ */ __name((kernel, shell, terminal) => {
125149
125311
  { name: "reinstall", type: Boolean, description: "Reinstall the package if it is already installed" }
125150
125312
  ],
125151
125313
  run: /* @__PURE__ */ __name(async (argv) => {
125152
- const { default: install } = await import("./install-CRrPdUs9.js");
125314
+ const { default: install } = await import("./install-Bs2UAdQv.js");
125153
125315
  return await install({ kernel, shell, terminal, args: [argv.package, argv.registry, argv.reinstall] });
125154
125316
  }, "run")
125155
125317
  }),
@@ -125164,7 +125326,7 @@ const TerminalCommands = /* @__PURE__ */ __name((kernel, shell, terminal) => {
125164
125326
  { name: "package", type: String, typeLabel: "{underline package}", defaultOption: true, description: "The package name and optional version (e.g. package@1.0.0). If no version is specified, all versions will be uninstalled." }
125165
125327
  ],
125166
125328
  run: /* @__PURE__ */ __name(async (argv) => {
125167
- const { default: uninstall } = await import("./uninstall-Bb4xsCq5.js");
125329
+ const { default: uninstall } = await import("./uninstall-_cO2Evrz.js");
125168
125330
  return await uninstall({ kernel, shell, terminal, args: [argv.package] });
125169
125331
  }, "run")
125170
125332
  }),
@@ -126537,10 +126699,11 @@ const _Terminal = class _Terminal extends Dl {
126537
126699
  try {
126538
126700
  this.events.dispatch(TerminalEvents.EXECUTE, { terminal: this, command: cmdToExecute });
126539
126701
  await this._shell.execute(cmdToExecute);
126540
- this._cursorPosition = 0;
126541
- this.write(ansi$6.erase.inLine(2) + this.prompt());
126542
126702
  } catch (error2) {
126543
126703
  this.writeln(chalk$2.red(`${error2}`));
126704
+ } finally {
126705
+ this._cursorPosition = 0;
126706
+ this.write(ansi$6.erase.inLine(2) + this.prompt());
126544
126707
  }
126545
126708
  } else {
126546
126709
  this._cmd = "";
@@ -142945,7 +143108,7 @@ async function createWasiPreview2Bindings({
142945
143108
  const stdinReader = streams2.stdin.getReader();
142946
143109
  const stdoutWriter = streams2.stdout.getWriter();
142947
143110
  const stderrWriter = streams2.stderr.getWriter();
142948
- const jco = await import("./browser-D_rzdy4k.js");
143111
+ const jco = await import("./browser-CX2g4OIh.js");
142949
143112
  const { transpile: transpileComponent } = jco;
142950
143113
  const wasiCli = await Promise.resolve().then(() => cli);
142951
143114
  const wasiCliAny = wasiCli;
@@ -145134,10 +145297,10 @@ function parseFstabFile(content) {
145134
145297
  return entries2;
145135
145298
  }
145136
145299
  __name(parseFstabFile, "parseFstabFile");
145137
- const __vite_import_meta_env__ = { "AUTHOR": { "name": "Jay Mathis", "email": "code@mathis.network", "url": "https://github.com/mathiscode" }, "BASE_URL": "/", "DESCRIPTION": "ecmaOS: Micro-kernel and framework for web technologies", "DEV": false, "ECMAOS_APP_SHOW_DEFAULT_LOGIN": "true", "ECMAOS_BOOT_DISABLE_ISSUES": "true", "ECMAOS_BOOT_DISABLE_LOGO_CONSOLE": "false", "ECMAOS_BOOT_DISABLE_LOGO_FIGLET": "false", "ECMAOS_BOOT_DISABLE_TIPS": "false", "ECMAOS_INITFS": "/initfs.tar.gz", "ECMAOS_KERNEL_INTERVALS_PROC": "1000", "ECMAOS_KERNEL_MODULES": "@ecmaos-modules/boilerplate@0.1.0", "ECMAOS_METAL_SOCKET": "ws://localhost:30445/socket", "ECMAOS_OPENTELEMETRY_ENDPOINT": "http://localhost:4318/v1/traces", "ECMAOS_PORT": "30443", "ECMAOS_RECOMMENDED_APPS": "@ecmaos-apps/code,@ecmaos-apps/edit,@ecmaos-apps/ai,@ecmaos-apps/webamp,@ecmaos-apps/news", "HOMEPAGE": "https://ecmaos.sh", "KNOWN_ISSUES": ["It's best to stick to Chromium-based browsers for the most features", "Keyboard is broken on mobile; ecmaOS is not mobile-friendly at this time", "Don't expect any sort of POSIX compliance at this stage", "Most commands/devices are very basic implementations, not complete reproductions", "stdin/stdout/stderr streams and redirection can be wonky and don't work everywhere, but are coming along", "CTRL-C will return you to a prompt, but doesn't currently interrupt a process", "Lots of unfinished work; watch your step"], "MODE": "production", "NAME": "@ecmaos/kernel", "PROD": true, "REPOSITORY": "https://github.com/ecmaos/ecmaos", "SSR": false, "TIPS": ["ecmaos.sh has no backend server; all data is stored and processed entirely in your browser", "If it ever fails to boot, check your logs, try clearing all data, try incognito mode, or try another browser", "You can switch between TTYs using CTRL+SHIFT+<0-9>", "You can run some devices that offer a CLI - e.g. '/dev/battery --help'", "Use the 'install' command to install packages - e.g. 'install @ecmaos-apps/news'", "You can install any NPM package - e.g. 'install jquery'", "You can use the 'mount' command to view and mount filesystems (/etc/fstab supported)", "Use the 'news' command to see the latest news about ecmaOS", "Type 'ls /bin' to see all built-in commands", "Type 'ls /usr/bin' to see all installed commands", "Type 'ls /dev' to see all available devices", "You can set your environment variables in ~/.env (try setting PROMPT to a PS1-like format)", "You can register and login with a passkey: 'passkey register' and 'passkey list'", "The 'man' command can be used to view the manual pages for packages: 'man @ecmaos/kernel'", "Try 'fetch /xkcd-os.sixel'"], "VERSION": "0.10.2", "XTERM_VERSION": "6.0.0", "ZENFS_VERSION": "2.4.4" };
145300
+ const __vite_import_meta_env__ = { "AUTHOR": { "name": "Jay Mathis", "email": "code@mathis.network", "url": "https://github.com/mathiscode" }, "BASE_URL": "/", "DESCRIPTION": "ecmaOS: A web-native operating system and framework for web technologies", "DEV": false, "ECMAOS_APP_SHOW_DEFAULT_LOGIN": "true", "ECMAOS_AUTOLOGIN_PASSWORD": "root", "ECMAOS_AUTOLOGIN_USERNAME": "root", "ECMAOS_BOOT_DISABLE_ISSUES": "true", "ECMAOS_BOOT_DISABLE_LOGO_CONSOLE": "false", "ECMAOS_BOOT_DISABLE_LOGO_FIGLET": "false", "ECMAOS_BOOT_DISABLE_TIPS": "false", "ECMAOS_INITFS": "/initfs.tar.gz", "ECMAOS_KERNEL_INTERVALS_PROC": "1000", "ECMAOS_KERNEL_MODULES": "@ecmaos-modules/boilerplate@0.1.0", "ECMAOS_METAL_SOCKET": "ws://localhost:30445/socket", "ECMAOS_OPENTELEMETRY_ENDPOINT": "http://localhost:4318/v1/traces", "ECMAOS_PORT": "30443", "ECMAOS_RECOMMENDED_APPS": "@ecmaos-apps/code,@ecmaos-apps/edit,@ecmaos-apps/ai,@ecmaos-apps/webamp,@ecmaos-apps/news", "HOMEPAGE": "https://ecmaos.sh", "KNOWN_ISSUES": ["To disable known issues, type `touch /etc/noissues`", "It's best to stick to Chromium-based browsers for the most features", "Keyboard is broken on mobile; ecmaOS is not mobile-friendly at this time", "Don't expect any sort of POSIX compliance at this stage", "Most commands/devices are very basic implementations, not complete reproductions", "CTRL-C will return you to a prompt, but doesn't currently interrupt a process", "Lots of unfinished work; watch your step"], "MODE": "production", "NAME": "@ecmaos/kernel", "PROD": true, "REPOSITORY": "https://github.com/ecmaos/ecmaos", "SSR": false, "TIPS": ["To disable tips, type `touch /etc/notips`", "ecmaos.sh has no backend server; all data is stored and processed entirely in your browser", "If it ever fails to boot, check your logs, try clearing all data, try incognito mode, or try another browser", "You can switch between TTYs using CTRL+SHIFT+<0-9>", "You can run some devices that offer a CLI - e.g. '/dev/battery --help'", "Use the 'install' command to install packages - e.g. 'install @ecmaos-apps/news'", "You can install any NPM package - e.g. 'install jquery'", "You can use the 'mount' command to view and mount filesystems (/etc/fstab supported)", "Use the 'news' command to see the latest news about ecmaOS", "Type 'ls /bin' to see all built-in commands", "Type 'ls /usr/bin' to see all installed commands", "Type 'ls /dev' to see all available devices", "You can set your environment variables in ~/.env (try setting PROMPT to a PS1-like format)", "You can register and login with a passkey: 'passkey register' and 'passkey list'", "The 'man' command can be used to view the manual pages for packages: 'man @ecmaos/kernel'", "Try 'fetch /xkcd-os.sixel'"], "VERSION": "0.10.4", "XTERM_VERSION": "6.0.0", "ZENFS_VERSION": "2.4.4" };
145138
145301
  var define_import_meta_env_AUTHOR_default = { name: "Jay Mathis", email: "code@mathis.network", url: "https://github.com/mathiscode" };
145139
- var define_import_meta_env_KNOWN_ISSUES_default = ["It's best to stick to Chromium-based browsers for the most features", "Keyboard is broken on mobile; ecmaOS is not mobile-friendly at this time", "Don't expect any sort of POSIX compliance at this stage", "Most commands/devices are very basic implementations, not complete reproductions", "stdin/stdout/stderr streams and redirection can be wonky and don't work everywhere, but are coming along", "CTRL-C will return you to a prompt, but doesn't currently interrupt a process", "Lots of unfinished work; watch your step"];
145140
- var define_import_meta_env_TIPS_default = ["ecmaos.sh has no backend server; all data is stored and processed entirely in your browser", "If it ever fails to boot, check your logs, try clearing all data, try incognito mode, or try another browser", "You can switch between TTYs using CTRL+SHIFT+<0-9>", "You can run some devices that offer a CLI - e.g. '/dev/battery --help'", "Use the 'install' command to install packages - e.g. 'install @ecmaos-apps/news'", "You can install any NPM package - e.g. 'install jquery'", "You can use the 'mount' command to view and mount filesystems (/etc/fstab supported)", "Use the 'news' command to see the latest news about ecmaOS", "Type 'ls /bin' to see all built-in commands", "Type 'ls /usr/bin' to see all installed commands", "Type 'ls /dev' to see all available devices", "You can set your environment variables in ~/.env (try setting PROMPT to a PS1-like format)", "You can register and login with a passkey: 'passkey register' and 'passkey list'", "The 'man' command can be used to view the manual pages for packages: 'man @ecmaos/kernel'", "Try 'fetch /xkcd-os.sixel'"];
145302
+ var define_import_meta_env_KNOWN_ISSUES_default = ["To disable known issues, type `touch /etc/noissues`", "It's best to stick to Chromium-based browsers for the most features", "Keyboard is broken on mobile; ecmaOS is not mobile-friendly at this time", "Don't expect any sort of POSIX compliance at this stage", "Most commands/devices are very basic implementations, not complete reproductions", "CTRL-C will return you to a prompt, but doesn't currently interrupt a process", "Lots of unfinished work; watch your step"];
145303
+ var define_import_meta_env_TIPS_default = ["To disable tips, type `touch /etc/notips`", "ecmaos.sh has no backend server; all data is stored and processed entirely in your browser", "If it ever fails to boot, check your logs, try clearing all data, try incognito mode, or try another browser", "You can switch between TTYs using CTRL+SHIFT+<0-9>", "You can run some devices that offer a CLI - e.g. '/dev/battery --help'", "Use the 'install' command to install packages - e.g. 'install @ecmaos-apps/news'", "You can install any NPM package - e.g. 'install jquery'", "You can use the 'mount' command to view and mount filesystems (/etc/fstab supported)", "Use the 'news' command to see the latest news about ecmaOS", "Type 'ls /bin' to see all built-in commands", "Type 'ls /usr/bin' to see all installed commands", "Type 'ls /dev' to see all available devices", "You can set your environment variables in ~/.env (try setting PROMPT to a PS1-like format)", "You can register and login with a passkey: 'passkey register' and 'passkey list'", "The 'man' command can be used to view the manual pages for packages: 'man @ecmaos/kernel'", "Try 'fetch /xkcd-os.sixel'"];
145141
145304
  const DefaultKernelOptions = {
145142
145305
  devices: DefaultDevices,
145143
145306
  dom: DefaultDomOptions,
@@ -145179,7 +145342,7 @@ const _Kernel = class _Kernel {
145179
145342
  /** Name of the kernel */
145180
145343
  __publicField(this, "name", "@ecmaos/kernel");
145181
145344
  /** Version string of the kernel */
145182
- __publicField(this, "version", "0.10.2");
145345
+ __publicField(this, "version", "0.10.4");
145183
145346
  /** Authentication and authorization service */
145184
145347
  __publicField(this, "auth");
145185
145348
  /** BIOS module providing low-level functionality */
@@ -145232,8 +145395,6 @@ const _Kernel = class _Kernel {
145232
145395
  __publicField(this, "telemetry");
145233
145396
  /** Terminal interface for user interaction */
145234
145397
  __publicField(this, "terminal");
145235
- /** Toast notification service */
145236
- __publicField(this, "toast");
145237
145398
  /** User management service */
145238
145399
  __publicField(this, "users");
145239
145400
  /** WebAssembly service */
@@ -145271,7 +145432,6 @@ const _Kernel = class _Kernel {
145271
145432
  this.storage = new Storage({ kernel: this });
145272
145433
  this.telemetry = new Telemetry({ kernel: this });
145273
145434
  this.terminal = new Terminal({ kernel: this, socket: this.options.socket, tty: 0 });
145274
- this.toast = new Notyf(this.options.toast);
145275
145435
  this.users = new Users({ kernel: this });
145276
145436
  this.windows = new Windows();
145277
145437
  this.wasm = new Wasm({ kernel: this });
@@ -145477,7 +145637,7 @@ const _Kernel = class _Kernel {
145477
145637
  ];
145478
145638
  this.terminal.writeln(chalk$2.red.bold(`🐉 ${this.i18n.ns.kernel("experimental")} 🐉`));
145479
145639
  this.terminal.writeln(
145480
- `${this.terminal.createSpecialLink("https://ecmaos.sh", "@ecmaos/kernel")}@${"0.10.2"}` + chalk$2.cyan(` [${dependencyLinks.map((link2) => link2.link).join(", ")}]`)
145640
+ `${this.terminal.createSpecialLink("https://ecmaos.sh", "@ecmaos/kernel")}@${"0.10.4"}` + chalk$2.cyan(` [${dependencyLinks.map((link2) => link2.link).join(", ")}]`)
145481
145641
  );
145482
145642
  this.terminal.writeln(`${this.i18n.ns.kernel("madeBy")} ${this.terminal.createSpecialLink(
145483
145643
  define_import_meta_env_AUTHOR_default?.url || "https://github.com/mathiscode",
@@ -145485,7 +145645,7 @@ const _Kernel = class _Kernel {
145485
145645
  )}`);
145486
145646
  this.terminal.writeln("https://github.com/ecmaos/ecmaos\n");
145487
145647
  if (define_import_meta_env_KNOWN_ISSUES_default && false) ;
145488
- if (true) {
145648
+ if (!this.filesystem.fsSync.existsSync("/etc/notips")) {
145489
145649
  const tipsList = this.i18n.ns.kernel("tipsList", { returnObjects: true });
145490
145650
  if (Array.isArray(tipsList) && tipsList.length > 0) {
145491
145651
  this.terminal.writeln(chalk$2.green.bold(this.i18n.ns.kernel("tips")));
@@ -145500,15 +145660,15 @@ const _Kernel = class _Kernel {
145500
145660
  if (logoFiglet && true) {
145501
145661
  console.log(`%c${logoFiglet}`, "color: green");
145502
145662
  console.log(`%c${"https://github.com/ecmaos/ecmaos"}`, "color: blue; text-decoration: underline; font-size: 16px");
145503
- this.log.info(`${"@ecmaos/kernel"} v${"0.10.2"}`);
145663
+ this.log.info(`${"@ecmaos/kernel"} v${"0.10.4"}`);
145504
145664
  }
145505
145665
  if (Notification?.permission === "default") Notification.requestPermission();
145506
145666
  if (Notification?.permission === "denied") this.log.warn(t2("kernel.permissionNotificationDenied", "Notification permission denied"));
145507
145667
  this.intervals.set("title-blink", () => {
145508
145668
  globalThis.document.title = globalThis.document.title.includes("_") ? "ecmaos# " : "ecmaos# _";
145509
145669
  }, 600);
145510
- this.toast.success(`${"@ecmaos/kernel"} v${"0.10.2"}`);
145511
- this._showTtyIndicator(this._activeTty);
145670
+ this.dom.toast.success(`${"@ecmaos/kernel"} v${"0.10.4"}`);
145671
+ this.dom.showTtyIndicator(this._activeTty);
145512
145672
  }
145513
145673
  if (await this.filesystem.fs.exists("/run")) {
145514
145674
  const entries2 = await this.filesystem.fs.readdir("/run");
@@ -145650,7 +145810,7 @@ const _Kernel = class _Kernel {
145650
145810
  this.shell.cwd = localStorage.getItem(`cwd:${this.shell.credentials.uid}`) ?? (user.uid === 0 ? "/" : user.home || "/");
145651
145811
  const userCrontabPath = path$2.join(user.home || "/root", ".config", "crontab");
145652
145812
  await this.loadCrontab(userCrontabPath, "user");
145653
- const screensavers = /* @__PURE__ */ Object.assign({ "./lib/screensavers/blank.ts": __vite_glob_0_0, "./lib/screensavers/matrix.ts": __vite_glob_0_1 });
145813
+ const screensavers = /* @__PURE__ */ Object.assign({ "./lib/screensavers/blank.ts": __vite_glob_0_0, "./lib/screensavers/matrix.ts": __vite_glob_0_1, "./lib/screensavers/toasters.ts": __vite_glob_0_2 });
145654
145814
  for (const [key, saver] of Object.entries(screensavers)) {
145655
145815
  this.screensavers.set(
145656
145816
  key.replace("./lib/screensavers/", "").replace(".ts", ""),
@@ -145720,7 +145880,7 @@ const _Kernel = class _Kernel {
145720
145880
  this.log.error(error2);
145721
145881
  this._state = KernelState.PANIC;
145722
145882
  this.events.dispatch(KernelEvents.PANIC, { error: error2 });
145723
- this.toast.error({
145883
+ this.dom.toast.error({
145724
145884
  message: this.i18n.ns.kernel("panic"),
145725
145885
  duration: 0,
145726
145886
  dismissible: false
@@ -145794,17 +145954,25 @@ const _Kernel = class _Kernel {
145794
145954
  const device = Array.from(this.devices.values()).find((d2) => d2.drivers?.some((driver) => driver.name === options.command.replace(/^\/dev\//, "")));
145795
145955
  if (device) return await this.executeDevice(device.device, options.args);
145796
145956
  }
145797
- const header = await this.readFileHeader(options.command);
145957
+ const header = await this.readFileHeader(options.command, options.shell);
145798
145958
  if (!header) return -1;
145799
145959
  let exitCode = -1;
145800
145960
  switch (header.type) {
145801
145961
  case "wasm":
145802
145962
  exitCode = await this.executeWasm(options);
145803
145963
  break;
145964
+ case "js":
145965
+ exitCode = await this.executeJavaScript(options);
145966
+ break;
145967
+ case "view":
145968
+ exitCode = await this.execute({
145969
+ ...options,
145970
+ command: "/bin/view",
145971
+ args: [options.command, ...options.args || []]
145972
+ });
145973
+ break;
145804
145974
  case "bin":
145805
145975
  switch (header.namespace) {
145806
- case "terminal":
145807
- // left for backward-compatibility
145808
145976
  case "command":
145809
145977
  if (!header.name) return -1;
145810
145978
  exitCode = await this.executeCommand({ ...options, command: header.name });
@@ -146009,7 +146177,7 @@ const _Kernel = class _Kernel {
146009
146177
  const shouldUnlisten = terminal && stdinIsTTY;
146010
146178
  let keyListener = null;
146011
146179
  try {
146012
- const wasmBytes = await this.shell.context.fs.promises.readFile(options.command);
146180
+ const wasmBytes = await options.shell.context.fs.promises.readFile(options.command);
146013
146181
  const needsWasi = await this.wasm.detectWasiRequirements(wasmBytes);
146014
146182
  let stdin2;
146015
146183
  let closeStdin = null;
@@ -146121,13 +146289,13 @@ const _Kernel = class _Kernel {
146121
146289
  * @returns Exit code of the script
146122
146290
  */
146123
146291
  async executeScript(options) {
146124
- const header = await this.readFileHeader(options.command);
146292
+ const header = await this.readFileHeader(options.command, options.shell);
146125
146293
  if (!header) return -1;
146126
146294
  if (header.type !== "bin" || header.namespace !== "script") {
146127
146295
  this.log.error(`File is not a script: ${options.command}`);
146128
146296
  return -1;
146129
146297
  }
146130
- const script = await this.shell.context.fs.promises.readFile(options.command, "utf-8");
146298
+ const script = await options.shell.context.fs.promises.readFile(options.command, "utf-8");
146131
146299
  if (script) {
146132
146300
  const terminalCmdBefore = options.terminal?.cmd || "";
146133
146301
  for (const line3 of script.split("\n")) {
@@ -146142,6 +146310,27 @@ const _Kernel = class _Kernel {
146142
146310
  } else this.log.error(`Script ${options.command} not found`);
146143
146311
  return -1;
146144
146312
  }
146313
+ /**
146314
+ * Executes a JavaScript file
146315
+ * @param options - Execution options containing JavaScript file path and shell
146316
+ * @returns Exit code of the JavaScript execution
146317
+ */
146318
+ async executeJavaScript(options) {
146319
+ try {
146320
+ const code2 = await options.shell.context.fs.promises.readFile(options.command, "utf-8");
146321
+ if (!code2) {
146322
+ this.log.error(`JavaScript file not found or empty: ${options.command}`);
146323
+ return -1;
146324
+ }
146325
+ const script = new Function(code2);
146326
+ script();
146327
+ return 0;
146328
+ } catch (error2) {
146329
+ this.log.error(`Failed to execute JavaScript file: ${error2}`);
146330
+ options.terminal?.writeln(chalk$2.red(error2.message));
146331
+ return -1;
146332
+ }
146333
+ }
146145
146334
  /**
146146
146335
  * Shows a system notification if permissions are granted
146147
146336
  * @param {string} title - Notification title
@@ -146173,9 +146362,10 @@ const _Kernel = class _Kernel {
146173
146362
  /**
146174
146363
  * Reads and parses a file header to determine its type
146175
146364
  * @param {string} filePath - Path to the file
146365
+ * @param {IShell} shell - Optional shell instance to use for filesystem operations
146176
146366
  * @returns {Promise<FileHeader|null>} Parsed header information or null if invalid
146177
146367
  */
146178
- async readFileHeader(filePath) {
146368
+ async readFileHeader(filePath, shell) {
146179
146369
  const parseHeader = /* @__PURE__ */ __name((header) => {
146180
146370
  if (!header.startsWith("#!")) return null;
146181
146371
  if (header.startsWith("#!ecmaos:")) {
@@ -146186,50 +146376,145 @@ const _Kernel = class _Kernel {
146186
146376
  if (header.startsWith("#!/usr/bin/env node")) return { type: "bin", namespace: "node", name: "node" };
146187
146377
  return null;
146188
146378
  }, "parseHeader");
146189
- return new Promise((resolve2, reject) => {
146190
- (async () => {
146191
- try {
146192
- if (!await this.shell.context.fs.promises.exists(filePath)) return resolve2(null);
146193
- const wasmMagicBytes = new Uint8Array([0, 97, 115, 109]);
146194
- try {
146195
- const handle = await this.shell.context.fs.promises.open(filePath, "r");
146196
- const buffer2 = new Uint8Array(4);
146197
- const { bytesRead } = await handle.read(buffer2, 0, 4, 0);
146198
- await handle.close();
146199
- if (bytesRead >= 4) {
146200
- const isWasm = wasmMagicBytes.every((byte, index2) => byte === buffer2[index2]);
146201
- if (isWasm) {
146202
- return resolve2({ type: "wasm" });
146203
- }
146204
- }
146205
- } catch {
146206
- const readable22 = this.shell.context.fs.createReadStream(filePath);
146207
- readable22.on("data", (chunk) => {
146208
- if (chunk.length >= 4) {
146209
- const firstBytes = new Uint8Array(chunk.buffer, chunk.byteOffset, 4);
146210
- const isWasm = wasmMagicBytes.every((byte, index2) => byte === firstBytes[index2]);
146211
- if (isWasm) {
146212
- readable22.destroy();
146213
- return resolve2({ type: "wasm" });
146379
+ const checkMagicBytes = /* @__PURE__ */ __name((buffer2, magicBytes, offset = 0) => {
146380
+ if (buffer2.length < offset + magicBytes.length) return false;
146381
+ return magicBytes.every((byte, index2) => byte === buffer2[offset + index2]);
146382
+ }, "checkMagicBytes");
146383
+ const checkMagicBytesPattern = /* @__PURE__ */ __name((buffer2, pattern2) => {
146384
+ if (pattern2.checker) {
146385
+ return pattern2.checker(buffer2);
146386
+ }
146387
+ return checkMagicBytes(buffer2, pattern2.bytes, pattern2.offset || 0);
146388
+ }, "checkMagicBytesPattern");
146389
+ const shellContext = shell?.context || this.shell.context;
146390
+ try {
146391
+ if (!await shellContext.fs.promises.exists(filePath)) return null;
146392
+ const magicBytesPatterns = [
146393
+ { bytes: new Uint8Array([0, 97, 115, 109]), type: "wasm" },
146394
+ // WebAssembly Binary
146395
+ { bytes: new Uint8Array([255, 216, 255]), type: "view" },
146396
+ // JPEG Image (Start of Image / SOI)
146397
+ { bytes: new Uint8Array([137, 80, 78, 71]), type: "view" },
146398
+ // PNG Image (ASCII ".PNG")
146399
+ { bytes: new Uint8Array([71, 73, 70, 56]), type: "view" },
146400
+ // GIF Image (ASCII "GIF8" - matches GIF87a and GIF89a)
146401
+ { bytes: new Uint8Array([71, 73, 70, 57]), type: "view" },
146402
+ // GIF Image (ASCII "GIF9" - likely a typo intended for GIF89a)
146403
+ { bytes: new Uint8Array([66, 77]), type: "view" },
146404
+ // BMP Image (ASCII "BM" - Windows Bitmap)
146405
+ { bytes: new Uint8Array([37, 80, 68, 70]), type: "view" },
146406
+ // PDF Document (ASCII "%PDF")
146407
+ { bytes: new Uint8Array([102, 76, 97, 67]), type: "view" },
146408
+ // FLAC Audio (ASCII "fLaC")
146409
+ { bytes: new Uint8Array([79, 103, 103, 83]), type: "view" },
146410
+ // Ogg Container (ASCII "OggS" - Vorbis, Theora, etc.)
146411
+ { bytes: new Uint8Array([255, 251]), type: "view" },
146412
+ // MP3 Audio (MPEG-1 Layer 3, No CRC)
146413
+ { bytes: new Uint8Array([255, 243]), type: "view" },
146414
+ // MP3 Audio (MPEG-2 Layer 3, No CRC - Lower sampling rates)
146415
+ { bytes: new Uint8Array([255, 242]), type: "view" },
146416
+ // MP3 Audio (MPEG-2 Layer 3, CRC Protected)
146417
+ { bytes: new Uint8Array([73, 68, 51]), type: "view" },
146418
+ // MP3 Metadata (ID3v2 container - often at start of MP3)
146419
+ { bytes: new Uint8Array([26, 69, 223, 163]), type: "view" },
146420
+ // Matroska / WebM (EBML Header ID)
146421
+ {
146422
+ bytes: new Uint8Array([82, 73, 70, 70]),
146423
+ // RIFF (ASCII "RIFF")
146424
+ type: "view",
146425
+ checker: /* @__PURE__ */ __name((buf) => {
146426
+ if (buf.length < 12) return false;
146427
+ if (!checkMagicBytes(buf, new Uint8Array([82, 73, 70, 70]))) return false;
146428
+ const avi = new Uint8Array([65, 86, 73, 32]);
146429
+ const webp = new Uint8Array([87, 69, 66, 80]);
146430
+ const wave = new Uint8Array([87, 65, 86, 69]);
146431
+ return checkMagicBytes(buf, avi, 8) || checkMagicBytes(buf, webp, 8) || checkMagicBytes(buf, wave, 8);
146432
+ }, "checker")
146433
+ },
146434
+ {
146435
+ bytes: new Uint8Array([0]),
146436
+ // MP4 Video (ASCII "MP4V")
146437
+ type: "view",
146438
+ checker: /* @__PURE__ */ __name((buf) => {
146439
+ if (buf.length < 8) return false;
146440
+ const ftyp = new Uint8Array([102, 116, 121, 112]);
146441
+ return checkMagicBytes(buf, ftyp, 4);
146442
+ }, "checker")
146443
+ }
146444
+ ];
146445
+ const maxMagicBytesLength = Math.max(12, ...magicBytesPatterns.map((p2) => (p2.offset || 0) + p2.bytes.length));
146446
+ let handle;
146447
+ let firstBytes = null;
146448
+ const checkExtensionType = /* @__PURE__ */ __name((filePath2) => {
146449
+ if (filePath2.endsWith(".js")) return "js";
146450
+ else if (filePath2.endsWith(".md")) return "view";
146451
+ else if (filePath2.endsWith(".json")) return "view";
146452
+ else if (filePath2.endsWith(".txt")) return "view";
146453
+ else return "application/octet-stream";
146454
+ }, "checkExtensionType");
146455
+ try {
146456
+ handle = await shellContext.fs.promises.open(filePath, "r");
146457
+ const buffer2 = new Uint8Array(maxMagicBytesLength);
146458
+ const result = await handle.read(buffer2, 0, maxMagicBytesLength, 0);
146459
+ if (result.bytesRead >= maxMagicBytesLength) firstBytes = buffer2;
146460
+ } catch {
146461
+ const readable2 = shellContext.fs.createReadStream(filePath);
146462
+ return new Promise((resolve2, reject) => {
146463
+ let firstChunk = null;
146464
+ readable2.on("data", (chunk) => {
146465
+ if (firstChunk === null) {
146466
+ firstChunk = chunk;
146467
+ if (chunk.length >= maxMagicBytesLength) {
146468
+ const chunkBytes = new Uint8Array(chunk.buffer, chunk.byteOffset, maxMagicBytesLength);
146469
+ for (const pattern2 of magicBytesPatterns) {
146470
+ if (checkMagicBytesPattern(chunkBytes, pattern2)) {
146471
+ readable2.destroy();
146472
+ return resolve2({ type: pattern2.type });
146473
+ }
146214
146474
  }
146215
146475
  }
146216
- resolve2(parseHeader(chunk.toString().split("\n")[0] || ""));
146217
- readable22.destroy();
146218
- });
146219
- readable22.on("error", (error2) => reject(error2));
146220
- readable22.on("close", () => resolve2(null));
146221
- return;
146222
- }
146223
- const readable2 = this.shell.context.fs.createReadStream(filePath);
146224
- readable2.on("data", (chunk) => resolve2(parseHeader(chunk.toString().split("\n")[0] || "")));
146476
+ const firstLine = chunk.toString().split("\n")[0] || "";
146477
+ const header = parseHeader(firstLine);
146478
+ if (header) {
146479
+ readable2.destroy();
146480
+ return resolve2(header);
146481
+ }
146482
+ readable2.destroy();
146483
+ const extensionType2 = checkExtensionType(filePath);
146484
+ return extensionType2 ? resolve2({ type: extensionType2 }) : resolve2(null);
146485
+ }
146486
+ });
146225
146487
  readable2.on("error", (error2) => reject(error2));
146226
- readable2.on("close", () => resolve2(null));
146227
- } catch (error2) {
146228
- this.log.error(error2);
146229
- reject(error2);
146488
+ readable2.on("close", () => {
146489
+ readable2.destroy();
146490
+ const extensionType2 = checkExtensionType(filePath);
146491
+ return extensionType2 ? resolve2({ type: extensionType2 }) : resolve2(null);
146492
+ });
146493
+ });
146494
+ }
146495
+ if (!handle) return null;
146496
+ if (firstBytes) {
146497
+ for (const pattern2 of magicBytesPatterns) {
146498
+ if (checkMagicBytesPattern(firstBytes, pattern2)) {
146499
+ await handle.close();
146500
+ return { type: pattern2.type };
146501
+ }
146230
146502
  }
146231
- })();
146232
- });
146503
+ }
146504
+ const firstLineBuffer = new Uint8Array(512);
146505
+ const firstLineResult = await handle.read(firstLineBuffer, 0, 512, 0);
146506
+ await handle.close();
146507
+ if (firstLineResult.bytesRead > 0) {
146508
+ const firstLine = new TextDecoder().decode(firstLineBuffer.slice(0, firstLineResult.bytesRead)).split("\n")[0] || "";
146509
+ const header = parseHeader(firstLine);
146510
+ if (header) return header;
146511
+ }
146512
+ const extensionType = checkExtensionType(filePath);
146513
+ return extensionType ? { type: extensionType } : null;
146514
+ } catch (error2) {
146515
+ this.log.error(error2);
146516
+ throw error2;
146517
+ }
146233
146518
  }
146234
146519
  /**
146235
146520
  * Reboots the kernel by performing a shutdown and page reload
@@ -146275,6 +146560,27 @@ const _Kernel = class _Kernel {
146275
146560
  switch (event) {
146276
146561
  case KernelEvents.PANIC:
146277
146562
  this.log.fatal("KernelPanic:", detail);
146563
+ if (this.telemetry.active) {
146564
+ const tracer = this.telemetry.getTracer("ecmaos.kernel", this.version);
146565
+ const panicSpan = tracer.startSpan("kernel.panic", {
146566
+ attributes: {
146567
+ "kernel.id": this.id,
146568
+ "kernel.state": this._state,
146569
+ "kernel.version": this.version
146570
+ }
146571
+ });
146572
+ const panicDetail = detail;
146573
+ if (panicDetail?.error) {
146574
+ panicSpan.recordException(panicDetail.error);
146575
+ panicSpan.setStatus({ code: 2, message: panicDetail.error.message });
146576
+ panicSpan.setAttribute("error.name", panicDetail.error.name);
146577
+ panicSpan.setAttribute("error.message", panicDetail.error.message);
146578
+ if (panicDetail.error.stack) {
146579
+ panicSpan.setAttribute("error.stack", panicDetail.error.stack);
146580
+ }
146581
+ }
146582
+ panicSpan.end();
146583
+ }
146278
146584
  break;
146279
146585
  }
146280
146586
  });
@@ -146451,7 +146757,7 @@ const _Kernel = class _Kernel {
146451
146757
  memory: "?",
146452
146758
  platform: navigator.userAgentData?.platform || navigator?.platform || navigator.userAgent,
146453
146759
  querystring: location.search,
146454
- version: `${"@ecmaos/kernel"} ${"0.10.2"}`,
146760
+ version: `${"@ecmaos/kernel"} ${"0.10.4"}`,
146455
146761
  language: navigator.language,
146456
146762
  host: location.host,
146457
146763
  userAgent: navigator.userAgent,
@@ -146869,7 +147175,7 @@ const _Kernel = class _Kernel {
146869
147175
  }
146870
147176
  const targetContainer = document.getElementById(`terminal-tty${ttyNumber}`);
146871
147177
  if (targetContainer) targetContainer.classList.add("active");
146872
- this._showTtyIndicator(ttyNumber);
147178
+ this.dom.showTtyIndicator(ttyNumber);
146873
147179
  let targetShell = this._shells.get(ttyNumber);
146874
147180
  if (!targetShell) targetShell = await this.createShell(ttyNumber);
146875
147181
  requestAnimationFrame(() => {
@@ -146878,26 +147184,6 @@ const _Kernel = class _Kernel {
146878
147184
  targetShell.terminal.listen();
146879
147185
  });
146880
147186
  }
146881
- /**
146882
- * Shows a quick flash indicator for the TTY number in the top-right corner
146883
- * @param ttyNumber - TTY number to display
146884
- */
146885
- _showTtyIndicator(ttyNumber) {
146886
- const existingIndicator = document.getElementById("tty-indicator");
146887
- if (existingIndicator) existingIndicator.remove();
146888
- const indicator = document.createElement("div");
146889
- indicator.id = "tty-indicator";
146890
- indicator.className = "tty-indicator";
146891
- indicator.textContent = `TTY ${ttyNumber}`;
146892
- document.body.appendChild(indicator);
146893
- requestAnimationFrame(() => indicator.classList.add("show"));
146894
- setTimeout(() => {
146895
- indicator.classList.remove("show");
146896
- setTimeout(() => {
146897
- if (indicator.parentNode) indicator.remove();
146898
- }, 300);
146899
- }, 1500);
146900
- }
146901
147187
  /**
146902
147188
  * Executes an operation with root (or other) privileges
146903
147189
  * @param {() => Promise<T>} operation - Operation to execute
@@ -147005,4 +147291,4 @@ export {
147005
147291
  semver as s,
147006
147292
  types$1 as t
147007
147293
  };
147008
- //# sourceMappingURL=kernel-Io5VyIzi.js.map
147294
+ //# sourceMappingURL=kernel-M80zlY8S.js.map