agentlas 1.0.45 → 1.0.46
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 +13 -0
- package/engine/commands/graph.cjs +16 -10
- package/engine/commands/search.cjs +6 -1
- package/engine/ui/shell.cjs +104 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.0.46 — 2026-08-11
|
|
4
|
+
|
|
5
|
+
Pick from a list instead of retyping a slug.
|
|
6
|
+
|
|
7
|
+
- `/search` in the shell now shows its results as a list you move through with the
|
|
8
|
+
arrow keys; Enter installs the one you chose. `/graph` does the same and runs the
|
|
9
|
+
graph you pick. Escape cancels either.
|
|
10
|
+
- Search results say what the listing actually means for you — "callable without
|
|
11
|
+
installing" or "install to use" — rather than repeating the server's own enum.
|
|
12
|
+
- Commands now know which surface you are standing on, so the next step they print is
|
|
13
|
+
one you can actually type there. Inside the shell, `search` ends with `/install <slug>`
|
|
14
|
+
instead of `agentlas install <slug>`, which the shell would have refused.
|
|
15
|
+
|
|
3
16
|
## 1.0.45 — 2026-08-11
|
|
4
17
|
|
|
5
18
|
The command surface was rebuilt from one catalog, and failures stopped printing JSON.
|
|
@@ -153,8 +153,8 @@ function listGraphs(ctx) {
|
|
|
153
153
|
}
|
|
154
154
|
ctx.out("");
|
|
155
155
|
ctx.out(ctx.ui.dim(en
|
|
156
|
-
?
|
|
157
|
-
: "
|
|
156
|
+
? `Run one with: ${ctx.surface === "shell" ? "/graph" : "agentlas graph run \"<name>\""}`
|
|
157
|
+
: `실행하려면: ${ctx.surface === "shell" ? "/graph" : "agentlas graph run \"<이름>\""}`));
|
|
158
158
|
return 0;
|
|
159
159
|
}
|
|
160
160
|
|
|
@@ -278,12 +278,11 @@ function graphProblems(graph, en) {
|
|
|
278
278
|
/** 노드 한 줄. 무엇인지, 바깥을 바꾸는지, 어떤 값을 만들고 쓰는지. */
|
|
279
279
|
function nodeLine(ctx, node, en) {
|
|
280
280
|
const effect = node.config?.effect;
|
|
281
|
-
|
|
281
|
+
// ★승인 게이트 폐지(오너 이사회 결정 2026-08-10) — 데스크탑 커널은 실행 중에 멈춰
|
|
282
|
+
// 묻지 않는다. "확인 후 실행" 표시는 거짓이므로 없앴다. 옛 그래프의 approval
|
|
283
|
+
// 선언이 남아 있어도 마찬가지다. 사실 그대로의 고지는 "바깥을 바꿈" 하나다.
|
|
282
284
|
const marks = [
|
|
283
285
|
effect === "mutation" ? (en ? "changes things outside" : "바깥을 바꿈") : null,
|
|
284
|
-
approval === "ask" || (effect === "mutation" && approval !== "auto")
|
|
285
|
-
? (en ? "asks first" : "확인 후 실행")
|
|
286
|
-
: null,
|
|
287
286
|
node.config?.consumes ? `${en ? "uses" : "사용"} {{${node.config.consumes}}}` : null,
|
|
288
287
|
node.config?.produces ? `${en ? "makes" : "생성"} {{${node.config.produces}}}` : null,
|
|
289
288
|
].filter(Boolean);
|
|
@@ -470,7 +469,9 @@ async function runGraph(ctx, needle, flags) {
|
|
|
470
469
|
if (row?.ambiguous) { reportAmbiguous(ctx, needle, row.ambiguous, en); return 1; }
|
|
471
470
|
if (!row) {
|
|
472
471
|
ctx.err(en ? `No graph matches "${needle}".` : `"${needle}"와 맞는 그래프가 없습니다.`);
|
|
473
|
-
ctx.err(en
|
|
472
|
+
ctx.err(en
|
|
473
|
+
? `See what is saved with: ${ctx.surface === "shell" ? "/graph" : "agentlas graph list"}`
|
|
474
|
+
: `저장된 목록: ${ctx.surface === "shell" ? "/graph" : "agentlas graph list"}`);
|
|
474
475
|
return 1;
|
|
475
476
|
}
|
|
476
477
|
const graph = parseGraph(row);
|
|
@@ -746,7 +747,11 @@ async function newGraph(ctx, request, flags) {
|
|
|
746
747
|
const mutations = built.graph.nodes.filter((n) => n.config && n.config.effect === "mutation");
|
|
747
748
|
if (mutations.length) {
|
|
748
749
|
ctx.out("");
|
|
749
|
-
|
|
750
|
+
// ★사실 그대로의 고지 — 이 단계들은 실행 중에 멈춰 묻지 않는다(승인 게이트 폐지,
|
|
751
|
+
// 오너 이사회 결정 2026-08-10). "잠근다"는 거짓말 대신 무엇이 나가는지를 알린다.
|
|
752
|
+
ctx.out(en
|
|
753
|
+
? "Steps that change things outside (they run without stopping to ask):"
|
|
754
|
+
: "바깥을 바꾸는 단계 (실행 중에 멈춰 묻지 않습니다):");
|
|
750
755
|
for (const n of mutations) ctx.out(` · ${n.label}`);
|
|
751
756
|
}
|
|
752
757
|
ctx.out("");
|
|
@@ -1077,9 +1082,10 @@ function installPackage(ctx, filePath, flags = {}) {
|
|
|
1077
1082
|
if (mutations.length) {
|
|
1078
1083
|
ctx.out(en ? "It changes things outside at:" : "바깥을 바꾸는 지점:");
|
|
1079
1084
|
for (const m of mutations) ctx.out(` · ${m.label}`);
|
|
1085
|
+
// ★승인 게이트 폐지(2026-08-10) — "멈추고 묻는다"는 거짓말이었다. 사실만 말한다.
|
|
1080
1086
|
ctx.out(ctx.ui.dim(en
|
|
1081
|
-
? "Those steps stop
|
|
1082
|
-
: "그 단계들은
|
|
1087
|
+
? "Those steps do not stop to ask — once this is switched on, they really change things outside."
|
|
1088
|
+
: "그 단계들은 실행 중에 멈춰 묻지 않습니다 — 켜면 실제로 바깥을 바꿉니다."));
|
|
1083
1089
|
}
|
|
1084
1090
|
ctx.out(ctx.ui.dim(en
|
|
1085
1091
|
? "Nothing runs until you switch it on. The desktop app can simulate it first — the terminal cannot."
|
|
@@ -48,7 +48,12 @@ async function run(ctx, args) {
|
|
|
48
48
|
ctx.out(`${ctx.ui.accent(String(slug).padEnd(34).slice(0, 34))} ${String(name).slice(0, 26).padEnd(27)} ${ctx.ui.dim(String(kind).padEnd(14))} ${String(tagline).slice(0, 60)}`);
|
|
49
49
|
}
|
|
50
50
|
ctx.out("");
|
|
51
|
-
|
|
51
|
+
/*
|
|
52
|
+
* 안내는 사용자가 서 있는 표면에서 실제로 칠 수 있는 형태여야 한다. 셸 안에서
|
|
53
|
+
* "agentlas install"을 안내하면 그대로 따라 쳤을 때 "여기서는 안 됩니다"가 나온다
|
|
54
|
+
* (오너 실측: /agentlas install → not available here yet).
|
|
55
|
+
*/
|
|
56
|
+
ctx.out(ctx.ui.dim(ctx.surface === "shell" ? "Install: /install <slug>" : "Install: agentlas install <slug>"));
|
|
52
57
|
return 0;
|
|
53
58
|
}
|
|
54
59
|
|
package/engine/ui/shell.cjs
CHANGED
|
@@ -202,6 +202,8 @@ async function startShell(ctx, opts = {}) {
|
|
|
202
202
|
// ctx 초크포인트 재지정 — 55파일의 ctx.out 직출력이 전부 프레임 안으로 들어온다.
|
|
203
203
|
const shellCtx = {
|
|
204
204
|
...ctx,
|
|
205
|
+
// 명령이 "지금 사용자가 어디에 서 있는지"를 알아야 안내를 옳게 쓴다.
|
|
206
|
+
surface: "shell",
|
|
205
207
|
uiInstance: ui,
|
|
206
208
|
out: (s = "") => ui.line(String(s)),
|
|
207
209
|
err: (s = "") => ui.line(ui.c.amber(String(s))),
|
|
@@ -295,6 +297,38 @@ async function startShell(ctx, opts = {}) {
|
|
|
295
297
|
onMessage: (msg) => { ui.ensureNl(); ui.line(ui.c.dim(msg.text)); },
|
|
296
298
|
});
|
|
297
299
|
|
|
300
|
+
/*
|
|
301
|
+
* 목록 피커 — 슬러그를 손으로 받아치게 하지 않는다(오너 지적).
|
|
302
|
+
* SelectList 는 Focusable 이 아니라 포커스로는 키가 안 온다(Loader 와 같은 함정) —
|
|
303
|
+
* 전역 리스너에서 직접 forward 하고, 뜨는 동안 에디터 입력을 막는다.
|
|
304
|
+
*/
|
|
305
|
+
let activePicker = null;
|
|
306
|
+
function pick(items, opts = {}) {
|
|
307
|
+
return new Promise((resolve) => {
|
|
308
|
+
if (!items.length) { resolve(null); return; }
|
|
309
|
+
ui.ensureNl();
|
|
310
|
+
if (opts.title) ui.line(ui.c.bold(opts.title));
|
|
311
|
+
ui.line(ui.c.dim(en
|
|
312
|
+
? "↑/↓ choose · Enter confirm · Esc cancel"
|
|
313
|
+
: "↑/↓ 이동 · Enter 선택 · Esc 취소"));
|
|
314
|
+
const list = new pi.SelectList(items, Math.min(10, items.length), editorTheme.selectList, {});
|
|
315
|
+
const finish = (value) => {
|
|
316
|
+
if (activePicker !== list) return;
|
|
317
|
+
activePicker = null;
|
|
318
|
+
bottom.removeChild(list);
|
|
319
|
+
tui.setFocus(editor);
|
|
320
|
+
tui.requestRender();
|
|
321
|
+
resolve(value);
|
|
322
|
+
};
|
|
323
|
+
list.onSelect = (item) => finish(item);
|
|
324
|
+
list.onCancel = () => finish(null);
|
|
325
|
+
activePicker = list;
|
|
326
|
+
bottom.addChild(list);
|
|
327
|
+
tui.setFocus(null);
|
|
328
|
+
tui.requestRender();
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
|
|
298
332
|
const commands = require("../commands/index.cjs");
|
|
299
333
|
const handleSlash = async (cmdline) => {
|
|
300
334
|
const raw = cmdline.split(/\s+/)[0] || "";
|
|
@@ -339,6 +373,69 @@ async function startShell(ctx, opts = {}) {
|
|
|
339
373
|
} catch { /* 렌더 실패 → 아래 클래식 폴스루가 텍스트로 보여준다 */ }
|
|
340
374
|
}
|
|
341
375
|
}
|
|
376
|
+
/*
|
|
377
|
+
* /search — 결과를 목록으로 띄우고 방향키로 고른다. 슬러그를 손으로 받아치게
|
|
378
|
+
* 하지 않는다(오너 지적). 고르면 바로 설치까지 간다.
|
|
379
|
+
*
|
|
380
|
+
* kind 는 서버 열거값을 그대로 보여주지 않는다. "cloud-callable" 은 사용자에게
|
|
381
|
+
* "설치 안 해도 바로 부를 수 있음"이라는 뜻이지, 설치가 안 된다는 뜻이 아니다.
|
|
382
|
+
*/
|
|
383
|
+
if (cmd === "search" && rest.length) {
|
|
384
|
+
const query = rest.join(" ");
|
|
385
|
+
const { callHubTool, HubError } = require("../cloud/hub-client.cjs");
|
|
386
|
+
let result;
|
|
387
|
+
ui.updateSpinner(en ? "Searching the Hub…" : "Hub 검색 중…");
|
|
388
|
+
try {
|
|
389
|
+
result = await callHubTool("marketplace.search_agents", { q: query, query, limit: 12 });
|
|
390
|
+
} catch (e) {
|
|
391
|
+
ui.stopSpinner();
|
|
392
|
+
ui.error(Object.assign(new Error(e instanceof HubError ? e.message : String((e && e.message) || e)),
|
|
393
|
+
{ code: "hub_search_failed", honestStop: true }));
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
ui.stopSpinner();
|
|
397
|
+
const raw = (result && (result.results || result.agents || result.items)) || (Array.isArray(result) ? result : []);
|
|
398
|
+
const hidden = (slug) => /^researcher-\d+/.test(String(slug || "").toLowerCase())
|
|
399
|
+
|| String(slug || "").toLowerCase().startsWith("hephaestus-");
|
|
400
|
+
const rows = (Array.isArray(raw) ? raw : []).filter((it) => !hidden(it && (it.slug || it.id)));
|
|
401
|
+
if (!rows.length) { ui.line(ui.c.dim(en ? `No results for "${query}"` : `"${query}" 결과 없음`)); return; }
|
|
402
|
+
const callable = (k) => (String(k || "").includes("cloud")
|
|
403
|
+
? (en ? "callable without installing" : "설치 없이 호출 가능")
|
|
404
|
+
: (en ? "install to use" : "설치해야 사용"));
|
|
405
|
+
const chosen = await pick(rows.map((it) => ({
|
|
406
|
+
value: it.slug || it.id || "?",
|
|
407
|
+
label: `${it.slug || it.id}`,
|
|
408
|
+
description: `${it.name || it.title || ""} — ${callable(it.kind || it.entity_kind)}`,
|
|
409
|
+
})), { title: en ? `Hub results for "${query}"` : `"${query}" Hub 결과` });
|
|
410
|
+
if (!chosen) { ui.line(ui.c.dim(en ? "cancelled" : "취소됨")); return; }
|
|
411
|
+
ui.line(ui.c.dim(en ? `installing ${chosen.value}…` : `${chosen.value} 설치 중…`));
|
|
412
|
+
await commands.COMMANDS.install().run(shellCtx, [chosen.value]);
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/*
|
|
417
|
+
* /graph — 저장된 그래프를 목록으로 띄우고 고른 것을 실행한다.
|
|
418
|
+
* (저장 테이블 이름은 automations 이지만 이 화면이 다루는 건 그래프다.)
|
|
419
|
+
*/
|
|
420
|
+
if (cmd === "graph" && (!rest.length || rest[0] === "list")) {
|
|
421
|
+
const rowsOf = db.prepare("SELECT name, enabled, schedule, graph_json FROM automations ORDER BY name").all();
|
|
422
|
+
const graphs = rowsOf.filter((r) => r.graph_json);
|
|
423
|
+
if (!graphs.length) { ui.line(ui.c.dim(en ? "No saved graphs yet." : "저장된 그래프가 없습니다.")); return; }
|
|
424
|
+
const chosen = await pick(graphs.map((g) => {
|
|
425
|
+
let steps = 0;
|
|
426
|
+
try { steps = (JSON.parse(g.graph_json).nodes || []).length; } catch { steps = 0; }
|
|
427
|
+
return {
|
|
428
|
+
value: g.name,
|
|
429
|
+
label: g.name,
|
|
430
|
+
description: `${steps} ${en ? "steps" : "단계"} · ${g.enabled ? (en ? "on" : "켜짐") : (en ? "off" : "꺼짐")}`
|
|
431
|
+
+ (g.schedule ? ` · ${g.schedule}` : ""),
|
|
432
|
+
};
|
|
433
|
+
}), { title: en ? "Saved graphs" : "저장된 그래프" });
|
|
434
|
+
if (!chosen) { ui.line(ui.c.dim(en ? "cancelled" : "취소됨")); return; }
|
|
435
|
+
await commands.COMMANDS.graph().run(shellCtx, ["run", chosen.value]);
|
|
436
|
+
return;
|
|
437
|
+
}
|
|
438
|
+
|
|
342
439
|
/*
|
|
343
440
|
* 세션 설정 4종. 자동완성은 되는데 처리 case 가 없어 "여기서는 아직 안 됩니다"만
|
|
344
441
|
* 답하던 죽은 광고였다(신설 게이트가 잡았다). 기본 REPL 과 같은 의미로 배선하고,
|
|
@@ -474,6 +571,13 @@ async function startShell(ctx, opts = {}) {
|
|
|
474
571
|
};
|
|
475
572
|
|
|
476
573
|
tui.addInputListener((data) => {
|
|
574
|
+
// 피커가 떠 있으면 그 키는 피커 것이다 — 에디터로 새면 목록 위에서 글이 써진다.
|
|
575
|
+
if (activePicker) {
|
|
576
|
+
if (pi.matchesKey(data, "escape")) { activePicker.onCancel && activePicker.onCancel(); return { handled: true }; }
|
|
577
|
+
activePicker.handleInput(data);
|
|
578
|
+
tui.requestRender();
|
|
579
|
+
return { handled: true };
|
|
580
|
+
}
|
|
477
581
|
// Shift-Tab 권한 순환 — 렌더러가 raw mode 를 단독 소유하므로 readline 의
|
|
478
582
|
// swallowCompletion 우회 없이 여기서 직접 소비한다 (D2 위험 2의 해소 형태).
|
|
479
583
|
if (pi.matchesKey(data, "shift+tab")) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentlas",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.46",
|
|
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"
|