agentlas 1.0.43 → 1.0.45
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 +34 -0
- package/engine/agentlas-workforce.cjs +26 -6
- package/engine/commands/help.cjs +34 -153
- package/engine/commands/index.cjs +31 -8
- package/engine/ui/commands-catalog.cjs +217 -0
- package/engine/ui/palette.cjs +24 -93
- package/engine/ui/repl.cjs +36 -13
- package/engine/ui/shell.cjs +101 -10
- package/engine/workforce/deps.cjs +7 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,39 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.0.45 — 2026-08-11
|
|
4
|
+
|
|
5
|
+
The command surface was rebuilt from one catalog, and failures stopped printing JSON.
|
|
6
|
+
|
|
7
|
+
- **Commands.** The same list used to be maintained by hand in four places, and they
|
|
8
|
+
disagreed: an English screen advertised a Korean argument hint, one feature was sold
|
|
9
|
+
twice under two names, and a de-duplication pass then hid `/switch`, `/list` and
|
|
10
|
+
`/exit` entirely. There is now a single catalog. Aliases are a field on a command,
|
|
11
|
+
never a row of their own, so a duplicate can no longer appear or be silently dropped.
|
|
12
|
+
- **Help.** `/help` is grouped and short — 25 lines in the terminal instead of 133 —
|
|
13
|
+
ordered by what a new user needs first. `help all` lists everything; `help <command>`
|
|
14
|
+
answers about that one command instead of dumping the whole list. The CLI, the classic
|
|
15
|
+
REPL and the interactive shell now call the same renderer, so they cannot drift apart.
|
|
16
|
+
- **Removed.** `journal` reported success for runs that did not exist and read the wrong
|
|
17
|
+
folder; `career-graph`'s read commands silently created project state; `plugins` was a
|
|
18
|
+
second name for `plugin`. All three now stop with the exact replacement command instead
|
|
19
|
+
of leaking into a paid model turn.
|
|
20
|
+
- **Failures.** A failed staffing run used to print a machine code followed by a raw JSON
|
|
21
|
+
object, with the one useful sentence — run `agentlas login` — buried inside it and cut
|
|
22
|
+
mid-escape by two stacked truncations. The sentence now comes first and the code last;
|
|
23
|
+
no JSON reaches a human. Sign-in expiry is relayed intact instead of being re-wrapped.
|
|
24
|
+
- **Shell layout.** Output now stays above the input box instead of below it,
|
|
25
|
+
the box shows what to type, the whole terminal width is used, blank lines survive,
|
|
26
|
+
and `/permission` `/model` `/runtime` `/effort` work where they were only autocompleted.
|
|
27
|
+
|
|
28
|
+
## 1.0.44 — 2026-08-11
|
|
29
|
+
|
|
30
|
+
Turn the interactive shell on once and keep it.
|
|
31
|
+
|
|
32
|
+
- `/shell on` saves the choice, so plain `agentlas` opens the interactive shell
|
|
33
|
+
from then on; `/shell off` returns to the classic REPL. Both shells accept the
|
|
34
|
+
command, so you can always get back out.
|
|
35
|
+
- `AGENTLAS_TUI=1` still works and takes precedence for a single run.
|
|
36
|
+
|
|
3
37
|
## 1.0.43 — 2026-08-11
|
|
4
38
|
|
|
5
39
|
Zero runtime dependencies. The renderer now lives in this repository.
|
|
@@ -2916,6 +2916,12 @@ const TRANSIENT_MODEL_ERROR_RE = /Connection closed mid-response|"terminal_reaso
|
|
|
2916
2916
|
try {
|
|
2917
2917
|
runtimeContext = await D.loadWorkforceGoalRuntime(cwd, ctx.goalId || null);
|
|
2918
2918
|
} catch (error) {
|
|
2919
|
+
/*
|
|
2920
|
+
* 저자·호스트가 이미 한 문장으로 쓴 안내(로그인 필요, 정직 정지)는 그대로 올린다.
|
|
2921
|
+
* 여기서 다시 감싸면 code/honestStop 이 떨어져 나가고, 유일하게 실행 가능한
|
|
2922
|
+
* 문장이 JSON 의 cause 키 밑으로 들어가 사용자에게 blob 으로 보인다(실사고).
|
|
2923
|
+
*/
|
|
2924
|
+
if (error && (error.honestStop || error.code)) throw error;
|
|
2919
2925
|
fail(
|
|
2920
2926
|
"workforce_goal_runtime_unavailable",
|
|
2921
2927
|
"the active account/project Workforce binding could not be inspected",
|
|
@@ -3291,6 +3297,12 @@ const TRANSIENT_MODEL_ERROR_RE = /Connection closed mid-response|"terminal_reaso
|
|
|
3291
3297
|
hostRuntime: identity.runtimeId,
|
|
3292
3298
|
});
|
|
3293
3299
|
} catch (error) {
|
|
3300
|
+
/*
|
|
3301
|
+
* 저자·호스트가 이미 한 문장으로 쓴 안내(로그인 필요, 정직 정지)는 그대로 올린다.
|
|
3302
|
+
* 여기서 다시 감싸면 code/honestStop 이 떨어져 나가고, 유일하게 실행 가능한
|
|
3303
|
+
* 문장이 JSON 의 cause 키 밑으로 들어가 사용자에게 blob 으로 보인다(실사고).
|
|
3304
|
+
*/
|
|
3305
|
+
if (error && (error.honestStop || error.code)) throw error;
|
|
3294
3306
|
fail(
|
|
3295
3307
|
"workforce_goal_binding_failed",
|
|
3296
3308
|
"prepared execution was blocked because the durable goal binding could not be committed",
|
|
@@ -4552,14 +4564,22 @@ const TRANSIENT_MODEL_ERROR_RE = /Connection closed mid-response|"terminal_reaso
|
|
|
4552
4564
|
const otherDetails = details && typeof details === "object" && !Array.isArray(details)
|
|
4553
4565
|
? Object.fromEntries(Object.entries(details).filter(([key]) => key !== "issues"))
|
|
4554
4566
|
: details;
|
|
4555
|
-
|
|
4556
|
-
|
|
4557
|
-
|
|
4558
|
-
|
|
4567
|
+
// otherDetails 는 사람 줄에 쓰지 않는다 — 영수증에 그대로 남는다.
|
|
4568
|
+
void otherDetails;
|
|
4569
|
+
/*
|
|
4570
|
+
* 사람이 읽는 줄에 JSON 을 찍지 않는다(2026-08-11 오너 지적). 예전에는
|
|
4571
|
+
* `code: message — {"cause":"…"}` 형태로 나가서, 유일하게 실행 가능한 문장
|
|
4572
|
+
* ("agentlas login")이 JSON 안에 묻히고 두 번의 절단(1200자→800자)에 걸려
|
|
4573
|
+
* 이스케이프 중간에서 잘렸다. 지금은 문장이 먼저, 기계 코드는 맨 끝 한 줄.
|
|
4574
|
+
*/
|
|
4575
|
+
const failureError = receipt.failure.error;
|
|
4576
|
+
if (failureError && (failureError.honestStop || failureError.code)) ui.error(failureError);
|
|
4577
|
+
else ui.error(String(receipt.failure.message || ""), { reveal: true });
|
|
4559
4578
|
if (issues) {
|
|
4560
|
-
for (const issue of issues.slice(0, 16)) ui.
|
|
4561
|
-
if (issues.length > 16) ui.
|
|
4579
|
+
for (const issue of issues.slice(0, 16)) ui.line(ui.c.dim(` · ${String(issue).slice(0, 400)}`));
|
|
4580
|
+
if (issues.length > 16) ui.line(ui.c.dim(` · … ${issues.length - 16} more in the persisted receipt`));
|
|
4562
4581
|
}
|
|
4582
|
+
ui.line(ui.c.faint(` ${receipt.failure.code}`));
|
|
4563
4583
|
// 실패한 실행이야말로 토큰이 어디로 갔는지 알아야 하는 순간이다. issues 유무와
|
|
4564
4584
|
// 무관하게 낸다 — 첫 배선이 이 블록 안에 들어가는 바람에 issues 없는 실패에서는
|
|
4565
4585
|
// 장부가 통째로 사라졌다.
|
package/engine/commands/help.cjs
CHANGED
|
@@ -1,164 +1,45 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
/* help / usage — v2 명령 표면. 재구축이 진행되며 이 표가 곧 진실이다. */
|
|
3
|
-
|
|
4
|
-
const HELP = `agentlas — the operating system for agents, in your terminal
|
|
5
|
-
|
|
6
|
-
agentlas open the terminal (REPL)
|
|
7
|
-
agentlas "<task>" run once with this project's controller
|
|
8
|
-
graph new "<what you want run for you>" build an automation by talking it through
|
|
9
|
-
|
|
10
|
-
PROJECT WORK
|
|
11
|
-
run [agent] [prompt] project-first one-shot; exact agent is an explicit advanced override
|
|
12
|
-
firm <firm> [task] delegate to a CEO (--runtime · --model · --effort)
|
|
13
|
-
|
|
14
|
-
AGENTS & HUB
|
|
15
|
-
search "<what you need>" discover agents in the Hub
|
|
16
|
-
install <slug> install an agent from the Hub
|
|
17
|
-
plugin add <slug> · plugin list Hub plugins (MCP servers)
|
|
18
|
-
build "<request>" build an installable agent locally (auto-installs)
|
|
19
|
-
upload <path> save owner-private in Agent Cloud (--visibility marketplace to publish)
|
|
20
|
-
import <path> · cd · native prepare local folder agents
|
|
21
|
-
list installed agents/companies + orchestrator/worker runtimes
|
|
22
|
-
roles [set <role> <rt>] show or set orchestrator/worker model roles
|
|
23
|
-
experience <sub> portable Experience: list|inspect|validate|save|publish|status|export|unpublish
|
|
24
|
-
variant resolve --base-release <id> local variant selection (variant help)
|
|
25
|
-
|
|
26
|
-
EXECUTE
|
|
27
|
-
storm <goal> Goal+UltraCode harness: plan → allocate → execute → verify [--research]
|
|
28
|
-
swarm <goal> emergent agent swarm [--parallel N]
|
|
29
|
-
workforce | network <request> Agent Workforce Ontology route (public Hub menu)
|
|
30
|
-
hep-network "<request>" staff across Local + owner Cloud + public Hub (local Core federation)
|
|
31
|
-
hep-local | hep-cloud | hep-hub "<request>" same, restricted to one source scope
|
|
32
|
-
call "a,b" "<ctx>" · browser <url|status|sites|login> · route "<req>" [--json] · research <sub>
|
|
33
|
-
|
|
34
|
-
KNOWLEDGE
|
|
35
|
-
memory import · evolve memory & prompt-evolution proposals
|
|
36
|
-
ontology · career-graph project knowledge & source routing
|
|
37
|
-
journal <sub> Stormbreaker run journal
|
|
38
|
-
project <sub> connect this folder + set an ordered team, standalone
|
|
39
|
-
(status · init · use <agent> · team <agent>…)
|
|
40
|
-
context <sub> dependency map: refresh|locate|refs|slice|impact|verify
|
|
41
|
-
|
|
42
|
-
ACCOUNT & OPS
|
|
43
|
-
login | logout | whoami Agentlas Cloud sign-in (browser flow)
|
|
44
|
-
cloud <sub> cloud assets: save|publish|package|list|restore|field-test
|
|
45
|
-
automation <sub> list|add|on|off|remove|run <id>|runs|daemon
|
|
46
|
-
graph <sub> new "<what you want>"|list|show|run <name>|export|inspect|install
|
|
47
|
-
creds <sub> · env credentials and shared env keys
|
|
48
|
-
usage · telegram · mcp local usage · telegram bindings · MCP servers (mcp probe <id>)
|
|
49
|
-
multimodal image/video/audio provider settings
|
|
50
|
-
doctor · setup · update health check · first-run wizard · npm update check
|
|
51
|
-
oberon | film <sub> AI film render (scaffold|render|list|open)
|
|
52
|
-
hep <sub…> · netadmin Hephaestus passthrough · local agent network
|
|
53
|
-
version · help
|
|
54
|
-
|
|
55
|
-
IN-REPL (agentlas → interactive, Orca multi-session)
|
|
56
|
-
/sessions · /tree · /s <n> | /switch <n> · /kill <n> · /rm <n>
|
|
57
|
-
/runtime <kind> · /model <id> · /effort <level> · /permission <level> (applies to new sessions)
|
|
58
|
-
every command above also works as a slash command (/graph, /search, /automation, …) — /help lists them all
|
|
59
|
-
typing during a running turn queues steering; ctrl-c interrupts the turn
|
|
60
|
-
|
|
61
|
-
Options: -p|--print · --runtime claude-code|codex|gemini · --model <exact-id> ·
|
|
62
|
-
--effort none|minimal|low|medium|high|xhigh|max ·
|
|
63
|
-
--tier economy|balanced|frontier (requires --model) ·
|
|
64
|
-
--permission read|write|full
|
|
65
|
-
`;
|
|
66
|
-
|
|
67
2
|
/*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
3
|
+
* commands/help — 정본은 ui/commands-catalog.cjs 하나다(2026-08-11 재작성).
|
|
4
|
+
*
|
|
5
|
+
* 이 파일에는 EN 61줄 + KO 133줄의 손유지 블록 두 벌이 있었다. 팔레트와 어긋나
|
|
6
|
+
* 같은 명령이 표면마다 다른 인자·설명을 광고했고(`search "<what you need>"` vs
|
|
7
|
+
* `"<필요한 것>"`), `agentlas help doctor` 는 인자를 무시하고 전체를 쏟아냈다.
|
|
8
|
+
* 이제 CLI·기본 REPL·새 셸이 같은 renderHelp 를 부른다 — 다시 갈라질 수 없다.
|
|
71
9
|
*/
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
firm <firm> [task] 회사 CEO에게 위임 (--runtime · --model · --effort)
|
|
81
|
-
|
|
82
|
-
AGENTS & HUB
|
|
83
|
-
search "<필요한 것>" Hub에서 에이전트 찾기
|
|
84
|
-
install <slug> Hub 에이전트 설치
|
|
85
|
-
plugin add <slug> · plugin list Hub 플러그인 (MCP 서버)
|
|
86
|
-
build "<요청>" 에이전트를 로컬에서 만들고 바로 설치
|
|
87
|
-
upload <path> Agent Cloud에 소유자 비공개 저장 (--visibility marketplace 로 발행)
|
|
88
|
-
import <path> · cd · native prepare 로컬 폴더 에이전트
|
|
89
|
-
list 설치 에이전트/회사 + 오케스트레이터·워커 런타임
|
|
90
|
-
roles [set <role> <rt>] 오케스트레이터·워커 모델 역할 조회/설정
|
|
91
|
-
experience <sub> 이동식 Experience: list|inspect|validate|save|publish|status|export|unpublish
|
|
92
|
-
variant resolve --base-release <id> 로컬 변형 선택 (variant help)
|
|
93
|
-
|
|
94
|
-
EXECUTE
|
|
95
|
-
storm <goal> Goal+UltraCode 하니스: 계획 → 배정 → 실행 → 검증 [--research]
|
|
96
|
-
swarm <goal> 창발형 에이전트 스웜 [--parallel N]
|
|
97
|
-
workforce | network <request> Agent Workforce Ontology 편성 (공개 Hub 메뉴)
|
|
98
|
-
hep-network "<request>" 로컬+오너 클라우드+공개 Hub 연합 편성 (로컬 Core 연합)
|
|
99
|
-
hep-local | hep-cloud | hep-hub "<request>" 같은 편성, 한 소스 스코프로 제한
|
|
100
|
-
call "a,b" "<ctx>" · browser <url|status|sites|login> · route "<req>" [--json] · research <sub>
|
|
101
|
-
|
|
102
|
-
KNOWLEDGE
|
|
103
|
-
memory import · evolve 메모리·프롬프트 진화 제안
|
|
104
|
-
ontology · career-graph 프로젝트 지식·소스 라우팅
|
|
105
|
-
journal <sub> Stormbreaker 런 저널
|
|
106
|
-
project <sub> 이 폴더를 프로젝트로 연결 + 순서 팀 편성 (독립)
|
|
107
|
-
(status · init · use <에이전트> · team <에이전트>…)
|
|
108
|
-
context <sub> 의존성 지도: refresh|locate|refs|slice|impact|verify
|
|
109
|
-
|
|
110
|
-
ACCOUNT & OPS
|
|
111
|
-
login | logout | whoami Agentlas Cloud 로그인 (브라우저 플로)
|
|
112
|
-
cloud <sub> 클라우드 자산: save|publish|package|list|restore|field-test
|
|
113
|
-
automation <sub> list|add|on|off|remove|run <id>|runs|daemon
|
|
114
|
-
graph <sub> new "<시킬 일>"|list|show|run <이름>|export|inspect|install
|
|
115
|
-
creds <sub> · env 자격증명·공유 env 키 (creds list 로 확인)
|
|
116
|
-
usage · telegram · mcp 로컬 사용량 · 텔레그램 연결 · MCP 서버 (mcp probe <id>)
|
|
117
|
-
multimodal 이미지/영상/음성 제공자 설정
|
|
118
|
-
doctor · setup · update 건강 점검 · 첫 실행 마법사 · npm 업데이트 확인
|
|
119
|
-
oberon | film <sub> AI 필름 렌더 (scaffold|render|list|open)
|
|
120
|
-
hep <sub…> · netadmin Hephaestus 패스스루 · 로컬 에이전트 네트워크
|
|
121
|
-
version · help
|
|
122
|
-
|
|
123
|
-
IN-REPL (agentlas → 대화형, Orca 다중 세션)
|
|
124
|
-
/sessions · /tree · /s <n> | /switch <n> · /kill <n> · /rm <n>
|
|
125
|
-
/runtime <kind> · /model <id> · /effort <level> · /permission <level> (새 세션부터 적용)
|
|
126
|
-
위의 모든 명령은 슬래시 명령(/graph, /search, /automation, …)으로도 됩니다 — 전체 목록은 /help
|
|
127
|
-
실행 중 입력하면 조종 큐에 쌓이고, ctrl-c 로 턴을 중단합니다
|
|
128
|
-
|
|
129
|
-
Options: -p|--print · --runtime claude-code|codex|gemini · --model <exact-id> ·
|
|
130
|
-
--effort none|minimal|low|medium|high|xhigh|max ·
|
|
131
|
-
--tier economy|balanced|frontier (--model 필요) ·
|
|
132
|
-
--permission read|write|full
|
|
133
|
-
`;
|
|
134
|
-
|
|
135
|
-
function helpText(ctx) {
|
|
136
|
-
return ctx && ctx.lang === "ko" ? HELP_KO : HELP;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
function run(ctx) {
|
|
140
|
-
ctx.out(helpText(ctx).trimEnd());
|
|
10
|
+
const catalog = require("../ui/commands-catalog.cjs");
|
|
11
|
+
|
|
12
|
+
function run(ctx, args = []) {
|
|
13
|
+
const first = String((args && args[0]) || "").trim();
|
|
14
|
+
const all = first.toLowerCase() === "all";
|
|
15
|
+
const name = !all && first && !first.startsWith("-") ? first : null;
|
|
16
|
+
if (name) return runForCommand(ctx, name);
|
|
17
|
+
ctx.out(catalog.renderHelp({ lang: ctx.lang, surface: "cli", all }));
|
|
141
18
|
return 0;
|
|
142
19
|
}
|
|
143
20
|
|
|
144
21
|
function runForCommand(ctx, command) {
|
|
145
|
-
const name = String(command || "").trim();
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
ctx.out(`Usage: agentlas ${
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
}
|
|
159
|
-
|
|
22
|
+
const name = String(command || "").trim().replace(/^\//, "");
|
|
23
|
+
const entry = catalog.byName(name);
|
|
24
|
+
const ko = ctx && ctx.lang === "ko";
|
|
25
|
+
if (!entry) {
|
|
26
|
+
// 없는 이름을 지어내지 않는다 — 전체 목록으로 보낸다.
|
|
27
|
+
ctx.out(`Usage: agentlas ${name}`);
|
|
28
|
+
ctx.out(ko ? ' 전체 목록: agentlas help all' : ' Full list: agentlas help all');
|
|
29
|
+
return 0;
|
|
30
|
+
}
|
|
31
|
+
const replOnly = !entry.surfaces.includes("cli");
|
|
32
|
+
ctx.out(`Usage: agentlas ${catalog.usageFor(entry, ctx.lang)}`);
|
|
33
|
+
ctx.out(` ${catalog.descFor(entry, ctx.lang)}`);
|
|
34
|
+
if (entry.aliases && entry.aliases.length) {
|
|
35
|
+
ctx.out(ko ? ` 다른 이름: ${entry.aliases.join(", ")}` : ` Also: ${entry.aliases.join(", ")}`);
|
|
36
|
+
}
|
|
37
|
+
if (replOnly) {
|
|
38
|
+
ctx.out(ko
|
|
39
|
+
? ` 이 명령은 터미널 안에서 씁니다: agentlas 를 실행한 뒤 /${entry.name}`
|
|
40
|
+
: ` This one runs inside the terminal: start agentlas, then /${entry.name}`);
|
|
160
41
|
}
|
|
161
42
|
return 0;
|
|
162
43
|
}
|
|
163
44
|
|
|
164
|
-
module.exports = { run, runForCommand
|
|
45
|
+
module.exports = { run, runForCommand };
|
|
@@ -10,8 +10,9 @@ const path = require("node:path");
|
|
|
10
10
|
|
|
11
11
|
// 각 명령 파일은 { run(ctx, args) } 를 export한다. ctx는 엔진이 만든 얕은 DI 객체.
|
|
12
12
|
const COMMANDS = {
|
|
13
|
+
// 정본 이름은 agents. list 는 별칭으로 영구 호출 가능(스크립트·게이트 사용).
|
|
14
|
+
agents: () => require("./list.cjs"),
|
|
13
15
|
version: () => require("./version.cjs"),
|
|
14
|
-
list: () => require("./list.cjs"),
|
|
15
16
|
graph: () => require("./graph.cjs"),
|
|
16
17
|
doctor: () => require("./doctor.cjs"),
|
|
17
18
|
mcp: () => require("./mcp.cjs"),
|
|
@@ -31,14 +32,11 @@ const COMMANDS = {
|
|
|
31
32
|
cd: () => require("./cd.cjs"),
|
|
32
33
|
install: () => require("./install.cjs"),
|
|
33
34
|
plugin: () => require("./plugin.cjs"),
|
|
34
|
-
plugins: () => require("./plugin.cjs"),
|
|
35
35
|
automation: () => require("./automation.cjs"),
|
|
36
36
|
native: () => require("./native.cjs"),
|
|
37
37
|
multimodal: () => require("./multimodal.cjs"),
|
|
38
38
|
document: () => require("./document.cjs"),
|
|
39
39
|
workforce: () => require("./workforce.cjs"),
|
|
40
|
-
network: () => require("./workforce.cjs"),
|
|
41
|
-
taskforce: () => require("./workforce.cjs"),
|
|
42
40
|
// 소스 스코프 편성 4종 — 2026-08-05 네이티브 배선(경위는 workforce.cjs 참조).
|
|
43
41
|
// 별칭이 아니라 1급인 이유는 여전하다: 별칭은 스코프를 전달하지 못한다.
|
|
44
42
|
"hep-network": () => require("./hep-network.cjs"),
|
|
@@ -46,7 +44,6 @@ const COMMANDS = {
|
|
|
46
44
|
"hep-cloud": () => require("./hep-cloud.cjs"),
|
|
47
45
|
"hep-hub": () => require("./hep-hub.cjs"),
|
|
48
46
|
oberon: () => require("./oberon.cjs"),
|
|
49
|
-
film: () => require("./film.cjs"),
|
|
50
47
|
experience: () => require("./experience.cjs"),
|
|
51
48
|
memory: () => require("./memory.cjs"),
|
|
52
49
|
evolve: () => require("./evolve.cjs"),
|
|
@@ -60,7 +57,6 @@ const COMMANDS = {
|
|
|
60
57
|
route: () => require("./route.cjs"),
|
|
61
58
|
research: () => require("./research.cjs"),
|
|
62
59
|
netadmin: () => require("./netadmin.cjs"),
|
|
63
|
-
journal: () => require("./journal.cjs"),
|
|
64
60
|
cloud: () => require("./cloud.cjs"),
|
|
65
61
|
upload: () => require("./upload.cjs"),
|
|
66
62
|
storm: () => require("./storm.cjs"),
|
|
@@ -68,7 +64,6 @@ const COMMANDS = {
|
|
|
68
64
|
project: () => require("./project.cjs"),
|
|
69
65
|
context: () => require("./context.cjs"),
|
|
70
66
|
ontology: () => require("./ontology.cjs"),
|
|
71
|
-
"career-graph": () => require("./career-graph.cjs"),
|
|
72
67
|
creds: () => require("./creds.cjs"),
|
|
73
68
|
billing: () => require("./billing.cjs"),
|
|
74
69
|
uninstall: () => require("./uninstall.cjs"),
|
|
@@ -139,6 +134,30 @@ const COMMAND_ALIASES = {
|
|
|
139
134
|
"hep-storm": "storm",
|
|
140
135
|
"hep-browser": "browser",
|
|
141
136
|
"hep-connect": "connect",
|
|
137
|
+
// 2026-08-11: 같은 기능을 두 이름으로 광고하던 것을 별칭으로 접었다.
|
|
138
|
+
list: "agents",
|
|
139
|
+
network: "workforce",
|
|
140
|
+
taskforce: "workforce",
|
|
141
|
+
film: "oberon",
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
/*
|
|
145
|
+
* 제거된 명령 — 이름을 그냥 없애면 인자와 함께 프롬프트로 새어 유료 턴이 된다
|
|
146
|
+
* (아래 marketplace 사고 주석과 같은 계열). 착지 안내를 두고 arity 무관하게 잡는다.
|
|
147
|
+
*/
|
|
148
|
+
const REMOVED_COMMANDS = {
|
|
149
|
+
journal: {
|
|
150
|
+
en: "`journal` was removed — it reported \"ok\" for runs that do not exist and read the wrong folder.\nExperts: agentlas hep stormbreaker journal --run-id <id> --journal <path>",
|
|
151
|
+
ko: "`journal` 은 제거됐습니다 — 없는 실행에도 \"ok\" 를 답했고 다른 폴더를 봤습니다.\n전문가용: agentlas hep stormbreaker journal --run-id <id> --journal <path>",
|
|
152
|
+
},
|
|
153
|
+
"career-graph": {
|
|
154
|
+
en: "`career-graph` was removed — its read commands silently created project state.\nSources: agentlas ontology · Index: hephaestus career-graph ingest --project .",
|
|
155
|
+
ko: "`career-graph` 는 제거됐습니다 — 조회 명령이 말없이 프로젝트 상태를 만들었습니다.\n소스: agentlas ontology · 색인: hephaestus career-graph ingest --project .",
|
|
156
|
+
},
|
|
157
|
+
plugins: {
|
|
158
|
+
en: "Use: agentlas plugin list",
|
|
159
|
+
ko: "이렇게 쓰세요: agentlas plugin list",
|
|
160
|
+
},
|
|
142
161
|
};
|
|
143
162
|
|
|
144
163
|
function resolveCommandName(cmd) {
|
|
@@ -189,6 +208,10 @@ function dispatch(ctx, argv) {
|
|
|
189
208
|
// 낙하 가드부터 만들 것: 상위 오타 가드는 한 단어 전용이라 인자가 붙은
|
|
190
209
|
// 삭제 이름은 프롬프트로 흘러 에이전트를 기동한다(실측·토큰 소모).
|
|
191
210
|
|
|
211
|
+
if (REMOVED_COMMANDS[cmd]) {
|
|
212
|
+
ctx.err(REMOVED_COMMANDS[cmd][ctx.lang === "ko" ? "ko" : "en"]);
|
|
213
|
+
return 1;
|
|
214
|
+
}
|
|
192
215
|
if (DESKTOP_ONLY_SURFACES[cmd]) {
|
|
193
216
|
const asTask = [rawCmd, ...rest].join(" ");
|
|
194
217
|
ctx.err(`${DESKTOP_ONLY_SURFACES[cmd]}\nIt was not run as a prompt — rerun with quotes if you meant a task: agentlas "${asTask}"`);
|
|
@@ -207,4 +230,4 @@ function dispatch(ctx, argv) {
|
|
|
207
230
|
return undefined; // 알 수 없는 토큰 — 엔진이 에이전트 이름/프롬프트로 해석 시도
|
|
208
231
|
}
|
|
209
232
|
|
|
210
|
-
module.exports = { dispatch, COMMANDS, COMMAND_ALIASES, resolveCommandName, SELF_HELP_COMMANDS, NOT_YET_PORTED, GUARDED_NO_ARG, DESKTOP_ONLY_SURFACES };
|
|
233
|
+
module.exports = { dispatch, COMMANDS, COMMAND_ALIASES, resolveCommandName, SELF_HELP_COMMANDS, NOT_YET_PORTED, GUARDED_NO_ARG, DESKTOP_ONLY_SURFACES, REMOVED_COMMANDS };
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* ui/commands-catalog — 명령 정본 한 벌 (2026-08-11 전면 재작성).
|
|
4
|
+
*
|
|
5
|
+
* 배경: 같은 목록이 네 곳에 손으로 유지되고 있었다 — palette.SLASH_COMMANDS(71행),
|
|
6
|
+
* help.HELP(EN 61줄), help.HELP_KO(133줄), shell.toSlashCommands(파생). 넷이 서로
|
|
7
|
+
* 어긋난 것이 결함 대부분의 기계적 원인이었다:
|
|
8
|
+
* · 영문 화면에 한글 인자 힌트(`/graph [run <이름>]`)
|
|
9
|
+
* · 같은 기능이 서로 다른 설명으로 두 줄(`search "<what you need>"` vs `"<필요한 것>"`)
|
|
10
|
+
* · renderPalette 가 설명 텍스트로 중복 제거 → `/switch` `/list` `/exit` 가 조용히 사라짐
|
|
11
|
+
* · /help 가 표면마다 61 / 133 / 67줄
|
|
12
|
+
*
|
|
13
|
+
* 그래서 정본을 하나로 합치고, 별칭은 **행이 아니라 필드**로 둔다. 별칭이 행이 아니면
|
|
14
|
+
* 중복 설명 자체가 생기지 않으므로 위 dedup 이 필요 없어지고, 숨김 사고가 구조적으로 막힌다.
|
|
15
|
+
*
|
|
16
|
+
* 불변식(게이트 test/command-surface-contract.cjs 가 잠근다):
|
|
17
|
+
* - COMMANDS 키 ↔ 카탈로그 행 1:1. 예외는 surfaces:["repl"] (셸 switch 가 직접 처리).
|
|
18
|
+
* - args 는 ASCII 정본. 한국어는 argsKo 로만 — 언어 혼재 금지.
|
|
19
|
+
* - tier "core" 만 기본 /help 에 나온다. 나머지는 /help all. 단 Tab 완성은 전부 된다
|
|
20
|
+
* (완성에서 숨기는 것이 바로 `/switch` 결함이었다).
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
const { visWidth } = require("./width.cjs");
|
|
24
|
+
|
|
25
|
+
const GROUPS = [
|
|
26
|
+
{ key: "start", ko: "시작", en: "Start here" },
|
|
27
|
+
{ key: "work", ko: "일 시키기", en: "Do work" },
|
|
28
|
+
{ key: "agents", ko: "에이전트", en: "Agents" },
|
|
29
|
+
{ key: "automate", ko: "자동화", en: "Automate" },
|
|
30
|
+
{ key: "session", ko: "세션 (셸 안에서만)", en: "Sessions (in-shell only)" },
|
|
31
|
+
{ key: "settings", ko: "설정 (셸 안에서만)", en: "Settings (in-shell only)" },
|
|
32
|
+
{ key: "account", ko: "계정·자산", en: "Account & assets" },
|
|
33
|
+
{ key: "knowledge", ko: "프로젝트 지식", en: "Project knowledge" },
|
|
34
|
+
{ key: "advanced", ko: "고급", en: "Advanced" },
|
|
35
|
+
];
|
|
36
|
+
|
|
37
|
+
const CLI = ["cli"];
|
|
38
|
+
const BOTH = ["cli", "repl"];
|
|
39
|
+
const REPL = ["repl"];
|
|
40
|
+
|
|
41
|
+
/* eslint-disable max-len */
|
|
42
|
+
const CATALOG = [
|
|
43
|
+
// ── 1 start ───────────────────────────────────────────────────────────────
|
|
44
|
+
{ name: "setup", group: "start", tier: "core", surfaces: CLI, args: "", ko: "첫 실행 마법사 — 언어·런타임·권한", en: "First-run wizard — language, runtime, permission" },
|
|
45
|
+
{ name: "doctor", group: "start", tier: "core", surfaces: BOTH, args: "[--json]", ko: "설치 상태 점검", en: "Check this installation" },
|
|
46
|
+
{ name: "login", group: "start", tier: "core", surfaces: BOTH, args: "[--force]", ko: "Agentlas 로그인 (--force 로 계정 전환)", en: "Sign in to Agentlas (--force switches account)" },
|
|
47
|
+
{ name: "help", group: "start", tier: "core", surfaces: BOTH, args: "[all|<command>]", argsKo: "[all|<명령>]", ko: "명령 보기 (all = 전체 목록)", en: "Show commands (all = the full list)" },
|
|
48
|
+
|
|
49
|
+
// ── 2 work ────────────────────────────────────────────────────────────────
|
|
50
|
+
{ name: "run", group: "work", tier: "core", surfaces: CLI, args: '[agent] "<task>"', argsKo: '[에이전트] "<작업>"', ko: "이 프로젝트 컨트롤러로 1회 실행", en: "Run once with this project's controller" },
|
|
51
|
+
{ name: "project", group: "work", tier: "core", surfaces: BOTH, args: "[status|use <agent>]", argsKo: "[status|use <에이전트>]", ko: "이 폴더를 프로젝트로 연결", en: "Connect this folder to a project" },
|
|
52
|
+
{ name: "storm", group: "work", tier: "core", surfaces: BOTH, args: '"<goal>"', argsKo: '"<목표>"', ko: "목표 하나를 계획→실행→검증까지", en: "Drive one goal: plan, execute, verify" },
|
|
53
|
+
{ name: "workforce", group: "work", tier: "core", surfaces: BOTH, aliases: ["network", "taskforce"], args: '"<request>"', argsKo: '"<요청>"', ko: "여러 에이전트를 편성해 실행 (공개 Hub)", en: "Staff several agents and run (public Hub)" },
|
|
54
|
+
{ name: "call", group: "work", tier: "core", surfaces: BOTH, aliases: ["hep-call"], args: '"a,b" "<context>"', argsKo: '"a,b" "<맥락>"', ko: "이름을 아는 에이전트를 직접 호출", en: "Call agents you name" },
|
|
55
|
+
|
|
56
|
+
// ── 3 agents ──────────────────────────────────────────────────────────────
|
|
57
|
+
{ name: "agents", group: "agents", tier: "core", surfaces: BOTH, aliases: ["list"], args: "[--json]", ko: "설치된 에이전트·팀", en: "Installed agents and teams" },
|
|
58
|
+
{ name: "search", group: "agents", tier: "core", surfaces: BOTH, aliases: ["hep-search"], args: '"<what you need>"', argsKo: '"<필요한 것>"', ko: "Hub에서 에이전트 찾기", en: "Find agents in the Hub" },
|
|
59
|
+
{ name: "install", group: "agents", tier: "core", surfaces: BOTH, args: "<slug>", ko: "Hub 에이전트 설치", en: "Install an agent from the Hub" },
|
|
60
|
+
{ name: "build", group: "agents", tier: "core", surfaces: BOTH, aliases: ["hep-build"], args: '"<the agent you want>"', argsKo: '"<원하는 에이전트>"', ko: "에이전트를 여기서 만들어 바로 설치 (쓰기 권한)", en: "Build an agent here and install it (runs with write permission)" },
|
|
61
|
+
{ name: "roles", group: "agents", tier: "core", surfaces: BOTH, args: "[set <role> <runtime>]", argsKo: "[set <역할> <런타임>]", ko: "오케스트레이터·워커 모델 지정", en: "Set the orchestrator and worker models" },
|
|
62
|
+
|
|
63
|
+
// ── 4 automate ────────────────────────────────────────────────────────────
|
|
64
|
+
{ name: "automation", group: "automate", tier: "core", surfaces: BOTH, args: "[list|add|on|off|run]", ko: "예약 실행", en: "Scheduled runs" },
|
|
65
|
+
{ name: "graph", group: "automate", tier: "core", surfaces: BOTH, args: "[list|show|run <name>]", argsKo: "[list|show|run <이름>]", ko: "저장된 자동화 그래프", en: "Saved automation graphs" },
|
|
66
|
+
|
|
67
|
+
// ── 5 session (셸 전용) ───────────────────────────────────────────────────
|
|
68
|
+
{ name: "sessions", group: "session", tier: "core", surfaces: REPL, aliases: ["tree"], args: "", ko: "지금 도는 세션 목록", en: "Sessions running now" },
|
|
69
|
+
{ name: "s", group: "session", tier: "core", surfaces: REPL, aliases: ["switch"], args: "<n>", ko: "그 세션으로 전환", en: "Switch to that session" },
|
|
70
|
+
{ name: "kill", group: "session", tier: "core", surfaces: REPL, args: "<n>", ko: "그 세션의 턴 중단", en: "Interrupt that session's turn" },
|
|
71
|
+
{ name: "rm", group: "session", tier: "core", surfaces: REPL, args: "<n>", ko: "그 세션 닫기", en: "Close that session" },
|
|
72
|
+
{ name: "quit", group: "session", tier: "core", surfaces: REPL, aliases: ["exit"], args: "", ko: "종료", en: "Quit" },
|
|
73
|
+
|
|
74
|
+
// ── 6 settings (셸 전용 · 전부 세션 한정, 영구 경로를 설명에 못박는다) ────
|
|
75
|
+
{ name: "permission", group: "settings", tier: "core", surfaces: REPL, args: "read|write|full", ko: "이 셸의 새 세션 권한 (영구: agentlas setup)", en: "Permission for new sessions here (persist: agentlas setup)" },
|
|
76
|
+
{ name: "model", group: "settings", tier: "core", surfaces: REPL, args: "<id|default>", ko: "이 셸의 새 세션 모델 (영구: agentlas roles set)", en: "Model for new sessions here (persist: agentlas roles set)" },
|
|
77
|
+
{ name: "runtime", group: "settings", tier: "core", surfaces: REPL, args: "<kind>", ko: "이 셸의 새 세션 런타임 (영구: agentlas roles set)", en: "Runtime for new sessions here (persist: agentlas roles set)" },
|
|
78
|
+
{ name: "effort", group: "settings", tier: "core", surfaces: REPL, args: "<level>", ko: "이 셸의 새 세션 추론 강도 (영구: agentlas roles set --effort)", en: "Reasoning effort for new sessions here (persist: agentlas roles set --effort)" },
|
|
79
|
+
{ name: "shell", group: "settings", tier: "core", surfaces: REPL, args: "on|off", ko: "새 대화형 셸 켜기/끄기", en: "Turn the new interactive shell on or off" },
|
|
80
|
+
|
|
81
|
+
// ── 7 account ─────────────────────────────────────────────────────────────
|
|
82
|
+
{ name: "whoami", group: "account", tier: "more", surfaces: BOTH, args: "", ko: "로그인 계정 확인", en: "Show the signed-in account" },
|
|
83
|
+
{ name: "logout", group: "account", tier: "more", surfaces: BOTH, args: "", ko: "로그아웃", en: "Sign out" },
|
|
84
|
+
{ name: "billing", group: "account", tier: "more", surfaces: BOTH, args: "", ko: "크레딧 잔액 (구독·대여 수익)", en: "Credit balances (subscription and rental earnings)" },
|
|
85
|
+
{ name: "usage", group: "account", tier: "more", surfaces: BOTH, args: "", ko: "이 설치의 사용 현황", en: "Local usage on this install" },
|
|
86
|
+
{ name: "cloud", group: "account", tier: "more", surfaces: BOTH, args: "<save|publish|list|...>", ko: "Agent Cloud 자산", en: "Agent Cloud assets" },
|
|
87
|
+
{ name: "upload", group: "account", tier: "more", surfaces: BOTH, aliases: ["hep-upload"], args: "<path> [--visibility ...]", argsKo: "<경로> [--visibility ...]", ko: "기본은 비공개 저장, --visibility marketplace 로 공개 발행", en: "Owner-private by default; --visibility marketplace publishes" },
|
|
88
|
+
{ name: "uninstall", group: "account", tier: "more", surfaces: BOTH, args: "<slug> [--yes]", ko: "에이전트 삭제 (대화 기록도 함께 지워짐)", en: "Delete an agent (its chats are deleted too)" },
|
|
89
|
+
{ name: "update", group: "account", tier: "more", surfaces: BOTH, args: "[--json]", ko: "npm 업데이트 확인", en: "Check for an npm update" },
|
|
90
|
+
{ name: "version", group: "account", tier: "more", surfaces: BOTH, args: "", ko: "버전", en: "Version" },
|
|
91
|
+
|
|
92
|
+
// ── 8 knowledge ───────────────────────────────────────────────────────────
|
|
93
|
+
{ name: "ontology", group: "knowledge", tier: "more", surfaces: BOTH, args: "[status|list|add <path>]", argsKo: "[status|list|add <경로>]", ko: "이 프로젝트가 읽을 지식 소스 등록", en: "Register the knowledge sources this project may read" },
|
|
94
|
+
{ name: "context", group: "knowledge", tier: "more", surfaces: BOTH, args: "<locate|slice|impact|...>", ko: "코드 의존성 맵 (Agentlas OS Core 필요)", en: "Code dependency map (requires Agentlas OS Core)" },
|
|
95
|
+
{ name: "memory", group: "knowledge", tier: "more", surfaces: BOTH, args: "<sub>", ko: "메모리", en: "Memory" },
|
|
96
|
+
{ name: "experience", group: "knowledge", tier: "more", surfaces: BOTH, args: "<list|inspect|save|...>", ko: "이식 가능한 Experience", en: "Portable Experience" },
|
|
97
|
+
{ name: "evolve", group: "knowledge", tier: "more", surfaces: BOTH, args: "", ko: "프롬프트 진화 제안", en: "Prompt-evolution proposals" },
|
|
98
|
+
|
|
99
|
+
// ── 9 advanced ────────────────────────────────────────────────────────────
|
|
100
|
+
{ name: "route", group: "advanced", tier: "more", surfaces: BOTH, args: '"<request>"', argsKo: '"<요청>"', ko: "이 요청에 맞는 에이전트로 라우팅", en: "Route this request to the right agent" },
|
|
101
|
+
{ name: "swarm", group: "advanced", tier: "more", surfaces: BOTH, args: '"<goal>" [--parallel N]', argsKo: '"<목표>" [--parallel N]', ko: "창발형 에이전트 스웜", en: "Emergent agent swarm" },
|
|
102
|
+
{ name: "hep-network", group: "advanced", tier: "more", surfaces: BOTH, aliases: ["legacy-network"], args: '"<request>"', argsKo: '"<요청>"', ko: "로컬+오너 클라우드+공개 Hub 연합 편성 (로컬 Core 필요)", en: "Staff across Local + owner Cloud + public Hub (needs local Core)" },
|
|
103
|
+
{ name: "hep-local", group: "advanced", tier: "more", surfaces: BOTH, args: '"<request>"', argsKo: '"<요청>"', ko: "등록된 로컬 에이전트만으로 편성 (로컬 Core 필요)", en: "Staff from registered Local agents only (needs local Core)" },
|
|
104
|
+
{ name: "hep-cloud", group: "advanced", tier: "more", surfaces: BOTH, args: '"<request>"', argsKo: '"<요청>"', ko: "오너 Agent Cloud만으로 편성 (로그인·로컬 Core 필요)", en: "Staff from owner Agent Cloud only (needs sign-in + local Core)" },
|
|
105
|
+
{ name: "hep-hub", group: "advanced", tier: "more", surfaces: BOTH, args: '"<request>"', argsKo: '"<요청>"', ko: "공개 Hub 에이전트만으로 편성 (로컬 Core 필요)", en: "Staff from public Hub agents only (needs local Core)" },
|
|
106
|
+
{ name: "firm", group: "advanced", tier: "more", surfaces: CLI, args: "<firm> [task]", argsKo: "<회사> [작업]", ko: "회사 CEO에게 위임", en: "Delegate to a company CEO" },
|
|
107
|
+
{ name: "import", group: "advanced", tier: "more", surfaces: BOTH, args: "<path>", argsKo: "<경로>", ko: "로컬 폴더 에이전트 가져오기", en: "Import a local folder agent" },
|
|
108
|
+
{ name: "cd", group: "advanced", tier: "more", surfaces: BOTH, args: "<agent>", argsKo: "<에이전트>", ko: "그 에이전트의 폴더 경로를 출력", en: "Print that agent's folder path" },
|
|
109
|
+
{ name: "native", group: "advanced", tier: "more", surfaces: BOTH, args: "prepare <agent>", argsKo: "prepare <에이전트>", ko: "네이티브 CLI 컨텍스트 생성", en: "Prepare native CLI context" },
|
|
110
|
+
{ name: "mcp", group: "advanced", tier: "more", surfaces: BOTH, args: "[list|probe <id>]", ko: "MCP 서버", en: "MCP servers" },
|
|
111
|
+
{ name: "plugin", group: "advanced", tier: "more", surfaces: BOTH, args: "<add <slug>|list|remove>", ko: "Hub 플러그인 (MCP 서버)", en: "Hub plugins (MCP servers)" },
|
|
112
|
+
{ name: "creds", group: "advanced", tier: "more", surfaces: BOTH, args: "<list|save|file>", ko: "API 키 보관 (값은 절대 표시 안 함)", en: "API keys (values are never printed)" },
|
|
113
|
+
{ name: "env", group: "advanced", tier: "more", surfaces: BOTH, args: "", ko: "공유 환경 변수 이름", en: "Shared env key names" },
|
|
114
|
+
{ name: "multimodal", group: "advanced", tier: "more", surfaces: BOTH, args: "[set <kind> <provider>]", ko: "이미지·영상·음성 제공자", en: "Image, video and audio providers" },
|
|
115
|
+
{ name: "telegram", group: "advanced", tier: "more", surfaces: BOTH, args: "[sub]", ko: "텔레그램 연결", en: "Telegram bindings" },
|
|
116
|
+
{ name: "connect", group: "advanced", tier: "more", surfaces: BOTH, aliases: ["hep-connect"], args: "<target>", argsKo: "<대상>", ko: "에이전트·팀 연결", en: "Connect an agent or team" },
|
|
117
|
+
{ name: "browser", group: "advanced", tier: "more", surfaces: BOTH, aliases: ["hep-browser"], args: "<url|status|sites|login>", ko: "브라우저 하드포인트", en: "Browser hardpoint" },
|
|
118
|
+
{ name: "research", group: "advanced", tier: "more", surfaces: BOTH, args: "<sub>", ko: "리서치", en: "Research" },
|
|
119
|
+
{ name: "document", group: "advanced", tier: "more", surfaces: BOTH, args: "pdf <html|url>", ko: "문서 PDF 내보내기", en: "Export a document to PDF" },
|
|
120
|
+
{ name: "oberon", group: "advanced", tier: "more", surfaces: BOTH, aliases: ["film"], args: "<scaffold|render|list|open>", ko: "AI 필름 렌더", en: "AI film render" },
|
|
121
|
+
{ name: "variant", group: "advanced", tier: "more", surfaces: BOTH, args: "resolve --base-release", ko: "로컬 변형 선택", en: "Local variant selection" },
|
|
122
|
+
{ name: "netadmin", group: "advanced", tier: "more", surfaces: BOTH, args: "<init|status|reindex|...>", ko: "로컬 에이전트 네트워크 관리", en: "Local agent network administration" },
|
|
123
|
+
{ name: "hep", group: "advanced", tier: "more", surfaces: BOTH, aliases: ["hep-storm"], args: "<sub...>", ko: "Hephaestus 패스스루 (전문가용)", en: "Hephaestus passthrough (expert)" },
|
|
124
|
+
];
|
|
125
|
+
/* eslint-enable max-len */
|
|
126
|
+
|
|
127
|
+
const BY_NAME = new Map();
|
|
128
|
+
const ALIAS_TO_NAME = new Map();
|
|
129
|
+
for (const entry of CATALOG) {
|
|
130
|
+
BY_NAME.set(entry.name, entry);
|
|
131
|
+
for (const alias of entry.aliases || []) ALIAS_TO_NAME.set(alias, entry.name);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function byName(name) {
|
|
135
|
+
const key = String(name || "").replace(/^\//, "");
|
|
136
|
+
return BY_NAME.get(key) || BY_NAME.get(ALIAS_TO_NAME.get(key)) || null;
|
|
137
|
+
}
|
|
138
|
+
function aliasMap() { return Object.fromEntries(ALIAS_TO_NAME); }
|
|
139
|
+
function argsFor(entry, lang) { return (lang === "ko" && entry.argsKo) || entry.args || ""; }
|
|
140
|
+
function descFor(entry, lang) { return lang === "ko" ? entry.ko : entry.en; }
|
|
141
|
+
function usageFor(entry, lang) {
|
|
142
|
+
const args = argsFor(entry, lang);
|
|
143
|
+
return entry.name + (args ? " " + args : "");
|
|
144
|
+
}
|
|
145
|
+
function forSurface(surface) { return CATALOG.filter((e) => e.surfaces.includes(surface)); }
|
|
146
|
+
|
|
147
|
+
const padVis = (text, width) => text + " ".repeat(Math.max(0, width - visWidth(text)));
|
|
148
|
+
|
|
149
|
+
/*
|
|
150
|
+
* 정렬은 visWidth 로 잰다 — String.length 로 재면 한글 한 글자를 1칸으로 세어
|
|
151
|
+
* 설명 열이 어긋난다(현행 palette.cjs 의 결함).
|
|
152
|
+
*/
|
|
153
|
+
function renderHelp(options = {}) {
|
|
154
|
+
const lang = options.lang === "ko" ? "ko" : "en";
|
|
155
|
+
const surface = options.surface === "repl" ? "repl" : "cli";
|
|
156
|
+
const all = options.all === true;
|
|
157
|
+
const ko = lang === "ko";
|
|
158
|
+
const rows = forSurface(surface).filter((e) => all || e.tier === "core");
|
|
159
|
+
if (!rows.length) return "";
|
|
160
|
+
/*
|
|
161
|
+
* 머리말은 명령표가 아니라 "이게 무엇이고 어떻게 시작하나"다. 예전 HELP_KO 가
|
|
162
|
+
* 들고 있던 제품 한 줄(터미널 속 에이전트 운영체제)을 여기로 옮겼다 —
|
|
163
|
+
* 그 문장이 사라지면 첫 화면이 명령 나열로만 시작한다.
|
|
164
|
+
*/
|
|
165
|
+
const head = [];
|
|
166
|
+
{
|
|
167
|
+
let version = "";
|
|
168
|
+
try { version = require("../agentlas-banner.cjs").readVersion(); } catch { version = ""; }
|
|
169
|
+
head.push(`agentlas${version ? " " + version : ""} — ${ko ? "터미널 속 에이전트 운영체제" : "the agent operating system in your terminal"}`);
|
|
170
|
+
head.push("");
|
|
171
|
+
if (surface === "cli") {
|
|
172
|
+
head.push(ko ? ' agentlas 셸 열기' : ' agentlas open the shell');
|
|
173
|
+
head.push(ko ? ' agentlas "<하고 싶은 일>" 한 번 실행' : ' agentlas "<what you want>" run once');
|
|
174
|
+
}
|
|
175
|
+
head.push(ko
|
|
176
|
+
? " 셸 안에서는 그냥 문장을 치면 실행됩니다 · / 를 누르면 명령이 뜹니다"
|
|
177
|
+
: " In the shell, plain words run a task · press / for commands");
|
|
178
|
+
}
|
|
179
|
+
// 셸에서 셸 전용 명령은 슬래시를 붙여 보여준다 — 그게 실제로 치는 문자열이다.
|
|
180
|
+
const label = (e) => (surface === "repl" && e.surfaces.length === 1 ? "/" : "") + usageFor(e, lang);
|
|
181
|
+
/*
|
|
182
|
+
* 라벨 열에 상한을 둔다. 상한이 없으면 가장 긴 한 줄(automation 의 서브명령 나열)이
|
|
183
|
+
* 전체 열을 밀어 80칸 터미널에서 설명이 통째로 줄바꿈되고, 이어지는 줄은 들여쓰기를
|
|
184
|
+
* 잃는다. 상한을 넘는 소수 행만 자기 열을 넘어가고 나머지는 정렬을 지킨다.
|
|
185
|
+
*/
|
|
186
|
+
const LABEL_CAP = 34;
|
|
187
|
+
const width = Math.min(LABEL_CAP, Math.max(...rows.map((e) => visWidth(label(e)))));
|
|
188
|
+
const out = head.slice();
|
|
189
|
+
for (const group of GROUPS) {
|
|
190
|
+
const inGroup = rows.filter((e) => e.group === group.key);
|
|
191
|
+
if (!inGroup.length) continue;
|
|
192
|
+
out.push("", ko ? group.ko : group.en);
|
|
193
|
+
for (const e of inGroup) {
|
|
194
|
+
const text = label(e);
|
|
195
|
+
// 상한을 넘는 라벨은 정렬을 포기하되 설명과 붙지는 않게 최소 두 칸을 보장한다.
|
|
196
|
+
const gap = visWidth(text) >= width ? " " : " ".repeat(width + 2 - visWidth(text));
|
|
197
|
+
out.push(` ${text}${gap}${descFor(e, lang)}`);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
if (!all) {
|
|
201
|
+
const hidden = forSurface(surface).length - rows.length;
|
|
202
|
+
if (hidden > 0) {
|
|
203
|
+
out.push("", ko
|
|
204
|
+
? ` 나머지 ${hidden}개 명령: ${surface === "repl" ? "/help all" : "agentlas help all"}`
|
|
205
|
+
: ` ${hidden} more: ${surface === "repl" ? "/help all" : "agentlas help all"}`);
|
|
206
|
+
}
|
|
207
|
+
} else {
|
|
208
|
+
const withAliases = CATALOG.filter((e) => (e.aliases || []).length);
|
|
209
|
+
if (withAliases.length) {
|
|
210
|
+
out.push("", ko ? " 같은 명령의 다른 이름" : " Other names for the same command");
|
|
211
|
+
out.push(" " + withAliases.map((e) => `${e.name} (= ${e.aliases.join(", ")})`).join(" · "));
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
return out.join("\n").replace(/^\n/, "");
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
module.exports = { GROUPS, CATALOG, byName, aliasMap, argsFor, descFor, usageFor, forSurface, renderHelp };
|
package/engine/ui/palette.cjs
CHANGED
|
@@ -11,89 +11,21 @@
|
|
|
11
11
|
const { completePath, isAbsolutePathTask } = require("../agentlas-input.cjs");
|
|
12
12
|
|
|
13
13
|
// command, 인자 힌트, 한 줄 설명 — /help 팔레트와 Tab 완성이 같은 정본을 쓴다.
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
{ command: "/effort", args: "<level|none>", ko: "새 세션 추론 강도 지정", en: "Set effort for new sessions" },
|
|
30
|
-
{ command: "/permission", args: "<level>", ko: "새 세션 권한 지정", en: "Set permission for new sessions" },
|
|
31
|
-
{ command: "/login", args: "", ko: "Agentlas Cloud 로그인", en: "Sign in to Agentlas Cloud" },
|
|
32
|
-
{ command: "/whoami", args: "", ko: "로그인 상태", en: "Signed-in account" },
|
|
33
|
-
{ command: "/search", args: "\"<what you need>\"", ko: "Hub 에이전트 검색", en: "Search Hub agents" },
|
|
34
|
-
{ command: "/install", args: "<slug>", ko: "Hub 에이전트 설치", en: "Install a Hub agent" },
|
|
35
|
-
{ command: "/usage", args: "", ko: "로컬 사용 현황", en: "Local usage" },
|
|
36
|
-
{ command: "/billing", args: "", ko: "크레딧 잔액", en: "Credit balance" },
|
|
37
|
-
{ command: "/automation", args: "[sub]", ko: "자동화", en: "Automations" },
|
|
38
|
-
{ command: "/storm", args: "<goal>", ko: "Goal+UltraCode 하니스", en: "Goal+UltraCode harness" },
|
|
39
|
-
{ command: "/swarm", args: "<goal>", ko: "에이전트 스웜", en: "Agent swarm" },
|
|
40
|
-
{ command: "/network", args: "<request>", ko: "Workforce 라우트", en: "Workforce route" },
|
|
41
|
-
{ command: "/workforce", args: "<request>", ko: "Workforce 라우트", en: "Workforce route" },
|
|
42
|
-
{ command: "/taskforce", args: "<request>", ko: "임시 태스크포스 편성", en: "Assemble a task force" },
|
|
43
|
-
// 소스 스코프 편성 4종 — 2026-08-05 같은 날 삭제 후 네이티브 배선으로 복원.
|
|
44
|
-
// 이전에는 외부 CLI 스텁(exit 3)이라 죽은 메뉴였다. 지금은 이 터미널의 편성
|
|
45
|
-
// 루프가 직접 돌고 로컬 Agentlas-OS Core가 선언된 스코프의 메뉴를 연합한다.
|
|
46
|
-
// 팔레트 문구가 곧 사용자에게 하는 약속이다 — 스코프를 문장에 적는다.
|
|
47
|
-
{ command: "/hep-network", args: "\"<request>\"", ko: "로컬+오너 클라우드+공개 Hub 연합 편성", en: "Staff across Local + owner Cloud + public Hub" },
|
|
48
|
-
{ command: "/hep-local", args: "\"<request>\"", ko: "등록된 로컬 에이전트만으로 편성", en: "Staff from registered Local agents only" },
|
|
49
|
-
{ command: "/hep-cloud", args: "\"<request>\"", ko: "오너 Agent Cloud만으로 편성", en: "Staff from owner Agent Cloud only" },
|
|
50
|
-
{ command: "/hep-hub", args: "\"<request>\"", ko: "공개 Hub 에이전트만으로 편성", en: "Staff from public Hub agents only" },
|
|
51
|
-
{ command: "/build", args: "\"<request>\"", ko: "에이전트·팀 제작/수리/패키징", en: "Build, repair or package an agent or team" },
|
|
52
|
-
{ command: "/call", args: "\"a,b\" \"<ctx>\"", ko: "지정 에이전트 호출", en: "Call named agents" },
|
|
53
|
-
{ command: "/route", args: "\"<req>\"", ko: "최적 에이전트 라우팅", en: "Route to the best agent" },
|
|
54
|
-
{ command: "/browser", args: "[sub]", ko: "브라우저 하드포인트", en: "Browser hardpoint" },
|
|
55
|
-
{ command: "/connect", args: "<target>", ko: "에이전트·팀 연결", en: "Connect an agent or team" },
|
|
56
|
-
{ command: "/research", args: "<sub>", ko: "리서치", en: "Research" },
|
|
57
|
-
{ command: "/upload", args: "<path>", ko: "Agent Cloud에 저장·발행", en: "Save to Agent Cloud or publish" },
|
|
58
|
-
{ command: "/cloud", args: "<sub>", ko: "클라우드 자산 관리", en: "Cloud assets" },
|
|
59
|
-
{ command: "/import", args: "<path>", ko: "로컬 폴더 에이전트 가져오기", en: "Import a local folder agent" },
|
|
60
|
-
{ command: "/cd", args: "[path]", ko: "작업 폴더 이동", en: "Change working folder" },
|
|
61
|
-
{ command: "/native", args: "prepare <agent>", ko: "네이티브 CLI 컨텍스트 생성", en: "Prepare native CLI context" },
|
|
62
|
-
{ command: "/plugin", args: "<sub>", ko: "Hub 플러그인(MCP)", en: "Hub plugins (MCP servers)" },
|
|
63
|
-
{ command: "/plugins", args: "", ko: "설치된 플러그인", en: "Installed plugins" },
|
|
64
|
-
{ command: "/experience", args: "<sub>", ko: "이식 가능한 Experience", en: "Portable Experience" },
|
|
65
|
-
{ command: "/variant", args: "resolve", ko: "로컬 변형 선택", en: "Local variant selection" },
|
|
66
|
-
{ command: "/memory", args: "<sub>", ko: "메모리", en: "Memory" },
|
|
67
|
-
{ command: "/evolve", args: "", ko: "프롬프트 진화 제안", en: "Prompt-evolution proposals" },
|
|
68
|
-
// 데스크탑의 `ontology` 는 Core 의 지식·메모리 **런타임**(임베딩 포함)이고, 터미널의
|
|
69
|
-
// 이것은 **이 프로젝트의 지식 소스 등록부**다. 서로 다른 것이 같은 이름을 쓰고 있어
|
|
70
|
-
// (감사 D6) 라벨이라도 정확해야 한다 — 명령 이름은 사용자 습관과 스크립트가 걸려
|
|
71
|
-
// 있어 바꾸지 않는다. Core 의 지식 런타임은 터미널에 아직 미노출이다(결함 아님).
|
|
72
|
-
{ command: "/ontology", args: "", ko: "프로젝트 지식 소스 등록", en: "Project knowledge sources" },
|
|
73
|
-
{ command: "/career-graph", args: "", ko: "소스 라우팅 그래프", en: "Source routing graph" },
|
|
74
|
-
{ command: "/journal", args: "<sub>", ko: "Stormbreaker 실행 일지", en: "Stormbreaker run journal" },
|
|
75
|
-
{ command: "/project", args: "[status|init]", ko: ".agentlas 프로젝트 상태", en: "Private project state" },
|
|
76
|
-
{ command: "/context", args: "<sub>", ko: "의존성 맵", en: "Dependency map" },
|
|
77
|
-
{ command: "/creds", args: "<sub>", ko: "자격증명", en: "Credentials" },
|
|
78
|
-
{ command: "/env", args: "", ko: "공유 환경 키", en: "Shared env keys" },
|
|
79
|
-
{ command: "/multimodal", args: "", ko: "이미지·영상·음성 설정", en: "Image/video/audio providers" },
|
|
80
|
-
{ command: "/document", args: "pdf <html|url>", ko: "문서 PDF 내보내기", en: "Export a document to PDF" },
|
|
81
|
-
{ command: "/roles", args: "[set <role> <runtime>]", ko: "오케스트레이터·워커 모델 역할 조회/설정", en: "Show or set orchestrator/worker model roles" },
|
|
82
|
-
{ command: "/telegram", args: "[sub]", ko: "텔레그램 연결", en: "Telegram bindings" },
|
|
83
|
-
{ command: "/oberon", args: "[sub]", ko: "AI 필름", en: "AI film" },
|
|
84
|
-
{ command: "/film", args: "<sub>", ko: "필름 렌더", en: "Film render" },
|
|
85
|
-
{ command: "/hep", args: "<sub…>", ko: "Hephaestus 패스스루", en: "Hephaestus passthrough" },
|
|
86
|
-
// "네트워크"만 쓰면 WiFi·LAN 관리로 읽힌다. 이 명령이 다루는 것은 로컬
|
|
87
|
-
// 에이전트 네트워크(init|status|reindex|bench|add-source)다.
|
|
88
|
-
{ command: "/netadmin", args: "[sub]", ko: "로컬 에이전트 네트워크 관리", en: "Local agent network" },
|
|
89
|
-
{ command: "/update", args: "", ko: "npm 업데이트 확인", en: "npm update check" },
|
|
90
|
-
{ command: "/version", args: "", ko: "버전", en: "Version" },
|
|
91
|
-
{ command: "/logout", args: "", ko: "로그아웃", en: "Sign out" },
|
|
92
|
-
// 대화가 있으면 --yes 없이는 거절한다(챗/메시지 CASCADE 삭제) — 팔레트에도 노출.
|
|
93
|
-
{ command: "/uninstall", args: "<slug> [--yes]", ko: "에이전트 제거", en: "Uninstall an agent" },
|
|
94
|
-
{ command: "/quit", args: "", ko: "종료", en: "Quit" },
|
|
95
|
-
{ command: "/exit", args: "", ko: "종료", en: "Quit" },
|
|
96
|
-
];
|
|
14
|
+
const catalog = require("./commands-catalog.cjs");
|
|
15
|
+
|
|
16
|
+
/*
|
|
17
|
+
* 정본은 ui/commands-catalog.cjs 하나다(2026-08-11). 여기 있던 71행 리터럴은
|
|
18
|
+
* help.cjs 의 EN/KO 블록과 어긋나 언어 혼재·중복 숨김을 만들었다.
|
|
19
|
+
*/
|
|
20
|
+
const SLASH_COMMANDS = catalog.forSurface("repl").map((entry) => ({
|
|
21
|
+
command: "/" + entry.name,
|
|
22
|
+
args: entry.args || "",
|
|
23
|
+
argsKo: entry.argsKo,
|
|
24
|
+
ko: entry.ko,
|
|
25
|
+
en: entry.en,
|
|
26
|
+
group: entry.group,
|
|
27
|
+
tier: entry.tier,
|
|
28
|
+
}));
|
|
97
29
|
|
|
98
30
|
const SLASH_NAMES = SLASH_COMMANDS.map((c) => c.command);
|
|
99
31
|
const RUNTIME_KINDS = ["claude-code", "codex", "gemini"];
|
|
@@ -156,9 +88,9 @@ function suggestions(line, limit = 12, lang = "en") {
|
|
|
156
88
|
const rows = SLASH_COMMANDS.map((entry) => ({
|
|
157
89
|
command: entry.command,
|
|
158
90
|
description: ko ? entry.ko : entry.en,
|
|
159
|
-
usage:
|
|
91
|
+
usage: "/" + catalog.usageFor(catalog.byName(entry.command) || entry, lang),
|
|
160
92
|
detail: "",
|
|
161
|
-
category: "",
|
|
93
|
+
category: entry.group || "",
|
|
162
94
|
examples: [],
|
|
163
95
|
}));
|
|
164
96
|
const q = value.toLowerCase();
|
|
@@ -172,14 +104,13 @@ function suggestions(line, limit = 12, lang = "en") {
|
|
|
172
104
|
return starts.concat(contains).slice(0, limit);
|
|
173
105
|
}
|
|
174
106
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
.join("\n");
|
|
107
|
+
/*
|
|
108
|
+
* /help 팔레트 — CLI 와 완전히 같은 렌더러를 쓴다. 예전엔 여기서 설명 텍스트로
|
|
109
|
+
* 중복 제거를 해서 `/switch` `/list` `/exit` 가 조용히 사라졌다. 별칭이 필드가 된
|
|
110
|
+
* 지금은 중복 자체가 없으므로 그 필터도 없다.
|
|
111
|
+
*/
|
|
112
|
+
function renderPalette(lang, opts = {}) {
|
|
113
|
+
return catalog.renderHelp({ lang, surface: "repl", all: opts.all === true });
|
|
183
114
|
}
|
|
184
115
|
|
|
185
116
|
module.exports = { SLASH_COMMANDS, SLASH_NAMES, makeCompleter, renderPalette, suggestions };
|
package/engine/ui/repl.cjs
CHANGED
|
@@ -125,11 +125,17 @@ async function startRepl(ctx, opts = {}) {
|
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
/*
|
|
128
|
-
* 대화형 셸
|
|
129
|
-
*
|
|
130
|
-
*
|
|
128
|
+
* 대화형 셸 (D3 Phase 2~3). 온보딩 마법사(위 readline 블록)가 먼저 끝난 뒤
|
|
129
|
+
* 진입한다 — 순차 실행이라 stdin 경합이 없다.
|
|
130
|
+
*
|
|
131
|
+
* 선택 순서: 환경변수 > 저장된 설정. 환경변수는 그 실행에만, prefs.shell 은
|
|
132
|
+
* 영속이다(/shell on 으로 저장). 매번 환경변수를 치게 만들면 아무도 안 쓴다.
|
|
131
133
|
*/
|
|
132
|
-
|
|
134
|
+
const shellEnv = String(process.env.AGENTLAS_TUI || "").trim();
|
|
135
|
+
const shellChoice = shellEnv
|
|
136
|
+
? /^(1|true|on)$/i.test(shellEnv)
|
|
137
|
+
: (ctx.prefs && ctx.prefs.shell) === "interactive";
|
|
138
|
+
if (shellChoice && process.stdin.isTTY) {
|
|
133
139
|
return require("./shell.cjs").startShell(ctx, opts);
|
|
134
140
|
}
|
|
135
141
|
const orch = new Orchestrator({ db, lang: ctx.lang });
|
|
@@ -677,17 +683,34 @@ function handleSlash(ctx, cmdline, api) {
|
|
|
677
683
|
switch (cmd) {
|
|
678
684
|
case "quit": case "exit": return "quit";
|
|
679
685
|
case "help": {
|
|
680
|
-
|
|
681
|
-
ctx.out("");
|
|
682
|
-
ctx.out(ui.c.bold(en ? "Project Work runs" : "프로젝트 Work 실행"));
|
|
683
|
-
// 팔레트는 Tab 완성과 같은 정본(ui/palette)에서 렌더한다 — 목록 드리프트 금지.
|
|
684
|
-
ctx.out(require("./palette.cjs").renderPalette(ctx.lang));
|
|
686
|
+
// CLI 와 같은 렌더러 한 번. 예전엔 CLI 61줄 + 팔레트 67줄 + 트레일러 = 133줄이었다.
|
|
687
|
+
ctx.out(require("./palette.cjs").renderPalette(ctx.lang, { all: String(rest[0] || "") === "all" }));
|
|
685
688
|
ctx.out("");
|
|
686
689
|
ctx.out(ctx.uiInstance.c.dim(en
|
|
687
|
-
? "Tab completes commands
|
|
688
|
-
: "Tab:
|
|
689
|
-
|
|
690
|
-
|
|
690
|
+
? "Tab completes commands · ↑/↓ history · Shift-Tab cycles permission · ctrl-c interrupts a turn"
|
|
691
|
+
: "Tab: 명령 완성 · ↑/↓ 히스토리 · Shift-Tab 권한 순환 · ctrl-c 턴 중단"));
|
|
692
|
+
return;
|
|
693
|
+
}
|
|
694
|
+
case "shell": {
|
|
695
|
+
/*
|
|
696
|
+
* 새 대화형 셸 켜기/끄기. 저장하고 재실행을 안내한다 — 프로세스 중간에
|
|
697
|
+
* stdin 소유권을 바꾸면 지금 도는 readline 과 경합한다(실사고 계열).
|
|
698
|
+
*/
|
|
699
|
+
const want = String(rest[0] || "").toLowerCase();
|
|
700
|
+
if (!["on", "off"].includes(want)) {
|
|
701
|
+
const now = (ctx.prefs && ctx.prefs.shell) === "interactive";
|
|
702
|
+
ui.line(ui.c.dim(`Usage: /shell on|off (${en ? "currently" : "현재"}: ${now ? "on" : "off"})`));
|
|
703
|
+
return;
|
|
704
|
+
}
|
|
705
|
+
const config = require("../agentlas-config.cjs");
|
|
706
|
+
const { userDataDir } = require("../core/paths.cjs");
|
|
707
|
+
config.updatePrefs(userDataDir(), { shell: want === "on" ? "interactive" : "classic" });
|
|
708
|
+
if (ctx.prefs) ctx.prefs.shell = want === "on" ? "interactive" : "classic";
|
|
709
|
+
ui.line(ui.c.dim(want === "on"
|
|
710
|
+
? (en ? "Interactive shell enabled — restart agentlas to enter it (/shell off to revert)."
|
|
711
|
+
: "대화형 셸을 켰습니다 — agentlas 를 다시 실행하면 그 화면으로 들어갑니다 (/shell off 로 되돌림).")
|
|
712
|
+
: (en ? "Interactive shell disabled — restart agentlas for the classic REPL."
|
|
713
|
+
: "대화형 셸을 껐습니다 — agentlas 를 다시 실행하면 기본 REPL 입니다.")));
|
|
691
714
|
return;
|
|
692
715
|
}
|
|
693
716
|
case "agents": case "list": require("../commands/list.cjs").run(ctx, rest); return;
|
package/engine/ui/shell.cjs
CHANGED
|
@@ -47,9 +47,21 @@ function loadRenderer() {
|
|
|
47
47
|
|
|
48
48
|
/* Ui 를 상속해 write 초크포인트만 렌더러로 돌린다. */
|
|
49
49
|
class ShellUi extends Ui {
|
|
50
|
+
/*
|
|
51
|
+
* 실터미널 대신 dummy 스트림 — 놓친 직접 out.write 가 프레임을 찢는 대신 소멸한다.
|
|
52
|
+
* 단 columns 는 살려야 한다: Ui 의 줄바꿈·표·구분선이 전부 this.out.columns 를 읽는데
|
|
53
|
+
* PassThrough 에는 그 속성이 없어 전부 80/100 에 고정돼 있었다(폭 넓은 터미널에서
|
|
54
|
+
* 화면 절반만 쓰던 원인). 렌더러의 실제 폭을 게터로 물린다.
|
|
55
|
+
*/
|
|
56
|
+
static _sinkFor(tui) {
|
|
57
|
+
const sink = new PassThrough();
|
|
58
|
+
Object.defineProperty(sink, "columns", {
|
|
59
|
+
get() { return (tui.terminal && tui.terminal.columns) || 80; },
|
|
60
|
+
});
|
|
61
|
+
return sink;
|
|
62
|
+
}
|
|
50
63
|
constructor(opts, pi, tui, transcript) {
|
|
51
|
-
|
|
52
|
-
super({ ...opts, stream: new PassThrough(), color: true });
|
|
64
|
+
super({ ...opts, stream: ShellUi._sinkFor(tui), color: true });
|
|
53
65
|
this._pi = pi;
|
|
54
66
|
this._tui = tui;
|
|
55
67
|
this._transcript = transcript;
|
|
@@ -59,7 +71,12 @@ class ShellUi extends Ui {
|
|
|
59
71
|
this._loader = null;
|
|
60
72
|
}
|
|
61
73
|
_appendText(text) {
|
|
62
|
-
|
|
74
|
+
/*
|
|
75
|
+
* 벤더 Text.render 는 공백만 있는 줄에 [] 를 돌려준다 — screens.cjs 의 ui.line("")
|
|
76
|
+
* 22곳이 전부 조용히 사라져 화면이 한 덩어리로 붙어 있었다. 빈 줄은 Spacer 로.
|
|
77
|
+
*/
|
|
78
|
+
const value = String(text);
|
|
79
|
+
this._transcript.addChild(value.trim() === "" ? new this._pi.Spacer(1) : new this._pi.Text(value, 1, 0));
|
|
63
80
|
this._tui.requestRender();
|
|
64
81
|
}
|
|
65
82
|
write(s) {
|
|
@@ -101,7 +118,7 @@ class ShellUi extends Ui {
|
|
|
101
118
|
this.stopSpinner();
|
|
102
119
|
this.ensureNl();
|
|
103
120
|
this._mdText = "";
|
|
104
|
-
this._md = new this._pi.Markdown("",
|
|
121
|
+
this._md = new this._pi.Markdown("", 1, 0, this._mdTheme());
|
|
105
122
|
this._transcript.addChild(this._md);
|
|
106
123
|
this._streaming = true;
|
|
107
124
|
}
|
|
@@ -171,7 +188,16 @@ async function startShell(ctx, opts = {}) {
|
|
|
171
188
|
|
|
172
189
|
const terminal = new pi.ProcessTerminal();
|
|
173
190
|
const tui = new pi.TuiMainScreen(terminal);
|
|
174
|
-
|
|
191
|
+
/*
|
|
192
|
+
* Container.render 는 삽입 순서로 그린다. 예전엔 헤더 3줄 뒤에 Editor 를 넣어서
|
|
193
|
+
* 입력면이 4번째 줄에 영구 고정됐고, 이후 모든 출력이 그 아래로 흘러 입력 상자가
|
|
194
|
+
* 화면 한가운데 박혔다. 위=트랜스크립트 / 아래=입력면 두 칸으로 나눈다.
|
|
195
|
+
*/
|
|
196
|
+
const transcript = new pi.Container();
|
|
197
|
+
const bottom = new pi.Container();
|
|
198
|
+
tui.addChild(transcript);
|
|
199
|
+
tui.addChild(bottom);
|
|
200
|
+
const ui = new ShellUi({ lang: ctx.lang }, pi, tui, transcript);
|
|
175
201
|
|
|
176
202
|
// ctx 초크포인트 재지정 — 55파일의 ctx.out 직출력이 전부 프레임 안으로 들어온다.
|
|
177
203
|
const shellCtx = {
|
|
@@ -227,7 +253,26 @@ async function startShell(ctx, opts = {}) {
|
|
|
227
253
|
description: ui.c.dim, scrollInfo: ui.c.faint, noMatch: ui.c.dim,
|
|
228
254
|
},
|
|
229
255
|
};
|
|
230
|
-
|
|
256
|
+
/*
|
|
257
|
+
* 빈 입력 상자가 "구분선 사이의 빈 칸"으로 보이던 문제(오너 지적). 렌더러의 Editor 는
|
|
258
|
+
* placeholder 를 지원하지 않으므로, 비어 있을 때만 첫 내용 줄 뒤에 힌트를 덧붙인다.
|
|
259
|
+
* 커서는 그 줄에 이미 그려져 있으므로 교체가 아니라 append 여야 안전하다.
|
|
260
|
+
*/
|
|
261
|
+
class ShellEditor extends pi.Editor {
|
|
262
|
+
render(width) {
|
|
263
|
+
const lines = super.render(width);
|
|
264
|
+
if (this.getText() === "" && lines.length >= 3) {
|
|
265
|
+
const hint = ui.c.faint(en
|
|
266
|
+
? "type a task · / for commands"
|
|
267
|
+
: "할 일을 문장으로 · / 명령");
|
|
268
|
+
// 에디터가 줄을 폭까지 공백으로 채운다 — 그대로 덧붙이면 힌트가 오른쪽 끝으로 밀린다.
|
|
269
|
+
// 꼬리 공백만 걷어내고 커서 바로 뒤에 붙인다(ANSI 리셋은 보존).
|
|
270
|
+
lines[1] = lines[1].replace(/[ \t]+(\u001b\[0m)?$/, "$1") + " " + hint;
|
|
271
|
+
}
|
|
272
|
+
return lines;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
const editor = new ShellEditor(tui, editorTheme, { autocompleteMaxVisible: 8, paddingX: 1 });
|
|
231
276
|
editor.setAutocompleteProvider(new pi.CombinedAutocompleteProvider(toSlashCommands(ctx.lang), process.cwd()));
|
|
232
277
|
|
|
233
278
|
// ── 히스토리 디스크 영속 (증분 2) — cli-history.json v2 계약을 그대로 재사용 ──
|
|
@@ -253,11 +298,16 @@ async function startShell(ctx, opts = {}) {
|
|
|
253
298
|
const commands = require("../commands/index.cjs");
|
|
254
299
|
const handleSlash = async (cmdline) => {
|
|
255
300
|
const raw = cmdline.split(/\s+/)[0] || "";
|
|
256
|
-
|
|
301
|
+
// 팔레트가 따옴표 인자를 가르치므로 REPL 과 같은 토크나이저를 쓴다.
|
|
302
|
+
const rest = require("../agentlas-input.cjs").tokenizeCommandLine(cmdline).slice(1);
|
|
257
303
|
const cmd = commands.resolveCommandName(raw);
|
|
258
304
|
if (cmd === "quit" || cmd === "exit") return "quit";
|
|
259
305
|
if (cmd === "help") {
|
|
260
|
-
ui.line(palette.renderPalette(ctx.lang));
|
|
306
|
+
ui.line(palette.renderPalette(ctx.lang, { all: String(rest[0] || "") === "all" }));
|
|
307
|
+
ui.line("");
|
|
308
|
+
ui.line(ui.c.dim(en
|
|
309
|
+
? "Tab completes commands · ↑/↓ history · Shift-Tab cycles permission · Esc interrupts a turn"
|
|
310
|
+
: "Tab: 명령 완성 · ↑/↓ 히스토리 · Shift-Tab 권한 순환 · Esc 턴 중단"));
|
|
261
311
|
return;
|
|
262
312
|
}
|
|
263
313
|
// 그래프 보기 (Phase 4) — 캔버스를 흉내내지 않는다: mermaid → 유니코드 박스 아트.
|
|
@@ -275,7 +325,8 @@ async function startShell(ctx, opts = {}) {
|
|
|
275
325
|
lines.push(n.type === "condition" ? ` ${n.id}{${label}}` : ` ${n.id}[${label}]`);
|
|
276
326
|
}
|
|
277
327
|
for (const e of g.edges || []) {
|
|
278
|
-
const lbl = e.sourceHandle === "true" ?
|
|
328
|
+
const lbl = e.sourceHandle === "true" ? (en ? "|yes|" : "|참|")
|
|
329
|
+
: e.sourceHandle === "false" ? (en ? "|no|" : "|거짓|") : "";
|
|
279
330
|
lines.push(` ${e.source} -->${lbl} ${e.target}`);
|
|
280
331
|
}
|
|
281
332
|
const { render, toAnsi } = require("../vendor/mermaid/index.js");
|
|
@@ -288,6 +339,46 @@ async function startShell(ctx, opts = {}) {
|
|
|
288
339
|
} catch { /* 렌더 실패 → 아래 클래식 폴스루가 텍스트로 보여준다 */ }
|
|
289
340
|
}
|
|
290
341
|
}
|
|
342
|
+
/*
|
|
343
|
+
* 세션 설정 4종. 자동완성은 되는데 처리 case 가 없어 "여기서는 아직 안 됩니다"만
|
|
344
|
+
* 답하던 죽은 광고였다(신설 게이트가 잡았다). 기본 REPL 과 같은 의미로 배선하고,
|
|
345
|
+
* 영구 저장 경로를 같은 줄에서 알려준다 — 이 값들은 이 셸 한정이다.
|
|
346
|
+
*/
|
|
347
|
+
if (cmd === "permission" || cmd === "model" || cmd === "runtime" || cmd === "effort") {
|
|
348
|
+
const value = String(rest[0] || "").trim();
|
|
349
|
+
const entry = require("./commands-catalog.cjs").byName(cmd);
|
|
350
|
+
if (!value) {
|
|
351
|
+
ui.line(ui.c.dim(`Usage: /${cmd} ${entry ? entry.args : ""}`));
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
if (cmd === "permission") {
|
|
355
|
+
const next = permissions.normalize(value);
|
|
356
|
+
if (!next) { ui.line(ui.c.dim("Usage: /permission read|write|full")); return; }
|
|
357
|
+
permission = next;
|
|
358
|
+
ui.line(ui.c.dim(`permission: ${next} · ${en ? "persist: agentlas setup" : "영구 저장: agentlas setup"}`));
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
if (cmd === "model") opts.model = value === "default" ? null : value;
|
|
362
|
+
else if (cmd === "runtime") opts.runtime = value;
|
|
363
|
+
else opts.effort = value;
|
|
364
|
+
ui.line(ui.c.dim(`${cmd}: ${value} · ${en
|
|
365
|
+
? "applies to new sessions here (persist: agentlas roles set)"
|
|
366
|
+
: "이 셸의 새 세션부터 (영구 저장: agentlas roles set)"}`));
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
// 셸 끄기 — 여기서도 되돌아갈 수 있어야 한다(들어와서 못 나가면 갇힌다)
|
|
370
|
+
if (cmd === "shell") {
|
|
371
|
+
const want = String(rest[0] || "").toLowerCase();
|
|
372
|
+
if (!["on", "off"].includes(want)) { ui.line(ui.c.dim(en ? "Usage: /shell on|off" : "사용법: /shell on|off")); return; }
|
|
373
|
+
const config = require("../agentlas-config.cjs");
|
|
374
|
+
const { userDataDir } = require("../core/paths.cjs");
|
|
375
|
+
config.updatePrefs(userDataDir(), { shell: want === "on" ? "interactive" : "classic" });
|
|
376
|
+
ui.line(ui.c.dim(want === "on"
|
|
377
|
+
? (en ? "Already here." : "이미 이 셸입니다.")
|
|
378
|
+
: (en ? "Interactive shell disabled — restart agentlas for the classic REPL."
|
|
379
|
+
: "대화형 셸을 껐습니다 — agentlas 를 다시 실행하면 기본 REPL 입니다.")));
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
291
382
|
// 데스크탑 대응 화면 (Phase 3) — 정직 정지였던 표면들을 실물로 대체
|
|
292
383
|
{
|
|
293
384
|
const screens = require("./screens.cjs");
|
|
@@ -373,7 +464,7 @@ async function startShell(ctx, opts = {}) {
|
|
|
373
464
|
}
|
|
374
465
|
})();
|
|
375
466
|
};
|
|
376
|
-
|
|
467
|
+
bottom.addChild(editor);
|
|
377
468
|
tui.setFocus(editor);
|
|
378
469
|
|
|
379
470
|
const shutdown = (code) => {
|
|
@@ -296,7 +296,13 @@ function coreHarness() {
|
|
|
296
296
|
|
|
297
297
|
async function workforceAccountContext() {
|
|
298
298
|
const cookie = await hubClient.cloudSessionCookie();
|
|
299
|
-
|
|
299
|
+
// 가장 흔한 로그아웃 경로 — 마커가 없으면 표시 경계가 삼켜 "복구 중" 한 줄이 된다.
|
|
300
|
+
if (!cookie) {
|
|
301
|
+
throw Object.assign(
|
|
302
|
+
new Error("Agentlas sign-in required — run `agentlas login`, then retry."),
|
|
303
|
+
{ code: "auth_required", honestStop: true },
|
|
304
|
+
);
|
|
305
|
+
}
|
|
300
306
|
const webBase = (process.env.AGENTLAS_WEB_BASE_URL || "https://agentlas.cloud").replace(/\/$/, "");
|
|
301
307
|
const mcpBase = (process.env.AGENTLAS_MCP_BASE_URL || `${webBase}/api/mcp/v1`).replace(/\/$/, "");
|
|
302
308
|
const response = await hubClient.fetchHub(mcpBase, {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentlas",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.45",
|
|
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"
|