lampson 0.2.5 → 0.2.6

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/chat.syn CHANGED
@@ -79,6 +79,10 @@ task dim(s)
79
79
  give c("2", s)
80
80
  task yellow(s)
81
81
  give c("33", s)
82
+ -- actividad de tools (▸, $): amarillo atenuado, para que el 33 pleno quede solo como "atención
83
+ -- requerida" (⚠ aprobaciones, avisos) — semáforo: actividad ≠ advertencia (2026-08-31)
84
+ task act(s)
85
+ give c("2;33", s)
82
86
  task green(s)
83
87
  give c("32", s)
84
88
  task red(s)
@@ -276,7 +280,7 @@ task on_event(kind, data, tag)
276
280
  set pending_call to desc
277
281
  otherwise
278
282
  set pending_call to ""
279
- print(" " + yellow("▸ " + desc))
283
+ print(" " + act("▸ " + desc))
280
284
  otherwise when kind == "tool_result"
281
285
  let out be data["output"]
282
286
  let name be data["call"]["name"]
@@ -284,7 +288,7 @@ task on_event(kind, data, tag)
284
288
  let d be diff_of(name, out)
285
289
  let path be when d != nothing then text(data["call"]["args"]["path"]) otherwise ""
286
290
  set turn_outputs to append(turn_outputs, {"name": name, "args": data["call"]["args"], "output": out, "diff": d, "path": path})
287
- let lead be when pending_call != "" then " " + yellow("▸ " + pending_call) + " " otherwise " "
291
+ let lead be when pending_call != "" then " " + act("▸ " + pending_call) + " " otherwise " "
288
292
  set pending_call to ""
289
293
  when d != nothing
290
294
  print_diff_with(lead, path, d)
@@ -1015,7 +1019,7 @@ while running
1015
1019
  print(dim(" hay " + text(length(turn_outputs)) + " resultados en este turno: /out 1 … /out " + text(length(turn_outputs))))
1016
1020
  otherwise
1017
1021
  let o be turn_outputs[length(turn_outputs) - back]
1018
- print(" " + yellow("▸ " + permission.describe_call(o["name"], o["args"])))
1022
+ print(" " + act("▸ " + permission.describe_call(o["name"], o["args"])))
1019
1023
  print_full(o)
1020
1024
  otherwise when starts_with(input, "/trace")
1021
1025
  let n be trim(slice(input, 6, length(input)))
@@ -1354,7 +1358,7 @@ while running
1354
1358
  when cmd == ""
1355
1359
  print(" uso: !<comando> p.ej. !git status · !npm test · !cat .env")
1356
1360
  otherwise
1357
- print(" " + yellow("$ " + cmd))
1361
+ print(" " + act("$ " + cmd))
1358
1362
  flush()
1359
1363
  let out be run_interactive(cmd)
1360
1364
  set messages to append(messages, {"role": "user", "content": "[The user ran this command in the shell themselves]\n$ " + cmd + "\n" + tools.truncate(out, 6000)})
package/lib/diff.syn CHANGED
@@ -8,6 +8,10 @@ use "./ui.syn" as ui
8
8
 
9
9
  let ESC be decode(bytes("1b", "hex"))
10
10
  let LIMIT be 80
11
+ -- corridas largas de +/- se colapsan: HEAD líneas, "⋮ ±N líneas más", TAIL líneas (un rewrite de 200
12
+ -- líneas pintaba 200 rojas + 200 verdes; el diff completo sigue en la UI web, que recibe old/new crudos)
13
+ let HEAD be 4
14
+ let TAIL be 2
11
15
 
12
16
  -- línea de diff con fondo (verde/rojo) rellenada hasta el ancho útil, cortada si se pasa
13
17
  task row(color, kind, num, body, width)
@@ -40,6 +44,26 @@ task lpad(s, n)
40
44
  set out to " " + out
41
45
  give out
42
46
 
47
+ -- vuelca una corrida de líneas +/- ya formateadas: entera si es corta, colapsada si supera HEAD+TAIL+1
48
+ task flush_run(lines, rows, op, color, width)
49
+ when length(rows) <= HEAD + TAIL + 1
50
+ each r in rows
51
+ set lines to append(lines, r)
52
+ give lines
53
+ let i be 0
54
+ while i < HEAD
55
+ set lines to append(lines, rows[i])
56
+ set i to i + 1
57
+ let hidden be length(rows) - HEAD - TAIL
58
+ let sign be when op == "+" then "+" otherwise "−"
59
+ let code be when op == "+" then "32;2" otherwise "31;2"
60
+ set lines to append(lines, sgr(color, code, lpad("", width) + " ⋮ " + sign + text(hidden) + " líneas más"))
61
+ set i to length(rows) - TAIL
62
+ while i < length(rows)
63
+ set lines to append(lines, rows[i])
64
+ set i to i + 1
65
+ give lines
66
+
43
67
  -- LCS clásico: devuelve la lista de ops {"op": " "|"-"|"+", "a": idx_old, "b": idx_new}
44
68
  task lcs_ops(a, b)
45
69
  let n be length(a)
@@ -135,6 +159,9 @@ export task diff(old, new, ctx, color)
135
159
  set idx to idx + 1
136
160
  set idx to 0
137
161
  let skipping be false
162
+ -- corrida de +/- consecutivos: se junta y se vuelca colapsada (flush_run) al cambiar de tipo
163
+ let run_op be ""
164
+ let run_rows be []
138
165
  each o in ops
139
166
  let near be false
140
167
  let w be idx - ctx
@@ -142,6 +169,10 @@ export task diff(old, new, ctx, color)
142
169
  when w >= 0 and w < length(ops) and ops[w]["op"] != " "
143
170
  set near to true
144
171
  set w to w + 1
172
+ when o["op"] != run_op and run_op != ""
173
+ set lines to flush_run(lines, run_rows, run_op, color, width)
174
+ set run_op to ""
175
+ set run_rows to []
145
176
  when o["op"] == " "
146
177
  when near
147
178
  set lines to append(lines, row(color, " ", text(pre + o["b"] + 1), mid_b[o["b"]], width))
@@ -150,12 +181,16 @@ export task diff(old, new, ctx, color)
150
181
  set lines to append(lines, sgr(color, "2", lpad("", width) + " ⋯"))
151
182
  set skipping to true
152
183
  otherwise when o["op"] == "-"
153
- set lines to append(lines, row(color, "-", text(pre + o["a"] + 1), mid_a[o["a"]], width))
184
+ set run_op to "-"
185
+ set run_rows to append(run_rows, row(color, "-", text(pre + o["a"] + 1), mid_a[o["a"]], width))
154
186
  set skipping to false
155
187
  otherwise
156
- set lines to append(lines, row(color, "+", text(pre + o["b"] + 1), mid_b[o["b"]], width))
188
+ set run_op to "+"
189
+ set run_rows to append(run_rows, row(color, "+", text(pre + o["b"] + 1), mid_b[o["b"]], width))
157
190
  set skipping to false
158
191
  set idx to idx + 1
192
+ when run_op != ""
193
+ set lines to flush_run(lines, run_rows, run_op, color, width)
159
194
  -- contexto posterior (del sufijo común)
160
195
  let after_start be length(b) - suf
161
196
  let upto be when after_start + ctx < length(b) then after_start + ctx otherwise length(b)
@@ -11,6 +11,13 @@ export let ROOT be "workspace"
11
11
  export let MAX_OUTPUT be 30000
12
12
  export let IGNORED_DIRS be [".git", "node_modules", ".synsema", ".lampson", "workspace", "target", "dist", "build", "coverage", "__pycache__", ".venv", ".next", ".netlify", ".cache", ".turbo"]
13
13
 
14
+ -- true si algún segmento del path es ".." (no cuenta "foo..bar")
15
+ task has_dotdot(p)
16
+ each part in split(p, "/")
17
+ when part == ".."
18
+ give true
19
+ give false
20
+
14
21
  -- path del modelo → path real bajo workspace/
15
22
  export task ws(path)
16
23
  let p be when path == nothing then "." otherwise replace_text(text(path), "\\", "/")
@@ -22,6 +29,12 @@ export task ws(path)
22
29
  set p to slice(p, 1, length(p))
23
30
  otherwise
24
31
  set stripping to false
32
+ -- escape del workspace (C:\… o ..): mensaje instructivo ANTES del runtime. Sin esto el modelo
33
+ -- recibía "Capability not granted: file_write(…)" (con ..) u "os error 123" (con C:\…, que parece
34
+ -- un error de sintaxis de la ruta) y quemaba reintentos probando variantes (visto 2026-08-31:
35
+ -- quiso guardar una "memoria global" fuera del workspace, como el install global de skills).
36
+ when contains(split(p, "/")[0], ":") or has_dotdot(p)
37
+ raise("path escapes the workspace: \"" + text(path) + "\" — file tools only reach the mounted workspace; use paths relative to its root (e.g. \"src/app.ts\"). Do not retry with other path variants. To keep notes across sessions use the memory tool (the harness stores them per project, outside the repo); for anything else outside the workspace, explain what you need and ask the user.")
25
38
  when p == "." or p == "" or p == ROOT
26
39
  give ROOT
27
40
  when starts_with(p, ROOT + "/")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lampson",
3
- "version": "0.2.5",
3
+ "version": "0.2.6",
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": {