agentlas 0.4.0 → 0.5.5
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/README.md +112 -23
- package/bin/agentlas.cjs +55 -8
- package/engine/agentlas-api-agent.cjs +1 -1
- package/engine/agentlas-banner.cjs +66 -51
- package/engine/agentlas-capabilities.cjs +3 -0
- package/engine/agentlas-cloud-runtime.cjs +65 -11
- package/engine/agentlas-composer.cjs +109 -44
- package/engine/agentlas-doctor.cjs +65 -14
- package/engine/agentlas-i18n.cjs +132 -12
- package/engine/agentlas-input.cjs +123 -19
- package/engine/agentlas-native-host.cjs +381 -83
- package/engine/agentlas-parity.cjs +373 -53
- package/engine/agentlas-permissions.cjs +90 -0
- package/engine/agentlas-repl.cjs +149 -47
- package/engine/agentlas-tasks.cjs +111 -0
- package/engine/agentlas-tools.cjs +174 -12
- package/engine/agentlas-ui.cjs +349 -24
- package/engine/agentlas.cjs +3074 -379
- package/engine/architecture.data.json +5 -1
- package/engine/semver.cjs +64 -0
- package/package.json +1 -1
- package/test/bootstrap-race.cjs +47 -0
- package/test/capture-runtime-guard.cjs +122 -0
- package/test/cloud-asset-restore.cjs +423 -0
- package/test/cloud-cas-client.cjs +333 -0
- package/test/cloud-owner-restore.cjs +183 -0
- package/test/cloud-runtime-paths.cjs +40 -0
- package/test/cloud-save-publish.cjs +453 -0
- package/test/credential-env-regression.cjs +52 -0
- package/test/login-loopback-security.cjs +115 -0
- package/test/mcp-config-isolation.cjs +36 -0
- package/test/permission-mapping.cjs +180 -0
- package/test/run-api-regression.cjs +322 -0
- package/test/runtime-env-protection.cjs +45 -0
- package/test/semver-precedence.cjs +39 -0
- package/test/smoke.sh +33 -0
- package/test/sqlite-driver-probe.cjs +22 -0
- package/test/terminal-ui-regression.cjs +454 -0
- package/test/timeout-regression.cjs +218 -0
- package/test/tool-workspace-boundary.cjs +165 -0
- package/test/update-safety.cjs +376 -0
|
@@ -11,6 +11,7 @@ const fs = require("node:fs");
|
|
|
11
11
|
const os = require("node:os");
|
|
12
12
|
const path = require("node:path");
|
|
13
13
|
const readline = require("node:readline");
|
|
14
|
+
const i18n = require("./agentlas-i18n.cjs");
|
|
14
15
|
|
|
15
16
|
function userDataDir() {
|
|
16
17
|
const override = process.env.AGENTLAS_USER_DATA_DIR;
|
|
@@ -75,6 +76,7 @@ const SLASH_COMMAND_META = [
|
|
|
75
76
|
{ command: "/help", description: "Show Agentlas terminal commands", category: "Help", usage: "/help", detail: "Open the command reference, shortcuts, and common flows." },
|
|
76
77
|
{ command: "/status", description: "Show model/runtime, agent, permission, and directory", category: "Session", usage: "/status", detail: "Print the current runtime, active agent or company, permission level, and cwd." },
|
|
77
78
|
{ command: "/skills", description: "List available Agentlas terminal skills", category: "Discovery", usage: "/skills", detail: "Show the slash-command skills Agentlas can run inside this terminal." },
|
|
79
|
+
{ command: "/career-graph", description: "Show or add Career Graph source refs", category: "Knowledge", usage: "/career-graph add ./docs", detail: "Career Graph routes agents to source Markdown, JSONL ledgers, sitemap, and code map before broad scans.", examples: ["/career-graph status", "/career-graph add ./docs", "/career-graph open"] },
|
|
78
80
|
{ command: "/ontology", description: "Turn on, list, or add project ontology sources", category: "Knowledge", usage: "/ontology add ./docs", detail: "Also understands natural text like /ontology use ./docs as company knowledge.", examples: ["/ontology list", "/ontology use ./docs as company knowledge", "/ontology open"] },
|
|
79
81
|
{ command: "/agents", description: "List installed agents", category: "Routing", usage: "/agents", detail: "Show local agents and their routed runtime." },
|
|
80
82
|
{ command: "/team", description: "View or pin each agent runtime", category: "Routing", usage: "/team <agent> <runtime|auto>", detail: "Pin one agent to claude-code, codex, gemini, or automatic routing." },
|
|
@@ -91,7 +93,7 @@ const SLASH_COMMAND_META = [
|
|
|
91
93
|
{ command: "/memory", description: "Show the memory injected into this run", category: "Context", usage: "/memory", detail: "Print the project memory that Agentlas adds to agent turns." },
|
|
92
94
|
{ command: "/side", description: "Ask a side question without saving it to chat context", category: "Context", usage: "/side <question>", detail: "Runs a one-off answer using current context, then returns without appending to chat history.", aliases: ["/btw"] },
|
|
93
95
|
{ command: "/multimodal", description: "Show or set image, video, and audio fallback providers", category: "Settings", usage: "/multimodal", detail: "Inspect or change fallback providers for media work." },
|
|
94
|
-
{ command: "/mcp", description: "List configured MCP servers", category: "Settings", usage: "/mcp", detail: "Show MCP servers
|
|
96
|
+
{ command: "/mcp", description: "List configured MCP servers", category: "Settings", usage: "/mcp", detail: "Show MCP servers available only during explicit full-access turns." },
|
|
95
97
|
{ command: "/diff", description: "Show the current git diff", category: "Files", usage: "/diff", detail: "Print the working-tree diff for the current cwd." },
|
|
96
98
|
{ command: "/history", description: "Show recent inputs", category: "Session", usage: "/history", detail: "Show persisted terminal input history." },
|
|
97
99
|
{ command: "/resume", description: "Resume a recent runtime session", category: "Session", usage: "/resume [n]", detail: "List recent agent/runtime sessions and continue one (restores the native session thread)." },
|
|
@@ -101,12 +103,16 @@ const SLASH_COMMAND_META = [
|
|
|
101
103
|
{ command: "/clear", description: "Clear the chat and redraw", category: "Session", usage: "/clear", detail: "Clear local conversation state and redraw the Agentlas banner." },
|
|
102
104
|
{ command: "/import", description: "Import a local agent or team folder", category: "Files", usage: "/import <path>", detail: "Install a local agent or team into Agentlas." },
|
|
103
105
|
{ command: "/marketplace", description: "Browse/install marketplace agents", category: "Routing", usage: "/marketplace", detail: "Show how to install agents from the Agentlas cloud marketplace or a local folder.", aliases: ["/market"] },
|
|
104
|
-
{ command: "/install", description: "Install a cloud agent by slug", category: "Routing", usage: "/install <slug>", detail: "Download and install an agent from the Agentlas cloud marketplace by slug." },
|
|
105
106
|
{ command: "/storm", description: "Run a force-robust Stormbreaker pipeline on a goal", category: "Engine", usage: "/storm <goal> [--research]", detail: "Route the goal through Hephaestus Stormbreaker and execute the verified pipeline; --research grounds it with Research Engine evidence." },
|
|
106
107
|
{ command: "/swarm", description: "Fan out an emergent agent swarm on a goal", category: "Engine", usage: "/swarm <goal> [--parallel N]", detail: "Parallel workers share a blackboard and spawn subtasks with ## Spawn; a synthesizer merges results into one answer." },
|
|
107
108
|
{ command: "/build", description: "Build/repair/package an agent or team (Hephaestus)", category: "Engine", usage: "/build <what to build>", detail: "Runs Hephaestus hep-build natively — deep interview, scaffolding, packaging." },
|
|
108
109
|
{ command: "/route", description: "Preview which agent/pipeline would take a request", category: "Engine", usage: "/route <request>", detail: "Runs the Hephaestus router without executing — shows the selected agent, candidates, and reasons." },
|
|
109
110
|
{ command: "/research", description: "Run the Hephaestus Research Engine", category: "Engine", usage: "/research search \"query\"", detail: "status|gather|search|read|plan — evidence-grade web research from the terminal." },
|
|
111
|
+
{ command: "/search", description: "Discover agents in the Hub", category: "Hub", usage: "/search <what you need>", detail: "Search the Agentlas Hub + local for an agent that fits the task (hep-search)." },
|
|
112
|
+
{ command: "/install", description: "Install an agent from the Hub by slug", category: "Hub", usage: "/install <slug>", detail: "Install a marketplace agent into this terminal (hep-cloud)." },
|
|
113
|
+
{ command: "/network", description: "Decompose a request into an A2A task force", category: "Engine", usage: "/network <request>", detail: "Runs Hephaestus hep-network — splits a composite request across agents.", aliases: ["/taskforce"] },
|
|
114
|
+
{ command: "/browser", description: "Real browser execution hardpoint", category: "Engine", usage: "/browser [sub]", detail: "Runs the Agentlas browser hardpoint (hep-browser)." },
|
|
115
|
+
{ command: "/connect", description: "Wire Telegram / platforms to an agent team", category: "Hub", usage: "/connect", detail: "Runs Hephaestus hep-connect for platform integration." },
|
|
110
116
|
{ command: "/doctor", description: "Check runtimes and local data", category: "Health", usage: "/doctor", detail: "Run local checks for runtimes, data, credentials, and setup." },
|
|
111
117
|
{ command: "/exit", description: "Quit Agentlas", category: "Session", usage: "/exit", detail: "Close the terminal session.", aliases: ["/quit"] },
|
|
112
118
|
];
|
|
@@ -114,19 +120,79 @@ const SLASH_COMMANDS = SLASH_COMMAND_META.flatMap((entry) => [entry.command].con
|
|
|
114
120
|
const RUNTIME_SPECS = ["claude-code", "codex", "gemini", "anthropic", "openai", "google", "ollama", "upstage"];
|
|
115
121
|
const PERM_LEVELS = ["read", "write", "full"];
|
|
116
122
|
|
|
123
|
+
const HELP_KEY_BY_COMMAND = {
|
|
124
|
+
"/help": "help.help",
|
|
125
|
+
"/status": "help.status",
|
|
126
|
+
"/skills": "help.skills",
|
|
127
|
+
"/career-graph": "help.careerGraph",
|
|
128
|
+
"/ontology": "help.ontology",
|
|
129
|
+
"/agents": "help.agents",
|
|
130
|
+
"/team": "help.team",
|
|
131
|
+
"/agent": "help.agent",
|
|
132
|
+
"/firms": "help.firms",
|
|
133
|
+
"/firm": "help.firms",
|
|
134
|
+
"/runtime": "help.runtime",
|
|
135
|
+
"/model": "help.model",
|
|
136
|
+
"/effort": "help.effort",
|
|
137
|
+
"/permission": "help.permission",
|
|
138
|
+
"/permissions": "help.permissions",
|
|
139
|
+
"/setup": "help.setup",
|
|
140
|
+
"/cwd": "help.cwd",
|
|
141
|
+
"/memory": "help.memory",
|
|
142
|
+
"/side": "help.side",
|
|
143
|
+
"/multimodal": "help.multimodal",
|
|
144
|
+
"/mcp": "help.mcp",
|
|
145
|
+
"/diff": "help.diff",
|
|
146
|
+
"/history": "help.history",
|
|
147
|
+
"/resume": "help.resume",
|
|
148
|
+
"/compact": "help.compact",
|
|
149
|
+
"/cost": "help.cost",
|
|
150
|
+
"/keybindings": "help.keybindings",
|
|
151
|
+
"/clear": "help.clear",
|
|
152
|
+
"/import": "help.import",
|
|
153
|
+
"/marketplace": "help.market",
|
|
154
|
+
"/install": "help.install",
|
|
155
|
+
"/storm": "help.storm",
|
|
156
|
+
"/swarm": "help.swarm",
|
|
157
|
+
"/build": "help.build",
|
|
158
|
+
"/route": "help.route",
|
|
159
|
+
"/research": "help.research",
|
|
160
|
+
"/search": "help.search",
|
|
161
|
+
"/network": "help.network",
|
|
162
|
+
"/browser": "help.browser",
|
|
163
|
+
"/connect": "help.connect",
|
|
164
|
+
"/doctor": "help.doctor",
|
|
165
|
+
"/exit": "help.exit",
|
|
166
|
+
};
|
|
167
|
+
|
|
117
168
|
function uniqStartsWith(cands, token) {
|
|
118
169
|
const hits = cands.filter((c) => c.startsWith(token));
|
|
119
170
|
return hits.length ? hits : cands;
|
|
120
171
|
}
|
|
121
172
|
|
|
122
|
-
function
|
|
173
|
+
function localizeSlashEntry(entry, lang) {
|
|
174
|
+
const helpKey = HELP_KEY_BY_COMMAND[entry.command];
|
|
175
|
+
const description = helpKey ? i18n.t(lang, helpKey) : entry.description;
|
|
176
|
+
const category = entry.category ? i18n.t(lang, `category.${entry.category}`) : entry.category;
|
|
177
|
+
return {
|
|
178
|
+
...entry,
|
|
179
|
+
description,
|
|
180
|
+
category,
|
|
181
|
+
// English keeps the longer authored detail. Other languages must not fall back to
|
|
182
|
+
// an English paragraph under an otherwise-localized command palette.
|
|
183
|
+
detail: lang === "en" ? entry.detail : description,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function slashCommandEntries(lang = "en") {
|
|
123
188
|
const rows = [];
|
|
124
|
-
for (const
|
|
189
|
+
for (const rawEntry of SLASH_COMMAND_META) {
|
|
190
|
+
const entry = localizeSlashEntry(rawEntry, lang);
|
|
125
191
|
rows.push({ ...entry, aliasOf: null });
|
|
126
192
|
for (const alias of entry.aliases || []) {
|
|
127
193
|
rows.push({
|
|
128
194
|
command: alias,
|
|
129
|
-
description: `Alias for ${entry.command}`,
|
|
195
|
+
description: lang === "ko" ? `${entry.command} 별칭` : `Alias for ${entry.command}`,
|
|
130
196
|
category: entry.category,
|
|
131
197
|
usage: alias + (entry.usage && entry.usage.includes(" ") ? entry.usage.slice(entry.usage.indexOf(" ")) : ""),
|
|
132
198
|
detail: entry.detail,
|
|
@@ -146,11 +212,11 @@ function slashCommandQuery(line) {
|
|
|
146
212
|
return value;
|
|
147
213
|
}
|
|
148
214
|
|
|
149
|
-
function slashCommandSuggestions(line, limit = 12) {
|
|
215
|
+
function slashCommandSuggestions(line, limit = 12, lang = "en") {
|
|
150
216
|
const query = slashCommandQuery(line);
|
|
151
217
|
if (query == null) return [];
|
|
152
218
|
const q = query.toLowerCase();
|
|
153
|
-
const entries = slashCommandEntries();
|
|
219
|
+
const entries = slashCommandEntries(lang);
|
|
154
220
|
const starts = entries.filter((entry) => entry.command.toLowerCase().startsWith(q));
|
|
155
221
|
const contains = entries.filter(
|
|
156
222
|
(entry) =>
|
|
@@ -161,9 +227,9 @@ function slashCommandSuggestions(line, limit = 12) {
|
|
|
161
227
|
}
|
|
162
228
|
|
|
163
229
|
function padVisible(value, width) {
|
|
164
|
-
const
|
|
165
|
-
if (
|
|
166
|
-
return value + " ".repeat(width -
|
|
230
|
+
const current = visibleWidthLite(value);
|
|
231
|
+
if (current >= width) return value;
|
|
232
|
+
return value + " ".repeat(width - current);
|
|
167
233
|
}
|
|
168
234
|
|
|
169
235
|
function stripAnsiLite(value) {
|
|
@@ -173,8 +239,40 @@ function stripAnsiLite(value) {
|
|
|
173
239
|
|
|
174
240
|
function truncateVisible(value, width) {
|
|
175
241
|
const clean = stripAnsiLite(value);
|
|
176
|
-
if (clean
|
|
177
|
-
|
|
242
|
+
if (visibleWidthLite(clean) <= width) return value;
|
|
243
|
+
let out = "";
|
|
244
|
+
let used = 0;
|
|
245
|
+
const room = Math.max(0, width - 1);
|
|
246
|
+
for (const ch of clean) {
|
|
247
|
+
const cells = cellWidthLite(ch);
|
|
248
|
+
if (used + cells > room) break;
|
|
249
|
+
out += ch;
|
|
250
|
+
used += cells;
|
|
251
|
+
}
|
|
252
|
+
return out + "…";
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function cellWidthLite(ch) {
|
|
256
|
+
const cp = ch.codePointAt(0);
|
|
257
|
+
if (cp < 0x20) return 0;
|
|
258
|
+
return (
|
|
259
|
+
(cp >= 0x1100 && cp <= 0x115f) ||
|
|
260
|
+
(cp >= 0x2e80 && cp <= 0x303e) ||
|
|
261
|
+
(cp >= 0x3041 && cp <= 0x33ff) ||
|
|
262
|
+
(cp >= 0x3400 && cp <= 0x4dbf) ||
|
|
263
|
+
(cp >= 0x4e00 && cp <= 0x9fff) ||
|
|
264
|
+
(cp >= 0xac00 && cp <= 0xd7a3) ||
|
|
265
|
+
(cp >= 0xf900 && cp <= 0xfaff) ||
|
|
266
|
+
(cp >= 0xfe30 && cp <= 0xfe4f) ||
|
|
267
|
+
(cp >= 0xff00 && cp <= 0xff60) ||
|
|
268
|
+
(cp >= 0x1f300 && cp <= 0x1faff)
|
|
269
|
+
) ? 2 : 1;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
function visibleWidthLite(value) {
|
|
273
|
+
let width = 0;
|
|
274
|
+
for (const ch of stripAnsiLite(value)) width += cellWidthLite(ch);
|
|
275
|
+
return width;
|
|
178
276
|
}
|
|
179
277
|
|
|
180
278
|
function renderSlashPalette(rows, selectedIndex, opts = {}) {
|
|
@@ -188,32 +286,35 @@ function renderSlashPalette(rows, selectedIndex, opts = {}) {
|
|
|
188
286
|
inverse: (s) => String(s),
|
|
189
287
|
};
|
|
190
288
|
const c = { ...fallbackColors, ...(opts.colors || {}) };
|
|
289
|
+
const lang = opts.lang || "en";
|
|
191
290
|
const commandWidth = Math.min(24, Math.max(16, rows.reduce((n, row) => Math.max(n, row.command.length), 0) + 2));
|
|
192
291
|
const descWidth = Math.max(12, columns - commandWidth - 8);
|
|
193
292
|
const lineWidth = Math.min(columns - 1, commandWidth + descWidth + 5);
|
|
194
293
|
const selected = rows[Math.max(0, Math.min(selectedIndex, rows.length - 1))] || rows[0];
|
|
195
294
|
const out = [
|
|
196
|
-
c.faint(
|
|
295
|
+
c.faint(truncateVisible(`${i18n.t(lang, "palette.title")} ${i18n.t(lang, "palette.search")}`, lineWidth)),
|
|
197
296
|
c.faint("─".repeat(lineWidth)),
|
|
198
297
|
];
|
|
199
298
|
rows.forEach((row, index) => {
|
|
200
299
|
const command = padVisible(row.command, commandWidth);
|
|
201
300
|
const desc = truncateVisible(row.description, descWidth);
|
|
202
301
|
const body = " " + c.blue(command) + c.text(desc);
|
|
203
|
-
out.push(index === selectedIndex ? c.inverse(body
|
|
302
|
+
out.push(index === selectedIndex ? c.inverse(padVisible(body, lineWidth)) : body);
|
|
204
303
|
});
|
|
205
304
|
out.push(c.faint("─".repeat(lineWidth)));
|
|
206
305
|
if (selected) {
|
|
207
306
|
const usage = truncateVisible(selected.usage || selected.command, lineWidth - 2);
|
|
208
307
|
const detail = truncateVisible(selected.detail || selected.description || "", lineWidth - 2);
|
|
209
|
-
const category = selected.category ?
|
|
210
|
-
|
|
308
|
+
const category = selected.category ? i18n.t(lang, "palette.category", selected.category) : "";
|
|
309
|
+
const categoryRoom = Math.max(0, lineWidth - visibleWidthLite(usage) - 3);
|
|
310
|
+
const categoryText = categoryRoom > 0 ? truncateVisible(category, categoryRoom) : "";
|
|
311
|
+
out.push(" " + c.text(usage) + (categoryText ? c.dim(" " + categoryText) : ""));
|
|
211
312
|
if (detail) out.push(" " + c.dim(detail));
|
|
212
313
|
if (selected.examples && selected.examples.length) {
|
|
213
|
-
out.push(" " +
|
|
314
|
+
out.push(c.dim(truncateVisible(" " + i18n.t(lang, "palette.examples", selected.examples.slice(0, 2).join(" | ")), lineWidth)));
|
|
214
315
|
}
|
|
215
316
|
}
|
|
216
|
-
out.push(c.dim("
|
|
317
|
+
out.push(c.dim(truncateVisible(" " + i18n.t(lang, "palette.controls"), lineWidth)));
|
|
217
318
|
return out.join("\n");
|
|
218
319
|
}
|
|
219
320
|
|
|
@@ -238,7 +339,7 @@ function attachSlashPalette(rl, opts = {}) {
|
|
|
238
339
|
|
|
239
340
|
function rows() {
|
|
240
341
|
if (!state.enabled) return [];
|
|
241
|
-
return slashCommandSuggestions(rl.line || "");
|
|
342
|
+
return slashCommandSuggestions(rl.line || "", 12, opts.lang || (opts.ui && opts.ui.lang) || "en");
|
|
242
343
|
}
|
|
243
344
|
function active() {
|
|
244
345
|
return rows().length > 0 && state.dismissedForLine !== (rl.line || "");
|
|
@@ -270,6 +371,7 @@ function attachSlashPalette(rl, opts = {}) {
|
|
|
270
371
|
const body = renderSlashPalette(list, state.selected, {
|
|
271
372
|
columns: stream.columns || process.stdout.columns || 88,
|
|
272
373
|
colors,
|
|
374
|
+
lang: opts.lang || (opts.ui && opts.ui.lang) || "en",
|
|
273
375
|
});
|
|
274
376
|
stream.write("\x1b7\x1b[E\x1b[0J" + body + "\x1b8");
|
|
275
377
|
state.visible = true;
|
|
@@ -359,6 +461,7 @@ function isAbsolutePathTask(line) {
|
|
|
359
461
|
const value = String(line || "").trim();
|
|
360
462
|
if (!value.startsWith("/")) return false;
|
|
361
463
|
const first = value.split(/\s+/)[0] || "";
|
|
464
|
+
if (first === "/") return false;
|
|
362
465
|
if (!first || SLASH_COMMANDS.includes(first)) return false;
|
|
363
466
|
if (!path.isAbsolute(first)) return false;
|
|
364
467
|
if (fs.existsSync(first)) return true;
|
|
@@ -406,6 +509,7 @@ function makeCompleter(ctx) {
|
|
|
406
509
|
return [uniqStartsWith(RUNTIME_SPECS.concat(["auto"]), last), last];
|
|
407
510
|
case "/cwd":
|
|
408
511
|
case "/import":
|
|
512
|
+
case "/career-graph":
|
|
409
513
|
case "/ontology":
|
|
410
514
|
return [completePath(last, getCwd(), ""), last];
|
|
411
515
|
default:
|