agentlas 1.0.65 → 1.0.67
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 +94 -0
- package/README.md +12 -4
- package/bin/agentlas.cjs +354 -16
- package/engine/acp/server.cjs +34 -3
- package/engine/agentlas-api-agent.cjs +151 -120
- package/engine/agentlas-banner.cjs +6 -2
- package/engine/agentlas-capabilities.cjs +17 -10
- package/engine/agentlas-cloud-runtime.cjs +4 -5
- package/engine/agentlas-config.cjs +19 -54
- package/engine/agentlas-core-harness.cjs +59 -5
- package/engine/agentlas-desktop-loadout.cjs +17 -3
- package/engine/agentlas-evolution.cjs +75 -18
- package/engine/agentlas-experience-exchange.cjs +145 -14
- package/engine/agentlas-experience-intake.cjs +2 -2
- package/engine/agentlas-i18n.cjs +0 -2
- package/engine/agentlas-input.cjs +273 -20
- package/engine/agentlas-judgment.cjs +0 -0
- package/engine/agentlas-mcp-env.cjs +84 -23
- package/engine/agentlas-mcp-wrapper.cjs +36 -4
- package/engine/agentlas-memory-governance.cjs +2 -1
- package/engine/agentlas-memory-import.cjs +49 -12
- package/engine/agentlas-native-host.cjs +279 -44
- package/engine/agentlas-onboard.cjs +23 -1
- package/engine/agentlas-permissions.cjs +5 -1
- package/engine/agentlas-sqlite-policy.cjs +40 -2
- package/engine/agentlas-tasks.cjs +7 -0
- package/engine/agentlas-tools.cjs +37 -10
- package/engine/agentlas-ui.cjs +26 -4
- package/engine/agentlas-workforce.cjs +30 -5
- package/engine/agentlas-workload-routing.cjs +83 -10
- package/engine/agentlas.cjs +21 -4
- package/engine/agents/builder.cjs +35 -10
- package/engine/agents/files.cjs +81 -10
- package/engine/agents/import-local.cjs +10 -2
- package/engine/agents/registry.cjs +10 -3
- package/engine/agents/router.cjs +7 -7
- package/engine/agents/routes.cjs +31 -9
- package/engine/automation/daemon.cjs +154 -40
- package/engine/automation/launchd.cjs +395 -16
- package/engine/automation/schedule.cjs +90 -3
- package/engine/automation/store.cjs +163 -59
- package/engine/browser/cdp.cjs +190 -17
- package/engine/browser/vault.cjs +1 -0
- package/engine/cli-output.cjs +96 -30
- package/engine/cloud/auth.cjs +131 -13
- package/engine/cloud/hub-client.cjs +41 -16
- package/engine/cloud-assets/cas.cjs +18 -9
- package/engine/cloud-assets/commands.cjs +108 -30
- package/engine/cloud-assets/package.cjs +66 -3
- package/engine/cloud-assets/restore.cjs +12 -9
- package/engine/cloud-assets/state.cjs +609 -116
- package/engine/commands/acp.cjs +13 -2
- package/engine/commands/automation.cjs +75 -24
- package/engine/commands/billing.cjs +6 -1
- package/engine/commands/browser.cjs +61 -29
- package/engine/commands/build.cjs +72 -14
- package/engine/commands/call.cjs +1 -1
- package/engine/commands/cd.cjs +1 -1
- package/engine/commands/cloud.cjs +2 -1
- package/engine/commands/connect.cjs +38 -13
- package/engine/commands/creds.cjs +74 -29
- package/engine/commands/doctor.cjs +17 -1
- package/engine/commands/document.cjs +38 -10
- package/engine/commands/env.cjs +6 -1
- package/engine/commands/firm.cjs +42 -12
- package/engine/commands/graph.cjs +36 -32
- package/engine/commands/help.cjs +11 -1
- package/engine/commands/hep.cjs +1 -1
- package/engine/commands/import.cjs +5 -4
- package/engine/commands/index.cjs +1 -1
- package/engine/commands/install.cjs +6 -4
- package/engine/commands/list.cjs +56 -16
- package/engine/commands/login.cjs +5 -0
- package/engine/commands/logout.cjs +6 -1
- package/engine/commands/mcp.cjs +150 -37
- package/engine/commands/memory.cjs +3 -2
- package/engine/commands/multimodal.cjs +12 -0
- package/engine/commands/native.cjs +5 -1
- package/engine/commands/one.cjs +78 -33
- package/engine/commands/plugin.cjs +13 -2
- package/engine/commands/project.cjs +15 -12
- package/engine/commands/research.cjs +18 -7
- package/engine/commands/roles.cjs +104 -28
- package/engine/commands/route.cjs +2 -2
- package/engine/commands/run.cjs +42 -9
- package/engine/commands/search.cjs +23 -2
- package/engine/commands/setup.cjs +6 -1
- package/engine/commands/storm.cjs +44 -6
- package/engine/commands/swarm.cjs +47 -9
- package/engine/commands/telegram.cjs +6 -1
- package/engine/commands/uninstall.cjs +12 -6
- package/engine/commands/update.cjs +5 -0
- package/engine/commands/upload.cjs +2 -1
- package/engine/commands/usage.cjs +6 -1
- package/engine/commands/version.cjs +6 -1
- package/engine/commands/whoami.cjs +6 -1
- package/engine/commands/workforce.cjs +60 -16
- package/engine/core/capability-grants.cjs +7 -2
- package/engine/core/daemon-client.cjs +36 -7
- package/engine/core/db.cjs +10 -2
- package/engine/core/desktop-core-fetch.cjs +477 -77
- package/engine/core/schema-ensure.cjs +23 -11
- package/engine/experience/build.cjs +5 -1
- package/engine/experience/intents.cjs +35 -82
- package/engine/experience/runtime.cjs +7 -1
- package/engine/experience/variant.cjs +58 -4
- package/engine/firms/orchestrate.cjs +9 -6
- package/engine/graph/ask-model.cjs +22 -11
- package/engine/graph/interview.cjs +74 -23
- package/engine/graph/package.cjs +63 -8
- package/engine/hephaestus/local-core.cjs +18 -5
- package/engine/hephaestus/runtime.cjs +48 -43
- package/engine/hub/install.cjs +484 -63
- package/engine/hub/plugins.cjs +391 -29
- package/engine/mcp/consent.cjs +25 -17
- package/engine/mcp/contract.cjs +229 -24
- package/engine/mcp/inventory.cjs +46 -10
- package/engine/mcp/plan.cjs +10 -1
- package/engine/mcp/probe.cjs +24 -9
- package/engine/memory-cli/curate.cjs +74 -16
- package/engine/oberon/common.cjs +37 -12
- package/engine/oberon/manifest.cjs +25 -2
- package/engine/oberon/outputs.cjs +49 -19
- package/engine/oberon/render.cjs +665 -40
- package/engine/project/career-graph.cjs +15 -2
- package/engine/project/controller.cjs +133 -15
- package/engine/project/credentials.cjs +382 -34
- package/engine/project/env-file.cjs +93 -8
- package/engine/project/memory-context.cjs +11 -57
- package/engine/project/ontology.cjs +66 -25
- package/engine/project/paths.cjs +42 -8
- package/engine/project/seed.cjs +88 -51
- package/engine/project/state.cjs +41 -16
- package/engine/project/team.cjs +26 -1
- package/engine/runtime-refusal.cjs +4 -1
- package/engine/runtimes/acp-driver.cjs +56 -9
- package/engine/runtimes/auth-evidence.cjs +21 -2
- package/engine/runtimes/detect.cjs +28 -8
- package/engine/runtimes/kinds.cjs +12 -4
- package/engine/runtimes/overrides.cjs +4 -3
- package/engine/runtimes/resolve.cjs +8 -7
- package/engine/runtimes/roles.cjs +7 -5
- package/engine/sessions/apply-fences.cjs +396 -56
- package/engine/sessions/fences.cjs +111 -27
- package/engine/sessions/memory-turn.cjs +62 -3
- package/engine/sessions/orchestrator.cjs +11 -1
- package/engine/sessions/prompt.cjs +66 -9
- package/engine/sessions/session.cjs +70 -10
- package/engine/sessions/sink.cjs +78 -12
- package/engine/sessions/store.cjs +29 -7
- package/engine/storm/storm.cjs +26 -3
- package/engine/storm/swarm.cjs +31 -3
- package/engine/telegram/connect.cjs +185 -22
- package/engine/ui/commands-catalog.cjs +1 -1
- package/engine/ui/palette.cjs +12 -2
- package/engine/ui/repl.cjs +57 -9
- package/engine/ui/screens.cjs +2 -4
- package/engine/vendor/desktop-core.manifest.json +5 -5
- package/engine/workforce/capture.cjs +9 -27
- package/engine/workforce/deps.cjs +18 -6
- package/engine/workforce/local-core-transport.cjs +68 -5
- package/package.json +1 -1
- package/engine/commands/career-graph.cjs +0 -51
package/engine/commands/list.cjs
CHANGED
|
@@ -7,6 +7,10 @@
|
|
|
7
7
|
const { activeRuntimeRow, listAvailableCliRuntimes } = require("../runtimes/detect.cjs");
|
|
8
8
|
const { resolvedModelRole } = require("../runtimes/roles.cjs");
|
|
9
9
|
const { listAgents } = require("../agents/registry.cjs");
|
|
10
|
+
const { render, single } = require("../cli-output.cjs");
|
|
11
|
+
|
|
12
|
+
const LIST_OUTPUT_SCHEMA = Object.freeze({ idField: "slug", columns: [] });
|
|
13
|
+
const LIST_OUTPUT_FLAGS = new Set(["--json", "--yaml", "--quiet", "-q", "--no-headers", "--no-color"]);
|
|
10
14
|
|
|
11
15
|
function roleRuntimeLabel(selection, role, en) {
|
|
12
16
|
if (!selection) return en ? "(not set)" : "(미설정)";
|
|
@@ -25,6 +29,12 @@ function roleRuntimeLabel(selection, role, en) {
|
|
|
25
29
|
}
|
|
26
30
|
|
|
27
31
|
function run(ctx, args = []) {
|
|
32
|
+
const invalidArgs = args.filter((arg) => !LIST_OUTPUT_FLAGS.has(arg));
|
|
33
|
+
if (invalidArgs.length) {
|
|
34
|
+
const error = new Error(`Usage: agentlas list [--json|--yaml|--quiet|--no-headers|--no-color]. Unknown argument: ${invalidArgs[0]}`);
|
|
35
|
+
error.code = "INVALID_ARGUMENT";
|
|
36
|
+
throw error;
|
|
37
|
+
}
|
|
28
38
|
const db = ctx.db();
|
|
29
39
|
// 프라이버시 정책(웹 전용/백그라운드 제외)은 registry가 소유한다 — 직접 SQL 금지.
|
|
30
40
|
const agents = listAgents(db).map((a) => ({
|
|
@@ -33,18 +43,40 @@ function run(ctx, args = []) {
|
|
|
33
43
|
const firms = ctx.tableExists(db, "firms")
|
|
34
44
|
? db.prepare("SELECT id, slug, name FROM firms ORDER BY name").all()
|
|
35
45
|
: [];
|
|
46
|
+
const output = ctx.output || {};
|
|
47
|
+
let format = output.format || "table";
|
|
48
|
+
for (const arg of args) {
|
|
49
|
+
if (arg === "--json") format = "json";
|
|
50
|
+
if (arg === "--yaml") format = "yaml";
|
|
51
|
+
}
|
|
52
|
+
const quiet = Boolean(output.quiet) || args.includes("--quiet") || args.includes("-q");
|
|
53
|
+
const noHeaders = Boolean(output.noHeaders) || args.includes("--no-headers");
|
|
54
|
+
const noColor = Boolean(output.noColor) || args.includes("--no-color");
|
|
55
|
+
const payload = () => ({
|
|
56
|
+
agents,
|
|
57
|
+
firms,
|
|
58
|
+
modelRoles: {
|
|
59
|
+
orchestrator: resolvedModelRole(db, "orchestrator"),
|
|
60
|
+
worker: resolvedModelRole(db, "worker"),
|
|
61
|
+
multimodal: resolvedModelRole(db, "multimodal"),
|
|
62
|
+
},
|
|
63
|
+
});
|
|
36
64
|
|
|
37
|
-
// clig.dev: 스크립트 소비자는 사람용 표를 파싱하게 두지 말 것 —
|
|
38
|
-
//
|
|
39
|
-
if (
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
65
|
+
// clig.dev: 스크립트 소비자는 사람용 표를 파싱하게 두지 말 것 — 공통 출력
|
|
66
|
+
// renderer가 quiet 우선과 JSON/YAML 형식을 한 곳에서 해석한다.
|
|
67
|
+
if (quiet) {
|
|
68
|
+
const ids = agents.map((agent) => agent.slug).concat(firms.map((firm) => firm.slug || firm.id));
|
|
69
|
+
if (ids.length) ctx.out(ids.join("\n"));
|
|
70
|
+
return 0;
|
|
71
|
+
}
|
|
72
|
+
if (format === "json" || format === "yaml") {
|
|
73
|
+
ctx.out(render(single(payload(), LIST_OUTPUT_SCHEMA), { ...output, format, quiet: false }));
|
|
43
74
|
return 0;
|
|
44
75
|
}
|
|
45
76
|
|
|
46
77
|
const en = ctx.lang === "en";
|
|
47
|
-
|
|
78
|
+
const paint = (name, value) => noColor ? String(value) : ctx.ui[name](value);
|
|
79
|
+
if (!noHeaders) ctx.out(paint("bold", en ? "Installed agents" : "설치된 에이전트"));
|
|
48
80
|
if (!agents.length) {
|
|
49
81
|
ctx.out(" " + (en ? "(none yet — try: agentlas search \"what you need\")" : " (아직 없음 — agentlas search \"필요한 것\" 으로 찾아보세요)"));
|
|
50
82
|
}
|
|
@@ -104,31 +136,39 @@ function run(ctx, args = []) {
|
|
|
104
136
|
// 2 indent + slug + space + name + " — " + tagline must fit one line.
|
|
105
137
|
const budget = Math.max(20, cols - (2 + slugWidth + 1 + displayWidth(name) + 3));
|
|
106
138
|
const shown = tag ? clampTag(tag, budget) : "";
|
|
107
|
-
ctx.out(` ${
|
|
139
|
+
ctx.out(` ${paint("accent", clampSlug(a.slug))} ${name}${shown ? paint("dim", " — " + shown) : ""}`);
|
|
108
140
|
}
|
|
109
141
|
if (firms.length) {
|
|
110
|
-
|
|
111
|
-
|
|
142
|
+
if (!noHeaders) {
|
|
143
|
+
ctx.out("");
|
|
144
|
+
ctx.out(paint("bold", en ? "Companies" : "회사"));
|
|
145
|
+
}
|
|
112
146
|
for (const f of firms) {
|
|
113
147
|
const callable = String(f.slug || f.id);
|
|
114
|
-
ctx.out(` ${
|
|
148
|
+
ctx.out(` ${paint("accent", callable.padEnd(28))} ${f.name}`);
|
|
115
149
|
}
|
|
116
|
-
ctx.out(
|
|
150
|
+
ctx.out(paint("dim", en
|
|
117
151
|
? " Run one with: agentlas firm <company-key> \"<task>\""
|
|
118
152
|
: " 실행: agentlas firm <회사 키> \"<작업>\""));
|
|
119
153
|
}
|
|
120
154
|
|
|
121
155
|
const active = activeRuntimeRow(db);
|
|
122
156
|
const clis = listAvailableCliRuntimes();
|
|
123
|
-
|
|
124
|
-
|
|
157
|
+
if (!noHeaders) {
|
|
158
|
+
ctx.out("");
|
|
159
|
+
ctx.out(paint("bold", en ? "Model roles" : "모델 역할"));
|
|
160
|
+
}
|
|
125
161
|
const orchestrator = resolvedModelRole(db, "orchestrator");
|
|
126
162
|
const worker = resolvedModelRole(db, "worker");
|
|
163
|
+
const multimodal = resolvedModelRole(db, "multimodal");
|
|
127
164
|
ctx.out(` orchestrator: ${roleRuntimeLabel(orchestrator, "orchestrator", en)}`);
|
|
128
165
|
ctx.out(` worker: ${roleRuntimeLabel(worker, "worker", en)}`);
|
|
166
|
+
ctx.out(` multimodal: ${roleRuntimeLabel(multimodal, "multimodal", en)}`);
|
|
129
167
|
|
|
130
|
-
|
|
131
|
-
|
|
168
|
+
if (!noHeaders) {
|
|
169
|
+
ctx.out("");
|
|
170
|
+
ctx.out(paint("bold", en ? "Legacy runtime compatibility" : "레거시 런타임 호환"));
|
|
171
|
+
}
|
|
132
172
|
if (active) {
|
|
133
173
|
ctx.out(` active: ${active.kind}${active.model ? ` (${active.model})` : ""}${active.backend ? ` via ${active.backend}` : ""}`);
|
|
134
174
|
} else {
|
|
@@ -9,6 +9,11 @@ const auth = require("../cloud/auth.cjs");
|
|
|
9
9
|
|
|
10
10
|
async function run(ctx, args = []) {
|
|
11
11
|
const ko = ctx.lang === "ko";
|
|
12
|
+
if (args.some((arg) => arg !== "--force") || args.filter((arg) => arg === "--force").length > 1) {
|
|
13
|
+
const error = new Error("usage: agentlas login [--force]");
|
|
14
|
+
error.code = "INVALID_ARGUMENT";
|
|
15
|
+
throw error;
|
|
16
|
+
}
|
|
12
17
|
const force = args.includes("--force");
|
|
13
18
|
if (!force) {
|
|
14
19
|
const existing = auth.cloudSessionCookie();
|
|
@@ -5,8 +5,13 @@
|
|
|
5
5
|
*/
|
|
6
6
|
const auth = require("../cloud/auth.cjs");
|
|
7
7
|
|
|
8
|
-
function run(ctx) {
|
|
8
|
+
function run(ctx, args = []) {
|
|
9
9
|
const ko = ctx.lang === "ko";
|
|
10
|
+
if (args.length) {
|
|
11
|
+
const error = new Error("usage: agentlas logout");
|
|
12
|
+
error.code = "INVALID_ARGUMENT";
|
|
13
|
+
throw error;
|
|
14
|
+
}
|
|
10
15
|
let result;
|
|
11
16
|
try {
|
|
12
17
|
result = auth.deleteCliSession();
|
package/engine/commands/mcp.cjs
CHANGED
|
@@ -13,35 +13,124 @@
|
|
|
13
13
|
const { userDataDir } = require("../core/paths.cjs");
|
|
14
14
|
const { materializeTrustedSystemMcpServer } = require("../mcp/inventory.cjs");
|
|
15
15
|
const { probeSystemMcpServerConnection } = require("../mcp/probe.cjs");
|
|
16
|
+
const {
|
|
17
|
+
DEFAULT_OPTIONS,
|
|
18
|
+
list: outputList,
|
|
19
|
+
render,
|
|
20
|
+
single,
|
|
21
|
+
parseOutputFlags,
|
|
22
|
+
displayWidth,
|
|
23
|
+
terminalTextOf,
|
|
24
|
+
} = require("../cli-output.cjs");
|
|
25
|
+
|
|
26
|
+
const OUTPUT_FLAGS = new Set(["--json", "--yaml", "--quiet", "-q", "--no-headers", "--no-color"]);
|
|
27
|
+
|
|
28
|
+
function commandError(message, code = "INVALID_ARGUMENT", details) {
|
|
29
|
+
const error = new Error(message);
|
|
30
|
+
error.code = code;
|
|
31
|
+
if (details !== undefined) error.details = details;
|
|
32
|
+
return error;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function withOutputFlags(ctx, args) {
|
|
36
|
+
if (!args.some((arg) => OUTPUT_FLAGS.has(arg))) return { ctx, args };
|
|
37
|
+
const parsed = parseOutputFlags(args);
|
|
38
|
+
return {
|
|
39
|
+
ctx: { ...ctx, output: { ...(ctx.output || DEFAULT_OPTIONS), ...parsed.options } },
|
|
40
|
+
args: parsed.rest,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function emit(ctx, result) {
|
|
45
|
+
if (typeof ctx.emit === "function") {
|
|
46
|
+
ctx.emit(result);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
ctx.out(render(result, ctx.output || DEFAULT_OPTIONS));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function ansi(options, code, value) {
|
|
53
|
+
const text = String(value);
|
|
54
|
+
return options?.noColor ? text : `\u001b[${code}m${text}\u001b[0m`;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function isMachineOutput(ctx) {
|
|
58
|
+
const output = ctx.output || DEFAULT_OPTIONS;
|
|
59
|
+
return output.quiet || output.format === "json" || output.format === "yaml";
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function mcpListSchema(en) {
|
|
63
|
+
return Object.freeze({
|
|
64
|
+
idField: "id",
|
|
65
|
+
columns: [
|
|
66
|
+
{ header: "id", field: "id" },
|
|
67
|
+
{ header: en ? "name" : "이름", field: "name" },
|
|
68
|
+
],
|
|
69
|
+
renderHuman(result, options = {}) {
|
|
70
|
+
const rows = Array.isArray(result.data) ? result.data : [];
|
|
71
|
+
if (!rows.length) {
|
|
72
|
+
return options.noHeaders ? "" : (en ? "No MCP servers registered." : "등록된 MCP 서버가 없습니다.");
|
|
73
|
+
}
|
|
74
|
+
const lines = [];
|
|
75
|
+
if (!options.noHeaders) lines.push(ansi(options, 1, en ? "MCP servers" : "MCP 서버"));
|
|
76
|
+
for (const row of rows) {
|
|
77
|
+
const id = terminalTextOf(row.id, 256);
|
|
78
|
+
const name = terminalTextOf(row.name, 4096);
|
|
79
|
+
const padding = " ".repeat(Math.max(1, 28 - displayWidth(id)));
|
|
80
|
+
lines.push(` ${ansi(options, 36, id)}${padding}${name}`);
|
|
81
|
+
}
|
|
82
|
+
return lines.join("\n");
|
|
83
|
+
},
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function mcpProbeSchema(en) {
|
|
88
|
+
return Object.freeze({
|
|
89
|
+
idField: "serverId",
|
|
90
|
+
columns: [
|
|
91
|
+
{ header: en ? "server" : "서버", field: "serverId" },
|
|
92
|
+
{ header: en ? "status" : "상태", field: "status" },
|
|
93
|
+
{ header: en ? "tools" : "툴", field: "toolCount" },
|
|
94
|
+
],
|
|
95
|
+
renderHuman(result, options = {}) {
|
|
96
|
+
const row = result.data || {};
|
|
97
|
+
const serverId = terminalTextOf(row.serverId, 256);
|
|
98
|
+
const toolCount = Number.isSafeInteger(row.toolCount) ? row.toolCount : 0;
|
|
99
|
+
const status = row.connected ? ansi(options, 32, en ? "connected" : "연결됨") : ansi(options, 31, en ? "failed" : "실패");
|
|
100
|
+
const toolLabel = en ? `${toolCount} tool(s) listed` : `툴 ${toolCount}개 확인`;
|
|
101
|
+
const note = en
|
|
102
|
+
? "Preflight only: connection readiness does not imply tool-call success."
|
|
103
|
+
: "프리플라이트일 뿐입니다: 연결 준비됨 ≠ 툴 호출 성공.";
|
|
104
|
+
return [
|
|
105
|
+
`${status} ${ansi(options, 1, serverId)} · ${toolLabel}`,
|
|
106
|
+
ansi(options, 2, note),
|
|
107
|
+
].join("\n");
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
}
|
|
16
111
|
|
|
17
112
|
function list(ctx) {
|
|
18
113
|
const en = ctx.lang === "en";
|
|
19
114
|
const db = ctx.db();
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
return 0;
|
|
28
|
-
}
|
|
29
|
-
ctx.out(ctx.ui.bold(en ? "MCP servers" : "MCP 서버"));
|
|
30
|
-
for (const r of rows) ctx.out(` ${ctx.ui.accent(String(r.id).padEnd(28))} ${r.name || ""}`);
|
|
115
|
+
const rows = ctx.tableExists(db, "mcp_servers")
|
|
116
|
+
? db.prepare("SELECT id, name FROM mcp_servers ORDER BY name").all().map((row) => ({
|
|
117
|
+
id: String(row.id || ""),
|
|
118
|
+
name: String(row.name || ""),
|
|
119
|
+
}))
|
|
120
|
+
: [];
|
|
121
|
+
emit(ctx, outputList(rows, mcpListSchema(en)));
|
|
31
122
|
return 0;
|
|
32
123
|
}
|
|
33
124
|
|
|
34
125
|
async function probe(ctx, args) {
|
|
35
126
|
const en = ctx.lang === "en";
|
|
36
127
|
const ref = String(args[0] || "").trim();
|
|
37
|
-
if (!ref) {
|
|
38
|
-
|
|
39
|
-
return 1;
|
|
128
|
+
if (!ref || args.length !== 1 || ref.startsWith("-")) {
|
|
129
|
+
throw commandError(en ? "Usage: agentlas mcp probe <server-id|catalog-id>" : "사용법: agentlas mcp probe <server-id|catalog-id>");
|
|
40
130
|
}
|
|
41
131
|
const db = ctx.db();
|
|
42
132
|
if (!ctx.tableExists(db, "mcp_servers")) {
|
|
43
|
-
|
|
44
|
-
return 1;
|
|
133
|
+
throw commandError(en ? "No MCP servers registered." : "등록된 MCP 서버가 없습니다.", "MCP_SERVER_NOT_FOUND");
|
|
45
134
|
}
|
|
46
135
|
// catalog_id는 데스크탑 스키마 열 — 오래된 DB에는 없을 수 있어 방어적으로 조회.
|
|
47
136
|
const byCatalog = ctx.columnExists(db, "mcp_servers", "catalog_id");
|
|
@@ -49,47 +138,71 @@ async function probe(ctx, args) {
|
|
|
49
138
|
? db.prepare("SELECT id, catalog_id, name, name_en, transport, command, args_json, env_keys_json, enabled FROM mcp_servers WHERE id=? OR catalog_id=? LIMIT 1").get(ref, ref)
|
|
50
139
|
: db.prepare("SELECT id, NULL AS catalog_id, name, name_en, transport, command, args_json, env_keys_json, enabled FROM mcp_servers WHERE id=? LIMIT 1").get(ref);
|
|
51
140
|
if (!row) {
|
|
52
|
-
|
|
53
|
-
|
|
141
|
+
throw commandError(
|
|
142
|
+
en ? `MCP server not found: ${ref}` : `MCP 서버를 찾을 수 없습니다: ${ref}`,
|
|
143
|
+
"MCP_SERVER_NOT_FOUND",
|
|
144
|
+
{ serverId: ref },
|
|
145
|
+
);
|
|
54
146
|
}
|
|
55
147
|
const server = materializeTrustedSystemMcpServer(row, { userDataDir: userDataDir() });
|
|
56
148
|
if (!server) {
|
|
57
149
|
// 이유를 지어내지 않는다 — materialize는 비활성/비-stdio/안전하지 않은
|
|
58
150
|
// 정의를 하나의 fail-closed로 접기 때문에 관찰 가능한 사실만 알린다.
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
151
|
+
throw commandError(
|
|
152
|
+
en
|
|
153
|
+
? `'${ref}' is not probe-eligible (disabled, non-stdio transport, or an unsafe runtime definition).`
|
|
154
|
+
: `'${ref}' 은(는) probe 대상이 아닙니다 (비활성, stdio가 아닌 transport, 또는 안전하지 않은 실행 정의).`,
|
|
155
|
+
"MCP_PROBE_INELIGIBLE",
|
|
156
|
+
{ serverId: ref },
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
if (!isMachineOutput(ctx)) {
|
|
160
|
+
const options = ctx.output || DEFAULT_OPTIONS;
|
|
161
|
+
ctx.out(ansi(options, 2, en
|
|
162
|
+
? `Probing ${server.catalog_id} (isolated child env, handshake only)…`
|
|
163
|
+
: `${server.catalog_id} 연결 확인 중 (격리 자식 env, 핸드셰이크만)…`));
|
|
63
164
|
}
|
|
64
|
-
ctx.out(ctx.ui.dim(en
|
|
65
|
-
? `Probing ${server.catalog_id} (isolated child env, handshake only)…`
|
|
66
|
-
: `${server.catalog_id} 연결 확인 중 (격리 자식 env, 핸드셰이크만)…`));
|
|
67
165
|
const result = await probeSystemMcpServerConnection(server, { userDataDir: userDataDir(), cwd: process.cwd() });
|
|
68
|
-
if (result.connected) {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
166
|
+
if (!result.connected) {
|
|
167
|
+
throw commandError(
|
|
168
|
+
en
|
|
169
|
+
? `MCP probe failed: ${server.catalog_id} · ${result.reason || "connection_failed"}`
|
|
170
|
+
: `MCP 연결 확인 실패: ${server.catalog_id} · ${result.reason || "connection_failed"}`,
|
|
171
|
+
"MCP_PROBE_FAILED",
|
|
172
|
+
{ serverId: server.catalog_id, reason: result.reason || "connection_failed" },
|
|
173
|
+
);
|
|
75
174
|
}
|
|
76
|
-
|
|
77
|
-
|
|
175
|
+
const toolCount = Array.isArray(result.tools) ? result.tools.length : 0;
|
|
176
|
+
emit(ctx, single({
|
|
177
|
+
serverId: server.catalog_id,
|
|
178
|
+
status: "connected",
|
|
179
|
+
connected: true,
|
|
180
|
+
reason: result.reason || "connected",
|
|
181
|
+
toolCount,
|
|
182
|
+
}, mcpProbeSchema(en)));
|
|
183
|
+
return 0;
|
|
78
184
|
}
|
|
79
185
|
|
|
80
186
|
function run(ctx, args = []) {
|
|
187
|
+
const normalized = withOutputFlags(ctx, args);
|
|
188
|
+
ctx = normalized.ctx;
|
|
189
|
+
args = normalized.args;
|
|
81
190
|
const [sub, ...rest] = args;
|
|
82
191
|
if (!sub) return list(ctx);
|
|
83
192
|
// 무인자 기본 동작이 목록인데 이름으로 부르면 거부되는 비대칭이 있었다
|
|
84
193
|
// (2026-08-05 감사 결함 G): 다른 명령들(cloud list, plugin list)이 만든
|
|
85
194
|
// "list를 붙이는" 습관이 여기서만 usage 오류가 됐다.
|
|
86
|
-
if (sub === "list" || sub === "ls")
|
|
195
|
+
if (sub === "list" || sub === "ls") {
|
|
196
|
+
if (rest.length) {
|
|
197
|
+
throw commandError(ctx.lang === "en" ? "Usage: agentlas mcp list" : "사용법: agentlas mcp list");
|
|
198
|
+
}
|
|
199
|
+
return list(ctx);
|
|
200
|
+
}
|
|
87
201
|
if (sub === "probe") return probe(ctx, rest);
|
|
88
202
|
const en = ctx.lang === "en";
|
|
89
|
-
|
|
203
|
+
throw commandError(en
|
|
90
204
|
? `unknown mcp subcommand: ${sub} (available: list · probe)`
|
|
91
205
|
: `알 수 없는 mcp 하위 명령: ${sub} (사용 가능: list · probe)`);
|
|
92
|
-
return 1;
|
|
93
206
|
}
|
|
94
207
|
|
|
95
208
|
module.exports = { run };
|
|
@@ -6,11 +6,12 @@
|
|
|
6
6
|
* engine/agentlas-memory-import.cjs 가 소유한다(여기서는 주입만).
|
|
7
7
|
* v1의 fail(process.exit)은 v2에서 throw 로 바꿔 엔진이 stderr+exit 1 처리한다.
|
|
8
8
|
*/
|
|
9
|
-
const { cmdMemory } = require("../agentlas-memory-import.cjs");
|
|
9
|
+
const { cmdMemory, parseMemoryArgs } = require("../agentlas-memory-import.cjs");
|
|
10
10
|
|
|
11
11
|
function run(ctx, args) {
|
|
12
|
+
const parsed = parseMemoryArgs(args);
|
|
12
13
|
cmdMemory({
|
|
13
|
-
db: ctx.db(),
|
|
14
|
+
db: parsed.help ? null : ctx.db(),
|
|
14
15
|
args,
|
|
15
16
|
out: ctx.out,
|
|
16
17
|
fail: (msg) => { throw new Error(String(msg ?? "")); },
|
|
@@ -51,6 +51,18 @@ function saveSettings(db, patch) {
|
|
|
51
51
|
|
|
52
52
|
function run(ctx, args) {
|
|
53
53
|
const ko = ctx.lang === "ko";
|
|
54
|
+
const usage = ko
|
|
55
|
+
? "사용법: agentlas multimodal [set <image|video|audio> <provider-id>]"
|
|
56
|
+
: "Usage: agentlas multimodal [set <image|video|audio> <provider-id>]";
|
|
57
|
+
if (args.length === 1 && ["help", "--help", "-h"].includes(args[0])) {
|
|
58
|
+
ctx.out(usage);
|
|
59
|
+
return 0;
|
|
60
|
+
}
|
|
61
|
+
if (args.length !== 0 && !(args.length === 3 && args[0] === "set")) {
|
|
62
|
+
const error = new Error(usage);
|
|
63
|
+
error.code = "INVALID_ARGUMENT";
|
|
64
|
+
throw error;
|
|
65
|
+
}
|
|
54
66
|
const db = ctx.db();
|
|
55
67
|
|
|
56
68
|
if (args[0] === "set") {
|
|
@@ -8,6 +8,10 @@ function run(ctx, args) {
|
|
|
8
8
|
const sub = String(args[0] || "help");
|
|
9
9
|
const query = args[1];
|
|
10
10
|
if (sub === "help" || sub === "--help" || sub === "-h") {
|
|
11
|
+
if (args.length > 1) {
|
|
12
|
+
ctx.err(ko ? "사용법: agentlas native help" : "usage: agentlas native help");
|
|
13
|
+
return 1;
|
|
14
|
+
}
|
|
11
15
|
// SELF_HELP_COMMANDS 계약: --help 는 스텁이 아니라 실제 안내여야 한다 —
|
|
12
16
|
// 무엇이 만들어지고 언제 필요한지까지 말한다.
|
|
13
17
|
ctx.out(ko
|
|
@@ -29,7 +33,7 @@ function run(ctx, args) {
|
|
|
29
33
|
].join("\n"));
|
|
30
34
|
return 0;
|
|
31
35
|
}
|
|
32
|
-
if (sub !== "prepare" || !query) {
|
|
36
|
+
if (sub !== "prepare" || !query || args.length !== 2) {
|
|
33
37
|
ctx.err(ko ? "사용법: agentlas native prepare <에이전트>" : "usage: agentlas native prepare <agent>");
|
|
34
38
|
return 1;
|
|
35
39
|
}
|
package/engine/commands/one.cjs
CHANGED
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
* agentlas one --list One 대화 목록
|
|
21
21
|
* agentlas one --new "<프롬프트>" 새 One 대화로 시작
|
|
22
22
|
* agentlas one --chat <id> "<p>" 특정 One 대화에 이어 붙임
|
|
23
|
+
* agentlas one -- "list 같은 옵션 모양의 프롬프트"
|
|
23
24
|
* 공통: -p/--print · --runtime · --model · --effort · --permission
|
|
24
25
|
*/
|
|
25
26
|
const readline = require("node:readline");
|
|
@@ -30,7 +31,7 @@ const { Renderer } = require("../ui/renderer.cjs");
|
|
|
30
31
|
const permissions = require("../agentlas-permissions.cjs");
|
|
31
32
|
const { EFFORTS } = require("../agentlas-workload-routing.cjs");
|
|
32
33
|
const { projectCwd } = require("../project/paths.cjs");
|
|
33
|
-
const {
|
|
34
|
+
const { runWriteTransaction } = require("../core/db.cjs");
|
|
34
35
|
const store = require("../sessions/store.cjs");
|
|
35
36
|
|
|
36
37
|
/** 데스크탑 정본 신원(electron/architecture/manifest.ts + builtinAgentId). */
|
|
@@ -45,13 +46,8 @@ const ONE_ORIGIN_SURFACE = "one";
|
|
|
45
46
|
* 걸러 낸다(설계). One 은 라우팅 후보가 아니라 **신원 행**이므로 직접 읽는다.
|
|
46
47
|
*/
|
|
47
48
|
function resolveOneAgent(db) {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
row = db.prepare("SELECT * FROM installed_agents WHERE id=?").get(ONE_AGENT_ID)
|
|
51
|
-
|| db.prepare("SELECT * FROM installed_agents WHERE slug=?").get(ONE_AGENT_SLUG);
|
|
52
|
-
} catch {
|
|
53
|
-
row = null;
|
|
54
|
-
}
|
|
49
|
+
const row = db.prepare("SELECT * FROM installed_agents WHERE id=?").get(ONE_AGENT_ID)
|
|
50
|
+
|| db.prepare("SELECT * FROM installed_agents WHERE slug=?").get(ONE_AGENT_SLUG);
|
|
55
51
|
return rowToAgent(row);
|
|
56
52
|
}
|
|
57
53
|
|
|
@@ -78,26 +74,22 @@ function desktopOnePersona() {
|
|
|
78
74
|
}
|
|
79
75
|
|
|
80
76
|
function chatsHaveOriginSurface(db) {
|
|
81
|
-
return
|
|
77
|
+
return db.prepare("PRAGMA table_info(chats)").all().some((column) => column.name === "origin_surface");
|
|
82
78
|
}
|
|
83
79
|
|
|
84
80
|
/** One 소유 대화 목록(최근 순). origin_surface 열이 없는 구형 DB 는 에이전트 소유로 폴백. */
|
|
85
81
|
function listOneChats(db, limit = 20) {
|
|
86
82
|
const bounded = Math.max(1, Math.min(Number(limit) || 20, 200));
|
|
87
|
-
|
|
88
|
-
if (chatsHaveOriginSurface(db)) {
|
|
89
|
-
return db.prepare(
|
|
90
|
-
"SELECT id, title, updated_at, origin_surface FROM chats " +
|
|
91
|
-
"WHERE origin_surface = ? ORDER BY updated_at DESC, rowid DESC LIMIT ?",
|
|
92
|
-
).all(ONE_ORIGIN_SURFACE, bounded);
|
|
93
|
-
}
|
|
83
|
+
if (chatsHaveOriginSurface(db)) {
|
|
94
84
|
return db.prepare(
|
|
95
|
-
"SELECT id, title, updated_at FROM chats
|
|
96
|
-
"ORDER BY updated_at DESC, rowid DESC LIMIT ?",
|
|
97
|
-
).all(
|
|
98
|
-
} catch {
|
|
99
|
-
return [];
|
|
85
|
+
"SELECT id, title, updated_at, origin_surface FROM chats " +
|
|
86
|
+
"WHERE origin_surface = ? ORDER BY updated_at DESC, rowid DESC LIMIT ?",
|
|
87
|
+
).all(ONE_ORIGIN_SURFACE, bounded);
|
|
100
88
|
}
|
|
89
|
+
return db.prepare(
|
|
90
|
+
"SELECT id, title, updated_at FROM chats WHERE agent_id IN (?, ?) AND (kind IS NULL OR kind <> 'division') " +
|
|
91
|
+
"ORDER BY updated_at DESC, rowid DESC LIMIT ?",
|
|
92
|
+
).all(ONE_AGENT_ID, ONE_AGENT_SLUG, bounded);
|
|
101
93
|
}
|
|
102
94
|
|
|
103
95
|
/**
|
|
@@ -121,19 +113,48 @@ function createOneChat(db, { agentId, title, workingFolder }) {
|
|
|
121
113
|
}
|
|
122
114
|
|
|
123
115
|
function parseArgs(args) {
|
|
124
|
-
const out = { print: false, list: false, fresh: false, chatId: null, runtime: null, model: null, effort: null, permission: null, rest: [] };
|
|
116
|
+
const out = { print: false, list: false, fresh: false, chatId: null, runtime: null, model: null, effort: null, permission: null, rest: [], error: null };
|
|
117
|
+
const readValue = (index, flag) => {
|
|
118
|
+
const value = args[index + 1];
|
|
119
|
+
if (typeof value !== "string" || !value || value === "--" || value.startsWith("--")) {
|
|
120
|
+
out.error = `${flag} requires a value`;
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
return value;
|
|
124
|
+
};
|
|
125
125
|
for (let i = 0; i < args.length; i++) {
|
|
126
126
|
const a = args[i];
|
|
127
|
+
if (a === "--") {
|
|
128
|
+
out.rest.push(...args.slice(i + 1));
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
127
131
|
if (a === "-p" || a === "--print") out.print = true;
|
|
128
|
-
else if (a === "--list"
|
|
129
|
-
else if (a === "--new"
|
|
130
|
-
else if (
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
132
|
+
else if (a === "--list") out.list = true;
|
|
133
|
+
else if (a === "--new") out.fresh = true;
|
|
134
|
+
else if (["--chat", "--runtime", "--model", "--effort", "--permission"].includes(a)) {
|
|
135
|
+
const value = readValue(i, a);
|
|
136
|
+
if (value === null) break;
|
|
137
|
+
if (a === "--chat") out.chatId = value;
|
|
138
|
+
else if (a === "--runtime") out.runtime = value;
|
|
139
|
+
else if (a === "--model") out.model = value;
|
|
140
|
+
else if (a === "--effort") out.effort = value;
|
|
141
|
+
else out.permission = value;
|
|
142
|
+
i += 1;
|
|
143
|
+
}
|
|
144
|
+
else if (a.startsWith("-")) {
|
|
145
|
+
out.error = `unknown option ${a}`;
|
|
146
|
+
break;
|
|
147
|
+
}
|
|
135
148
|
else out.rest.push(a);
|
|
136
149
|
}
|
|
150
|
+
if (!out.error && out.list && (
|
|
151
|
+
out.fresh || out.chatId || out.runtime || out.model || out.effort || out.permission || out.rest.length > 0
|
|
152
|
+
)) {
|
|
153
|
+
out.error = "--list cannot be combined with a prompt or execution options";
|
|
154
|
+
}
|
|
155
|
+
if (!out.error && out.fresh && out.chatId) {
|
|
156
|
+
out.error = "--new cannot be combined with --chat";
|
|
157
|
+
}
|
|
137
158
|
return out;
|
|
138
159
|
}
|
|
139
160
|
|
|
@@ -153,6 +174,10 @@ function renderList(ctx, rows) {
|
|
|
153
174
|
|
|
154
175
|
async function runOne(ctx, args) {
|
|
155
176
|
const parsed = parseArgs(args);
|
|
177
|
+
if (parsed.error) {
|
|
178
|
+
ctx.err(`invalid one arguments: ${parsed.error}`);
|
|
179
|
+
return 1;
|
|
180
|
+
}
|
|
156
181
|
if (parsed.permission && !permissions.LEVELS.includes(String(parsed.permission))) {
|
|
157
182
|
ctx.err(`unknown --permission ${parsed.permission} (use: ${permissions.LEVELS.join(" | ")})`);
|
|
158
183
|
return 1;
|
|
@@ -163,12 +188,29 @@ async function runOne(ctx, args) {
|
|
|
163
188
|
}
|
|
164
189
|
|
|
165
190
|
const db = ctx.db();
|
|
191
|
+
const readChats = (limit) => {
|
|
192
|
+
try {
|
|
193
|
+
return listOneChats(db, limit);
|
|
194
|
+
} catch (error) {
|
|
195
|
+
ctx.err(`Could not read One conversations: ${String((error && error.message) || error)}`);
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
};
|
|
166
199
|
|
|
167
200
|
// 목록은 신원 행이 없어도 답할 수 있어야 한다 — 대화는 chats 에 있고, One 행은
|
|
168
201
|
// 실행에만 필요하다. 조회를 실행 전제조건 뒤에 두면 "볼 수도 없는" 화면이 된다.
|
|
169
|
-
if (parsed.list)
|
|
202
|
+
if (parsed.list) {
|
|
203
|
+
const rows = readChats(20);
|
|
204
|
+
return rows ? renderList(ctx, rows) : 1;
|
|
205
|
+
}
|
|
170
206
|
|
|
171
|
-
|
|
207
|
+
let agent;
|
|
208
|
+
try {
|
|
209
|
+
agent = resolveOneAgent(db);
|
|
210
|
+
} catch (error) {
|
|
211
|
+
ctx.err(`Could not read the Agentlas One identity: ${String((error && error.message) || error)}`);
|
|
212
|
+
return 1;
|
|
213
|
+
}
|
|
172
214
|
if (!agent) {
|
|
173
215
|
ctx.err(
|
|
174
216
|
"Agentlas One is not present in the shared database yet.\n" +
|
|
@@ -212,14 +254,17 @@ async function runOne(ctx, args) {
|
|
|
212
254
|
let chatId = null;
|
|
213
255
|
let created = false;
|
|
214
256
|
if (parsed.chatId) {
|
|
215
|
-
const
|
|
257
|
+
const rows = readChats(200);
|
|
258
|
+
if (!rows) return 1;
|
|
259
|
+
const row = rows.find((item) => item.id === parsed.chatId);
|
|
216
260
|
if (!row) {
|
|
217
261
|
ctx.err(`No One conversation with id ${parsed.chatId} (see: agentlas one --list)`);
|
|
218
262
|
return 1;
|
|
219
263
|
}
|
|
220
264
|
chatId = row.id;
|
|
221
265
|
} else if (!parsed.fresh) {
|
|
222
|
-
const recent =
|
|
266
|
+
const recent = readChats(1);
|
|
267
|
+
if (!recent) return 1;
|
|
223
268
|
if (recent.length) chatId = recent[0].id;
|
|
224
269
|
}
|
|
225
270
|
if (!chatId) {
|