lampson 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -526,7 +526,9 @@ export task pick_folder()
526
526
  require env("OS")
527
527
  try
528
528
  when is_win()
529
- let ps be "Add-Type -AssemblyName System.Windows.Forms; $d = New-Object System.Windows.Forms.FolderBrowserDialog; $d.Description = 'Elegí la carpeta del proyecto (workspace de Lampson)'; $d.ShowNewFolderButton = $true; $f = New-Object System.Windows.Forms.Form; $f.TopMost = $true; if ($d.ShowDialog($f) -eq 'OK') { Write-Output $d.SelectedPath }"
529
+ -- Shell.Application.BrowseForFolder: el diálogo del Explorador; sale al frente aunque este proceso no tenga
530
+ -- ventana (FolderBrowserDialog de WinForms quedaba detrás desde un proceso oculto). 0x40 = con campo de ruta, 0x1 = solo carpetas
531
+ let ps be "$s = New-Object -ComObject Shell.Application; $f = $s.BrowseForFolder(0, 'Elegí la carpeta del proyecto (workspace de Lampson)', 0x41, 0); if ($f) { Write-Output $f.Self.Path }"
530
532
  let r be run("powershell", ["-NoProfile", "-STA", "-Command", ps], 300)
531
533
  give trim(text(r["stdout"]))
532
534
  let r be run("sh", ["-c", "if command -v osascript >/dev/null; then osascript -e 'POSIX path of (choose folder with prompt \"Carpeta del proyecto\")'; elif command -v zenity >/dev/null; then zenity --file-selection --directory --title='Carpeta del proyecto'; else exit 3; fi"], 300)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lampson",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "A coding agent written in Synsema: terminal + web, tools confined to the mounted project, lamps (your own tool plugins), LSP, MCP, sub-agents.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -123,3 +123,12 @@
123
123
  .panel .phelp p { margin:0 0 12px; max-width:78ch; }
124
124
  .panel .phelp ul { margin:0 0 16px 20px; padding:0; display:grid; gap:4px; max-width:78ch; }
125
125
  .panel .phelp button { text-transform:none; letter-spacing:0; font:400 12px/1 var(--mono); padding:6px 10px; }
126
+
127
+ /* detalle: la prosa y los formularios de las vistas no heredan la mono del contenedor */
128
+ .panel .bdetail .lead, .panel .bdetail .ddesc, .panel .bdetail .ds, .panel .bdetail .none { font-family:var(--serif); }
129
+ .panel .bdetail .ds { display:block; color:var(--ink-3); font:400 11.5px/1.45 var(--serif); }
130
+ .panel .bdetail .dform input, .panel .bdetail .dform select, .panel .bdetail .dform textarea { max-width:560px; }
131
+ .panel .bdetail .dform label { color:var(--ink-3); }
132
+ .panel .bdetail .dform label.col { max-width:560px; }
133
+ .panel .bdetail .dacts .ds { display:inline; color:var(--ink-3); }
134
+ .panel .bdetail .dfoot { font-family:var(--mono); }
package/public/hub.html CHANGED
@@ -32,5 +32,6 @@
32
32
  </main>
33
33
  <script src="/js/panel.js"></script>
34
34
  <script src="/js/hub.js"></script>
35
+ <script src="/js/workspaces.js"></script>
35
36
  </body>
36
37
  </html>
package/public/js/hub.js CHANGED
@@ -22,9 +22,8 @@ paintTheme();
22
22
  // tarjetas
23
23
  async function paintGrid() {
24
24
  const grid = $('#wsGrid'); let r; try { r = await (await fetch(BASE + '/api/workspaces')).json(); } catch (e) { grid.innerHTML = '<div class="card"><p>el hub no responde</p></div>'; return; }
25
- wsList = r.workspaces || []; wsIdle = r.idle_hours;
26
25
  grid.innerHTML = '';
27
- for (const w of wsList) {
26
+ for (const w of (r.workspaces || [])) {
28
27
  const c = document.createElement('a'); c.className = 'card ws' + (w.alive ? ' on' : ''); c.href = w.url;
29
28
  c.innerHTML = `<h3>${w.alive ? '● vivo' : '○ apagado'}${w.schedules_on ? ' · ⏰ ' + w.schedules_on : ''}</h3><p class="nm">${esc(w.name)}</p><p class="pth">${esc(w.path)}</p><p class="meta">último uso ${esc(fmtWhen(w.last_used))}</p>`;
30
29
  grid.appendChild(c);
@@ -27,7 +27,7 @@ function openWorkspaces(selectSlug) {
27
27
  <div class="ddesc">${w.schedules_on ? `${w.schedules_on} tarea${w.schedules_on === 1 ? '' : 's'} programada${w.schedules_on === 1 ? '' : 's'} encendida${w.schedules_on === 1 ? '' : 's'} (lo mantienen vivo). ` : ''}Último uso: ${esc(fmtWhen(w.last_used))}.</div>
28
28
  <div class="dacts"><button class="primary" data-open>${w.slug === WS_SLUG ? 'Ya estás acá' : 'Abrir'}</button>${w.alive ? '<button data-stop>■ apagar</button>' : '<button data-start>▶ encender</button>'}</div>
29
29
  <div class="dform" style="margin-top:14px"><label>vida <select name="policy"><option value="auto" ${w.policy === 'auto' ? 'selected' : ''}>auto — vivo mientras se use (${wsIdle === 0 ? 'nunca se apaga' : 'se apaga tras ' + wsIdle + ' h sin uso'}) o tenga tareas</option><option value="always" ${w.policy === 'always' ? 'selected' : ''}>siempre vivo</option><option value="off" ${w.policy === 'off' ? 'selected' : ''}>apagado — solo cuando lo abrís</option></select></label><span class="ds">las horas de inactividad se cambian en ⚙ → General</span></div>
30
- <div class="dfoot"><span>/w/${esc(w.slug)}/ · :${w.port} (solo loopback)</span><span class="del">quitar del registro</span></div><div class="derr"></div>`,
30
+ <div class="dfoot"><span>/w/${esc(w.slug)} · :${w.port} (solo loopback)</span><span class="del">quitar del registro</span></div><div class="derr"></div>`,
31
31
  wire: (w, box) => {
32
32
  const err = (m) => { const e = box.querySelector('.derr'); if (e) e.textContent = m || ''; };
33
33
  if (w === WS_NEW) { wsNewWire(box, err); return; }
@@ -44,7 +44,7 @@ function openWorkspaces(selectSlug) {
44
44
  function wsNewForm() {
45
45
  return `<div class="dhead"><span class="nm serif">Nuevo workspace</span></div><div class="dform">
46
46
  <p class="lead">Un workspace es una carpeta de tu disco: el agente solo puede tocar lo que hay adentro. Corre en su propio proceso, con sus sesiones, tareas programadas, MCP y lámparas.</p>
47
- <div class="dacts" style="margin-top:0"><button class="primary" data-pick>Elegir carpeta…</button><span class="ds" data-pickhint>abre el diálogo de tu sistema</span></div>
47
+ <div class="dacts" style="margin-top:0;align-items:center"><button class="primary" data-pick>Elegir carpeta…</button><span class="ds" data-pickhint style="margin:0">abre el diálogo de carpetas de tu sistema</span></div>
48
48
  <label style="margin-top:14px">ruta <input name="path" spellcheck="false" autocomplete="off" placeholder="C:\\proyectos\\mi-app · /home/yo/proyectos/mi-app"></label>
49
49
  <div data-browser style="display:none"><div class="dcap" data-here></div><div class="bitems" data-dirs style="max-height:32vh;border:1px solid var(--rule);border-radius:var(--r);padding:4px"></div></div>
50
50
  <div class="pfoot"><button class="primary" data-go>Crear y abrir</button><button data-browse>explorar en el servidor</button><span class="derr"></span></div></div>`;
@@ -63,7 +63,7 @@ function wsNewWire(box, err) {
63
63
  };
64
64
  box.querySelector('[data-browse]').onclick = () => showDir(f('path').value.trim());
65
65
  box.querySelector('[data-pick]').onclick = async () => {
66
- err('esperando el diálogo… (mirá la barra de tareas)');
66
+ err('esperando el diálogo de carpetas… (si no aparece, mirá la barra de tareas o usá «explorar en el servidor»)');
67
67
  const r = await api('/api/workspaces/pick', {});
68
68
  if (!r.data.native) { err(''); box.querySelector('[data-pickhint]').textContent = 'no hay diálogo en este equipo (VPS): usá el explorador'; showDir(''); return; }
69
69
  err(''); if (r.data.path) f('path').value = r.data.path;