agentlas 0.9.10 → 1.0.2

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.
Files changed (145) hide show
  1. package/CHANGELOG.md +106 -0
  2. package/README.md +319 -341
  3. package/bin/agentlas.cjs +32 -9
  4. package/engine/agentlas-banner.cjs +24 -3
  5. package/engine/agentlas-composer.cjs +239 -31
  6. package/engine/agentlas-config.cjs +103 -7
  7. package/engine/agentlas-core-harness.cjs +48 -4
  8. package/engine/agentlas-evolution.cjs +3 -4
  9. package/engine/agentlas-i18n.cjs +88 -32
  10. package/engine/agentlas-input.cjs +234 -18
  11. package/engine/agentlas-memory-governance.cjs +3 -5
  12. package/engine/agentlas-memory-import.cjs +3 -3
  13. package/engine/agentlas-native-host.cjs +200 -9
  14. package/engine/agentlas-onboard.cjs +112 -20
  15. package/engine/agentlas-permissions.cjs +14 -7
  16. package/engine/agentlas-sqlite-policy.cjs +34 -0
  17. package/engine/agentlas-ui.cjs +93 -42
  18. package/engine/agentlas-workforce.cjs +472 -58
  19. package/engine/agentlas-workload-routing.cjs +8 -3
  20. package/engine/agentlas.cjs +140 -12367
  21. package/engine/agents/files.cjs +61 -0
  22. package/engine/agents/import-local.cjs +237 -0
  23. package/engine/agents/registry.cjs +158 -0
  24. package/engine/agents/router.cjs +565 -0
  25. package/engine/agents/routes.cjs +43 -0
  26. package/engine/architecture.data.json +2 -2
  27. package/engine/automation/daemon.cjs +335 -0
  28. package/engine/automation/schedule.cjs +181 -0
  29. package/engine/automation/store.cjs +209 -0
  30. package/engine/cloud/auth.cjs +279 -0
  31. package/engine/cloud/hub-client.cjs +239 -0
  32. package/engine/cloud-assets/cargo.cjs +49 -0
  33. package/engine/cloud-assets/cas.cjs +235 -0
  34. package/engine/cloud-assets/commands.cjs +273 -0
  35. package/engine/cloud-assets/package.cjs +936 -0
  36. package/engine/cloud-assets/restore.cjs +172 -0
  37. package/engine/cloud-assets/state.cjs +268 -0
  38. package/engine/commands/automation.cjs +195 -0
  39. package/engine/commands/billing.cjs +96 -0
  40. package/engine/commands/browser.cjs +20 -0
  41. package/engine/commands/build.cjs +33 -0
  42. package/engine/commands/call.cjs +24 -0
  43. package/engine/commands/career-graph.cjs +51 -0
  44. package/engine/commands/cd.cjs +22 -0
  45. package/engine/commands/chat.cjs +12 -0
  46. package/engine/commands/chats.cjs +28 -0
  47. package/engine/commands/cloud.cjs +17 -0
  48. package/engine/commands/connect.cjs +20 -0
  49. package/engine/commands/context.cjs +66 -0
  50. package/engine/commands/creds.cjs +203 -0
  51. package/engine/commands/doctor.cjs +68 -0
  52. package/engine/commands/env.cjs +33 -0
  53. package/engine/commands/evolve.cjs +23 -0
  54. package/engine/commands/experience.cjs +34 -0
  55. package/engine/commands/film.cjs +8 -0
  56. package/engine/commands/firm.cjs +115 -0
  57. package/engine/commands/help.cjs +65 -0
  58. package/engine/commands/hep.cjs +23 -0
  59. package/engine/commands/import.cjs +35 -0
  60. package/engine/commands/index.cjs +136 -0
  61. package/engine/commands/install.cjs +27 -0
  62. package/engine/commands/journal.cjs +31 -0
  63. package/engine/commands/legacy-network.cjs +29 -0
  64. package/engine/commands/list.cjs +49 -0
  65. package/engine/commands/login.cjs +68 -0
  66. package/engine/commands/logout.cjs +28 -0
  67. package/engine/commands/mcp.cjs +91 -0
  68. package/engine/commands/memory.cjs +21 -0
  69. package/engine/commands/multimodal.cjs +91 -0
  70. package/engine/commands/native.cjs +34 -0
  71. package/engine/commands/netadmin.cjs +31 -0
  72. package/engine/commands/oberon.cjs +70 -0
  73. package/engine/commands/ontology.cjs +24 -0
  74. package/engine/commands/open.cjs +48 -0
  75. package/engine/commands/plugin.cjs +101 -0
  76. package/engine/commands/project.cjs +47 -0
  77. package/engine/commands/research.cjs +36 -0
  78. package/engine/commands/route.cjs +37 -0
  79. package/engine/commands/run.cjs +149 -0
  80. package/engine/commands/search.cjs +55 -0
  81. package/engine/commands/setup.cjs +45 -0
  82. package/engine/commands/storm.cjs +75 -0
  83. package/engine/commands/swarm.cjs +75 -0
  84. package/engine/commands/telegram.cjs +32 -0
  85. package/engine/commands/uninstall.cjs +68 -0
  86. package/engine/commands/update.cjs +54 -0
  87. package/engine/commands/upload.cjs +18 -0
  88. package/engine/commands/usage.cjs +35 -0
  89. package/engine/commands/variant.cjs +25 -0
  90. package/engine/commands/version.cjs +9 -0
  91. package/engine/commands/whoami.cjs +38 -0
  92. package/engine/commands/workforce.cjs +103 -0
  93. package/engine/core/db.cjs +160 -0
  94. package/engine/core/paths.cjs +35 -0
  95. package/engine/experience/build.cjs +181 -0
  96. package/engine/experience/intents.cjs +492 -0
  97. package/engine/experience/runtime.cjs +242 -0
  98. package/engine/experience/variant.cjs +196 -0
  99. package/engine/firms/orchestrate.cjs +333 -0
  100. package/engine/hephaestus/runtime.cjs +697 -0
  101. package/engine/hub/install.cjs +872 -0
  102. package/engine/hub/plugins.cjs +213 -0
  103. package/engine/mcp/consent.cjs +289 -0
  104. package/engine/mcp/contract.cjs +202 -0
  105. package/engine/mcp/index.cjs +43 -0
  106. package/engine/mcp/inventory.cjs +322 -0
  107. package/engine/mcp/plan.cjs +286 -0
  108. package/engine/mcp/probe.cjs +151 -0
  109. package/engine/memory-cli/curate.cjs +163 -0
  110. package/engine/oberon/common.cjs +69 -0
  111. package/engine/oberon/manifest.cjs +164 -0
  112. package/engine/oberon/outputs.cjs +70 -0
  113. package/engine/oberon/render.cjs +164 -0
  114. package/engine/project/career-graph.cjs +249 -0
  115. package/engine/project/credentials.cjs +262 -0
  116. package/engine/project/env-file.cjs +46 -0
  117. package/engine/project/index.cjs +27 -0
  118. package/engine/project/memory-context.cjs +453 -0
  119. package/engine/project/ontology.cjs +467 -0
  120. package/engine/project/paths.cjs +39 -0
  121. package/engine/project/seed.cjs +200 -0
  122. package/engine/project/state.cjs +403 -0
  123. package/engine/project/super-ontology-seed.json +3288 -0
  124. package/engine/runtimes/detect.cjs +54 -0
  125. package/engine/runtimes/overrides.cjs +139 -0
  126. package/engine/runtimes/resolve.cjs +64 -0
  127. package/engine/sessions/apply-fences.cjs +188 -0
  128. package/engine/sessions/fences.cjs +362 -0
  129. package/engine/sessions/orchestrator.cjs +170 -0
  130. package/engine/sessions/prompt.cjs +212 -0
  131. package/engine/sessions/session.cjs +245 -0
  132. package/engine/sessions/sink.cjs +54 -0
  133. package/engine/sessions/store.cjs +79 -0
  134. package/engine/storm/deps.cjs +88 -0
  135. package/engine/storm/storm.cjs +218 -0
  136. package/engine/storm/swarm.cjs +422 -0
  137. package/engine/ui/palette.cjs +105 -0
  138. package/engine/ui/renderer.cjs +85 -0
  139. package/engine/ui/repl.cjs +444 -0
  140. package/engine/workforce/capture.cjs +701 -0
  141. package/engine/workforce/deps.cjs +472 -0
  142. package/package.json +2 -6
  143. package/engine/agentlas-experience-mcp.cjs +0 -1709
  144. package/engine/agentlas-parity.cjs +0 -1499
  145. package/engine/agentlas-repl.cjs +0 -1780
@@ -2,28 +2,124 @@
2
2
  /*
3
3
  * CLI preferences (separate from the app's SQLite/keychain) — first-run onboarding result.
4
4
  * Stored at <userData>/cli-prefs.json: { onboarded, lang, runtime, permission }.
5
+ * Persisted permission is read|write; unrestricted/full is session-only.
5
6
  */
6
7
  const fs = require("node:fs");
7
8
  const path = require("node:path");
9
+ const LOCK_WAIT_MS = 2_000;
10
+ const LOCK_STALE_MS = 30_000;
8
11
 
9
12
  function prefsPath(userDataDir) {
10
13
  return path.join(userDataDir, "cli-prefs.json");
11
14
  }
15
+ function backupPath(userDataDir) {
16
+ return prefsPath(userDataDir) + ".bak";
17
+ }
18
+ function readPrefsFile(file) {
19
+ try {
20
+ const value = JSON.parse(fs.readFileSync(file, "utf8"));
21
+ return value && typeof value === "object" && !Array.isArray(value) ? value : null;
22
+ } catch {
23
+ return null;
24
+ }
25
+ }
12
26
  function loadPrefs(userDataDir) {
27
+ return readPrefsFile(prefsPath(userDataDir)) || readPrefsFile(backupPath(userDataDir)) || {};
28
+ }
29
+
30
+ function sleepSync(ms) {
13
31
  try {
14
- return JSON.parse(fs.readFileSync(prefsPath(userDataDir), "utf8")) || {};
32
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
15
33
  } catch {
16
- return {};
34
+ const until = Date.now() + ms;
35
+ while (Date.now() < until) { /* old Node fallback */ }
17
36
  }
18
37
  }
19
- function savePrefs(userDataDir, prefs) {
38
+
39
+ function withPrefsLock(userDataDir, callback) {
40
+ const lock = prefsPath(userDataDir) + ".lock";
41
+ const deadline = Date.now() + LOCK_WAIT_MS;
42
+ while (true) {
43
+ try {
44
+ fs.mkdirSync(lock, { mode: 0o700 });
45
+ break;
46
+ } catch (error) {
47
+ if (!error || error.code !== "EEXIST") throw error;
48
+ try {
49
+ if (Date.now() - fs.statSync(lock).mtimeMs > LOCK_STALE_MS) {
50
+ fs.rmdirSync(lock);
51
+ continue;
52
+ }
53
+ } catch {
54
+ continue;
55
+ }
56
+ if (Date.now() >= deadline) throw new Error("preferences lock timeout");
57
+ sleepSync(10);
58
+ }
59
+ }
60
+ try {
61
+ return callback();
62
+ } finally {
63
+ try { fs.rmdirSync(lock); } catch { /* stale lock recovery handles interrupted writers */ }
64
+ }
65
+ }
66
+
67
+ function atomicWrite(file, value) {
68
+ const tmp = `${file}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`;
69
+ let fd;
70
+ try {
71
+ fd = fs.openSync(tmp, "wx", 0o600);
72
+ fs.writeFileSync(fd, JSON.stringify(value, null, 2), "utf8");
73
+ fs.fsyncSync(fd);
74
+ fs.closeSync(fd);
75
+ fd = null;
76
+ fs.renameSync(tmp, file);
77
+ try { fs.chmodSync(file, 0o600); } catch { /* win32 */ }
78
+ } finally {
79
+ if (fd != null) {
80
+ try { fs.closeSync(fd); } catch { /* ignore */ }
81
+ }
82
+ try { fs.unlinkSync(tmp); } catch { /* already renamed or never created */ }
83
+ }
84
+ }
85
+
86
+ function mergePrefs(base, patch) {
87
+ const next = { ...base };
88
+ for (const [key, value] of Object.entries(patch || {})) {
89
+ if (
90
+ value && typeof value === "object" && !Array.isArray(value)
91
+ && next[key] && typeof next[key] === "object" && !Array.isArray(next[key])
92
+ ) {
93
+ next[key] = mergePrefs(next[key], value);
94
+ } else {
95
+ next[key] = value;
96
+ }
97
+ }
98
+ return next;
99
+ }
100
+
101
+ function updatePrefs(userDataDir, patch) {
20
102
  try {
21
103
  fs.mkdirSync(userDataDir, { recursive: true });
22
- fs.writeFileSync(prefsPath(userDataDir), JSON.stringify(prefs, null, 2), "utf8");
23
- return true;
104
+ return withPrefsLock(userDataDir, () => {
105
+ const file = prefsPath(userDataDir);
106
+ const currentWasValid = Boolean(readPrefsFile(file));
107
+ const current = loadPrefs(userDataDir);
108
+ if (fs.existsSync(file) && !currentWasValid) {
109
+ try { fs.renameSync(file, `${file}.corrupt-${Date.now()}-${process.pid}`); } catch { /* recover from backup */ }
110
+ }
111
+ const next = mergePrefs(current, patch);
112
+ if (currentWasValid) atomicWrite(backupPath(userDataDir), current);
113
+ atomicWrite(file, next);
114
+ return next;
115
+ });
24
116
  } catch {
25
- return false;
117
+ return null;
26
118
  }
27
119
  }
28
120
 
29
- module.exports = { prefsPath, loadPrefs, savePrefs };
121
+ function savePrefs(userDataDir, prefs) {
122
+ return Boolean(updatePrefs(userDataDir, prefs));
123
+ }
124
+
125
+ module.exports = { prefsPath, loadPrefs, savePrefs, updatePrefs, mergePrefs };
@@ -5,10 +5,13 @@ const fs = require("node:fs");
5
5
  const os = require("node:os");
6
6
  const path = require("node:path");
7
7
  const { spawn, spawnSync } = require("node:child_process");
8
+ const { compareSemVer, normalizeSemVer } = require("./semver.cjs");
8
9
 
9
10
  const HARNESS_SCHEMA_VERSION = "agentlas.stormbreaker.goal-ultracode-harness.v1";
10
11
  const HARNESS_ID = "agentlas-core/stormbreaker-goal-ultracode";
11
12
  const HARNESS_MODE = "stormbreaker-goal-ultracode";
13
+ const CONTEXT_MAP_MIN_CORE_VERSION = "1.1.66";
14
+ const CORE_MANIFEST_MAX_BYTES = 64 * 1024;
12
15
  const CORE_RUNTIME_MARKERS = [
13
16
  ["agentlas_cloud", "__main__.py"],
14
17
  ["schemas", "workforce-work-order.schema.json"],
@@ -42,12 +45,46 @@ function runtimeRoots(explicitRoot) {
42
45
  return unique(roots);
43
46
  }
44
47
 
45
- function resolveCoreRuntimeRoot(explicitRoot) {
46
- for (const root of runtimeRoots(explicitRoot)) {
48
+ function readCoreRuntimeVersion(root) {
49
+ const jsonCandidates = [
50
+ path.join(root, "manifest.json"),
51
+ path.join(root, "host_adapters", "manifest.json"),
52
+ ];
53
+ for (const manifestPath of jsonCandidates) {
54
+ try {
55
+ const stat = fs.statSync(manifestPath);
56
+ if (!stat.isFile() || stat.size > CORE_MANIFEST_MAX_BYTES) continue;
57
+ const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
58
+ const version = normalizeSemVer(String(manifest.version || ""));
59
+ if (version) return version;
60
+ } catch {
61
+ // Try the next bounded local manifest.
62
+ }
63
+ }
64
+ try {
65
+ const releasePath = path.join(root, "RELEASE");
66
+ const stat = fs.statSync(releasePath);
67
+ if (stat.isFile() && stat.size <= 256) {
68
+ return normalizeSemVer(fs.readFileSync(releasePath, "utf8").trim());
69
+ }
70
+ } catch {
71
+ // A legacy runtime may not publish RELEASE metadata.
72
+ }
73
+ return null;
74
+ }
75
+
76
+ function resolveCoreRuntimeRootFromCandidates(candidateRoots, requiredMarkers = [], options = {}) {
77
+ const markers = [...CORE_RUNTIME_MARKERS, ...requiredMarkers];
78
+ const minVersion = options.minVersion ? normalizeSemVer(String(options.minVersion)) : null;
79
+ if (options.minVersion && !minVersion) throw new Error(`Invalid minimum Core version: ${options.minVersion}`);
80
+ for (const root of unique(candidateRoots)) {
47
81
  try {
48
- if (CORE_RUNTIME_MARKERS.every((segments) => fs.existsSync(path.join(root, ...segments)))) {
49
- return root;
82
+ if (!markers.every((segments) => fs.existsSync(path.join(root, ...segments)))) continue;
83
+ if (minVersion) {
84
+ const version = readCoreRuntimeVersion(root);
85
+ if (!version || compareSemVer(version, minVersion) < 0) continue;
50
86
  }
87
+ return root;
51
88
  } catch {
52
89
  // Continue to the next installed/bundled root.
53
90
  }
@@ -55,6 +92,10 @@ function resolveCoreRuntimeRoot(explicitRoot) {
55
92
  return null;
56
93
  }
57
94
 
95
+ function resolveCoreRuntimeRoot(explicitRoot, requiredMarkers = [], options = {}) {
96
+ return resolveCoreRuntimeRootFromCandidates(runtimeRoots(explicitRoot), requiredMarkers, options);
97
+ }
98
+
58
99
  function pythonCandidates() {
59
100
  return [...new Set([
60
101
  process.env.HEPHAESTUS_PYTHON,
@@ -200,7 +241,10 @@ module.exports = {
200
241
  HARNESS_SCHEMA_VERSION,
201
242
  HARNESS_ID,
202
243
  HARNESS_MODE,
244
+ CONTEXT_MAP_MIN_CORE_VERSION,
203
245
  PY_BOOTSTRAP,
246
+ readCoreRuntimeVersion,
247
+ resolveCoreRuntimeRootFromCandidates,
204
248
  resolveCoreRuntimeRoot,
205
249
  resolvePython,
206
250
  spawnCoreModule,
@@ -15,6 +15,7 @@
15
15
  const fs = require("node:fs");
16
16
  const path = require("node:path");
17
17
  const { createHash, randomUUID } = require("node:crypto");
18
+ const { runWriteTransaction } = require("./agentlas-sqlite-policy.cjs");
18
19
 
19
20
  function sha256(content) {
20
21
  return createHash("sha256").update(String(content), "utf8").digest("hex");
@@ -217,7 +218,7 @@ function cmdApply(db, id, out, fail, agentFolder) {
217
218
  fs.writeFileSync(file, row.before_content, "utf8");
218
219
  return fail("Applied content did not match the approved hash; restored the original.");
219
220
  }
220
- const tx = db.transaction(() => {
221
+ runWriteTransaction(db, () => {
221
222
  db.prepare("UPDATE installed_agents SET system_prompt = ? WHERE id = ?").run(row.after_content, row.agent_id);
222
223
  insertReceipt(db, row, "apply", row.before_hash, row.after_hash, now);
223
224
  db.prepare(
@@ -227,7 +228,6 @@ function cmdApply(db, id, out, fail, agentFolder) {
227
228
  WHERE id = ? AND status = 'candidate'`,
228
229
  ).run(now, now, row.id);
229
230
  });
230
- tx();
231
231
  out(`applied ${id} → ${row.target_path} (agent ${row.agent_id}). Revert with: agentlas evolve revert ${id}`);
232
232
  }
233
233
 
@@ -255,7 +255,7 @@ function cmdRevert(db, id, out, fail, agentFolder) {
255
255
  fs.writeFileSync(file, row.after_content, "utf8");
256
256
  return fail("Reverted content did not match the original hash; restored the applied version.");
257
257
  }
258
- const tx = db.transaction(() => {
258
+ runWriteTransaction(db, () => {
259
259
  db.prepare("UPDATE installed_agents SET system_prompt = ? WHERE id = ?").run(row.before_content, row.agent_id);
260
260
  insertReceipt(db, row, "rollback", row.after_hash, row.before_hash, now);
261
261
  db.prepare(
@@ -265,7 +265,6 @@ function cmdRevert(db, id, out, fail, agentFolder) {
265
265
  WHERE id = ? AND status IN ('applied','measured')`,
266
266
  ).run(now, now, row.id);
267
267
  });
268
- tx();
269
268
  out(`reverted ${id} → restored ${row.target_path} (agent ${row.agent_id}).`);
270
269
  }
271
270
 
@@ -21,13 +21,15 @@ const STRINGS = {
21
21
  "banner.location": "%s · / commands · Shift-Tab permissions",
22
22
  "status.title": "Session",
23
23
  "status.runtime": "runtime",
24
+ "status.model": "model",
25
+ "status.effort": "effort",
24
26
  "status.agent": "agent",
25
27
  "status.directory": "directory",
26
28
  "status.permission": "permission",
27
29
  // picker
28
30
  "picker.agents": "Agents",
29
31
  "picker.companies": "Companies",
30
- "picker.none": "(none yet — open the Agentlas app to install agents, or /import <path>)",
32
+ "picker.none": "(none yet — use /search <task>, /install <slug>, or /import <path>)",
31
33
  "picker.prompt": "pick a number/name, or type a task to auto-route (/help, /import <path>, /exit) › ",
32
34
  "picker.hint": "Just type — Agentlas routes your task to the right agent. /agents to choose one, / for commands.",
33
35
  "composer.autoroute": "auto-route",
@@ -37,6 +39,8 @@ const STRINGS = {
37
39
  "picker.noMatch": 'no match for "%s" — try a number or a name',
38
40
  // repl
39
41
  "interrupted": "interrupted",
42
+ "cancelling": "cancelling — waiting for child processes to stop",
43
+ "cancellationUnverified": "cancellation requested, but child-process shutdown could not be verified",
40
44
  "ctrlcAgain": "Press Ctrl-C again to exit.",
41
45
  "bye": "Goodbye.",
42
46
  "stalled": "stream stalled — interrupted (idle timeout)",
@@ -54,24 +58,41 @@ const STRINGS = {
54
58
  "noKey": "No %s API key. Add one in the app (Settings → BYOK), or switch with /runtime.",
55
59
  "runtimeSet": "runtime → %s",
56
60
  "runtimeNotInstalled": "%s CLI is not installed.",
61
+ "runtimeUnknown": "Unknown runtime: %s (claude-code|codex|gemini)",
62
+ "runtimeUnavailable": "No runtime is available. Install a CLI (claude/codex/gemini) or configure an API key/Ollama in the app.",
57
63
  "runtimeUsage": "usage: /runtime claude-code|codex|gemini|anthropic|openai|google|ollama|upstage",
58
64
  "modelOnlyApi": "/model only applies to BYOK/Ollama (api) runtimes.",
59
65
  "modelSet": "model → %s",
66
+ "modelCurrent": "current model: %s",
60
67
  "modelDefault": "(default)",
61
68
  "effortSet": "effort → %s",
62
69
  "effortCurrent": "current effort: %s",
63
70
  "effortUsage": "usage: /effort low|medium|high|max|off|auto",
64
71
  "permSet": "permission → %s",
65
72
  "permUsage": "usage: /permission read|write|full",
73
+ "legacyNetworkUsage": "usage: /legacy-network <request>",
74
+ "stormUsage": "usage: /storm <goal> [--research]",
75
+ "buildUsage": "usage: /build <agent-or-team request>",
76
+ "routeUsage": "usage: /route <request> [--json]",
77
+ "researchUsage": "usage: /research status|gather|search|read|plan [args]",
78
+ "commandQuoteError": "unclosed quote — close it and try again",
79
+ "searchUsage": "usage: /search <what you need>",
80
+ "networkUsage": "usage: /network <request> [--parallel N] [--benchmark]",
81
+ "browserUsage": "usage: /browser <url-or-query>",
82
+ "connectUsage": "usage: /connect <status|telegram|subcommand>",
83
+ "swarmUsage": "usage: /swarm <goal> [--parallel N]",
66
84
  "permCurrent": "current permission: %s",
67
85
  "permCycleHint": "Shift-Tab to cycle",
68
86
  "permCycleConfirm": "permission → %s",
69
87
  "permFullArm": "FULL ACCESS IS UNRESTRICTED — press Shift-Tab again within 5 seconds to confirm",
88
+ "permFullCommandArm": "FULL ACCESS IS UNRESTRICTED — run /permission full again within 5 seconds to confirm",
70
89
  "permFullConfirm": "FULL ACCESS ON FOR THIS SESSION — approvals and sandboxing are bypassed",
71
90
  "sideUsage": "usage: /side <question>",
72
91
  "sideNeedsSubject": "pick an agent first, or type the task normally so Agentlas can auto-route it",
73
92
  "sideStart": "side question; this answer will not be saved to chat context",
74
93
  "sideDone": "side question complete; main chat context unchanged",
94
+ "sideCancelled": "side question cancelled; main chat context unchanged",
95
+ "sideFailed": "side question failed; main chat context unchanged",
75
96
  "noAgent": "no agent: %s",
76
97
  "noCompany": "no company: %s",
77
98
  "agentUsage": "usage: /agent <name>",
@@ -81,17 +102,19 @@ const STRINGS = {
81
102
  "installing": "installing %s…",
82
103
  "cloudInstalled": "installed: %s",
83
104
  "market.title": "Marketplace",
84
- "market.help": "Install agents and teams from the Agentlas cloud marketplace or a local folder.",
85
- "market.installHint": "install a cloud agent by slug",
86
- "market.importHint": "install a local agent/team folder",
87
- "market.loggedIn": "cloud session: signed in",
88
- "market.loggedOut": "cloud session: signed out — sign in via the app (or set AGENTLAS_SESSION) to install cloud agents",
105
+ "market.help": "Install agents or teams from the Hub or a local folder.",
106
+ "market.installHint": "install a Hub agent",
107
+ "market.importHint": "import a local agent/team",
108
+ "market.loggedIn": "credential present validity unverified",
109
+ "market.loggedOut": "credential not found — sign in via app or set AGENTLAS_SESSION",
89
110
  "mcp.none": "(no MCP servers configured — add them in the app)",
90
111
  "mcp.playwright": "Playwright browser",
91
112
  "mcp.fullOnly": "full only",
92
- "mcp.wired": "%s server(s) available only in full-access turns (incl. playwright)",
113
+ "mcp.wired": "%s reviewed server(s) available only in full-access turns",
93
114
  "mcp.usage": "add/remove MCP servers in the app; read/write never inject external MCP tools",
115
+ "mcp.commandUsage": "usage: /mcp",
94
116
  "help.mcp": "list configured MCP servers and which are wired",
117
+ "help.project": "inspect or explicitly initialize local project state",
95
118
  "resume.title": "Resume — recent sessions",
96
119
  "resume.none": "(no saved sessions yet — they're saved after each turn)",
97
120
  "resume.usage": "usage: /resume <number>",
@@ -113,12 +136,13 @@ const STRINGS = {
113
136
  "routedImage": "routed to %s for image support",
114
137
  "judge.source.llm": "judged by the connected model",
115
138
  "judge.source.fallback": "deterministic fallback (no connected-model verdict)",
116
- "usageBar": "tokens",
139
+ "usageBar": "session usage",
117
140
  "config.title": "Engine auto engagement — explicit on/off (default: off)",
118
141
  "config.storm": "Stormbreaker auto-engage on direct-routed real work",
119
142
  "config.network": "Workforce Ontology auto-staffing on direct-routed real work",
120
143
  "config.usage": "usage: /config storm|network on|off · explicit /storm and /network always work",
121
144
  "config.set": "%s → %s",
145
+ "config.externalChange": "preferences changed in another Agentlas terminal: %s",
122
146
  "config.autoEngage": "auto-engaging %s (opted in via /config — turn off with /config %s off)",
123
147
  "help.config": "explicit on/off for Stormbreaker/Workforce Ontology auto engagement",
124
148
  "guard.imageWarn": "this agent works with images, but %s can't generate them — try /runtime gemini (or codex), or /team to pin one",
@@ -162,6 +186,7 @@ const STRINGS = {
162
186
  "help.search": "discover agents in the Hub",
163
187
  "help.install": "install an agent from the Hub by slug",
164
188
  "help.network": "let the host LLM staff and execute an ontology-grounded exact-release task force",
189
+ "help.legacyNetwork": "run the explicit compatibility-only Hephaestus network route",
165
190
  "help.browser": "real browser execution hardpoint",
166
191
  "help.connect": "wire Telegram / platforms to an agent team",
167
192
  "help.swarm": "fan out an emergent agent swarm on a goal",
@@ -223,10 +248,13 @@ const STRINGS = {
223
248
  "wiz.runtimeInstalled": "installed",
224
249
  "wiz.runtimeMissing": "not installed",
225
250
  "wiz.permQ": "How much should agents be allowed to do by default?",
226
- "wiz.permRead": "read — inspect only; runtime is read-only/plan",
227
- "wiz.permWrite": "write — edit this workspace in the runtime sandbox; no external MCP (recommended)",
228
- "wiz.permFull": "full — unrestricted; bypass runtime approvals and sandboxing",
229
- "wiz.pick": "Enter a number",
251
+ "wiz.permRead": "read — inspect only; workspace writes blocked",
252
+ "wiz.permWrite": "write — workspace + runtime temp writes; external MCP off (recommended)",
253
+ "wiz.permFull": "full — bypass approvals and sandbox; trusted use only",
254
+ "wiz.nav": "↑↓ move · Enter select · or type a number",
255
+ "wiz.pick": "choice › ",
256
+ "wiz.default": "(Enter default)",
257
+ "wiz.invalid": "Choose 1–%s.",
230
258
  "wiz.saved": "All set. You can change any of this later with /runtime, /permission.",
231
259
  "wiz.changeLang": "Tip: re-run setup anytime with agentlas setup",
232
260
  },
@@ -239,12 +267,14 @@ const STRINGS = {
239
267
  "banner.location": "%s · / 명령 · Shift-Tab 권한",
240
268
  "status.title": "세션",
241
269
  "status.runtime": "런타임",
270
+ "status.model": "모델",
271
+ "status.effort": "추론 강도",
242
272
  "status.agent": "에이전트",
243
273
  "status.directory": "작업 폴더",
244
274
  "status.permission": "권한",
245
275
  "picker.agents": "에이전트",
246
276
  "picker.companies": "회사",
247
- "picker.none": "(아직 없음 — Agentlas 앱에서 에이전트를 설치하거나 /import <경로>)",
277
+ "picker.none": "(아직 없음 — /search <할 일>, /install <식별자>, /import <경로>를 사용하세요)",
248
278
  "picker.prompt": "번호/이름을 고르거나, 할 일을 바로 입력하면 자동 라우팅합니다 (/help, /import <경로>, /exit) › ",
249
279
  "picker.hint": "그냥 입력하세요 — 할 일을 알맞은 에이전트로 자동 라우팅합니다. /agents 로 직접 선택, / 로 명령.",
250
280
  "composer.autoroute": "자동 라우팅",
@@ -253,6 +283,8 @@ const STRINGS = {
253
283
  "picker.noFirm": "그런 회사가 없습니다",
254
284
  "picker.noMatch": '"%s"에 맞는 항목이 없습니다 — 번호나 이름으로',
255
285
  "interrupted": "중단됨",
286
+ "cancelling": "취소 중 — 하위 프로세스 종료 확인 중",
287
+ "cancellationUnverified": "취소를 요청했지만 하위 프로세스 종료를 확인하지 못했습니다",
256
288
  "ctrlcAgain": "종료하려면 Ctrl-C를 한 번 더 누르세요.",
257
289
  "bye": "안녕",
258
290
  "stalled": "응답이 지연되어 중단했습니다 (idle timeout)",
@@ -270,44 +302,63 @@ const STRINGS = {
270
302
  "noKey": "%s API 키가 없습니다. 앱 설정 → BYOK에서 등록하거나 /runtime으로 전환하세요.",
271
303
  "runtimeSet": "런타임 → %s",
272
304
  "runtimeNotInstalled": "%s CLI가 설치돼 있지 않습니다.",
305
+ "runtimeUnknown": "알 수 없는 런타임: %s (claude-code|codex|gemini)",
306
+ "runtimeUnavailable": "사용 가능한 런타임이 없습니다. CLI(claude/codex/gemini)를 설치하거나 앱에서 API 키/Ollama를 설정하세요.",
273
307
  "runtimeUsage": "사용법: /runtime claude-code|codex|gemini|anthropic|openai|google|ollama|upstage",
274
308
  "modelOnlyApi": "/model은 BYOK/Ollama(api) 런타임에서만 적용됩니다.",
275
309
  "modelSet": "모델 → %s",
310
+ "modelCurrent": "현재 모델: %s",
276
311
  "modelDefault": "(기본값)",
277
312
  "effortSet": "추론 강도 → %s",
278
313
  "effortCurrent": "현재 추론 강도: %s",
279
314
  "effortUsage": "사용법: /effort low|medium|high|max|off|auto",
280
315
  "permSet": "권한 → %s",
281
316
  "permUsage": "사용법: /permission read|write|full",
317
+ "legacyNetworkUsage": "사용법: /legacy-network <요청>",
318
+ "stormUsage": "사용법: /storm <목표> [--research]",
319
+ "buildUsage": "사용법: /build <만들 에이전트·팀 설명>",
320
+ "routeUsage": "사용법: /route <요청> [--json]",
321
+ "researchUsage": "사용법: /research status|gather|search|read|plan [인자]",
322
+ "commandQuoteError": "따옴표가 닫히지 않았습니다 — 닫은 뒤 다시 시도하세요",
323
+ "searchUsage": "사용법: /search <필요한 에이전트 설명>",
324
+ "networkUsage": "사용법: /network <요청> [--parallel N] [--benchmark]",
325
+ "browserUsage": "사용법: /browser <URL 또는 검색어>",
326
+ "connectUsage": "사용법: /connect <status|telegram|하위 명령>",
327
+ "swarmUsage": "사용법: /swarm <목표> [--parallel N]",
282
328
  "permCurrent": "현재 권한: %s",
283
329
  "permCycleHint": "Shift-Tab으로 변경",
284
330
  "permCycleConfirm": "권한 → %s",
285
331
  "permFullArm": "무제한 권한은 승인과 샌드박스를 우회합니다 — 5초 안에 Shift-Tab을 다시 눌러 확인",
332
+ "permFullCommandArm": "무제한 권한은 승인과 샌드박스를 우회합니다 — 5초 안에 /permission full을 다시 실행해 확인",
286
333
  "permFullConfirm": "이 세션에서만 무제한 권한 켜짐 — 승인과 샌드박스를 우회함",
287
334
  "sideUsage": "사용법: /side <질문>",
288
335
  "sideNeedsSubject": "먼저 에이전트를 고르거나, 그냥 할 일을 입력해서 Agentlas가 자동 라우팅하게 하세요.",
289
336
  "sideStart": "사이드 질문입니다. 이 답변은 메인 대화 맥락에 저장하지 않습니다.",
290
337
  "sideDone": "사이드 질문 완료. 메인 대화 맥락은 그대로입니다.",
338
+ "sideCancelled": "사이드 질문이 중단되었습니다. 메인 대화 맥락은 그대로입니다.",
339
+ "sideFailed": "사이드 질문이 실패했습니다. 메인 대화 맥락은 그대로입니다.",
291
340
  "noAgent": "에이전트 없음: %s",
292
341
  "noCompany": "회사 없음: %s",
293
342
  "agentUsage": "사용법: /agent <이름>",
294
343
  "firmUsage": "사용법: /firm <이름>",
295
344
  "importUsage": "사용법: /import <폴더>",
296
- "installUsage": "사용법: /install <slug> (마켓플레이스는 앱에서 보거나 /marketplace)",
345
+ "installUsage": "사용법: /install <식별자> (마켓플레이스는 앱에서 보거나 /marketplace)",
297
346
  "installing": "%s 설치 중…",
298
347
  "cloudInstalled": "설치됨: %s",
299
348
  "market.title": "마켓플레이스",
300
- "market.help": "Agentlas 클라우드 마켓플레이스 또는 로컬 폴더에서 에이전트/팀을 설치합니다.",
301
- "market.installHint": "slug로 클라우드 에이전트 설치",
302
- "market.importHint": "로컬 에이전트/팀 폴더 설치",
303
- "market.loggedIn": "클라우드 세션: 로그인됨",
304
- "market.loggedOut": "클라우드 세션: 로그아웃 클라우드 설치는 앱에서 로그인(또는 AGENTLAS_SESSION) 필요",
349
+ "market.help": "Hub 또는 로컬 폴더에서 에이전트/팀을 설치합니다.",
350
+ "market.installHint": "Hub 에이전트 설치",
351
+ "market.importHint": "로컬 에이전트/팀 가져오기",
352
+ "market.loggedIn": "자격정보 있음 — 유효성 미확인",
353
+ "market.loggedOut": "자격정보 없음 — 앱에서 로그인 또는 AGENTLAS_SESSION 설정",
305
354
  "mcp.none": "(설정된 MCP 서버 없음 — 앱에서 추가)",
306
355
  "mcp.playwright": "Playwright 브라우저",
307
356
  "mcp.fullOnly": "full 전용",
308
- "mcp.wired": "무제한 권한 턴에서만 %s개 서버 사용 가능 (playwright 포함)",
357
+ "mcp.wired": "검토된 서버 %s개를 무제한 권한 턴에서만 사용 가능",
309
358
  "mcp.usage": "MCP 서버 추가/삭제는 앱에서; read/write에는 외부 MCP 도구를 주입하지 않음",
359
+ "mcp.commandUsage": "사용법: /mcp",
310
360
  "help.mcp": "설정된 MCP 서버와 연결 상태 보기",
361
+ "help.project": "로컬 프로젝트 상태 확인/명시적 초기화",
311
362
  "resume.title": "이어하기 — 최근 세션",
312
363
  "resume.none": "(저장된 세션 없음 — 각 턴 후 저장됩니다)",
313
364
  "resume.usage": "사용법: /resume <번호>",
@@ -329,16 +380,17 @@ const STRINGS = {
329
380
  "routedImage": "이미지 지원을 위해 %s로 라우팅",
330
381
  "judge.source.llm": "판정: 연결 모델",
331
382
  "judge.source.fallback": "판정: 결정적 폴백(연결 모델 없음)",
332
- "usageBar": "토큰",
383
+ "usageBar": "세션 사용량",
333
384
  "config.title": "엔진 자동 개입 — 명시적 on/off (기본: off)",
334
385
  "config.storm": "직답 라우팅된 실작업에 Stormbreaker 자동 개입",
335
386
  "config.network": "직답 라우팅된 실작업에 Workforce Ontology 자동 선발",
336
387
  "config.usage": "사용법: /config storm|network on|off · /storm·/network 명시 실행은 항상 가능",
337
388
  "config.set": "%s → %s",
389
+ "config.externalChange": "다른 Agentlas 터미널의 설정 변경을 반영했습니다: %s",
338
390
  "config.autoEngage": "%s 자동 개입 (/config로 켜져 있음 — 해제: /config %s off)",
339
391
  "help.config": "Stormbreaker/Workforce Ontology 자동 개입 명시적 on/off",
340
392
  "guard.imageWarn": "이 에이전트는 이미지 작업인데 %s는 이미지 생성 불가 — /runtime gemini(또는 codex), 또는 /team으로 고정",
341
- "multimodal.title": "멀티모달 fallback",
393
+ "multimodal.title": "멀티모달 대체 제공자",
342
394
  "multimodal.set": "멀티모달 %s → %s",
343
395
  "multimodal.usage": "/multimodal set <image|video|audio> <provider-id> 로 변경",
344
396
  "help.talk": "현재 에이전트/회사와 대화 — 스트리밍 + 툴",
@@ -349,7 +401,7 @@ const STRINGS = {
349
401
  "skills.title": "스킬",
350
402
  "permissions.title": "권한",
351
403
  "permissions.current": "현재",
352
- "help.skills": "slash 명령 스킬 목록",
404
+ "help.skills": "슬래시 명령 스킬 목록",
353
405
  "help.agents": "설치된 에이전트 목록",
354
406
  "help.team": "에이전트별 LLM 보기/지정 (능력 기반 자동)",
355
407
  "help.agent": "다른 에이전트로 전환",
@@ -362,11 +414,11 @@ const STRINGS = {
362
414
  "help.setup": "언어·런타임·권한 설정 다시 실행",
363
415
  "help.cwd": "작업 폴더 보기/변경",
364
416
  "help.memory": "주입되는 메모리 보기",
365
- "help.careerGraph": "Career Graph 라우팅 색인의 원본 경로 보기/등록",
417
+ "help.careerGraph": "경력 그래프 라우팅 색인의 원본 경로 보기/등록",
366
418
  "help.ontology": "짧은 자연어로 프로젝트 온톨로지 켜기/목록/자료 등록",
367
419
  "help.side": "메인 대화 맥락에 저장하지 않는 사이드 질문",
368
420
  "help.status": "모델/런타임, 에이전트, 권한, 작업 폴더 보기",
369
- "help.multimodal": "이미지·영상·음성 fallback provider 보기/변경",
421
+ "help.multimodal": "이미지·영상·음성 대체 제공자 보기/변경",
370
422
  "help.import": "로컬 폴더(에이전트/팀) 임포트",
371
423
  "help.market": "마켓플레이스 에이전트 보기/설치",
372
424
  "help.clear": "대화 비우고 다시 그리기",
@@ -375,11 +427,12 @@ const STRINGS = {
375
427
  "help.route": "요청이 어떤 에이전트로 라우팅되는지 미리보기",
376
428
  "help.research": "Research Engine 실행 (search/gather/read)",
377
429
  "help.search": "Hub에서 에이전트 발견",
378
- "help.install": "slug로 Hub 에이전트 설치",
430
+ "help.install": "식별자로 Hub 에이전트 설치",
379
431
  "help.network": "상위 LLM이 온톨로지에서 정확한 릴리스 TF를 선발·실행",
432
+ "help.legacyNetwork": "호환성 전용 Hephaestus 네트워크 경로를 명시적으로 실행",
380
433
  "help.browser": "실제 브라우저 실행 하드포인트",
381
434
  "help.connect": "Telegram/플랫폼을 에이전트 팀에 연결",
382
- "help.swarm": "목표에 emergent 에이전트 스웜 전개",
435
+ "help.swarm": "목표에 창발형 에이전트 스웜 전개",
383
436
  "help.doctor": "런타임/데이터 점검",
384
437
  "help.compact": "오래된 대화 맥락을 줄이고 최근 맥락 유지",
385
438
  "help.keybindings": "터미널 단축키 보기",
@@ -395,7 +448,7 @@ const STRINGS = {
395
448
  "help.diff": "작업 트리 git diff 보기",
396
449
  "help.history": "최근 입력 목록 (세션 간 유지)",
397
450
  "help.tipsTitle": "단축키",
398
- "help.slash": "/help, /status 같은 slash 명령 시작",
451
+ "help.slash": "/help, /status 같은 슬래시 명령 시작",
399
452
  "help.atfile": "파일 내용을 메시지에 첨부",
400
453
  "help.bang": "작업 폴더에서 셸 명령 실행",
401
454
  "help.multiline": "다음 줄에 이어서 입력",
@@ -436,10 +489,13 @@ const STRINGS = {
436
489
  "wiz.runtimeInstalled": "설치됨",
437
490
  "wiz.runtimeMissing": "미설치",
438
491
  "wiz.permQ": "에이전트가 기본적으로 어디까지 할 수 있게 할까요?",
439
- "wiz.permRead": "read — 조회만; 런타임 read-only/plan",
440
- "wiz.permWrite": "write — 런타임 샌드박스 안에서 작업 공간 편집; 외부 MCP 없음 (권장)",
441
- "wiz.permFull": "full — 무제한; 런타임 승인과 샌드박스 우회",
442
- "wiz.pick": "번호 입력",
492
+ "wiz.permRead": "read — 조회만; 작업 공간 쓰기 차단",
493
+ "wiz.permWrite": "write — 작업 공간·런타임 임시 경로 쓰기; 외부 MCP 꺼짐 (권장)",
494
+ "wiz.permFull": "full — 승인과 샌드박스 우회; 신뢰 환경 전용",
495
+ "wiz.nav": "↑↓ 이동 · Enter 선택 · 또는 번호 입력",
496
+ "wiz.pick": "선택 › ",
497
+ "wiz.default": "(Enter 기본값)",
498
+ "wiz.invalid": "1–%s 중 고르세요.",
443
499
  "wiz.saved": "완료. 나중에 /runtime, /permission으로 언제든 바꿀 수 있어요.",
444
500
  "wiz.changeLang": "팁: 언제든 agentlas setup 으로 다시 설정",
445
501
  },