@lasso-ai/cli 1.1.0 → 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/overlay.js CHANGED
@@ -4609,7 +4609,7 @@
4609
4609
  }(ElementContainer)
4610
4610
  );
4611
4611
  var LIST_OWNERS = ["OL", "UL", "MENU"];
4612
- var parseNodeTree = function(context, node, parent, root) {
4612
+ var parseNodeTree = function(context, node, parent, root2) {
4613
4613
  for (var childNode = node.firstChild, nextNode = void 0; childNode; childNode = nextNode) {
4614
4614
  nextNode = childNode.nextSibling;
4615
4615
  if (isTextNode(childNode) && childNode.data.trim().length > 0) {
@@ -4617,12 +4617,12 @@
4617
4617
  } else if (isElementNode(childNode)) {
4618
4618
  if (isSlotElement(childNode) && childNode.assignedNodes) {
4619
4619
  childNode.assignedNodes().forEach(function(childNode2) {
4620
- return parseNodeTree(context, childNode2, parent, root);
4620
+ return parseNodeTree(context, childNode2, parent, root2);
4621
4621
  });
4622
4622
  } else {
4623
4623
  var container = createContainer(context, childNode);
4624
4624
  if (container.styles.isVisible()) {
4625
- if (createsRealStackingContext(childNode, container, root)) {
4625
+ if (createsRealStackingContext(childNode, container, root2)) {
4626
4626
  container.flags |= 4;
4627
4627
  } else if (createsStackingContext(container.styles)) {
4628
4628
  container.flags |= 2;
@@ -4633,9 +4633,9 @@
4633
4633
  parent.elements.push(container);
4634
4634
  childNode.slot;
4635
4635
  if (childNode.shadowRoot) {
4636
- parseNodeTree(context, childNode.shadowRoot, container, root);
4636
+ parseNodeTree(context, childNode.shadowRoot, container, root2);
4637
4637
  } else if (!isTextareaElement(childNode) && !isSVGElement(childNode) && !isSelectElement(childNode)) {
4638
- parseNodeTree(context, childNode, container, root);
4638
+ parseNodeTree(context, childNode, container, root2);
4639
4639
  }
4640
4640
  }
4641
4641
  }
@@ -4678,8 +4678,8 @@
4678
4678
  parseNodeTree(context, element, container, container);
4679
4679
  return container;
4680
4680
  };
4681
- var createsRealStackingContext = function(node, container, root) {
4682
- return container.styles.isPositionedWithZIndex() || container.styles.opacity < 1 || container.styles.isTransformed() || isBodyElement(node) && root.styles.isTransparent();
4681
+ var createsRealStackingContext = function(node, container, root2) {
4682
+ return container.styles.isPositionedWithZIndex() || container.styles.opacity < 1 || container.styles.isTransformed() || isBodyElement(node) && root2.styles.isTransparent();
4683
4683
  };
4684
4684
  var createsStackingContext = function(styles) {
4685
4685
  return styles.isPositioned() || styles.isFloating();
@@ -6263,11 +6263,11 @@
6263
6263
  };
6264
6264
  var parseStackingContexts = function(container) {
6265
6265
  var paintContainer = new ElementPaint(container, null);
6266
- var root = new StackingContext(paintContainer);
6266
+ var root2 = new StackingContext(paintContainer);
6267
6267
  var listItems = [];
6268
- parseStackTree(paintContainer, root, root, listItems);
6268
+ parseStackTree(paintContainer, root2, root2, listItems);
6269
6269
  processListItems(paintContainer.container, listItems);
6270
- return root;
6270
+ return root2;
6271
6271
  };
6272
6272
  var parsePathForBorder = function(curves, borderSide) {
6273
6273
  switch (borderSide) {
@@ -7711,7 +7711,7 @@
7711
7711
  }
7712
7712
  var renderElement = function(element, opts) {
7713
7713
  return __awaiter(void 0, void 0, void 0, function() {
7714
- var ownerDocument, defaultView, resourceOptions, contextOptions, windowOptions, windowBounds, context, foreignObjectRendering, cloneOptions, documentCloner, clonedElement, container, _a, width, height, left, top, backgroundColor2, renderOptions, canvas, renderer, root, renderer;
7714
+ var ownerDocument, defaultView, resourceOptions, contextOptions, windowOptions, windowBounds, context, foreignObjectRendering, cloneOptions, documentCloner, clonedElement, container, _a, width, height, left, top, backgroundColor2, renderOptions, canvas, renderer, root2, renderer;
7715
7715
  var _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
7716
7716
  return __generator(this, function(_u) {
7717
7717
  switch (_u.label) {
@@ -7780,13 +7780,13 @@
7780
7780
  case 3:
7781
7781
  context.logger.debug("Document cloned, element located at " + left + "," + top + " with size " + width + "x" + height + " using computed rendering");
7782
7782
  context.logger.debug("Starting DOM parsing");
7783
- root = parseTree(context, clonedElement);
7784
- if (backgroundColor2 === root.styles.backgroundColor) {
7785
- root.styles.backgroundColor = COLORS.TRANSPARENT;
7783
+ root2 = parseTree(context, clonedElement);
7784
+ if (backgroundColor2 === root2.styles.backgroundColor) {
7785
+ root2.styles.backgroundColor = COLORS.TRANSPARENT;
7786
7786
  }
7787
7787
  context.logger.debug("Starting renderer for element at " + renderOptions.x + "," + renderOptions.y + " with size " + renderOptions.width + "x" + renderOptions.height);
7788
7788
  renderer = new CanvasRenderer(context, renderOptions);
7789
- return [4, renderer.render(root)];
7789
+ return [4, renderer.render(root2)];
7790
7790
  case 4:
7791
7791
  canvas = _u.sent();
7792
7792
  _u.label = 5;
@@ -8115,7 +8115,7 @@
8115
8115
  align-items: center;
8116
8116
  gap: 6px;
8117
8117
  height: 34px;
8118
- padding: 0 11px;
8118
+ padding: 0 12px;
8119
8119
  border: 0;
8120
8120
  border-radius: var(--lo-radius-full);
8121
8121
  background: var(--lo-primary);
@@ -8126,22 +8126,62 @@
8126
8126
  cursor: pointer;
8127
8127
  transition: transform 150ms ease, filter 150ms ease;
8128
8128
  }
8129
- .lasso-new-page-btn span:first-child { font-size: 19px; font-weight: 400; line-height: 1; }
8130
8129
  .lasso-new-page-btn:hover { filter: brightness(1.08); transform: translateY(-1px); }
8131
8130
  .lasso-new-page-btn:active { transform: scale(.97); }
8132
- .lasso-new-page-panel { position: fixed; left: calc(50% + 280px); bottom: 82px; width: 310px; max-width: calc(100vw - 24px); padding: 14px; border: 1px solid var(--lo-border); border-radius: var(--lo-radius-lg); background: var(--lo-surface); color: var(--lo-text); box-shadow: var(--lo-shadow-lg); pointer-events: auto; z-index: 20; }
8133
- .lasso-new-page-panel[hidden] { display: none; }
8134
- .lasso-new-page-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; font-size: 13px; }
8135
- .lasso-new-page-close { border: 0; background: transparent; color: var(--lo-text-3); font-size: 20px; line-height: 1; cursor: pointer; }
8136
- .lasso-new-page-panel label { display: block; margin: 9px 0; color: var(--lo-text-2); font-size: 11px; }
8137
- .lasso-new-page-name, .lasso-new-page-content { width: 100%; box-sizing: border-box; margin-top: 5px; padding: 8px; border: 1px solid var(--lo-border); border-radius: var(--lo-radius-md); background: var(--lo-surface-2); color: var(--lo-text); font: inherit; font-size: 12px; }
8138
- .lasso-new-page-content { resize: vertical; line-height: 1.4; }
8139
- .lasso-page-folder-list { display: flex; flex-direction: column; gap: 3px; max-height: 130px; margin-top: 5px; padding: 4px; overflow: auto; border: 1px solid var(--lo-border); border-radius: var(--lo-radius-md); background: var(--lo-surface-2); }
8140
- .lasso-page-folder-list button { padding: 6px 8px; border: 0; border-radius: 5px; background: transparent; color: var(--lo-text-2); text-align: left; font: inherit; font-size: 11px; cursor: pointer; }
8141
- .lasso-page-folder-list button:hover, .lasso-page-folder-list button.selected { background: var(--lo-surface-hover); color: var(--lo-text); }
8142
- .lasso-new-page-status { min-height: 16px; margin: 7px 0; color: var(--lo-text-3); font-size: 11px; }
8143
- .lasso-new-page-status.error { color: #f87171; }
8144
- .lasso-new-page-create { width: 100%; padding: 8px; border: 0; border-radius: var(--lo-radius-full); background: var(--lo-primary); color: #111214; font: inherit; font-size: 12px; font-weight: 650; cursor: pointer; }
8131
+
8132
+ /* ==========================================================
8133
+ NEW PAGE \u2014 nested project explorer
8134
+ ========================================================== */
8135
+ .lasso-page-backdrop { position: fixed; inset: 0; z-index: 30; display: flex; align-items: center; justify-content: center; padding: 16px; background: rgba(8, 9, 11, 0.5); backdrop-filter: blur(3px); -webkit-backdrop-filter: blur(3px); pointer-events: auto; }
8136
+ .lasso-page-backdrop[hidden] { display: none; }
8137
+ .lasso-page-panel { display: flex; flex-direction: column; width: min(400px, 100%); max-height: calc(100vh - 32px); padding: 16px; border: 1px solid var(--lo-border); border-radius: var(--lo-radius-xl); background: var(--lo-surface); color: var(--lo-text); box-shadow: var(--lo-shadow-lg); pointer-events: auto; animation: lasso-page-in 170ms cubic-bezier(0.16, 1, 0.3, 1); }
8138
+ @keyframes lasso-page-in { from { opacity: 0; transform: translateY(10px) scale(0.98); } to { opacity: 1; transform: none; } }
8139
+ .lasso-page-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 14px; }
8140
+ .lasso-page-title-row { display: flex; align-items: center; gap: 7px; color: var(--lo-text); }
8141
+ .lasso-page-title { font-size: 13px; font-weight: 650; letter-spacing: -0.01em; }
8142
+ .lasso-page-close { display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; border: 0; border-radius: 6px; background: transparent; color: var(--lo-text-3); cursor: pointer; transition: background 120ms, color 120ms; }
8143
+ .lasso-page-close:hover { background: var(--lo-surface-hover); color: var(--lo-text); }
8144
+ .lasso-page-field { display: block; margin-bottom: 13px; }
8145
+ .lasso-page-label-text { display: block; margin-bottom: 6px; color: var(--lo-text-3); font-size: 10.5px; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; }
8146
+ .lasso-page-name { width: 100%; box-sizing: border-box; padding: 9px 11px; border: 1px solid var(--lo-border); border-radius: var(--lo-radius-md); background: var(--lo-surface-2); color: var(--lo-text); font: inherit; font-size: 12.5px; }
8147
+ .lasso-page-name::placeholder, .lasso-page-filter::placeholder, .lasso-page-inline-input::placeholder { color: var(--lo-text-3); }
8148
+ .lasso-page-name:focus, .lasso-page-filter:focus, .lasso-page-inline-input:focus { outline: none; border-color: var(--lo-primary); box-shadow: 0 0 0 3px var(--lo-primary-soft); }
8149
+ .lasso-page-name.invalid { border-color: var(--lo-error); }
8150
+ .lasso-page-field-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 6px; }
8151
+ .lasso-page-field-head .lasso-page-label-text { margin-bottom: 0; }
8152
+ .lasso-page-field-tools { display: flex; align-items: center; gap: 5px; }
8153
+ .lasso-page-filter { width: 96px; box-sizing: border-box; padding: 4px 8px; border: 1px solid var(--lo-border); border-radius: var(--lo-radius-full); background: var(--lo-surface-2); color: var(--lo-text); font: inherit; font-size: 11px; }
8154
+ .lasso-page-new-folder { display: inline-flex; align-items: center; justify-content: center; width: 22px; height: 22px; border: 1px solid var(--lo-border); border-radius: 6px; background: var(--lo-surface-2); color: var(--lo-text-2); cursor: pointer; transition: background 120ms, color 120ms; }
8155
+ .lasso-page-new-folder:hover { background: var(--lo-surface-hover); color: var(--lo-text); }
8156
+ .lasso-page-tree { max-height: 240px; overflow: auto; padding: 5px; border: 1px solid var(--lo-border); border-radius: var(--lo-radius-md); background: var(--lo-surface-2); }
8157
+ .lasso-page-row { display: flex; align-items: center; gap: 4px; min-height: 24px; padding-left: calc(4px + var(--lasso-page-depth, 0) * 13px); padding-right: 4px; border-radius: 5px; color: var(--lo-text-2); font: inherit; font-size: 12px; cursor: pointer; user-select: none; }
8158
+ .lasso-page-row:hover { background: var(--lo-surface-hover); color: var(--lo-text); }
8159
+ .lasso-page-row.selected { background: var(--lo-primary-soft); color: var(--lo-text); box-shadow: inset 2px 0 0 var(--lo-primary); }
8160
+ .lasso-page-row.muted { color: var(--lo-text-3); font-size: 11px; font-style: italic; cursor: default; }
8161
+ .lasso-page-row.muted:hover { background: transparent; color: var(--lo-text-3); }
8162
+ .lasso-page-row.creating { cursor: default; }
8163
+ .lasso-page-row.creating:hover { background: transparent; }
8164
+ .lasso-page-twisty { display: inline-flex; align-items: center; justify-content: center; width: 14px; height: 14px; flex: 0 0 auto; color: var(--lo-text-3); transition: transform 120ms ease; }
8165
+ .lasso-page-twisty.open { transform: rotate(90deg); }
8166
+ .lasso-page-twisty svg { width: 11px; height: 11px; }
8167
+ .lasso-page-icon { display: inline-flex; align-items: center; justify-content: center; width: 14px; height: 14px; flex: 0 0 auto; }
8168
+ .lasso-page-icon svg { width: 14px; height: 14px; }
8169
+ .lasso-page-icon.folder { color: var(--lo-primary); }
8170
+ .lasso-page-icon.file { color: var(--lo-text-3); }
8171
+ .lasso-page-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
8172
+ .lasso-page-inline-input { min-width: 0; flex: 1; padding: 3px 6px; border: 1px solid var(--lo-primary); border-radius: 5px; background: var(--lo-surface); color: var(--lo-text); font: inherit; font-size: 12px; }
8173
+ .lasso-page-inline-confirm, .lasso-page-inline-cancel { display: inline-flex; align-items: center; justify-content: center; width: 20px; height: 20px; flex: 0 0 auto; padding: 0; border: 0; border-radius: 5px; cursor: pointer; }
8174
+ .lasso-page-inline-confirm { background: var(--lo-primary-soft); color: var(--lo-primary); }
8175
+ .lasso-page-inline-cancel { background: transparent; color: var(--lo-text-3); }
8176
+ .lasso-page-inline-confirm:hover, .lasso-page-inline-cancel:hover { filter: brightness(1.2); }
8177
+ .lasso-page-inline-confirm svg, .lasso-page-inline-cancel svg { width: 12px; height: 12px; }
8178
+ .lasso-page-footer { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
8179
+ .lasso-page-status { min-width: 0; flex: 1; color: var(--lo-text-3); font-size: 11px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
8180
+ .lasso-page-status.error { color: var(--lo-error); }
8181
+ .lasso-page-create { flex: 0 0 auto; padding: 8px 15px; border: 0; border-radius: var(--lo-radius-full); background: var(--lo-primary); color: #111214; font: inherit; font-size: 12px; font-weight: 650; cursor: pointer; transition: filter 120ms, opacity 120ms; }
8182
+ .lasso-page-create:disabled { opacity: 0.45; cursor: not-allowed; }
8183
+ .lasso-page-create:not(:disabled):hover { filter: brightness(1.08); }
8184
+ @media (max-width: 600px) { .lasso-page-panel { width: 100%; } }
8145
8185
 
8146
8186
  .lasso-tb-sep {
8147
8187
  width: 1px;
@@ -11017,14 +11057,26 @@
11017
11057
  .lasso-task-apply { padding: 7px 11px; border: 0; border-radius: var(--lo-radius-full); background: var(--lo-primary); color: #111214; font: inherit; font-size: 11px; font-weight: 600; cursor: pointer; }
11018
11058
 
11019
11059
  .lasso-agent-tasks-badge { position: absolute; top: 5px; right: 5px; width: 6px; height: 6px; border-radius: 50%; background: var(--lo-primary); }
11020
- .lasso-agent-prompt { position: fixed; left: 50%; top: 50%; width: min(360px, calc(100vw - 32px)); transform: translate(-50%, -50%); padding: 16px; border: 1px solid var(--lo-border); border-radius: var(--lo-radius-lg); background: var(--lo-surface); color: var(--lo-text); box-shadow: 0 18px 60px rgba(0,0,0,.42); z-index: 80; }
11021
- .lasso-agent-prompt[hidden] { display: none; }
11022
- .lasso-agent-prompt-title { margin-bottom: 7px; font-size: 13px; font-weight: 700; }
11023
- .lasso-agent-prompt-message { margin-bottom: 12px; color: var(--lo-text-2); font-size: 12px; line-height: 1.45; white-space: pre-wrap; }
11024
- .lasso-agent-prompt-input { width: 100%; box-sizing: border-box; margin-bottom: 12px; padding: 8px 10px; border: 1px solid var(--lo-border); border-radius: var(--lo-radius-md); background: var(--lo-surface-2); color: var(--lo-text); font: inherit; font-size: 12px; }
11060
+ .lasso-agent-prompt-backdrop { position: fixed; inset: 0; z-index: 80; display: flex; align-items: center; justify-content: center; padding: 16px; background: rgba(8, 9, 11, 0.55); backdrop-filter: blur(3px); -webkit-backdrop-filter: blur(3px); pointer-events: auto; }
11061
+ .lasso-agent-prompt-backdrop[hidden] { display: none; }
11062
+ .lasso-agent-prompt { display: flex; flex-direction: column; width: min(420px, 100%); max-height: calc(100vh - 32px); overflow: auto; padding: 16px; border: 1px solid var(--lo-border); border-radius: var(--lo-radius-lg); background: var(--lo-surface); color: var(--lo-text); box-shadow: var(--lo-shadow-lg); pointer-events: auto; animation: lasso-agent-prompt-in 160ms cubic-bezier(0.16, 1, 0.3, 1); }
11063
+ @keyframes lasso-agent-prompt-in { from { opacity: 0; transform: translateY(8px) scale(0.98); } to { opacity: 1; transform: none; } }
11064
+ .lasso-agent-prompt-head { display: flex; align-items: flex-start; gap: 10px; margin-bottom: 12px; }
11065
+ .lasso-agent-prompt-mark { display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; flex: 0 0 auto; border-radius: 8px; background: var(--lo-primary-soft); color: var(--lo-primary); }
11066
+ .lasso-agent-prompt-mark svg { width: 15px; height: 15px; }
11067
+ .lasso-agent-prompt-headings { min-width: 0; flex: 1; }
11068
+ .lasso-agent-prompt-title { font-size: 13px; font-weight: 650; letter-spacing: -0.01em; }
11069
+ .lasso-agent-prompt-subtitle { margin-top: 2px; color: var(--lo-text-3); font-size: 11px; }
11070
+ .lasso-agent-prompt-close { display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; flex: 0 0 auto; border: 0; border-radius: 6px; background: transparent; color: var(--lo-text-3); cursor: pointer; transition: background 120ms, color 120ms; }
11071
+ .lasso-agent-prompt-close:hover { background: var(--lo-surface-hover); color: var(--lo-text); }
11072
+ .lasso-agent-prompt-message { max-height: 220px; margin-bottom: 14px; padding: 10px 11px; overflow: auto; border: 1px solid var(--lo-border); border-radius: var(--lo-radius-md); background: var(--lo-surface-2); color: var(--lo-text-2); font: inherit; font-size: 12px; line-height: 1.5; overflow-wrap: anywhere; user-select: text; }
11073
+ .lasso-agent-prompt-input { width: 100%; box-sizing: border-box; margin-bottom: 12px; padding: 9px 11px; border: 1px solid var(--lo-border); border-radius: var(--lo-radius-md); background: var(--lo-surface-2); color: var(--lo-text); font: inherit; font-size: 12px; }
11074
+ .lasso-agent-prompt-input[hidden] { display: none; }
11025
11075
  .lasso-agent-prompt-actions { display: flex; justify-content: flex-end; gap: 7px; }
11026
- .lasso-agent-prompt-actions button { padding: 7px 11px; border: 0; border-radius: var(--lo-radius-full); background: var(--lo-surface-2); color: var(--lo-text); font: inherit; font-size: 11px; cursor: pointer; }
11027
- .lasso-agent-prompt-actions button[data-agent-response="Allow"], .lasso-agent-prompt-actions button[data-agent-response="input"] { background: var(--lo-primary); color: #111214; font-weight: 600; }
11076
+ .lasso-agent-prompt-actions button { padding: 7px 13px; border: 0; border-radius: var(--lo-radius-full); background: var(--lo-surface-2); color: var(--lo-text); font: inherit; font-size: 11.5px; font-weight: 500; cursor: pointer; transition: filter 120ms, transform 120ms; }
11077
+ .lasso-agent-prompt-actions button:hover { filter: brightness(1.12); }
11078
+ .lasso-agent-prompt-actions button:active { transform: scale(0.97); }
11079
+ .lasso-agent-prompt-actions button.primary { background: var(--lo-primary); color: #111214; font-weight: 600; }
11028
11080
 
11029
11081
  .lasso-todo-header {
11030
11082
  display: flex;
@@ -12386,15 +12438,15 @@
12386
12438
  return panel;
12387
12439
  }
12388
12440
  function renderTasks() {
12389
- const panelEl = panel;
12390
- if (!panelEl || !list || !badge) return;
12441
+ const panelEl2 = panel;
12442
+ if (!panelEl2 || !list || !badge) return;
12391
12443
  const activeCount = state.agentTasks.filter((task) => task.status !== "complete" && task.status !== "error" && task.status !== "stopped").length;
12392
12444
  badge.hidden = state.agentTasks.length === 0;
12393
12445
  badge.textContent = String(activeCount || state.agentTasks.length);
12394
12446
  const navBadge = getDOM().shadow.querySelector(".lasso-agent-tasks-badge");
12395
12447
  if (navBadge) navBadge.hidden = activeCount === 0;
12396
12448
  list.replaceChildren();
12397
- const activeTab = panelEl.querySelector(".lasso-task-tab.active")?.dataset.taskTab || "active";
12449
+ const activeTab = panelEl2.querySelector(".lasso-task-tab.active")?.dataset.taskTab || "active";
12398
12450
  const visibleTasks = state.agentTasks.filter((task) => activeTab === "complete" ? task.status === "complete" : task.status !== "complete");
12399
12451
  if (!visibleTasks.length) {
12400
12452
  list.innerHTML = `<div class="lasso-task-empty">Prompt an element to start a task.</div>`;
@@ -17782,7 +17834,7 @@
17782
17834
  const textarea = el.querySelector(".lasso-notepad-textarea");
17783
17835
  const preview = el.querySelector(".lasso-notepad-preview");
17784
17836
  const countEl = el.querySelector(".lasso-notepad-count");
17785
- const statusEl = el.querySelector(".lasso-notepad-status");
17837
+ const statusEl2 = el.querySelector(".lasso-notepad-status");
17786
17838
  textarea.value = initialContent;
17787
17839
  collabEmit("note:get", {}, (response) => {
17788
17840
  if (response.ok && typeof response.body === "string") {
@@ -17804,7 +17856,7 @@
17804
17856
  voiceBtn.classList.remove("recording");
17805
17857
  voiceBtn.classList.add("transcribing");
17806
17858
  voiceBtn.title = "Transcribing\u2026";
17807
- statusEl.textContent = "Transcribing\u2026";
17859
+ statusEl2.textContent = "Transcribing\u2026";
17808
17860
  try {
17809
17861
  const result = await stopVoiceRecording();
17810
17862
  if (result.text) {
@@ -17818,20 +17870,20 @@
17818
17870
  textarea.setSelectionRange(cursor, cursor);
17819
17871
  textarea.dispatchEvent(new Event("input"));
17820
17872
  textarea.focus();
17821
- statusEl.textContent = "Transcribed";
17873
+ statusEl2.textContent = "Transcribed";
17822
17874
  window.setTimeout(() => {
17823
- statusEl.textContent = "Autosaved";
17875
+ statusEl2.textContent = "Autosaved";
17824
17876
  }, 2e3);
17825
17877
  } else {
17826
- statusEl.textContent = "No speech detected";
17878
+ statusEl2.textContent = "No speech detected";
17827
17879
  window.setTimeout(() => {
17828
- statusEl.textContent = "Autosaved";
17880
+ statusEl2.textContent = "Autosaved";
17829
17881
  }, 1500);
17830
17882
  }
17831
17883
  } catch (err) {
17832
- statusEl.textContent = err?.message || "Transcription failed";
17884
+ statusEl2.textContent = err?.message || "Transcription failed";
17833
17885
  window.setTimeout(() => {
17834
- statusEl.textContent = "Autosaved";
17886
+ statusEl2.textContent = "Autosaved";
17835
17887
  }, 2500);
17836
17888
  } finally {
17837
17889
  voiceBtn.classList.remove("transcribing");
@@ -17842,11 +17894,11 @@
17842
17894
  await startVoiceRecording();
17843
17895
  voiceBtn.classList.add("recording");
17844
17896
  voiceBtn.title = "Recording\u2026 click again to stop & transcribe";
17845
- statusEl.textContent = "Listening\u2026";
17897
+ statusEl2.textContent = "Listening\u2026";
17846
17898
  } catch (err) {
17847
- statusEl.textContent = err?.message || "Microphone access denied";
17899
+ statusEl2.textContent = err?.message || "Microphone access denied";
17848
17900
  window.setTimeout(() => {
17849
- statusEl.textContent = "Autosaved";
17901
+ statusEl2.textContent = "Autosaved";
17850
17902
  }, 3e3);
17851
17903
  }
17852
17904
  }
@@ -17870,11 +17922,11 @@
17870
17922
  textarea.addEventListener("input", () => {
17871
17923
  const text = textarea.value;
17872
17924
  updateCounts(text.length, countEl);
17873
- statusEl.textContent = "Saving\u2026";
17925
+ statusEl2.textContent = "Saving\u2026";
17874
17926
  if (saveTimer) window.clearTimeout(saveTimer);
17875
17927
  saveTimer = window.setTimeout(() => {
17876
17928
  saveNote(text);
17877
- statusEl.textContent = "Autosaved";
17929
+ statusEl2.textContent = "Autosaved";
17878
17930
  }, 400);
17879
17931
  });
17880
17932
  copyBtn.addEventListener("click", async () => {
@@ -17894,12 +17946,12 @@
17894
17946
  ta.remove();
17895
17947
  }
17896
17948
  }
17897
- statusEl.textContent = "Copied!";
17949
+ statusEl2.textContent = "Copied!";
17898
17950
  setTimeout(() => {
17899
- statusEl.textContent = "Autosaved";
17951
+ statusEl2.textContent = "Autosaved";
17900
17952
  }, 1500);
17901
17953
  } catch {
17902
- statusEl.textContent = "Copy failed";
17954
+ statusEl2.textContent = "Copy failed";
17903
17955
  }
17904
17956
  });
17905
17957
  return el;
@@ -18671,29 +18723,56 @@
18671
18723
  dom.shadow.appendChild(el);
18672
18724
  promptEl = el;
18673
18725
  const agentPrompt = document.createElement("div");
18674
- agentPrompt.className = "lasso-agent-prompt";
18726
+ agentPrompt.className = "lasso-agent-prompt-backdrop";
18675
18727
  agentPrompt.hidden = true;
18676
18728
  agentPrompt.innerHTML = `
18677
- <div class="lasso-agent-prompt-title">Agent needs your input</div>
18678
- <div class="lasso-agent-prompt-message"></div>
18679
- <input class="lasso-agent-prompt-input" type="text" placeholder="Type a response\u2026" />
18680
- <div class="lasso-agent-prompt-actions">
18681
- <button type="button" data-agent-response="Allow">Allow</button>
18682
- <button type="button" data-agent-response="Deny">Deny</button>
18683
- <button type="button" data-agent-response="input">Send</button>
18729
+ <div class="lasso-agent-prompt" role="dialog" aria-modal="true" aria-labelledby="lasso-agent-prompt-title">
18730
+ <div class="lasso-agent-prompt-head">
18731
+ <span class="lasso-agent-prompt-mark" aria-hidden="true">
18732
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round">
18733
+ <path d="M12 3l7.5 3.2v5.1c0 4.4-3 8.4-7.5 9.7-4.5-1.3-7.5-5.3-7.5-9.7V6.2z"/>
18734
+ <path d="M9.4 12.1l1.9 1.9 3.4-3.7"/>
18735
+ </svg>
18736
+ </span>
18737
+ <div class="lasso-agent-prompt-headings">
18738
+ <div class="lasso-agent-prompt-title" id="lasso-agent-prompt-title">Agent needs your input</div>
18739
+ <div class="lasso-agent-prompt-subtitle"></div>
18740
+ </div>
18741
+ <button class="lasso-agent-prompt-close" type="button" aria-label="Deny and continue">
18742
+ <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round">
18743
+ <path d="M18 6L6 18M6 6l12 12"/>
18744
+ </svg>
18745
+ </button>
18746
+ </div>
18747
+ <div class="lasso-agent-prompt-message" tabindex="0"></div>
18748
+ <input class="lasso-agent-prompt-input" type="text" placeholder="Type a response\u2026" hidden />
18749
+ <div class="lasso-agent-prompt-actions"></div>
18684
18750
  </div>
18685
18751
  `;
18686
18752
  dom.shadow.appendChild(agentPrompt);
18687
18753
  agentPromptPanel = agentPrompt;
18688
- agentPrompt.querySelectorAll("[data-agent-response]").forEach((button) => {
18689
- button.addEventListener("click", () => {
18690
- if (!agentPromptTaskId || state.bridgeSocket?.readyState !== WebSocket.OPEN) return;
18691
- const response = button.dataset.agentResponse === "input" ? agentPrompt.querySelector(".lasso-agent-prompt-input")?.value.trim() || "" : button.dataset.agentResponse || "";
18692
- if (!response) return;
18693
- state.bridgeSocket.send(JSON.stringify({ type: "agent_prompt_response", taskId: agentPromptTaskId, response }));
18694
- agentPromptTaskId = null;
18695
- agentPrompt.hidden = true;
18696
- });
18754
+ agentPrompt.addEventListener("pointerdown", (event) => {
18755
+ if (event.target === agentPrompt) respondToAgentPrompt("Deny");
18756
+ });
18757
+ agentPrompt.addEventListener("keydown", (event) => {
18758
+ const key = event.key;
18759
+ if (key === "Escape") {
18760
+ event.preventDefault();
18761
+ event.stopPropagation();
18762
+ respondToAgentPrompt("Deny");
18763
+ }
18764
+ });
18765
+ agentPrompt.querySelector(".lasso-agent-prompt-close").addEventListener("click", (event) => {
18766
+ event.preventDefault();
18767
+ event.stopPropagation();
18768
+ respondToAgentPrompt("Deny");
18769
+ });
18770
+ agentPrompt.querySelector(".lasso-agent-prompt-input").addEventListener("keydown", (event) => {
18771
+ if (event.key !== "Enter") return;
18772
+ event.preventDefault();
18773
+ event.stopPropagation();
18774
+ const value2 = agentPrompt.querySelector(".lasso-agent-prompt-input")?.value.trim();
18775
+ if (value2) respondToAgentPrompt(value2);
18697
18776
  });
18698
18777
  promptInput = el.querySelector(".lasso-prompt-input");
18699
18778
  promptElement = el.querySelector(".lasso-prompt-element-name");
@@ -18771,9 +18850,9 @@
18771
18850
  });
18772
18851
  modelMenu.addEventListener("click", (event) => {
18773
18852
  event.stopPropagation();
18774
- const filter = event.target.closest(".lasso-model-filter");
18775
- if (filter?.dataset.providerFilter) {
18776
- state.modelFilter = filter.dataset.providerFilter;
18853
+ const filter2 = event.target.closest(".lasso-model-filter");
18854
+ if (filter2?.dataset.providerFilter) {
18855
+ state.modelFilter = filter2.dataset.providerFilter;
18777
18856
  refreshModelMenu();
18778
18857
  return;
18779
18858
  }
@@ -18897,17 +18976,59 @@
18897
18976
  function showAgentPrompt(taskId2, prompt) {
18898
18977
  if (!agentPromptPanel) return;
18899
18978
  agentPromptTaskId = taskId2;
18979
+ const isPermission = prompt.kind === "permission";
18900
18980
  const message = agentPromptPanel.querySelector(".lasso-agent-prompt-message");
18981
+ const subtitle = agentPromptPanel.querySelector(".lasso-agent-prompt-subtitle");
18901
18982
  const input = agentPromptPanel.querySelector(".lasso-agent-prompt-input");
18902
- if (message) message.textContent = prompt.message;
18983
+ const actions = agentPromptPanel.querySelector(".lasso-agent-prompt-actions");
18984
+ agentPromptPanel.dataset.kind = prompt.kind;
18985
+ if (message) {
18986
+ message.textContent = prompt.message.trim() || "The agent is waiting for a response before it can continue.";
18987
+ }
18988
+ if (subtitle) {
18989
+ subtitle.textContent = isPermission ? "Lasso is paused until you choose an option." : "Type your answer and press Enter.";
18990
+ }
18903
18991
  if (input) {
18904
18992
  input.value = "";
18905
- input.hidden = prompt.kind === "permission";
18993
+ input.hidden = isPermission;
18994
+ }
18995
+ if (actions) {
18996
+ const options = isPermission ? prompt.options?.length ? prompt.options : ["Allow", "Deny"] : ["Send"];
18997
+ actions.replaceChildren(
18998
+ ...options.map((option) => {
18999
+ const button = document.createElement("button");
19000
+ button.type = "button";
19001
+ button.dataset.agentResponse = option;
19002
+ button.textContent = option;
19003
+ button.className = isDenyOption(option) ? "" : "primary";
19004
+ button.addEventListener("click", (event) => {
19005
+ event.preventDefault();
19006
+ event.stopPropagation();
19007
+ const typed = isPermission ? option : input?.value.trim() || "";
19008
+ if (typed) respondToAgentPrompt(typed);
19009
+ });
19010
+ return button;
19011
+ })
19012
+ );
18906
19013
  }
18907
- agentPromptPanel.querySelector('[data-agent-response="Allow"]').hidden = prompt.kind !== "permission";
18908
- agentPromptPanel.querySelector('[data-agent-response="Deny"]').hidden = prompt.kind !== "permission";
18909
19014
  agentPromptPanel.hidden = false;
18910
- if (prompt.kind === "input") input?.focus();
19015
+ if (!isPermission) input?.focus();
19016
+ else agentPromptPanel.querySelector(".lasso-agent-prompt-message")?.focus();
19017
+ }
19018
+ function isDenyOption(option) {
19019
+ return /^(deny|decline|no|cancel|reject|stop|abort)$/i.test(option.trim());
19020
+ }
19021
+ function respondToAgentPrompt(response) {
19022
+ const taskId2 = agentPromptTaskId;
19023
+ if (!taskId2 || !agentPromptPanel) return;
19024
+ agentPromptTaskId = null;
19025
+ agentPromptPanel.hidden = true;
19026
+ if (state.bridgeSocket?.readyState !== WebSocket.OPEN) {
19027
+ appendChat("error", "The Lasso agent bridge disconnected before the response was sent.", taskId2);
19028
+ return;
19029
+ }
19030
+ state.bridgeSocket.send(JSON.stringify({ type: "agent_prompt_response", taskId: taskId2, response }));
19031
+ appendChat("assistant", `Responded to the agent: ${response}`, taskId2);
18911
19032
  }
18912
19033
  function refreshModelMenu() {
18913
19034
  if (!modelMenu) return;
@@ -18915,12 +19036,12 @@
18915
19036
  filters.className = "lasso-model-filters";
18916
19037
  const providers = ["all", ...Array.from(new Set(state.MODELS.map((m) => m.provider)))];
18917
19038
  for (const provider of providers) {
18918
- const filter = document.createElement("button");
18919
- filter.type = "button";
18920
- filter.className = `lasso-model-filter${state.modelFilter === provider ? " active" : ""}`;
18921
- filter.dataset.providerFilter = provider;
18922
- filter.textContent = provider === "all" ? "All" : providerLabels[provider];
18923
- filters.appendChild(filter);
19039
+ const filter2 = document.createElement("button");
19040
+ filter2.type = "button";
19041
+ filter2.className = `lasso-model-filter${state.modelFilter === provider ? " active" : ""}`;
19042
+ filter2.dataset.providerFilter = provider;
19043
+ filter2.textContent = provider === "all" ? "All" : providerLabels[provider];
19044
+ filters.appendChild(filter2);
18924
19045
  }
18925
19046
  const children = [filters];
18926
19047
  const visibleProviders = state.modelFilter === "all" ? providers.slice(1) : [state.modelFilter];
@@ -20591,6 +20712,483 @@
20591
20712
  }
20592
20713
  }
20593
20714
 
20715
+ // src/overlay/pages/pages.ts
20716
+ var ROOT_PATH = ".";
20717
+ var DEFAULT_FILE_NAME = "page.tsx";
20718
+ var ICON_FOLDER = `<svg viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M1.75 4.2c0-.6.5-1.1 1.1-1.1h3.1c.35 0 .68.16.9.45l.7.95h4.4c.6 0 1.1.5 1.1 1.1v6.3c0 .6-.5 1.1-1.1 1.1H2.85c-.6 0-1.1-.5-1.1-1.1z" fill="currentColor" fill-opacity=".16" stroke="currentColor" stroke-width="1.1" stroke-linejoin="round"/></svg>`;
20719
+ var ICON_FOLDER_OPEN = `<svg viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M1.75 12.4V4.2c0-.6.5-1.1 1.1-1.1h3.1c.35 0 .68.16.9.45l.7.95h3.9c.5 0 .92.34 1.05.8l.9 3.3H4.4l-1.5 3.1H2.85c-.6 0-1.1-.5-1.1-1.1z" fill="currentColor" fill-opacity=".16" stroke="currentColor" stroke-width="1.1" stroke-linejoin="round"/><path d="M4.2 12.4l1.6-3.3h8.6l-1.7 3.3z" fill="currentColor" fill-opacity=".16" stroke="currentColor" stroke-width="1.1" stroke-linejoin="round"/></svg>`;
20720
+ var ICON_FILE = `<svg viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M4 2.2h4.6L12 5.6v8.2H4z" fill="currentColor" fill-opacity=".1" stroke="currentColor" stroke-width="1.1" stroke-linejoin="round"/><path d="M8.4 2.4V5.7H11.7" stroke="currentColor" stroke-width="1.1" stroke-linejoin="round"/></svg>`;
20721
+ var ICON_CHEVRON = `<svg viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M6 4l4 4-4 4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>`;
20722
+ var panelEl = null;
20723
+ var treeEl = null;
20724
+ var nameInput = null;
20725
+ var filterInput = null;
20726
+ var statusEl = null;
20727
+ var newFolderBtn = null;
20728
+ var createBtn = null;
20729
+ var root = { name: "Project", path: ROOT_PATH, type: "directory", expanded: true, loaded: false, children: [] };
20730
+ var selectedFolder = ROOT_PATH;
20731
+ var filter = "";
20732
+ var inlineCreate = null;
20733
+ var loadingPaths = /* @__PURE__ */ new Set();
20734
+ function findNode(path, nodes = [root]) {
20735
+ for (const node of nodes) {
20736
+ if (node.path === path) return node;
20737
+ if (node.type === "directory") {
20738
+ const found = findNode(path, node.children);
20739
+ if (found) return found;
20740
+ }
20741
+ }
20742
+ return null;
20743
+ }
20744
+ function toNode(entry) {
20745
+ return { ...entry, expanded: false, loaded: false, children: [] };
20746
+ }
20747
+ function requestChildren(path, force = false) {
20748
+ const node = findNode(path);
20749
+ if (!node || node.type !== "directory") return;
20750
+ if (node.loaded && !force) return;
20751
+ if (state.bridgeSocket?.readyState !== WebSocket.OPEN) {
20752
+ setStatus2("The Lasso agent bridge is not connected.", true);
20753
+ return;
20754
+ }
20755
+ loadingPaths.add(path);
20756
+ render2();
20757
+ state.bridgeSocket.send(JSON.stringify({ type: "list_page_folders", path }));
20758
+ }
20759
+ function revealSelected() {
20760
+ const found = findNode(selectedFolder);
20761
+ if (!found || found === root) return;
20762
+ const chain = [];
20763
+ const collect = (nodes, trail) => {
20764
+ for (const node of nodes) {
20765
+ if (node === found) {
20766
+ chain.push(...trail);
20767
+ return true;
20768
+ }
20769
+ if (node.type === "directory" && collect(node.children, [...trail, node])) return true;
20770
+ }
20771
+ return false;
20772
+ };
20773
+ if (!collect(root.children, [])) return;
20774
+ for (const node of chain) {
20775
+ if (!node.expanded) {
20776
+ node.expanded = true;
20777
+ if (!node.loaded) requestChildren(node.path);
20778
+ }
20779
+ }
20780
+ }
20781
+ function setStatus2(message, isError = false) {
20782
+ if (!statusEl) return;
20783
+ statusEl.textContent = message;
20784
+ statusEl.classList.toggle("error", isError);
20785
+ }
20786
+ function matchesFilter(node, term) {
20787
+ if (node.name.toLowerCase().includes(term)) return true;
20788
+ return node.children.some((child) => child.type === "directory" && child.expanded && matchesFilter(child, term));
20789
+ }
20790
+ function render2() {
20791
+ if (!treeEl) return;
20792
+ const rows = [];
20793
+ const term = filter.trim().toLowerCase();
20794
+ const walk = (nodes, depth) => {
20795
+ for (const node of nodes) {
20796
+ if (term && !matchesFilter(node, term)) continue;
20797
+ rows.push(renderRow(node, depth));
20798
+ if (node.type === "directory" && node.expanded) {
20799
+ if (inlineCreate?.parent === node.path) rows.push(renderInlineCreate(depth + 1));
20800
+ if (loadingPaths.has(node.path)) {
20801
+ rows.push(placeholderRow(depth + 1, "Loading\u2026"));
20802
+ continue;
20803
+ }
20804
+ if (!node.children.length) {
20805
+ if (node.loaded) rows.push(placeholderRow(depth + 1, "Empty"));
20806
+ continue;
20807
+ }
20808
+ walk(node.children, depth + 1);
20809
+ }
20810
+ }
20811
+ };
20812
+ walk([root], 0);
20813
+ if (!rows.length) {
20814
+ rows.push(placeholderRow(0, term ? "No matching folders" : loadingPaths.size ? "Loading folders\u2026" : "No folders to show"));
20815
+ }
20816
+ treeEl.replaceChildren(...rows);
20817
+ syncCreateButton();
20818
+ }
20819
+ function placeholderRow(depth, label) {
20820
+ const row = document.createElement("div");
20821
+ row.className = "lasso-page-row muted";
20822
+ row.style.setProperty("--lasso-page-depth", String(depth));
20823
+ row.textContent = label;
20824
+ return row;
20825
+ }
20826
+ function renderRow(node, depth) {
20827
+ const isDirectory = node.type === "directory";
20828
+ const row = document.createElement("div");
20829
+ row.className = "lasso-page-row";
20830
+ row.dataset.path = node.path;
20831
+ row.dataset.type = node.type;
20832
+ row.style.setProperty("--lasso-page-depth", String(depth));
20833
+ row.setAttribute("role", "treeitem");
20834
+ if (isDirectory) {
20835
+ row.setAttribute("aria-expanded", String(node.expanded));
20836
+ }
20837
+ row.classList.toggle("selected", isDirectory && node.path === selectedFolder);
20838
+ const twisty = document.createElement("span");
20839
+ twisty.className = "lasso-page-twisty";
20840
+ if (isDirectory) {
20841
+ twisty.innerHTML = ICON_CHEVRON;
20842
+ twisty.classList.toggle("open", node.expanded);
20843
+ twisty.title = node.expanded ? "Collapse" : "Expand";
20844
+ twisty.addEventListener("click", (event) => {
20845
+ event.preventDefault();
20846
+ event.stopPropagation();
20847
+ toggleDirectory(node);
20848
+ });
20849
+ }
20850
+ const icon = document.createElement("span");
20851
+ icon.className = `lasso-page-icon ${isDirectory ? "folder" : "file"}`;
20852
+ icon.innerHTML = isDirectory && node.expanded ? ICON_FOLDER_OPEN : isDirectory ? ICON_FOLDER : ICON_FILE;
20853
+ const label = document.createElement("span");
20854
+ label.className = "lasso-page-label";
20855
+ label.textContent = node.name;
20856
+ row.append(twisty, icon, label);
20857
+ row.addEventListener("click", (event) => {
20858
+ event.preventDefault();
20859
+ event.stopPropagation();
20860
+ if (isDirectory) {
20861
+ selectFolder(node.path);
20862
+ if (!node.expanded) toggleDirectory(node);
20863
+ } else {
20864
+ selectFolder(node.path.includes("/") ? node.path.slice(0, node.path.lastIndexOf("/")) : ROOT_PATH);
20865
+ if (nameInput && !nameInput.value.trim()) nameInput.value = node.name;
20866
+ }
20867
+ });
20868
+ return row;
20869
+ }
20870
+ function renderInlineCreate(depth) {
20871
+ const row = document.createElement("div");
20872
+ row.className = "lasso-page-row creating";
20873
+ row.style.setProperty("--lasso-page-depth", String(depth));
20874
+ const icon = document.createElement("span");
20875
+ icon.className = "lasso-page-icon folder";
20876
+ icon.innerHTML = ICON_FOLDER;
20877
+ const input = document.createElement("input");
20878
+ input.className = "lasso-page-inline-input";
20879
+ input.type = "text";
20880
+ input.placeholder = "New folder name";
20881
+ input.setAttribute("aria-label", "New folder name");
20882
+ const confirm = document.createElement("button");
20883
+ confirm.type = "button";
20884
+ confirm.className = "lasso-page-inline-confirm";
20885
+ confirm.title = "Create folder";
20886
+ confirm.setAttribute("aria-label", "Create folder");
20887
+ confirm.innerHTML = `<svg viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M3.5 8.4l3 3 6-6.4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg>`;
20888
+ const cancel = document.createElement("button");
20889
+ cancel.type = "button";
20890
+ cancel.className = "lasso-page-inline-cancel";
20891
+ cancel.title = "Cancel";
20892
+ cancel.setAttribute("aria-label", "Cancel folder creation");
20893
+ cancel.innerHTML = `<svg viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M4.5 4.5l7 7M11.5 4.5l-7 7" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/></svg>`;
20894
+ const submit = () => {
20895
+ const name = input.value.trim();
20896
+ if (!name) {
20897
+ cancelCreate();
20898
+ return;
20899
+ }
20900
+ if (state.bridgeSocket?.readyState !== WebSocket.OPEN) {
20901
+ setStatus2("The Lasso agent bridge is not connected.", true);
20902
+ return;
20903
+ }
20904
+ const parent = inlineCreate?.parent || selectedFolder;
20905
+ setStatus2(`Creating ${name}\u2026`);
20906
+ state.bridgeSocket.send(JSON.stringify({ type: "create_page_folder", parent, name }));
20907
+ inlineCreate = null;
20908
+ render2();
20909
+ };
20910
+ input.addEventListener("keydown", (event) => {
20911
+ event.stopPropagation();
20912
+ if (event.key === "Enter") {
20913
+ event.preventDefault();
20914
+ submit();
20915
+ } else if (event.key === "Escape") {
20916
+ event.preventDefault();
20917
+ cancelCreate();
20918
+ }
20919
+ });
20920
+ input.addEventListener("click", (event) => event.stopPropagation());
20921
+ confirm.addEventListener("click", (event) => {
20922
+ event.preventDefault();
20923
+ event.stopPropagation();
20924
+ submit();
20925
+ });
20926
+ cancel.addEventListener("click", (event) => {
20927
+ event.preventDefault();
20928
+ event.stopPropagation();
20929
+ cancelCreate();
20930
+ });
20931
+ row.append(icon, input, confirm, cancel);
20932
+ requestAnimationFrame(() => input.focus());
20933
+ return row;
20934
+ }
20935
+ function cancelCreate() {
20936
+ inlineCreate = null;
20937
+ render2();
20938
+ }
20939
+ function startInlineCreate() {
20940
+ inlineCreate = { parent: selectedFolder };
20941
+ setStatus2("");
20942
+ render2();
20943
+ }
20944
+ function toggleDirectory(node) {
20945
+ node.expanded = !node.expanded;
20946
+ if (node.expanded && !node.loaded) requestChildren(node.path);
20947
+ render2();
20948
+ }
20949
+ function selectFolder(path) {
20950
+ selectedFolder = path;
20951
+ if (nameInput) {
20952
+ nameInput.placeholder = path === ROOT_PATH ? DEFAULT_FILE_NAME : `${path}/page.tsx`;
20953
+ }
20954
+ render2();
20955
+ }
20956
+ function syncCreateButton() {
20957
+ if (!createBtn) return;
20958
+ const name = nameInput?.value.trim() || "";
20959
+ createBtn.disabled = !name;
20960
+ if (nameInput) nameInput.classList.toggle("invalid", Boolean(name) && /(^|\/)(\.|\.\.)$/.test(name));
20961
+ }
20962
+ function selectedTargetLabel() {
20963
+ return selectedFolder === ROOT_PATH ? "project root" : selectedFolder;
20964
+ }
20965
+ function buildPagePanel() {
20966
+ const dom = getDOM();
20967
+ const el = document.createElement("div");
20968
+ el.className = "lasso-page-backdrop";
20969
+ el.hidden = true;
20970
+ el.innerHTML = `
20971
+ <div class="lasso-page-panel" role="dialog" aria-modal="true" aria-labelledby="lasso-page-title">
20972
+ <div class="lasso-page-header">
20973
+ <div class="lasso-page-title-row">
20974
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
20975
+ <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
20976
+ <path d="M14 2v6h6"/>
20977
+ </svg>
20978
+ <span class="lasso-page-title" id="lasso-page-title">New page</span>
20979
+ </div>
20980
+ <button class="lasso-page-close" type="button" aria-label="Close">
20981
+ <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round">
20982
+ <path d="M18 6L6 18M6 6l12 12"/>
20983
+ </svg>
20984
+ </button>
20985
+ </div>
20986
+
20987
+ <label class="lasso-page-field">
20988
+ <span class="lasso-page-label-text">Name</span>
20989
+ <input class="lasso-page-name" type="text" spellcheck="false" autocomplete="off" placeholder="${DEFAULT_FILE_NAME}" />
20990
+ </label>
20991
+
20992
+ <div class="lasso-page-field">
20993
+ <div class="lasso-page-field-head">
20994
+ <span class="lasso-page-label-text">Folder</span>
20995
+ <div class="lasso-page-field-tools">
20996
+ <input class="lasso-page-filter" type="text" spellcheck="false" autocomplete="off" placeholder="Filter" aria-label="Filter folders" />
20997
+ <button class="lasso-page-new-folder" type="button" title="New folder">
20998
+ <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
20999
+ <path d="M12 5v14M5 12h14"/>
21000
+ </svg>
21001
+ </button>
21002
+ </div>
21003
+ </div>
21004
+ <div class="lasso-page-tree" role="tree" aria-label="Project folders"></div>
21005
+ </div>
21006
+
21007
+ <div class="lasso-page-footer">
21008
+ <div class="lasso-page-status" aria-live="polite"></div>
21009
+ <button class="lasso-page-create" type="button">Create page</button>
21010
+ </div>
21011
+ </div>
21012
+ `;
21013
+ dom.shadow.appendChild(el);
21014
+ panelEl = el;
21015
+ treeEl = el.querySelector(".lasso-page-tree");
21016
+ nameInput = el.querySelector(".lasso-page-name");
21017
+ filterInput = el.querySelector(".lasso-page-filter");
21018
+ statusEl = el.querySelector(".lasso-page-status");
21019
+ newFolderBtn = el.querySelector(".lasso-page-new-folder");
21020
+ createBtn = el.querySelector(".lasso-page-create");
21021
+ el.addEventListener("pointerdown", (event) => {
21022
+ if (event.target === el) closePagePanel();
21023
+ });
21024
+ el.addEventListener("keydown", (event) => {
21025
+ if (event.key !== "Escape") return;
21026
+ if (inlineCreate) {
21027
+ cancelCreate();
21028
+ return;
21029
+ }
21030
+ event.preventDefault();
21031
+ event.stopPropagation();
21032
+ closePagePanel();
21033
+ });
21034
+ el.querySelector(".lasso-page-close").addEventListener("click", (event) => {
21035
+ event.preventDefault();
21036
+ event.stopPropagation();
21037
+ closePagePanel();
21038
+ });
21039
+ newFolderBtn.addEventListener("click", (event) => {
21040
+ event.preventDefault();
21041
+ event.stopPropagation();
21042
+ startInlineCreate();
21043
+ });
21044
+ nameInput.addEventListener("input", syncCreateButton);
21045
+ nameInput.addEventListener("keydown", (event) => {
21046
+ if (event.key === "Enter") {
21047
+ event.preventDefault();
21048
+ createPage();
21049
+ }
21050
+ });
21051
+ filterInput.addEventListener("input", () => {
21052
+ filter = filterInput?.value || "";
21053
+ render2();
21054
+ });
21055
+ filterInput.addEventListener("keydown", (event) => {
21056
+ if (event.key === "Escape") {
21057
+ event.preventDefault();
21058
+ if (filterInput?.value) {
21059
+ filterInput.value = "";
21060
+ filter = "";
21061
+ } else {
21062
+ closePagePanel();
21063
+ }
21064
+ render2();
21065
+ }
21066
+ });
21067
+ createBtn.addEventListener("click", (event) => {
21068
+ event.preventDefault();
21069
+ event.stopPropagation();
21070
+ createPage();
21071
+ });
21072
+ window.addEventListener("lasso-page-folders", (event) => {
21073
+ const detail = event.detail;
21074
+ if (!detail) return;
21075
+ loadingPaths.delete(detail.path);
21076
+ const node = findNode(detail.path);
21077
+ if (detail.error) {
21078
+ setStatus2(detail.error, true);
21079
+ } else if (node) {
21080
+ if (detail.project) root.name = detail.project;
21081
+ node.children = detail.entries.map(toNode);
21082
+ node.loaded = true;
21083
+ }
21084
+ render2();
21085
+ });
21086
+ window.addEventListener("lasso-page-folder-created", (event) => {
21087
+ const detail = event.detail;
21088
+ if (!detail) return;
21089
+ if (detail.error) {
21090
+ setStatus2(detail.error, true);
21091
+ return;
21092
+ }
21093
+ setStatus2(`Created folder ${detail.path}`);
21094
+ requestChildren(detail.path.replace(/\/[^/]+$/, "") || ROOT_PATH, true);
21095
+ selectFolder(detail.path);
21096
+ });
21097
+ window.addEventListener("lasso-page-created", (event) => {
21098
+ const detail = event.detail;
21099
+ if (!detail) return;
21100
+ if (detail.error) {
21101
+ setStatus2(detail.error, true);
21102
+ return;
21103
+ }
21104
+ const parent = detail.path.includes("/") ? detail.path.slice(0, detail.path.lastIndexOf("/")) : ROOT_PATH;
21105
+ requestChildren(parent, true);
21106
+ setStatus2(`Created ${detail.path}`);
21107
+ if (nameInput) {
21108
+ nameInput.value = "";
21109
+ nameInput.focus();
21110
+ }
21111
+ syncCreateButton();
21112
+ });
21113
+ return el;
21114
+ }
21115
+ function createPage() {
21116
+ if (!nameInput || !createBtn) return;
21117
+ const fileName = nameInput.value.trim();
21118
+ if (!fileName) {
21119
+ setStatus2("Enter a name for the new page.", true);
21120
+ nameInput.focus();
21121
+ return;
21122
+ }
21123
+ if (state.bridgeSocket?.readyState !== WebSocket.OPEN) {
21124
+ setStatus2("The Lasso agent bridge is not connected.", true);
21125
+ return;
21126
+ }
21127
+ createBtn.disabled = true;
21128
+ setStatus2(`Creating ${fileName} in ${selectedTargetLabel()}\u2026`);
21129
+ state.bridgeSocket.send(
21130
+ JSON.stringify({
21131
+ type: "create_page",
21132
+ folder: selectedFolder,
21133
+ fileName,
21134
+ content: starterContent(fileName)
21135
+ })
21136
+ );
21137
+ }
21138
+ function starterContent(fileName) {
21139
+ const extension = (fileName.split(".").pop() || "").toLowerCase();
21140
+ const base = (fileName.split("/").pop() || "page").replace(/\.[^.]+$/, "");
21141
+ const component = base.split(/[^A-Za-z0-9]+/).filter(Boolean).map((part) => part[0].toUpperCase() + part.slice(1)).join("") || "Page";
21142
+ const className = base.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "page";
21143
+ if (extension === "tsx" || extension === "jsx") {
21144
+ return `export default function ${component}() {
21145
+ return (
21146
+ <main className="${className}">
21147
+ <h1>${component}</h1>
21148
+ </main>
21149
+ );
21150
+ }
21151
+ `;
21152
+ }
21153
+ if (extension === "ts" || extension === "js") {
21154
+ return `export function ${component.toLowerCase()}() {
21155
+ return null;
21156
+ }
21157
+ `;
21158
+ }
21159
+ if (extension === "css") return `/* ${base} styles */
21160
+ `;
21161
+ if (extension === "json") return "{}\n";
21162
+ if (extension === "md") return `# ${base}
21163
+ `;
21164
+ return "";
21165
+ }
21166
+ function openPagePanel() {
21167
+ if (!panelEl) return;
21168
+ panelEl.hidden = false;
21169
+ setStatus2("");
21170
+ if (nameInput) nameInput.value = "";
21171
+ syncCreateButton();
21172
+ render2();
21173
+ requestChildren(ROOT_PATH, true);
21174
+ revealSelected();
21175
+ render2();
21176
+ requestAnimationFrame(() => nameInput?.focus());
21177
+ }
21178
+ function closePagePanel() {
21179
+ if (!panelEl) return;
21180
+ panelEl.hidden = true;
21181
+ inlineCreate = null;
21182
+ }
21183
+ function togglePagePanel() {
21184
+ if (!panelEl) return;
21185
+ if (panelEl.hidden) openPagePanel();
21186
+ else closePagePanel();
21187
+ }
21188
+ function isPagePanelOpen() {
21189
+ return panelEl ? !panelEl.hidden : false;
21190
+ }
21191
+
20594
21192
  // src/overlay/toolbar/toolbar.ts
20595
21193
  var COMMENT_CURSOR_SVG = `<svg xmlns="http://www.w3.org/2000/svg" width="28" height="32" viewBox="0 0 28 32"><defs><filter id="s" x="-30%" y="-30%" width="160%" height="160%"><feDropShadow dx="0" dy="1" stdDeviation="1.5" flood-color="rgba(0,0,0,0.5)"/></filter></defs><g filter="url(#s)"><path d="M4 2h16a3 3 0 0 1 3 3v13a3 3 0 0 1-3 3H10l-6 6V5a3 3 0 0 1 3-3z" fill="#7C3AED"/><path d="M4 2h16a3 3 0 0 1 3 3v13a3 3 0 0 1-3 3H10l-6 6V5a3 3 0 0 1 3-3z" fill="none" stroke="rgba(255,255,255,0.25)" stroke-width="0.8"/><line x1="12" y1="7" x2="12" y2="15" stroke="white" stroke-width="1.8" stroke-linecap="round"/><line x1="8" y1="11" x2="16" y2="11" stroke="white" stroke-width="1.8" stroke-linecap="round"/></g></svg>`;
20596
21194
  var COMMENT_CURSOR_URL = `url("data:image/svg+xml,${encodeURIComponent(COMMENT_CURSOR_SVG)}") 4 2, crosshair`;
@@ -20766,24 +21364,15 @@
20766
21364
  miniToolbar.className = "lasso-toolbar-mini";
20767
21365
  miniToolbar.innerHTML = `
20768
21366
  <button class="lasso-new-page-btn" type="button" aria-label="Create a new page" title="New page">
20769
- <span aria-hidden="true">+</span>
21367
+ <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
21368
+ <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
21369
+ <path d="M14 2v6h6"/>
21370
+ <path d="M12 12v6M9 15h6"/>
21371
+ </svg>
20770
21372
  <span>New Page</span>
20771
21373
  </button>
20772
21374
  `;
20773
- const pagePanel = document.createElement("div");
20774
- pagePanel.className = "lasso-new-page-panel";
20775
- pagePanel.hidden = true;
20776
- pagePanel.innerHTML = `
20777
- <div class="lasso-new-page-header"><strong>New page</strong><button type="button" class="lasso-new-page-close" aria-label="Close">\xD7</button></div>
20778
- <label>File name<input class="lasso-new-page-name" value="page.tsx" /></label>
20779
- <label>Folder<div class="lasso-page-folder-list"><span>Loading folders\u2026</span></div></label>
20780
- <label>Starter content<textarea class="lasso-new-page-content" rows="5">export default function Page() {
20781
- return <main />;
20782
- }</textarea></label>
20783
- <div class="lasso-new-page-status" aria-live="polite"></div>
20784
- <button type="button" class="lasso-new-page-create">Create page</button>
20785
- `;
20786
- dom.shadow.append(toolbar, miniToolbar, pagePanel, toolbarReopen, voiceBar);
21375
+ dom.shadow.append(toolbar, miniToolbar, toolbarReopen, voiceBar);
20787
21376
  const tooltip = document.createElement("div");
20788
21377
  tooltip.className = "lasso-toolbar-tooltip";
20789
21378
  tooltip.hidden = true;
@@ -20833,65 +21422,10 @@
20833
21422
  const voiceBtn = toolbar.querySelector(".voice-tool");
20834
21423
  const dismissBtn = toolbar.querySelector(".lasso-toolbar-dismiss");
20835
21424
  const newPageBtn = miniToolbar.querySelector(".lasso-new-page-btn");
20836
- const folderList = pagePanel.querySelector(".lasso-page-folder-list");
20837
- const pageStatus = pagePanel.querySelector(".lasso-new-page-status");
20838
- let selectedFolder = ".";
20839
- const requestFolders = () => {
20840
- if (state.bridgeSocket?.readyState === WebSocket.OPEN) {
20841
- folderList.innerHTML = "<span>Loading folders\u2026</span>";
20842
- state.bridgeSocket.send(JSON.stringify({ type: "list_page_folders" }));
20843
- } else {
20844
- folderList.innerHTML = "<span>Bridge is not connected.</span>";
20845
- }
20846
- };
20847
- window.addEventListener("lasso-page-folders", (event) => {
20848
- const folders = event.detail || [];
20849
- folderList.replaceChildren();
20850
- for (const folder of folders) {
20851
- const button = document.createElement("button");
20852
- button.type = "button";
20853
- button.textContent = folder === "." ? "Project root" : folder;
20854
- button.className = folder === selectedFolder ? "selected" : "";
20855
- button.addEventListener("click", () => {
20856
- selectedFolder = folder;
20857
- folderList.querySelectorAll("button").forEach((item) => item.classList.toggle("selected", item === button));
20858
- });
20859
- folderList.appendChild(button);
20860
- }
20861
- folderList.querySelector("button")?.click();
20862
- });
20863
- window.addEventListener("lasso-page-created", (event) => {
20864
- const result = event.detail;
20865
- pageStatus.textContent = result.error || `Created ${result.path}`;
20866
- pageStatus.classList.toggle("error", Boolean(result.error));
20867
- if (!result.error) pagePanel.hidden = true;
20868
- });
20869
21425
  newPageBtn.addEventListener("click", (event) => {
20870
21426
  event.preventDefault();
20871
21427
  event.stopPropagation();
20872
- pagePanel.hidden = false;
20873
- pageStatus.textContent = "";
20874
- pageStatus.classList.remove("error");
20875
- requestFolders();
20876
- });
20877
- pagePanel.querySelector(".lasso-new-page-close").addEventListener("click", () => {
20878
- pagePanel.hidden = true;
20879
- });
20880
- pagePanel.querySelector(".lasso-new-page-create").addEventListener("click", () => {
20881
- const fileName = pagePanel.querySelector(".lasso-new-page-name").value.trim();
20882
- const content = pagePanel.querySelector(".lasso-new-page-content").value;
20883
- if (!fileName) {
20884
- pageStatus.textContent = "Enter a file name.";
20885
- pageStatus.classList.add("error");
20886
- return;
20887
- }
20888
- if (state.bridgeSocket?.readyState !== WebSocket.OPEN) {
20889
- pageStatus.textContent = "Bridge is not connected.";
20890
- pageStatus.classList.add("error");
20891
- return;
20892
- }
20893
- pageStatus.textContent = "Creating\u2026";
20894
- state.bridgeSocket.send(JSON.stringify({ type: "create_page", folder: selectedFolder, fileName, content }));
21428
+ togglePagePanel();
20895
21429
  });
20896
21430
  selectBtn.addEventListener("click", (e) => {
20897
21431
  e.preventDefault();
@@ -21034,13 +21568,21 @@
21034
21568
  return;
21035
21569
  }
21036
21570
  if (message.type === "page_folders") {
21037
- window.dispatchEvent(new CustomEvent("lasso-page-folders", { detail: message.folders || [] }));
21571
+ window.dispatchEvent(
21572
+ new CustomEvent("lasso-page-folders", {
21573
+ detail: { path: message.path || ".", entries: message.entries || [], project: message.project, error: message.error }
21574
+ })
21575
+ );
21038
21576
  return;
21039
21577
  }
21040
21578
  if (message.type === "page_created") {
21041
21579
  window.dispatchEvent(new CustomEvent("lasso-page-created", { detail: { path: message.path || "", error: message.error } }));
21042
21580
  return;
21043
21581
  }
21582
+ if (message.type === "page_folder_created") {
21583
+ window.dispatchEvent(new CustomEvent("lasso-page-folder-created", { detail: { path: message.path || "", error: message.error } }));
21584
+ return;
21585
+ }
21044
21586
  if (message.type === "agent_status" && message.status && message.message) {
21045
21587
  const taskId2 = message.taskId;
21046
21588
  const task = taskId2 ? getAgentTask(taskId2) : void 0;
@@ -21143,6 +21685,7 @@
21143
21685
  buildNotepadPanel();
21144
21686
  buildClipboardPanel();
21145
21687
  buildTaskPanel();
21688
+ buildPagePanel();
21146
21689
  buildPrompt();
21147
21690
  buildDrag();
21148
21691
  initErrorListeners();
@@ -21217,6 +21760,10 @@
21217
21760
  closePinThread();
21218
21761
  return;
21219
21762
  }
21763
+ if (isPagePanelOpen()) {
21764
+ closePagePanel();
21765
+ return;
21766
+ }
21220
21767
  if (isPromptOpen()) {
21221
21768
  cancelPrompt(true);
21222
21769
  return;