agentlas 1.0.38 → 1.0.40
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/CHANGELOG.md +28 -0
- package/engine/architecture.data.json +1 -1
- package/engine/ui/palette.cjs +1 -0
- package/engine/ui/pitui-shell.cjs +109 -0
- package/engine/ui/repl.cjs +9 -9
- package/package.json +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.0.40 — 2026-08-11
|
|
4
|
+
|
|
5
|
+
Desktop surfaces reach the pi shell: dashboard and graph view.
|
|
6
|
+
|
|
7
|
+
- `/dashboard` (pi shell): agents/firms/telegram badges + automations panel
|
|
8
|
+
(enabled state, last run) from the local store — first of the thirteen
|
|
9
|
+
Desktop-only honest stops to be lifted.
|
|
10
|
+
- `/graph show <name>` (pi shell): the automation graph renders as Unicode
|
|
11
|
+
box art (grok-mermaid) — condition branches, loop-back edges, and Korean
|
|
12
|
+
labels align correctly. No canvas emulation; editing stays declarative.
|
|
13
|
+
- First-run onboarding now runs before the pi shell starts (sequential
|
|
14
|
+
readline → pi-tui, no stdin contention), so `AGENTLAS_TUI=pi` works for
|
|
15
|
+
brand-new installs too.
|
|
16
|
+
|
|
17
|
+
## 1.0.39 — 2026-08-11
|
|
18
|
+
|
|
19
|
+
pi-tui shell increment 2 + architecture mirror sync.
|
|
20
|
+
|
|
21
|
+
- Experimental pi shell (`AGENTLAS_TUI=pi`): persisted history (cli-history.json
|
|
22
|
+
v2 contract), Shift-Tab permission cycling (same two-step FULL arming state
|
|
23
|
+
machine as the classic REPL), `!` shell passthrough (full-permission gate,
|
|
24
|
+
secret masking), and `/s` `/switch` `/kill` `/rm` `/sessions` `/tree` session
|
|
25
|
+
observation wired to the same orchestrator/renderer pair.
|
|
26
|
+
- Streaming display masks the Memory Events envelope (runtime contract, not
|
|
27
|
+
user-facing text); the harvest pipeline is unchanged.
|
|
28
|
+
- ARCHITECTURE_VERSION mirror synced 1.7.0 → 1.7.1 (vendor regenerated from
|
|
29
|
+
the desktop dist, value-level parity gate green).
|
|
30
|
+
|
|
3
31
|
## 1.0.38 — 2026-08-11
|
|
4
32
|
|
|
5
33
|
Silence was the worst failure mode — this release makes failures speak.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.7.
|
|
2
|
+
"version": "1.7.1",
|
|
3
3
|
"emitterBlock": "## Memory (Agentlas curated memory)\n\nAt the end of EVERY completed normal reply, emit exactly one hidden Memory Events\nenvelope. The runtime removes it before display. This envelope is the per-turn receipt:\nalways include a compact safe turn_summary, and use an empty candidates array when\nnothing durable was learned. Do not skip the envelope.\n\nRules:\n- Never include secrets, credentials, API keys, raw logs, or full transcripts.\n- Real credential values may live only in local project .env/.env.local,\n ignored signing/ or credentials/ files, or a local keychain/vault. Memory\n Events may mention env names and local relative paths only.\n- For deploy, release, store, billing, auth, API, or cloud work, first read the\n project's .agentlas/local-credentials.map.json and the top\n \"Local Credential Index\" section of .agentlas/project-soul-memory.md\n before saying a credential is missing.\n- One candidate per durable item. Keep \"content\" to one or two sentences.\n- \"memory_kind\": fact | decision | preference | risk | procedure | hypothesis | evidence | deprecation | conflict\n- \"suggested_scope\": user_identity | team_memory | project (this folder) | agent_repo | session (temporary) | discard\n- Use user_identity for a stable operator preference or personal fact (their name, role, language, tone,\n how they want you to behave) — these must outlive any one project. The curator only files user_identity\n when you label it so with \"confidence\": \"high\"; it never promotes into that scope, so a preference emitted\n at lower confidence is demoted to a throwaway session note.\n- \"agent_team\" is accepted only as a legacy alias for team_memory.\n- Add \"request_context\" when it improves future recall: user_intent, trigger_terms,\n cwd_at_request, target_project, target_path, cross_context, outcome.\n- Never put the raw user prompt or transcript in request_context.\n- Suggest a scope; the separate Memory Curator decides the final destination.\n- turn_summary is one value-free sentence about the completed outcome. It is not the\n user prompt, a transcript, raw log, secret, or absolute local path.\n\nFormat (always emit, including an empty candidates array):\n\n## Memory Events\n```json\n{\n \"schema_version\": \"agentlas.memory-ticket.v1\",\n \"turn_summary\": \"Completed outcome in one safe sentence.\",\n \"candidates\": [\n {\n \"memory_kind\": \"decision\",\n \"content\": \"...\",\n \"suggested_scope\": \"project\",\n \"confidence\": \"high\",\n \"sensitivity\": \"internal\",\n \"evidence_refs\": [],\n \"request_context\": {\n \"user_intent\": \"...\",\n \"trigger_terms\": [\"...\"],\n \"cwd_at_request\": null,\n \"target_project\": null,\n \"target_path\": null,\n \"cross_context\": false,\n \"outcome\": \"...\"\n }\n }\n ]\n}\n```",
|
|
4
4
|
"eventsHeading": "## Memory Events",
|
|
5
5
|
"memoryDir": ".agentlas",
|
package/engine/ui/palette.cjs
CHANGED
|
@@ -24,6 +24,7 @@ const SLASH_COMMANDS = [
|
|
|
24
24
|
{ command: "/graph", args: "[run <이름>]", ko: "저장된 자동화 그래프", en: "Saved automation graphs" },
|
|
25
25
|
{ command: "/mcp", args: "", ko: "MCP 서버 목록", en: "MCP servers" },
|
|
26
26
|
{ command: "/doctor", args: "", ko: "런타임·데이터 점검", en: "Health check" },
|
|
27
|
+
{ command: "/dashboard", args: "", ko: "관제 대시보드 (pi 셸)", en: "Dashboard (pi shell)" },
|
|
27
28
|
{ command: "/runtime", args: "<kind>", ko: "새 세션 런타임 지정", en: "Set runtime for new sessions" },
|
|
28
29
|
{ command: "/model", args: "<id|default>", ko: "새 세션 모델 지정", en: "Set model for new sessions" },
|
|
29
30
|
{ command: "/effort", args: "<level|none>", ko: "새 세션 추론 강도 지정", en: "Set effort for new sessions" },
|
|
@@ -202,6 +202,26 @@ async function startPiShell(ctx, opts = {}) {
|
|
|
202
202
|
const editor = new pi.Editor(tui, editorTheme, { autocompleteMaxVisible: 8 });
|
|
203
203
|
editor.setAutocompleteProvider(new pi.CombinedAutocompleteProvider(toSlashCommands(ctx.lang), process.cwd()));
|
|
204
204
|
|
|
205
|
+
// ── 히스토리 디스크 영속 (증분 2) — cli-history.json v2 계약을 그대로 재사용 ──
|
|
206
|
+
const input = require("../agentlas-input.cjs");
|
|
207
|
+
const historyLedger = (() => { try { return input.loadHistory(process.cwd()); } catch { return []; } })();
|
|
208
|
+
// readline 히스토리는 최신-우선 배열 — Editor에는 과거→최신 순으로 먹인다.
|
|
209
|
+
for (const entry of [...historyLedger].reverse()) editor.addToHistory(entry);
|
|
210
|
+
const recordHistory = (line) => {
|
|
211
|
+
historyLedger.unshift(line);
|
|
212
|
+
if (historyLedger.length > input.HISTORY_MAX) historyLedger.length = input.HISTORY_MAX;
|
|
213
|
+
try { input.saveHistory(historyLedger, process.cwd()); } catch { /* 히스토리는 최선노력 */ }
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
// ── Shift-Tab 권한 순환 (증분 2) — repl의 순수 상태기계를 그대로 재사용 ──
|
|
217
|
+
const { createPermissionShortcut } = require("./repl.cjs");
|
|
218
|
+
const permShortcut = createPermissionShortcut({
|
|
219
|
+
lang: ctx.lang,
|
|
220
|
+
getPermission: () => permission,
|
|
221
|
+
setPermission: (level) => { permission = level; },
|
|
222
|
+
onMessage: (msg) => { ui.ensureNl(); ui.line(ui.c.dim(msg.text)); },
|
|
223
|
+
});
|
|
224
|
+
|
|
205
225
|
const commands = require("../commands/index.cjs");
|
|
206
226
|
const handleSlash = async (cmdline) => {
|
|
207
227
|
const raw = cmdline.split(/\s+/)[0] || "";
|
|
@@ -212,6 +232,82 @@ async function startPiShell(ctx, opts = {}) {
|
|
|
212
232
|
ui.line(palette.renderPalette(ctx.lang));
|
|
213
233
|
return;
|
|
214
234
|
}
|
|
235
|
+
// 그래프 보기 (Phase 4) — 캔버스를 흉내내지 않는다: mermaid → 유니코드 박스 아트.
|
|
236
|
+
if (cmd === "graph" && rest[0] === "show" && rest[1]) {
|
|
237
|
+
const name = rest.slice(1).join(" ");
|
|
238
|
+
const row = db.prepare(
|
|
239
|
+
"SELECT name, graph_json FROM automations WHERE name = ? AND graph_json IS NOT NULL").get(name);
|
|
240
|
+
if (row) {
|
|
241
|
+
try {
|
|
242
|
+
const g = JSON.parse(row.graph_json);
|
|
243
|
+
const esc = (s) => String(s || "").replace(/["[\]{}|<>]/g, " ").trim().slice(0, 28) || "·";
|
|
244
|
+
const lines = ["flowchart TD"];
|
|
245
|
+
for (const n of g.nodes || []) {
|
|
246
|
+
const label = esc(n.label || n.id);
|
|
247
|
+
lines.push(n.type === "condition" ? ` ${n.id}{${label}}` : ` ${n.id}[${label}]`);
|
|
248
|
+
}
|
|
249
|
+
for (const e of g.edges || []) {
|
|
250
|
+
const lbl = e.sourceHandle === "true" ? "|참|" : e.sourceHandle === "false" ? "|거짓|" : "";
|
|
251
|
+
lines.push(` ${e.source} -->${lbl} ${e.target}`);
|
|
252
|
+
}
|
|
253
|
+
const { render, toAnsi } = require("grok-mermaid");
|
|
254
|
+
const art = toAnsi(render(lines.join("\n")));
|
|
255
|
+
ui.ensureNl();
|
|
256
|
+
ui.line(ui.c.bold(row.name));
|
|
257
|
+
for (const rowLine of (Array.isArray(art) ? art : String(art).split("\n"))) ui.line(rowLine);
|
|
258
|
+
ui.line("");
|
|
259
|
+
return;
|
|
260
|
+
} catch { /* 렌더 실패 → 아래 클래식 폴스루가 텍스트로 보여준다 */ }
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
// 대시보드 (Phase 3-2) — 데스크탑 정직 정지 13종 중 첫 해제. 로컬 DB 직조회.
|
|
264
|
+
if (cmd === "dashboard") {
|
|
265
|
+
const chip = (paint, s) => paint(` ${s} `);
|
|
266
|
+
const agents = db.prepare(
|
|
267
|
+
"SELECT COALESCE(NULLIF(entity_kind,''),'agent') k, builtin, COUNT(*) n FROM installed_agents WHERE COALESCE(visibility,'')!='background' GROUP BY k, builtin").all();
|
|
268
|
+
const firms = db.prepare("SELECT COUNT(*) n FROM firms").get().n;
|
|
269
|
+
const autos = db.prepare(
|
|
270
|
+
"SELECT name, enabled, last_run_at FROM automations ORDER BY COALESCE(last_run_at,'') DESC LIMIT 5").all();
|
|
271
|
+
const autoTotal = db.prepare("SELECT COUNT(*) n, SUM(enabled) e FROM automations").get();
|
|
272
|
+
const tg = db.prepare("SELECT COUNT(*) n FROM telegram_bindings").get().n;
|
|
273
|
+
ui.ensureNl();
|
|
274
|
+
ui.line(ui.c.bold(en ? "Dashboard" : "대시보드"));
|
|
275
|
+
const local = agents.filter(a => !a.builtin).reduce((s, a) => s + a.n, 0);
|
|
276
|
+
const builtin = agents.filter(a => a.builtin).reduce((s, a) => s + a.n, 0);
|
|
277
|
+
ui.line(` ${chip(ui.c.inverse, en ? `agents ${local}` : `에이전트 ${local}`)} ${chip(ui.c.dim, `builtin ${builtin}`)} ${chip(ui.c.inverse, en ? `firms ${firms}` : `회사 ${firms}`)} ${chip(ui.c.dim, `telegram ${tg}`)}`);
|
|
278
|
+
ui.line("");
|
|
279
|
+
ui.line(ui.c.bold(en ? `Automations ${autoTotal.e || 0}/${autoTotal.n} on` : `자동화 ${autoTotal.e || 0}/${autoTotal.n} 켜짐`));
|
|
280
|
+
for (const a of autos) {
|
|
281
|
+
const st = a.enabled ? ui.c.green("●") : ui.c.faint("○");
|
|
282
|
+
ui.line(` ${st} ${a.name}${a.last_run_at ? ui.c.dim(` · ${String(a.last_run_at).slice(0, 16)}`) : ""}`);
|
|
283
|
+
}
|
|
284
|
+
if (!autos.length) ui.line(ui.c.dim(en ? " (none — /automation add)" : " (없음 — /automation add)"));
|
|
285
|
+
ui.line("");
|
|
286
|
+
ui.line(ui.c.dim(en
|
|
287
|
+
? "details: /agents · /automation list · /usage · /sessions"
|
|
288
|
+
: "자세히: /agents · /automation list · /usage · /sessions"));
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
// 세션 관찰/전환 (증분 2b) — 기본 REPL과 같은 orch/renderer 배선
|
|
292
|
+
if (cmd === "sessions" || cmd === "tree") {
|
|
293
|
+
require("./repl.cjs").printSessions(shellCtx, orch);
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
if (cmd === "s" || cmd === "switch" || cmd === "kill" || cmd === "rm") {
|
|
297
|
+
const token = rest[0];
|
|
298
|
+
if (!token) { ui.line(ui.c.dim(`Usage: /${cmd} <n>`)); return; }
|
|
299
|
+
const key = String(token).startsWith("s") ? token : `s${token}`;
|
|
300
|
+
if (cmd === "kill") { orch.kill(key); return; }
|
|
301
|
+
if (cmd === "rm") {
|
|
302
|
+
orch.remove(key);
|
|
303
|
+
const act = orch.active();
|
|
304
|
+
if (act) renderer.attach(act, { replay: false });
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
const session = orch.setActive(key);
|
|
308
|
+
renderer.attach(session, { replay: true });
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
215
311
|
const EXCLUDED = new Set(["firm", "setup", "run"]);
|
|
216
312
|
if (!EXCLUDED.has(cmd) && commands.COMMANDS[cmd]) {
|
|
217
313
|
await commands.COMMANDS[cmd]().run(shellCtx, rest);
|
|
@@ -229,10 +325,16 @@ async function startPiShell(ctx, opts = {}) {
|
|
|
229
325
|
const input = String(text || "").trim();
|
|
230
326
|
if (!input) return;
|
|
231
327
|
editor.addToHistory(input);
|
|
328
|
+
recordHistory(input);
|
|
232
329
|
editor.setText("");
|
|
233
330
|
ui.ensureNl();
|
|
234
331
|
ui.line(ui.c.emerald("› ") + ui.c.text(input));
|
|
235
332
|
(async () => {
|
|
333
|
+
if (input.startsWith("!")) {
|
|
334
|
+
await require("./repl.cjs").runShell(shellCtx, input.slice(1).trim(), permission)
|
|
335
|
+
.catch((e) => { if (e && (e.code || e.honestStop)) ui.error(e); else ui.error(); });
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
236
338
|
if (input.startsWith("/")) {
|
|
237
339
|
const verdict = await handleSlash(input.slice(1)).catch((e) => {
|
|
238
340
|
if (e && (e.code || e.honestStop)) ui.error(e);
|
|
@@ -265,6 +367,13 @@ async function startPiShell(ctx, opts = {}) {
|
|
|
265
367
|
};
|
|
266
368
|
|
|
267
369
|
tui.addInputListener((data) => {
|
|
370
|
+
// Shift-Tab 권한 순환 — pi-tui 가 raw mode 를 단독 소유하므로 readline 의
|
|
371
|
+
// swallowCompletion 우회 없이 여기서 직접 소비한다 (D2 위험 2의 해소 형태).
|
|
372
|
+
if (pi.matchesKey(data, "shift+tab")) {
|
|
373
|
+
permShortcut.handleKey("", { name: "tab", shift: true });
|
|
374
|
+
return { handled: true };
|
|
375
|
+
}
|
|
376
|
+
if (permShortcut.armed()) permShortcut.handleKey("", { name: "other" }); // 다른 키 = 무장 해제
|
|
268
377
|
if (pi.matchesKey(data, "ctrl+c")) {
|
|
269
378
|
const active = orch.active();
|
|
270
379
|
if (active && active.isBusy()) {
|
package/engine/ui/repl.cjs
CHANGED
|
@@ -86,14 +86,6 @@ function pickProjectController(db, cwd = process.cwd()) {
|
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
async function startRepl(ctx, opts = {}) {
|
|
89
|
-
/*
|
|
90
|
-
* 실험 셸 opt-in (D3 Phase 2 증분 1): AGENTLAS_TUI=pi + TTY 일 때만.
|
|
91
|
-
* 기본 REPL 이 정본이며, 온보딩 전(prefs.onboarded=false)에는 켜지 않는다 —
|
|
92
|
-
* 마법사는 아직 readline 계약이다(Phase 2-2 에서 이전).
|
|
93
|
-
*/
|
|
94
|
-
if (process.env.AGENTLAS_TUI === "pi" && process.stdin.isTTY && ctx.prefs && ctx.prefs.onboarded) {
|
|
95
|
-
return require("./pitui-shell.cjs").startPiShell(ctx, opts);
|
|
96
|
-
}
|
|
97
89
|
// 마법사가 언어를 바꾸면 이 뒤의 문구도 따라가야 한다 — 아래 온보딩 블록에서 갱신한다.
|
|
98
90
|
let en = ctx.lang === "en";
|
|
99
91
|
const ui = ctx.uiInstance;
|
|
@@ -132,6 +124,14 @@ async function startRepl(ctx, opts = {}) {
|
|
|
132
124
|
}
|
|
133
125
|
}
|
|
134
126
|
|
|
127
|
+
/*
|
|
128
|
+
* 실험 셸 opt-in (D3 Phase 2): AGENTLAS_TUI=pi + TTY.
|
|
129
|
+
* 온보딩 마법사(위 readline 블록)가 먼저 끝난 뒤 진입한다 — 순차 실행이라
|
|
130
|
+
* stdin 경합이 없고, 첫 실행 사용자도 pi 셸을 쓸 수 있다(증분 2c).
|
|
131
|
+
*/
|
|
132
|
+
if (process.env.AGENTLAS_TUI === "pi" && process.stdin.isTTY) {
|
|
133
|
+
return require("./pitui-shell.cjs").startPiShell(ctx, opts);
|
|
134
|
+
}
|
|
135
135
|
const orch = new Orchestrator({ db, lang: ctx.lang });
|
|
136
136
|
const renderer = new Renderer(ui);
|
|
137
137
|
let permission = permissions.normalize(opts.permission || (ctx.prefs && ctx.prefs.permission) || "write");
|
|
@@ -786,4 +786,4 @@ function handleSlash(ctx, cmdline, api) {
|
|
|
786
786
|
}
|
|
787
787
|
}
|
|
788
788
|
|
|
789
|
-
module.exports = { startRepl, printSessions, createPermissionShortcut };
|
|
789
|
+
module.exports = { startRepl, printSessions, createPermissionShortcut, runShell };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentlas",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.40",
|
|
4
4
|
"description": "Agentlas project terminal — run project controllers and task-scoped agent teams from the terminal. Standalone: no desktop app process required.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"agentlas": "bin/agentlas.cjs"
|
|
@@ -50,6 +50,7 @@
|
|
|
50
50
|
"author": "Agentlas (https://agentlas.cloud)",
|
|
51
51
|
"license": "Apache-2.0",
|
|
52
52
|
"dependencies": {
|
|
53
|
-
"@earendil-works/pi-tui": "0.84.1"
|
|
53
|
+
"@earendil-works/pi-tui": "0.84.1",
|
|
54
|
+
"grok-mermaid": "0.2.2"
|
|
54
55
|
}
|
|
55
56
|
}
|