agentlas 1.0.9 → 1.0.10
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 +25 -0
- package/engine/ui/repl.cjs +55 -10
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.0.10 — 2026-07-27
|
|
4
|
+
|
|
5
|
+
Four defects in the REPL's slash surface, all found by sweeping for the shape
|
|
6
|
+
that produced 1.0.8: a v2 caller using a v1-era contract.
|
|
7
|
+
|
|
8
|
+
- **Quoted arguments survive.** Slash arguments were split on whitespace, so
|
|
9
|
+
the quotes the palette itself advertises (`/search "<what you need>"`) were
|
|
10
|
+
passed through as part of the query — `/search "hello world"` searched for
|
|
11
|
+
`"hello`. The quote-aware tokenizer the top-level CLI uses was exported but
|
|
12
|
+
had no call sites; the REPL now uses it.
|
|
13
|
+
- **Aliases work inside the REPL.** `agentlas hep-network …` was accepted
|
|
14
|
+
while `/hep-network …` answered "unknown", because alias resolution lived
|
|
15
|
+
only in the top-level dispatcher. Both surfaces now resolve the same names,
|
|
16
|
+
and a test pins every alias to a command that actually exists.
|
|
17
|
+
- **A command issued just before `/quit` is no longer discarded.** Slash
|
|
18
|
+
commands are async and were fire-and-forget, so closing the prompt resolved
|
|
19
|
+
immediately and the process exited mid-flight: `/search …` followed by
|
|
20
|
+
`/quit` printed nothing at all, while the same pair typed 25 seconds apart
|
|
21
|
+
worked. In-flight commands are now awaited — bounded at 30s, so quitting
|
|
22
|
+
can never hang — and the wait is announced rather than silent.
|
|
23
|
+
- **The first-run wizard's language applies to the whole session.** Choosing a
|
|
24
|
+
language wrote it to preferences and to `ui.lang`, but not to `ctx.lang`, so
|
|
25
|
+
the banner switched while `/help`, the palette, orchestrator notices and the
|
|
26
|
+
shortcut hints stayed in the OS-locale language until the next launch.
|
|
27
|
+
|
|
3
28
|
## 1.0.9 — 2026-07-27
|
|
4
29
|
|
|
5
30
|
Three repairs of one mistake, found by a live run that a 4-agent task force
|
package/engine/ui/repl.cjs
CHANGED
|
@@ -23,6 +23,7 @@ const { findAgent, listAgents } = require("../agents/registry.cjs");
|
|
|
23
23
|
const { resolveRuntime, NoRuntimeError } = require("../runtimes/resolve.cjs");
|
|
24
24
|
const permissions = require("../agentlas-permissions.cjs");
|
|
25
25
|
const i18n = require("../agentlas-i18n.cjs");
|
|
26
|
+
const { tokenizeCommandLine } = require("../agentlas-input.cjs");
|
|
26
27
|
|
|
27
28
|
const DEFAULT_AGENT_SLUG = "agentlas-orchestrator";
|
|
28
29
|
|
|
@@ -90,7 +91,8 @@ function pickDefaultAgent(db) {
|
|
|
90
91
|
}
|
|
91
92
|
|
|
92
93
|
async function startRepl(ctx, opts = {}) {
|
|
93
|
-
|
|
94
|
+
// 마법사가 언어를 바꾸면 이 뒤의 문구도 따라가야 한다 — 아래 온보딩 블록에서 갱신한다.
|
|
95
|
+
let en = ctx.lang === "en";
|
|
94
96
|
const ui = ctx.uiInstance;
|
|
95
97
|
const db = ctx.db();
|
|
96
98
|
|
|
@@ -103,7 +105,17 @@ async function startRepl(ctx, opts = {}) {
|
|
|
103
105
|
const { runWizard } = require("../commands/setup.cjs");
|
|
104
106
|
const result = await runWizard(ctx, wizardRl);
|
|
105
107
|
if (result) {
|
|
106
|
-
|
|
108
|
+
/*
|
|
109
|
+
* 고른 언어를 이번 세션에도 즉시 반영한다. 예전에는 prefs 에만 적어서,
|
|
110
|
+
* runOnboard 가 손댄 ui.lang 덕에 배너만 새 언어로 나오고 /help·팔레트·
|
|
111
|
+
* 오케스트레이터·단축키 안내는 재시작 전까지 OS 로케일 언어로 남았다.
|
|
112
|
+
*/
|
|
113
|
+
if (result.lang) {
|
|
114
|
+
ctx.prefs.language = result.lang;
|
|
115
|
+
ctx.lang = result.lang;
|
|
116
|
+
ui.lang = result.lang;
|
|
117
|
+
en = ctx.lang === "en";
|
|
118
|
+
}
|
|
107
119
|
if (result.permission) ctx.prefs.permission = result.permission;
|
|
108
120
|
if (result.runtime) ctx.prefs.runtime = result.runtime;
|
|
109
121
|
ctx.prefs.onboarded = !!result.onboarded;
|
|
@@ -186,6 +198,13 @@ async function startRepl(ctx, opts = {}) {
|
|
|
186
198
|
getSessionKeys: () => orch.list().map((r) => r.key),
|
|
187
199
|
getCwd: () => process.cwd(),
|
|
188
200
|
});
|
|
201
|
+
// 진행 중인 비동기 슬래시 명령 — 종료가 이걸 잘라먹지 않도록 close 핸들러가 기다린다.
|
|
202
|
+
const pendingCommands = new Set();
|
|
203
|
+
const trackCommand = (promise) => {
|
|
204
|
+
pendingCommands.add(promise);
|
|
205
|
+
promise.then(() => pendingCommands.delete(promise), () => pendingCommands.delete(promise));
|
|
206
|
+
return promise;
|
|
207
|
+
};
|
|
189
208
|
// Shift-Tab 이 온 턴에는 완성 후보를 비운다 — 아래 권한 순환 주석 참고.
|
|
190
209
|
let swallowCompletion = false;
|
|
191
210
|
const rl = readline.createInterface({
|
|
@@ -299,7 +318,7 @@ async function startRepl(ctx, opts = {}) {
|
|
|
299
318
|
|
|
300
319
|
if (input.startsWith("/")) {
|
|
301
320
|
try {
|
|
302
|
-
const quit = handleSlash(ctx, input.slice(1), { orch, renderer, ensureMainSession, resolveRt, setPermission: (p) => { permission = p; }, getPermission: () => permission, setRuntime: (r) => { runtimeOverride = r; } });
|
|
321
|
+
const quit = handleSlash(ctx, input.slice(1), { orch, renderer, ensureMainSession, resolveRt, track: trackCommand, setPermission: (p) => { permission = p; }, getPermission: () => permission, setRuntime: (r) => { runtimeOverride = r; } });
|
|
303
322
|
if (quit === "quit") { rl.close(); return; }
|
|
304
323
|
} catch (e) {
|
|
305
324
|
ui.error(String((e && e.message) || e));
|
|
@@ -341,9 +360,24 @@ async function startRepl(ctx, opts = {}) {
|
|
|
341
360
|
process.stdin.removeListener("keypress", onShortcutKey);
|
|
342
361
|
slashPalette.detach();
|
|
343
362
|
renderer.detach();
|
|
344
|
-
|
|
363
|
+
/*
|
|
364
|
+
* 슬래시 명령은 비동기다. 예전에는 close 가 곧바로 resolve 해서 프로세스가 끝나 버렸고,
|
|
365
|
+
* `/search …` 직후 `/quit` 을 치면 그 명령이 출력 한 줄 없이 사라졌다(실측: 같은 입력을
|
|
366
|
+
* 25초 벌려 치면 결과가 나온다). 진행 중인 명령을 먼저 기다린다.
|
|
367
|
+
*
|
|
368
|
+
* 다만 무한정 기다리지는 않는다 — 종료를 누른 사용자를 응답 없는 프로세스에 가둘 수 없다.
|
|
369
|
+
*/
|
|
370
|
+
const finish = () => { orch.shutdown(); ui.ensureNl(); resolve(0); };
|
|
371
|
+
if (!pendingCommands.size) { finish(); return; }
|
|
345
372
|
ui.ensureNl();
|
|
346
|
-
|
|
373
|
+
ui.line(ui.c.dim(en
|
|
374
|
+
? `finishing ${pendingCommands.size} command(s)…`
|
|
375
|
+
: `실행 중인 명령 ${pendingCommands.size}개를 마무리하는 중…`));
|
|
376
|
+
let settled = false;
|
|
377
|
+
const once = () => { if (settled) return; settled = true; finish(); };
|
|
378
|
+
const timer = setTimeout(once, 30_000);
|
|
379
|
+
if (timer.unref) timer.unref();
|
|
380
|
+
Promise.allSettled([...pendingCommands]).then(() => { clearTimeout(timer); once(); }, once);
|
|
347
381
|
});
|
|
348
382
|
|
|
349
383
|
prompt();
|
|
@@ -448,8 +482,19 @@ function handleSlash(ctx, cmdline, api) {
|
|
|
448
482
|
const en = ctx.lang === "en";
|
|
449
483
|
const ui = ctx.uiInstance;
|
|
450
484
|
const { orch, renderer, ensureMainSession } = api;
|
|
451
|
-
const
|
|
452
|
-
|
|
485
|
+
const commands = require("../commands/index.cjs");
|
|
486
|
+
/*
|
|
487
|
+
* 인자는 따옴표를 인식해 쪼갠다. 공백 분해는 따옴표를 인자 안에 그대로 남겨,
|
|
488
|
+
* 팔레트가 안내하는 그대로 `/search "무엇이 필요한지"` 를 치면 따옴표째 검색어가 됐다.
|
|
489
|
+
* 최상위 CLI 와 같은 토크나이저를 쓴다. restStr 은 원문 꼬리를 그대로 넘기는 자리
|
|
490
|
+
* (/spawn·/steer·/broadcast)라 계속 원문에서 자른다.
|
|
491
|
+
*/
|
|
492
|
+
const rawCmd = cmdline.split(/\s+/)[0] || "";
|
|
493
|
+
const rest = tokenizeCommandLine(cmdline).slice(1);
|
|
494
|
+
const restStr = cmdline.slice(rawCmd.length).trim();
|
|
495
|
+
// 별칭도 최상위 CLI 와 동일하게 해석한다 — `agentlas hep-network` 는 되는데
|
|
496
|
+
// `/hep-network` 는 "알 수 없는 명령" 이던 비대칭을 없앤다.
|
|
497
|
+
const cmd = commands.resolveCommandName(rawCmd);
|
|
453
498
|
|
|
454
499
|
switch (cmd) {
|
|
455
500
|
case "quit": case "exit": return "quit";
|
|
@@ -564,11 +609,11 @@ function handleSlash(ctx, cmdline, api) {
|
|
|
564
609
|
*/
|
|
565
610
|
// help/agents/list/chats/mcp/doctor 등은 위 케이스에서 이미 처리된다.
|
|
566
611
|
const REPL_EXCLUDED = new Set(["chat", "open", "firm", "setup", "run"]);
|
|
567
|
-
const commands = require("../commands/index.cjs");
|
|
568
612
|
if (!REPL_EXCLUDED.has(cmd) && commands.COMMANDS[cmd]) {
|
|
569
613
|
const result = commands.COMMANDS[cmd]().run(ctx, rest);
|
|
570
|
-
if (result && typeof result.
|
|
571
|
-
|
|
614
|
+
if (result && typeof result.then === "function") {
|
|
615
|
+
// 진행 중임을 REPL 이 알아야 종료가 이걸 잘라먹지 않는다 (close 핸들러 참고).
|
|
616
|
+
api.track(result.catch((e) => ctx.err(String((e && e.message) || e))));
|
|
572
617
|
}
|
|
573
618
|
return;
|
|
574
619
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentlas",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.10",
|
|
4
4
|
"description": "Agentlas agent terminal — chat with your installed AI agents and teams from the terminal, Claude Code style. Standalone: no desktop app required.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"agentlas": "bin/agentlas.cjs"
|