lampson 0.1.0 → 0.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/README.md +394 -382
- package/bin/lampson.js +8 -2
- package/chat.syn +1029 -799
- package/lampson.cmd +4 -4
- package/lampson.ps1 +88 -88
- package/lampson.sh +42 -42
- package/lib/agents.syn +471 -471
- package/lib/diff.syn +142 -0
- package/lib/lamps.syn +386 -386
- package/lib/line.syn +365 -0
- package/lib/lsp.syn +503 -503
- package/lib/mcp.syn +403 -403
- package/lib/md.syn +171 -0
- package/lib/permission.syn +189 -154
- package/lib/prompt.syn +75 -75
- package/lib/session.syn +111 -111
- package/lib/skills.syn +179 -179
- package/lib/tools/bash.syn +105 -105
- package/lib/tools/edit.syn +35 -32
- package/lib/tools/memo.syn +148 -148
- package/lib/tools/process.syn +46 -46
- package/lib/tools/write.syn +4 -0
- package/lib/tools.syn +198 -198
- package/lib/tree.syn +59 -59
- package/package.json +2 -2
- package/public/index.html +1268 -1268
- package/skills/lampson/SKILL.md +117 -117
- package/skills/synsema/SKILL.md +15 -2
- package/web.syn +468 -468
package/lib/prompt.syn
CHANGED
|
@@ -1,75 +1,75 @@
|
|
|
1
|
-
-- lib/prompt.syn — el system prompt del agente
|
|
2
|
-
--
|
|
3
|
-
-- Estructura:
|
|
4
|
-
-- identidad → reglas de trabajo → uso de tools → entorno (cwd, OS, fecha) → contexto del proyecto
|
|
5
|
-
-- El contexto del proyecto se lee de AGENTS.md / LAMPSON.md si existen (convención habitual de los coding agents).
|
|
6
|
-
|
|
7
|
-
use "./skills.syn" as skills
|
|
8
|
-
use "./tools/memo.syn" as memo
|
|
9
|
-
|
|
10
|
-
let CONTEXT_FILES be ["AGENTS.md", "LAMPSON.md"]
|
|
11
|
-
|
|
12
|
-
task read_context_files()
|
|
13
|
-
require file.read("workspace")
|
|
14
|
-
require file.read("workspace/*")
|
|
15
|
-
let out be ""
|
|
16
|
-
each f in CONTEXT_FILES
|
|
17
|
-
try
|
|
18
|
-
let c be read_file("workspace/" + f)
|
|
19
|
-
set out to out + `\n\n# Project instructions ({f})\n` + c
|
|
20
|
-
recover err
|
|
21
|
-
set out to out
|
|
22
|
-
give out
|
|
23
|
-
|
|
24
|
-
export task build(env_info, addendum)
|
|
25
|
-
require file.read("workspace")
|
|
26
|
-
require file.read("workspace/*")
|
|
27
|
-
require file.read("skills")
|
|
28
|
-
require file.read("skills/*")
|
|
29
|
-
require file.read("memory")
|
|
30
|
-
require file.read("memory/*")
|
|
31
|
-
require env("LAMPSON_*")
|
|
32
|
-
let core be `You are Lampson, a coding agent that works inside the user's project through tools.
|
|
33
|
-
Operate like a careful senior engineer: precise, honest, and economical with words.
|
|
34
|
-
|
|
35
|
-
# Method — follow these five steps on every non-trivial request
|
|
36
|
-
1. PLAN. If the task needs 3+ distinct steps (not 3 tool calls for one conceptual step), call todo FIRST and keep it current: one item in_progress at a time, marked completed the moment its work is verified — never batched, never on intent. The todo list survives context compaction; your narration does not. Skip it for a single straightforward change; when in doubt, use it.
|
|
37
|
-
2. LOCATE. Find code with grep and find, never by reading directories at random. For a broad, open-ended question about how the codebase works, delegate ONE focused question to an explore sub-agent instead of reading everything yourself — the search stays out of your context. Batch independent lookups into a single turn.
|
|
38
|
-
3. READ ONLY WHAT YOU NEED. Read the files you will change plus the ones you must understand to change them — not the whole project. Every file you read is re-sent on every later call. Use offset/limit for long files, but avoid tiny repeated slices. Trace a symbol to its definition and usages rather than guessing its shape. Never invent files, symbols, APIs or imports — if you have not seen it in this repo, go look. HARD LIMITS enforced by the harness: after 8 read-only calls in a row without acting you get a warning, after 16 read/ls/find/grep are refused until you act; a file read twice unchanged comes back as a one-line receipt.
|
|
39
|
-
4. CHANGE. Act as soon as you know enough — usually within the first 6-10 reads. Prefer edit (exact-string replacement; old_string must be unique, include surrounding context) over write; write only for new files or full rewrites. edit/write on an existing file are rejected unless you read that file in this session and it has not changed since. Minimal, targeted changes: no drive-by refactors, renames or reformatting; add every import or dependency your code needs. Do NOT print code blocks to the user as a substitute for editing — apply the change, then summarise it. If an edit fails to apply, re-read the file and retry with the exact current text; if the same region fails twice, rewrite the enclosing function with write.
|
|
40
|
-
5. VERIFY AND REPORT. Run the relevant tests, linter or build with bash and confirm they pass before claiming the work is done — AFTER your edits, not before as reconnaissance. Never assume a test command: check the README, the package manifest or the project instructions. Finish with a short summary: what changed (files, path:line for specific code) and how you verified it. Do not narrate every step.
|
|
41
|
-
|
|
42
|
-
# Finishing the job
|
|
43
|
-
- The deliverable is a working artifact backed by real tool output — not a description of one. Do not stop after a stub, a plan or a single command. If a tool, install or network call fails and blocks the real path, say so and try an alternative. NEVER substitute plausible-looking fabricated output for results you could not produce; reporting a blocker honestly beats inventing a result.
|
|
44
|
-
- You MUST use your tools to take action — do not describe what you would do. When you say "I will run the tests" or "let me check the file", make that tool call in the same response. Never end a turn with a promise of future action. Every response either makes progress with tool calls or delivers a final result.
|
|
45
|
-
- When the harness tells you the token budget is nearly exhausted, stop exploring and produce the deliverable from what you already have.
|
|
46
|
-
|
|
47
|
-
# What NOT to do
|
|
48
|
-
- Never assume a library is available, even a well-known one: check the project manifest and how neighbouring files import it.
|
|
49
|
-
- Do exactly what was asked: no unrequested refactors, no extra features, no gratuitous comments, no new files unless necessary (prefer editing an existing one, including markdown).
|
|
50
|
-
- Do not commit, push or rewrite history unless asked. Never read, print or store secrets — leave .env and credential files alone unless the user asks.
|
|
51
|
-
- If an action is denied by policy or by the user, say so and propose an alternative; never retry the same denied action.
|
|
52
|
-
- Never use placeholders or guess missing parameters in tool calls.
|
|
53
|
-
|
|
54
|
-
# Tools
|
|
55
|
-
- read (offset/limit), ls, find (glob), grep (regex): use them instead of bash with cat/ls/find/grep — line-numbered and cheaper. lsp (symbols/definition/references/hover): the file's structure without reading it, and exact navigation when grep is ambiguous — prefer lsp symbols plus a ranged read over reading a big file whole. edit: targeted replacement. write: create or fully replace.
|
|
56
|
-
- bash: shell commands from the workspace root. State does not persist between calls (cd resets) — chain with &&. Check the [exit code: N] marker on every result (it is the last line) and investigate failures before moving on. Never pipe a build or test through head/tail: the output is already truncated for you (the full text is saved to a file whose path you get) and the pipe hides the real exit code. Never run a server or watcher here.
|
|
57
|
-
- process: start/logs/stop long-running commands (dev servers, watchers). Their new log lines arrive automatically with every later tool result — do not sleep or poll. Stop what you started when the task is done.
|
|
58
|
-
- delegate: sub-agents with a fresh context (explore, plan, review, worker); several tasks in one call run in parallel, background=true returns at once and the report arrives later as a message. Give a highly detailed, self-contained brief, say whether it should write code or only research, how to verify, and exactly what to return. Its report is a self-report — verify what matters before telling the user it is done. Its output is not visible to the user: summarise it.
|
|
59
|
-
- memory: durable facts across sessions (user preferences, environment details, tool quirks, conventions). Check it before investigating. Write declarative facts, not instructions to yourself; do not store task progress or anything stale in a week.
|
|
60
|
-
- skill: before starting a kind of task, scan the skill list below; if one matches or is even partially relevant, load it and follow it. Err on the side of loading.
|
|
61
|
-
- todo: your task list (whole-list replacement, one in_progress at a time; see Method step 1).
|
|
62
|
-
- MCP tools are named mcp_<server>_<tool>; calling one may ask the user for approval. The mcp tool lists, connects (action=add, with the user's approval) and disconnects servers; a new server's tools enter your catalog on the next turn.
|
|
63
|
-
- Call several independent tools in one turn (reads, searches, read-only commands); serialize only when a later call depends on an earlier result. Tool outputs are truncated at 30k chars — narrow your queries.
|
|
64
|
-
|
|
65
|
-
# Tone
|
|
66
|
-
Concise and direct; lead with the change or the answer, not a preamble. Prefer technical accuracy over agreeing with the user: investigate before confirming a belief, disagree when the facts warrant it. Communicate only in your response text — never through bash echo or code comments.
|
|
67
|
-
|
|
68
|
-
# Environment
|
|
69
|
-
- Workspace root (all tool paths are relative to it; you cannot access anything outside it): {env_info["cwd"]}
|
|
70
|
-
- OS: {env_info["os"]} Shell used by bash tool: {env_info["shell"]}
|
|
71
|
-
- Date: {env_info["date"]}
|
|
72
|
-
- Model: {env_info["model"]} via {env_info["provider"]}
|
|
73
|
-
- The user talks to you from the {env_info["ui"]} UI. When something needs the user's hand (turning a lamp on, adding an LSP server, connecting an MCP), tell them the way that exists in THEIR UI: web → the «lámparas» switch / the LSP and MCP sections of the sidebar; terminal → /lamps on <name>, /lsp add <preset>, /mcp add. Never tell a web user to type a slash command — or simply offer to do it yourself (the tool asks them for approval).`
|
|
74
|
-
let mode be when addendum == nothing then "" otherwise (when addendum == "" then "" otherwise "\n\n# Mode\n" + addendum)
|
|
75
|
-
give core + mode + skills.prompt_section(skills.index()) + memo.prompt_section() + read_context_files()
|
|
1
|
+
-- lib/prompt.syn — el system prompt del agente
|
|
2
|
+
--
|
|
3
|
+
-- Estructura:
|
|
4
|
+
-- identidad → reglas de trabajo → uso de tools → entorno (cwd, OS, fecha) → contexto del proyecto
|
|
5
|
+
-- El contexto del proyecto se lee de AGENTS.md / LAMPSON.md si existen (convención habitual de los coding agents).
|
|
6
|
+
|
|
7
|
+
use "./skills.syn" as skills
|
|
8
|
+
use "./tools/memo.syn" as memo
|
|
9
|
+
|
|
10
|
+
let CONTEXT_FILES be ["AGENTS.md", "LAMPSON.md"]
|
|
11
|
+
|
|
12
|
+
task read_context_files()
|
|
13
|
+
require file.read("workspace")
|
|
14
|
+
require file.read("workspace/*")
|
|
15
|
+
let out be ""
|
|
16
|
+
each f in CONTEXT_FILES
|
|
17
|
+
try
|
|
18
|
+
let c be read_file("workspace/" + f)
|
|
19
|
+
set out to out + `\n\n# Project instructions ({f})\n` + c
|
|
20
|
+
recover err
|
|
21
|
+
set out to out
|
|
22
|
+
give out
|
|
23
|
+
|
|
24
|
+
export task build(env_info, addendum)
|
|
25
|
+
require file.read("workspace")
|
|
26
|
+
require file.read("workspace/*")
|
|
27
|
+
require file.read("skills")
|
|
28
|
+
require file.read("skills/*")
|
|
29
|
+
require file.read("memory")
|
|
30
|
+
require file.read("memory/*")
|
|
31
|
+
require env("LAMPSON_*")
|
|
32
|
+
let core be `You are Lampson, a coding agent that works inside the user's project through tools.
|
|
33
|
+
Operate like a careful senior engineer: precise, honest, and economical with words.
|
|
34
|
+
|
|
35
|
+
# Method — follow these five steps on every non-trivial request
|
|
36
|
+
1. PLAN. If the task needs 3+ distinct steps (not 3 tool calls for one conceptual step), call todo FIRST and keep it current: one item in_progress at a time, marked completed the moment its work is verified — never batched, never on intent. The todo list survives context compaction; your narration does not. Skip it for a single straightforward change; when in doubt, use it.
|
|
37
|
+
2. LOCATE. Find code with grep and find, never by reading directories at random. For a broad, open-ended question about how the codebase works, delegate ONE focused question to an explore sub-agent instead of reading everything yourself — the search stays out of your context. Batch independent lookups into a single turn.
|
|
38
|
+
3. READ ONLY WHAT YOU NEED. Read the files you will change plus the ones you must understand to change them — not the whole project. Every file you read is re-sent on every later call. Use offset/limit for long files, but avoid tiny repeated slices. Trace a symbol to its definition and usages rather than guessing its shape. Never invent files, symbols, APIs or imports — if you have not seen it in this repo, go look. HARD LIMITS enforced by the harness: after 8 read-only calls in a row without acting you get a warning, after 16 read/ls/find/grep are refused until you act; a file read twice unchanged comes back as a one-line receipt.
|
|
39
|
+
4. CHANGE. Act as soon as you know enough — usually within the first 6-10 reads. Prefer edit (exact-string replacement; old_string must be unique, include surrounding context) over write; write only for new files or full rewrites. edit/write on an existing file are rejected unless you read that file in this session and it has not changed since. Minimal, targeted changes: no drive-by refactors, renames or reformatting; add every import or dependency your code needs. Do NOT print code blocks to the user as a substitute for editing — apply the change, then summarise it. If an edit fails to apply, re-read the file and retry with the exact current text; if the same region fails twice, rewrite the enclosing function with write.
|
|
40
|
+
5. VERIFY AND REPORT. Run the relevant tests, linter or build with bash and confirm they pass before claiming the work is done — AFTER your edits, not before as reconnaissance. Never assume a test command: check the README, the package manifest or the project instructions. Finish with a short summary: what changed (files, path:line for specific code) and how you verified it. Do not narrate every step.
|
|
41
|
+
|
|
42
|
+
# Finishing the job
|
|
43
|
+
- The deliverable is a working artifact backed by real tool output — not a description of one. Do not stop after a stub, a plan or a single command. If a tool, install or network call fails and blocks the real path, say so and try an alternative. NEVER substitute plausible-looking fabricated output for results you could not produce; reporting a blocker honestly beats inventing a result.
|
|
44
|
+
- You MUST use your tools to take action — do not describe what you would do. When you say "I will run the tests" or "let me check the file", make that tool call in the same response. Never end a turn with a promise of future action. Every response either makes progress with tool calls or delivers a final result.
|
|
45
|
+
- When the harness tells you the token budget is nearly exhausted, stop exploring and produce the deliverable from what you already have.
|
|
46
|
+
|
|
47
|
+
# What NOT to do
|
|
48
|
+
- Never assume a library is available, even a well-known one: check the project manifest and how neighbouring files import it.
|
|
49
|
+
- Do exactly what was asked: no unrequested refactors, no extra features, no gratuitous comments, no new files unless necessary (prefer editing an existing one, including markdown).
|
|
50
|
+
- Do not commit, push or rewrite history unless asked. Never read, print or store secrets — leave .env and credential files alone unless the user asks.
|
|
51
|
+
- If an action is denied by policy or by the user, say so and propose an alternative; never retry the same denied action.
|
|
52
|
+
- Never use placeholders or guess missing parameters in tool calls.
|
|
53
|
+
|
|
54
|
+
# Tools
|
|
55
|
+
- read (offset/limit), ls, find (glob), grep (regex): use them instead of bash with cat/ls/find/grep — line-numbered and cheaper. lsp (symbols/definition/references/hover): the file's structure without reading it, and exact navigation when grep is ambiguous — prefer lsp symbols plus a ranged read over reading a big file whole. edit: targeted replacement. write: create or fully replace.
|
|
56
|
+
- bash: shell commands from the workspace root. State does not persist between calls (cd resets) — chain with &&. Check the [exit code: N] marker on every result (it is the last line) and investigate failures before moving on. Never pipe a build or test through head/tail: the output is already truncated for you (the full text is saved to a file whose path you get) and the pipe hides the real exit code. Never run a server or watcher here.
|
|
57
|
+
- process: start/logs/stop long-running commands (dev servers, watchers). Their new log lines arrive automatically with every later tool result — do not sleep or poll. Stop what you started when the task is done.
|
|
58
|
+
- delegate: sub-agents with a fresh context (explore, plan, review, worker); several tasks in one call run in parallel, background=true returns at once and the report arrives later as a message. Give a highly detailed, self-contained brief, say whether it should write code or only research, how to verify, and exactly what to return. Its report is a self-report — verify what matters before telling the user it is done. Its output is not visible to the user: summarise it.
|
|
59
|
+
- memory: durable facts across sessions (user preferences, environment details, tool quirks, conventions). Check it before investigating. Write declarative facts, not instructions to yourself; do not store task progress or anything stale in a week.
|
|
60
|
+
- skill: before starting a kind of task, scan the skill list below; if one matches or is even partially relevant, load it and follow it. Err on the side of loading.
|
|
61
|
+
- todo: your task list (whole-list replacement, one in_progress at a time; see Method step 1).
|
|
62
|
+
- MCP tools are named mcp_<server>_<tool>; calling one may ask the user for approval. The mcp tool lists, connects (action=add, with the user's approval) and disconnects servers; a new server's tools enter your catalog on the next turn.
|
|
63
|
+
- Call several independent tools in one turn (reads, searches, read-only commands); serialize only when a later call depends on an earlier result. Tool outputs are truncated at 30k chars — narrow your queries.
|
|
64
|
+
|
|
65
|
+
# Tone
|
|
66
|
+
Concise and direct; lead with the change or the answer, not a preamble. Prefer technical accuracy over agreeing with the user: investigate before confirming a belief, disagree when the facts warrant it. Communicate only in your response text — never through bash echo or code comments.
|
|
67
|
+
|
|
68
|
+
# Environment
|
|
69
|
+
- Workspace root (all tool paths are relative to it; you cannot access anything outside it): {env_info["cwd"]}
|
|
70
|
+
- OS: {env_info["os"]} Shell used by bash tool: {env_info["shell"]}
|
|
71
|
+
- Date: {env_info["date"]}
|
|
72
|
+
- Model: {env_info["model"]} via {env_info["provider"]}
|
|
73
|
+
- The user talks to you from the {env_info["ui"]} UI. When something needs the user's hand (turning a lamp on, adding an LSP server, connecting an MCP), tell them the way that exists in THEIR UI: web → the «lámparas» switch / the LSP and MCP sections of the sidebar; terminal → /lamps on <name>, /lsp add <preset>, /mcp add. Never tell a web user to type a slash command — or simply offer to do it yourself (the tool asks them for approval).`
|
|
74
|
+
let mode be when addendum == nothing then "" otherwise (when addendum == "" then "" otherwise "\n\n# Mode\n" + addendum)
|
|
75
|
+
give core + mode + skills.prompt_section(skills.index()) + memo.prompt_section() + read_context_files()
|
package/lib/session.syn
CHANGED
|
@@ -1,111 +1,111 @@
|
|
|
1
|
-
-- lib/session.syn — persistencia de sesiones (historial canónico como JSON en .lampson/sessions/)
|
|
2
|
-
--
|
|
3
|
-
-- Aquí: un JSON por sesión, reescrito atómicamente en cada turno (write_file es atómico).
|
|
4
|
-
-- Suficiente para v1 y trivialmente inspeccionable. Migrar a `db("./.lampson/sessions.db")` si crece.
|
|
5
|
-
--
|
|
6
|
-
-- MIGA: no existe append_file → releer + reescribir. write_file crea los directorios padres.
|
|
7
|
-
|
|
8
|
-
use "./tools/memo.syn" as memo
|
|
9
|
-
|
|
10
|
-
let DIR be ".lampson/sessions"
|
|
11
|
-
|
|
12
|
-
export task new_id()
|
|
13
|
-
require time
|
|
14
|
-
give format_time(now(), "%Y%m%d-%H%M%S")
|
|
15
|
-
|
|
16
|
-
task path_of(id)
|
|
17
|
-
give DIR + "/" + id + ".json"
|
|
18
|
-
|
|
19
|
-
export task save(id, messages, meta)
|
|
20
|
-
require file(".lampson")
|
|
21
|
-
require file(".lampson/*")
|
|
22
|
-
require time
|
|
23
|
-
require env("LAMPSON_*")
|
|
24
|
-
-- cada sesión queda marcada con el proyecto (slug del workspace) para que list() no mezcle proyectos
|
|
25
|
-
set meta["project"] to memo.slug()
|
|
26
|
-
-- y con la corrida de lampson que la guardó (blackboard "lampson:run", lo comparte el entry al arrancar):
|
|
27
|
-
-- reanudar una sesión de OTRA corrida dispara la nota de procesos muertos (proc.resume_note)
|
|
28
|
-
observe "lampson:run" as run_info
|
|
29
|
-
when run_info != nothing
|
|
30
|
-
set meta["run"] to run_info["id"]
|
|
31
|
-
let doc be {"id": id, "updated": format_time(now()), "meta": meta, "messages": messages}
|
|
32
|
-
write_file(path_of(id), json_encode(doc))
|
|
33
|
-
give id
|
|
34
|
-
|
|
35
|
-
export task load(id)
|
|
36
|
-
require file.read(".lampson")
|
|
37
|
-
require file.read(".lampson/*")
|
|
38
|
-
let doc be json_decode(read_file(path_of(id)))
|
|
39
|
-
give doc
|
|
40
|
-
|
|
41
|
-
-- ¿el doc cargado fue guardado por OTRA corrida de lampson? (sin marca = sesión vieja → sí)
|
|
42
|
-
export task from_other_run(doc)
|
|
43
|
-
observe "lampson:run" as run_info
|
|
44
|
-
when run_info == nothing
|
|
45
|
-
give false
|
|
46
|
-
when not contains(doc["meta"], "run")
|
|
47
|
-
give true
|
|
48
|
-
give doc["meta"]["run"] != run_info["id"]
|
|
49
|
-
|
|
50
|
-
export task exists(id)
|
|
51
|
-
require file.read(".lampson")
|
|
52
|
-
require file.read(".lampson/*")
|
|
53
|
-
try
|
|
54
|
-
read_file(path_of(id), 1, 1)
|
|
55
|
-
give true
|
|
56
|
-
recover err
|
|
57
|
-
give false
|
|
58
|
-
|
|
59
|
-
-- [{id, updated, title}] del proyecto ACTUAL, ordenado por id descendente (los ids son timestamps).
|
|
60
|
-
-- Sesiones viejas sin marca de proyecto se listan igual (anteriores a esta marca).
|
|
61
|
-
export task list()
|
|
62
|
-
require file.read(".lampson")
|
|
63
|
-
require file.read(".lampson/*")
|
|
64
|
-
require env("LAMPSON_*")
|
|
65
|
-
let mine be memo.slug()
|
|
66
|
-
let out be []
|
|
67
|
-
try
|
|
68
|
-
let entries be list_dir(DIR)
|
|
69
|
-
each e in entries
|
|
70
|
-
when not e["is_dir"]
|
|
71
|
-
let id be replace_text(e["name"], ".json", "")
|
|
72
|
-
try
|
|
73
|
-
let d be load(id)
|
|
74
|
-
let title be when contains(d["meta"], "title") then d["meta"]["title"] otherwise ""
|
|
75
|
-
let project be when contains(d["meta"], "project") then d["meta"]["project"] otherwise mine
|
|
76
|
-
when project == mine
|
|
77
|
-
set out to append(out, {"id": id, "updated": d["updated"], "title": title})
|
|
78
|
-
recover err
|
|
79
|
-
set out to out
|
|
80
|
-
recover err
|
|
81
|
-
give []
|
|
82
|
-
give sort_by(out, (s) => 0 - number(replace_text(replace_text(s["id"], "-", ""), "test", "")))
|
|
83
|
-
|
|
84
|
-
-- Borrar una sesión (no hay delete_file en el runtime: se usa el shell del sistema sobre la ruta fija).
|
|
85
|
-
export task delete(id)
|
|
86
|
-
require exec
|
|
87
|
-
require env("OS")
|
|
88
|
-
require file.read(".lampson")
|
|
89
|
-
require file.read(".lampson/*")
|
|
90
|
-
when not matches(id, "[a-zA-Z0-9_-]{1,40}")
|
|
91
|
-
raise("invalid session id")
|
|
92
|
-
when not exists(id)
|
|
93
|
-
give "no existe " + id
|
|
94
|
-
-- la sesión y su traza (.lampson/trace/<id>.log + .last) se van juntas
|
|
95
|
-
let files be [path_of(id), ".lampson/trace/" + id + ".log", ".lampson/trace/" + id + ".last"]
|
|
96
|
-
each f in files
|
|
97
|
-
when env("OS", "") == "Windows_NT"
|
|
98
|
-
run("cmd", ["/c", "del", "/q", replace_text(f, "/", "\\")], 10)
|
|
99
|
-
otherwise
|
|
100
|
-
run("rm", ["-f", f], 10)
|
|
101
|
-
give "borrada " + id
|
|
102
|
-
|
|
103
|
-
-- Título = primer mensaje de usuario recortado.
|
|
104
|
-
export task title_of(messages)
|
|
105
|
-
each m in messages
|
|
106
|
-
when m["role"] == "user"
|
|
107
|
-
let t be replace_text(m["content"], "\n", " ")
|
|
108
|
-
when length(t) > 60
|
|
109
|
-
give slice(t, 0, 60) + "…"
|
|
110
|
-
give t
|
|
111
|
-
give "(sin título)"
|
|
1
|
+
-- lib/session.syn — persistencia de sesiones (historial canónico como JSON en .lampson/sessions/)
|
|
2
|
+
--
|
|
3
|
+
-- Aquí: un JSON por sesión, reescrito atómicamente en cada turno (write_file es atómico).
|
|
4
|
+
-- Suficiente para v1 y trivialmente inspeccionable. Migrar a `db("./.lampson/sessions.db")` si crece.
|
|
5
|
+
--
|
|
6
|
+
-- MIGA: no existe append_file → releer + reescribir. write_file crea los directorios padres.
|
|
7
|
+
|
|
8
|
+
use "./tools/memo.syn" as memo
|
|
9
|
+
|
|
10
|
+
let DIR be ".lampson/sessions"
|
|
11
|
+
|
|
12
|
+
export task new_id()
|
|
13
|
+
require time
|
|
14
|
+
give format_time(now(), "%Y%m%d-%H%M%S")
|
|
15
|
+
|
|
16
|
+
task path_of(id)
|
|
17
|
+
give DIR + "/" + id + ".json"
|
|
18
|
+
|
|
19
|
+
export task save(id, messages, meta)
|
|
20
|
+
require file(".lampson")
|
|
21
|
+
require file(".lampson/*")
|
|
22
|
+
require time
|
|
23
|
+
require env("LAMPSON_*")
|
|
24
|
+
-- cada sesión queda marcada con el proyecto (slug del workspace) para que list() no mezcle proyectos
|
|
25
|
+
set meta["project"] to memo.slug()
|
|
26
|
+
-- y con la corrida de lampson que la guardó (blackboard "lampson:run", lo comparte el entry al arrancar):
|
|
27
|
+
-- reanudar una sesión de OTRA corrida dispara la nota de procesos muertos (proc.resume_note)
|
|
28
|
+
observe "lampson:run" as run_info
|
|
29
|
+
when run_info != nothing
|
|
30
|
+
set meta["run"] to run_info["id"]
|
|
31
|
+
let doc be {"id": id, "updated": format_time(now()), "meta": meta, "messages": messages}
|
|
32
|
+
write_file(path_of(id), json_encode(doc))
|
|
33
|
+
give id
|
|
34
|
+
|
|
35
|
+
export task load(id)
|
|
36
|
+
require file.read(".lampson")
|
|
37
|
+
require file.read(".lampson/*")
|
|
38
|
+
let doc be json_decode(read_file(path_of(id)))
|
|
39
|
+
give doc
|
|
40
|
+
|
|
41
|
+
-- ¿el doc cargado fue guardado por OTRA corrida de lampson? (sin marca = sesión vieja → sí)
|
|
42
|
+
export task from_other_run(doc)
|
|
43
|
+
observe "lampson:run" as run_info
|
|
44
|
+
when run_info == nothing
|
|
45
|
+
give false
|
|
46
|
+
when not contains(doc["meta"], "run")
|
|
47
|
+
give true
|
|
48
|
+
give doc["meta"]["run"] != run_info["id"]
|
|
49
|
+
|
|
50
|
+
export task exists(id)
|
|
51
|
+
require file.read(".lampson")
|
|
52
|
+
require file.read(".lampson/*")
|
|
53
|
+
try
|
|
54
|
+
read_file(path_of(id), 1, 1)
|
|
55
|
+
give true
|
|
56
|
+
recover err
|
|
57
|
+
give false
|
|
58
|
+
|
|
59
|
+
-- [{id, updated, title}] del proyecto ACTUAL, ordenado por id descendente (los ids son timestamps).
|
|
60
|
+
-- Sesiones viejas sin marca de proyecto se listan igual (anteriores a esta marca).
|
|
61
|
+
export task list()
|
|
62
|
+
require file.read(".lampson")
|
|
63
|
+
require file.read(".lampson/*")
|
|
64
|
+
require env("LAMPSON_*")
|
|
65
|
+
let mine be memo.slug()
|
|
66
|
+
let out be []
|
|
67
|
+
try
|
|
68
|
+
let entries be list_dir(DIR)
|
|
69
|
+
each e in entries
|
|
70
|
+
when not e["is_dir"]
|
|
71
|
+
let id be replace_text(e["name"], ".json", "")
|
|
72
|
+
try
|
|
73
|
+
let d be load(id)
|
|
74
|
+
let title be when contains(d["meta"], "title") then d["meta"]["title"] otherwise ""
|
|
75
|
+
let project be when contains(d["meta"], "project") then d["meta"]["project"] otherwise mine
|
|
76
|
+
when project == mine
|
|
77
|
+
set out to append(out, {"id": id, "updated": d["updated"], "title": title})
|
|
78
|
+
recover err
|
|
79
|
+
set out to out
|
|
80
|
+
recover err
|
|
81
|
+
give []
|
|
82
|
+
give sort_by(out, (s) => 0 - number(replace_text(replace_text(s["id"], "-", ""), "test", "")))
|
|
83
|
+
|
|
84
|
+
-- Borrar una sesión (no hay delete_file en el runtime: se usa el shell del sistema sobre la ruta fija).
|
|
85
|
+
export task delete(id)
|
|
86
|
+
require exec
|
|
87
|
+
require env("OS")
|
|
88
|
+
require file.read(".lampson")
|
|
89
|
+
require file.read(".lampson/*")
|
|
90
|
+
when not matches(id, "[a-zA-Z0-9_-]{1,40}")
|
|
91
|
+
raise("invalid session id")
|
|
92
|
+
when not exists(id)
|
|
93
|
+
give "no existe " + id
|
|
94
|
+
-- la sesión y su traza (.lampson/trace/<id>.log + .last) se van juntas
|
|
95
|
+
let files be [path_of(id), ".lampson/trace/" + id + ".log", ".lampson/trace/" + id + ".last"]
|
|
96
|
+
each f in files
|
|
97
|
+
when env("OS", "") == "Windows_NT"
|
|
98
|
+
run("cmd", ["/c", "del", "/q", replace_text(f, "/", "\\")], 10)
|
|
99
|
+
otherwise
|
|
100
|
+
run("rm", ["-f", f], 10)
|
|
101
|
+
give "borrada " + id
|
|
102
|
+
|
|
103
|
+
-- Título = primer mensaje de usuario recortado.
|
|
104
|
+
export task title_of(messages)
|
|
105
|
+
each m in messages
|
|
106
|
+
when m["role"] == "user"
|
|
107
|
+
let t be replace_text(m["content"], "\n", " ")
|
|
108
|
+
when length(t) > 60
|
|
109
|
+
give slice(t, 0, 60) + "…"
|
|
110
|
+
give t
|
|
111
|
+
give "(sin título)"
|