agentlas 1.0.65 → 1.0.66

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 (163) hide show
  1. package/CHANGELOG.md +78 -0
  2. package/README.md +6 -4
  3. package/bin/agentlas.cjs +341 -16
  4. package/engine/acp/server.cjs +27 -1
  5. package/engine/agentlas-api-agent.cjs +151 -120
  6. package/engine/agentlas-banner.cjs +6 -2
  7. package/engine/agentlas-capabilities.cjs +17 -10
  8. package/engine/agentlas-cloud-runtime.cjs +4 -5
  9. package/engine/agentlas-config.cjs +19 -54
  10. package/engine/agentlas-core-harness.cjs +59 -5
  11. package/engine/agentlas-desktop-loadout.cjs +17 -3
  12. package/engine/agentlas-evolution.cjs +75 -18
  13. package/engine/agentlas-experience-exchange.cjs +145 -14
  14. package/engine/agentlas-experience-intake.cjs +2 -2
  15. package/engine/agentlas-i18n.cjs +0 -2
  16. package/engine/agentlas-input.cjs +273 -20
  17. package/engine/agentlas-judgment.cjs +0 -0
  18. package/engine/agentlas-mcp-env.cjs +84 -23
  19. package/engine/agentlas-mcp-wrapper.cjs +36 -4
  20. package/engine/agentlas-memory-governance.cjs +2 -1
  21. package/engine/agentlas-memory-import.cjs +49 -12
  22. package/engine/agentlas-native-host.cjs +279 -44
  23. package/engine/agentlas-onboard.cjs +23 -1
  24. package/engine/agentlas-permissions.cjs +5 -1
  25. package/engine/agentlas-sqlite-policy.cjs +40 -2
  26. package/engine/agentlas-tasks.cjs +7 -0
  27. package/engine/agentlas-tools.cjs +37 -10
  28. package/engine/agentlas-ui.cjs +26 -4
  29. package/engine/agentlas-workforce.cjs +29 -5
  30. package/engine/agentlas-workload-routing.cjs +83 -10
  31. package/engine/agentlas.cjs +10 -3
  32. package/engine/agents/builder.cjs +35 -10
  33. package/engine/agents/files.cjs +81 -10
  34. package/engine/agents/import-local.cjs +10 -2
  35. package/engine/agents/registry.cjs +10 -3
  36. package/engine/agents/router.cjs +7 -7
  37. package/engine/agents/routes.cjs +31 -9
  38. package/engine/automation/daemon.cjs +154 -40
  39. package/engine/automation/launchd.cjs +395 -16
  40. package/engine/automation/schedule.cjs +90 -3
  41. package/engine/automation/store.cjs +163 -59
  42. package/engine/browser/cdp.cjs +190 -17
  43. package/engine/browser/vault.cjs +1 -0
  44. package/engine/cli-output.cjs +80 -28
  45. package/engine/cloud/auth.cjs +131 -13
  46. package/engine/cloud/hub-client.cjs +41 -16
  47. package/engine/cloud-assets/cas.cjs +18 -9
  48. package/engine/cloud-assets/commands.cjs +108 -30
  49. package/engine/cloud-assets/package.cjs +66 -3
  50. package/engine/cloud-assets/restore.cjs +12 -9
  51. package/engine/cloud-assets/state.cjs +308 -113
  52. package/engine/commands/acp.cjs +13 -2
  53. package/engine/commands/automation.cjs +75 -24
  54. package/engine/commands/billing.cjs +6 -1
  55. package/engine/commands/browser.cjs +61 -29
  56. package/engine/commands/build.cjs +42 -12
  57. package/engine/commands/call.cjs +1 -1
  58. package/engine/commands/cd.cjs +1 -1
  59. package/engine/commands/cloud.cjs +2 -1
  60. package/engine/commands/connect.cjs +38 -13
  61. package/engine/commands/creds.cjs +74 -29
  62. package/engine/commands/doctor.cjs +17 -1
  63. package/engine/commands/document.cjs +38 -10
  64. package/engine/commands/env.cjs +6 -1
  65. package/engine/commands/firm.cjs +42 -12
  66. package/engine/commands/graph.cjs +36 -32
  67. package/engine/commands/help.cjs +11 -1
  68. package/engine/commands/hep.cjs +1 -1
  69. package/engine/commands/import.cjs +5 -4
  70. package/engine/commands/index.cjs +1 -1
  71. package/engine/commands/install.cjs +6 -4
  72. package/engine/commands/list.cjs +56 -16
  73. package/engine/commands/login.cjs +5 -0
  74. package/engine/commands/logout.cjs +6 -1
  75. package/engine/commands/mcp.cjs +8 -2
  76. package/engine/commands/memory.cjs +3 -2
  77. package/engine/commands/multimodal.cjs +12 -0
  78. package/engine/commands/native.cjs +5 -1
  79. package/engine/commands/one.cjs +78 -33
  80. package/engine/commands/plugin.cjs +13 -2
  81. package/engine/commands/project.cjs +15 -12
  82. package/engine/commands/research.cjs +18 -7
  83. package/engine/commands/roles.cjs +104 -28
  84. package/engine/commands/route.cjs +2 -2
  85. package/engine/commands/run.cjs +42 -9
  86. package/engine/commands/search.cjs +23 -2
  87. package/engine/commands/setup.cjs +6 -1
  88. package/engine/commands/storm.cjs +44 -6
  89. package/engine/commands/swarm.cjs +47 -9
  90. package/engine/commands/telegram.cjs +6 -1
  91. package/engine/commands/uninstall.cjs +12 -6
  92. package/engine/commands/update.cjs +5 -0
  93. package/engine/commands/upload.cjs +2 -1
  94. package/engine/commands/usage.cjs +6 -1
  95. package/engine/commands/version.cjs +6 -1
  96. package/engine/commands/whoami.cjs +6 -1
  97. package/engine/commands/workforce.cjs +60 -16
  98. package/engine/core/capability-grants.cjs +7 -2
  99. package/engine/core/daemon-client.cjs +36 -7
  100. package/engine/core/db.cjs +10 -2
  101. package/engine/core/desktop-core-fetch.cjs +477 -77
  102. package/engine/core/schema-ensure.cjs +23 -11
  103. package/engine/experience/build.cjs +5 -1
  104. package/engine/experience/intents.cjs +29 -82
  105. package/engine/experience/runtime.cjs +7 -1
  106. package/engine/experience/variant.cjs +58 -4
  107. package/engine/firms/orchestrate.cjs +9 -6
  108. package/engine/graph/ask-model.cjs +22 -11
  109. package/engine/graph/interview.cjs +74 -23
  110. package/engine/graph/package.cjs +63 -8
  111. package/engine/hephaestus/local-core.cjs +18 -5
  112. package/engine/hephaestus/runtime.cjs +48 -43
  113. package/engine/hub/install.cjs +230 -61
  114. package/engine/hub/plugins.cjs +391 -29
  115. package/engine/mcp/consent.cjs +25 -17
  116. package/engine/mcp/contract.cjs +229 -24
  117. package/engine/mcp/inventory.cjs +15 -5
  118. package/engine/mcp/plan.cjs +5 -1
  119. package/engine/mcp/probe.cjs +24 -9
  120. package/engine/memory-cli/curate.cjs +74 -16
  121. package/engine/oberon/common.cjs +37 -12
  122. package/engine/oberon/manifest.cjs +25 -2
  123. package/engine/oberon/outputs.cjs +49 -19
  124. package/engine/oberon/render.cjs +665 -40
  125. package/engine/project/career-graph.cjs +15 -2
  126. package/engine/project/controller.cjs +133 -15
  127. package/engine/project/credentials.cjs +212 -34
  128. package/engine/project/env-file.cjs +93 -8
  129. package/engine/project/memory-context.cjs +11 -57
  130. package/engine/project/ontology.cjs +66 -25
  131. package/engine/project/paths.cjs +42 -8
  132. package/engine/project/seed.cjs +88 -51
  133. package/engine/project/state.cjs +41 -16
  134. package/engine/project/team.cjs +26 -1
  135. package/engine/runtime-refusal.cjs +4 -1
  136. package/engine/runtimes/acp-driver.cjs +56 -9
  137. package/engine/runtimes/auth-evidence.cjs +21 -2
  138. package/engine/runtimes/detect.cjs +28 -8
  139. package/engine/runtimes/kinds.cjs +12 -4
  140. package/engine/runtimes/overrides.cjs +4 -3
  141. package/engine/runtimes/resolve.cjs +8 -7
  142. package/engine/runtimes/roles.cjs +7 -5
  143. package/engine/sessions/apply-fences.cjs +396 -56
  144. package/engine/sessions/fences.cjs +111 -27
  145. package/engine/sessions/memory-turn.cjs +62 -3
  146. package/engine/sessions/orchestrator.cjs +11 -1
  147. package/engine/sessions/prompt.cjs +66 -9
  148. package/engine/sessions/session.cjs +70 -10
  149. package/engine/sessions/sink.cjs +78 -12
  150. package/engine/sessions/store.cjs +29 -7
  151. package/engine/storm/storm.cjs +26 -3
  152. package/engine/storm/swarm.cjs +31 -3
  153. package/engine/telegram/connect.cjs +185 -22
  154. package/engine/ui/commands-catalog.cjs +1 -1
  155. package/engine/ui/palette.cjs +12 -2
  156. package/engine/ui/repl.cjs +57 -9
  157. package/engine/ui/screens.cjs +2 -4
  158. package/engine/vendor/desktop-core.manifest.json +5 -5
  159. package/engine/workforce/capture.cjs +9 -27
  160. package/engine/workforce/deps.cjs +18 -6
  161. package/engine/workforce/local-core-transport.cjs +68 -5
  162. package/package.json +1 -1
  163. package/engine/commands/career-graph.cjs +0 -51
@@ -27,9 +27,9 @@ function resolvePermission(ctx) {
27
27
  // persistent()가 fail-closed 로 강등한다.
28
28
  try {
29
29
  const policy = require("../agentlas-permissions.cjs");
30
- return policy.persistent(ctx && ctx.prefs && ctx.prefs.permission, "write");
30
+ return policy.persistent(ctx && ctx.prefs && ctx.prefs.permission, "read");
31
31
  } catch {
32
- return "write";
32
+ return "read";
33
33
  }
34
34
  }
35
35
 
@@ -37,16 +37,56 @@ function resolvePermission(ctx) {
37
37
  function splitRuntimeOverride(args) {
38
38
  const rest = [];
39
39
  let runtimeOverride = null;
40
+ let seen = false;
41
+ let passthrough = false;
40
42
  for (let i = 0; i < args.length; i += 1) {
41
- if (args[i] === "--runtime" && args[i + 1]) {
42
- runtimeOverride = String(args[++i]);
43
+ const token = String(args[i]);
44
+ if (passthrough) { rest.push(token); continue; }
45
+ if (token === "--") { passthrough = true; rest.push(token); continue; }
46
+ if (token === "--runtime" || token.startsWith("--runtime=")) {
47
+ if (seen) throw new Error("duplicate option: --runtime");
48
+ seen = true;
49
+ const inline = token.startsWith("--runtime=");
50
+ const value = inline ? token.slice(10) : args[++i];
51
+ if (value === undefined || value === "" || (!inline && String(value).startsWith("--"))) {
52
+ throw new Error("--runtime requires a value");
53
+ }
54
+ runtimeOverride = String(value);
43
55
  continue;
44
56
  }
45
- rest.push(args[i]);
57
+ rest.push(token);
46
58
  }
47
59
  return { rest, runtimeOverride };
48
60
  }
49
61
 
62
+ function validateWorkforceArgs(args) {
63
+ const seen = new Set();
64
+ let passthrough = false;
65
+ let hasTask = false;
66
+ for (let i = 0; i < args.length; i += 1) {
67
+ const token = String(args[i]);
68
+ if (passthrough) { hasTask = true; continue; }
69
+ if (token === "--") { passthrough = true; continue; }
70
+ if (token === "--benchmark" || token === "--json") {
71
+ const key = token.slice(2);
72
+ if (seen.has(key)) return { error: `duplicate option: ${token}`, hasTask };
73
+ seen.add(key);
74
+ } else if (token === "--parallel" || token === "-n" || token.startsWith("--parallel=")) {
75
+ if (seen.has("parallel")) return { error: "duplicate option: --parallel", hasTask };
76
+ seen.add("parallel");
77
+ const inline = token.startsWith("--parallel=");
78
+ const raw = inline ? token.slice(11) : args[++i];
79
+ const value = Number(raw);
80
+ if (raw === undefined || raw === "" || (!inline && String(raw).startsWith("--")) || !Number.isInteger(value) || value < 1 || value > 8) {
81
+ return { error: "--parallel requires a positive integer (maximum 8)", hasTask };
82
+ }
83
+ } else if (token.startsWith("-")) {
84
+ return { error: `unknown option: ${token} (use -- before a task token that starts with '-')`, hasTask };
85
+ } else hasTask = true;
86
+ }
87
+ return { error: null, hasTask };
88
+ }
89
+
50
90
  /**
51
91
  * command 별 디스패치. commands/index.cjs 는 명령 이름을 별도 인자로 넘기지 않으므로
52
92
  * run()이 기본 "workforce" 로 진입하고, 별칭 배선 시 이 dispatch 를 직접 쓴다.
@@ -56,13 +96,15 @@ async function dispatch(ctx, command, args) {
56
96
  case "workforce":
57
97
  case "network":
58
98
  case "taskforce": {
59
- const { rest, runtimeOverride } = splitRuntimeOverride(args);
99
+ let parsed;
100
+ try { parsed = splitRuntimeOverride(args); }
101
+ catch (error) { ctx.err(String((error && error.message) || error)); return 1; }
102
+ const { rest, runtimeOverride } = parsed;
103
+ const validation = validateWorkforceArgs(rest);
104
+ if (validation.error) { ctx.err(validation.error); return 1; }
60
105
  // usage 경로(작업 텍스트 없음)는 SQLite를 열 이유가 없다 — cmdWorkforce 의
61
106
  // parseArgs 와 동일한 판정: 플래그가 아닌 토큰이 하나도 없으면 빈 작업이다.
62
- const hasTask = rest.some((token, i) =>
63
- !["--benchmark", "--json", "--parallel", "-n"].includes(String(token))
64
- && !(i > 0 && ["--parallel", "-n"].includes(String(rest[i - 1]))));
65
- if (!hasTask) {
107
+ if (!validation.hasTask) {
66
108
  ctx.err("usage: agentlas workforce <task> [--parallel N] [--benchmark] [--json] [--runtime <kind>]");
67
109
  return 1;
68
110
  }
@@ -107,11 +149,13 @@ async function dispatch(ctx, command, args) {
107
149
  case "hep-hub": {
108
150
  const sourceScope = command.slice(4); // network|local|cloud|hub
109
151
  const ko = ctx.lang !== "en";
110
- const { rest, runtimeOverride } = splitRuntimeOverride(args);
111
- const hasTask = rest.some((token, i) =>
112
- !["--benchmark", "--json", "--parallel", "-n"].includes(String(token))
113
- && !(i > 0 && ["--parallel", "-n"].includes(String(rest[i - 1]))));
114
- if (!hasTask) {
152
+ let parsed;
153
+ try { parsed = splitRuntimeOverride(args); }
154
+ catch (error) { ctx.err(String((error && error.message) || error)); return 1; }
155
+ const { rest, runtimeOverride } = parsed;
156
+ const validation = validateWorkforceArgs(rest);
157
+ if (validation.error) { ctx.err(validation.error); return 1; }
158
+ if (!validation.hasTask) {
115
159
  ctx.err(`usage: agentlas ${command} "<task>" [--parallel N] [--json] [--runtime <kind>]`);
116
160
  return 1;
117
161
  }
@@ -162,4 +206,4 @@ function run(ctx, args) {
162
206
  return dispatch(ctx, "workforce", args);
163
207
  }
164
208
 
165
- module.exports = { run, dispatch };
209
+ module.exports = { run, dispatch, splitRuntimeOverride, validateWorkforceArgs };
@@ -55,7 +55,9 @@ function patternMatches(pattern, detail) {
55
55
  if (pattern === null || pattern === undefined || pattern === "") return true;
56
56
  if (!detail) return false;
57
57
  const text = String(pattern);
58
- if (text.endsWith("*")) return String(detail).startsWith(text.slice(0, -1).trimEnd());
58
+ // Keep the separator before `*`. Removing it turns `git push *` into the
59
+ // broader prefix `git push`, which also authorizes unrelated `git pushx`.
60
+ if (text.endsWith("*")) return String(detail).startsWith(text.slice(0, -1));
59
61
  return String(detail) === text;
60
62
  }
61
63
 
@@ -126,7 +128,10 @@ function recordCapabilityGrant(db, input) {
126
128
  if (!capabilityGrantsAvailable(db)) {
127
129
  return { ok: false, available: false, reason: UNAVAILABLE_REASON };
128
130
  }
129
- const decision = input && input.decision === "deny" ? "deny" : "allow";
131
+ const decision = input && input.decision;
132
+ if (decision !== "allow" && decision !== "deny") {
133
+ return { ok: false, available: true, reason: "capability_grants decision must be allow or deny" };
134
+ }
130
135
  try {
131
136
  db.prepare(
132
137
  `INSERT INTO ${TABLE} (capability, pattern, decision, scope, source, created_at)
@@ -17,9 +17,12 @@
17
17
  */
18
18
  const net = require("node:net");
19
19
  const crypto = require("node:crypto");
20
+ const fs = require("node:fs");
20
21
  const path = require("node:path");
21
22
  const { userDataDir } = require("./paths.cjs");
22
23
 
24
+ const DAEMON_MAX_RESPONSE_BYTES = 16 * 1024 * 1024;
25
+
23
26
  /** 데몬 소켓 주소 — control-socket.ts 의 defaultControlSocketPath 와 같은 규칙. */
24
27
  function daemonSocketPath() {
25
28
  const dir = userDataDir();
@@ -41,11 +44,13 @@ function callDaemon(method, params, timeoutMs) {
41
44
  return new Promise((resolve, reject) => {
42
45
  const socket = net.connect(daemonSocketPath());
43
46
  const id = crypto.randomUUID();
44
- let buffer = "";
47
+ let buffer = Buffer.alloc(0);
48
+ let responseBytes = 0;
45
49
  let settled = false;
46
50
  const finish = (fn) => {
47
51
  if (settled) return;
48
52
  settled = true;
53
+ buffer = Buffer.alloc(0);
49
54
  clearTimeout(timer);
50
55
  socket.destroy();
51
56
  fn();
@@ -56,10 +61,19 @@ function callDaemon(method, params, timeoutMs) {
56
61
  );
57
62
  socket.on("connect", () => socket.write(`${JSON.stringify({ id, method, params })}\n`));
58
63
  socket.on("data", (chunk) => {
59
- buffer += chunk.toString("utf8");
64
+ if (settled) return;
65
+ const bytes = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
66
+ responseBytes += bytes.length;
67
+ if (responseBytes > DAEMON_MAX_RESPONSE_BYTES) {
68
+ const error = new Error(`daemon response exceeded ${DAEMON_MAX_RESPONSE_BYTES} bytes`);
69
+ error.code = "DAEMON_RESPONSE_BODY_LIMIT";
70
+ finish(() => reject(error));
71
+ return;
72
+ }
73
+ buffer = buffer.length ? Buffer.concat([buffer, bytes]) : bytes;
60
74
  let nl;
61
- while ((nl = buffer.indexOf("\n")) >= 0) {
62
- const line = buffer.slice(0, nl).trim();
75
+ while (!settled && (nl = buffer.indexOf(0x0a)) >= 0) {
76
+ const line = buffer.subarray(0, nl).toString("utf8").trim();
63
77
  buffer = buffer.slice(nl + 1);
64
78
  if (!line) continue;
65
79
  let message;
@@ -109,8 +123,23 @@ function sharesOurStore(pong) {
109
123
  );
110
124
  return false;
111
125
  }
112
- const path = require("node:path");
113
- if (path.resolve(theirs) === path.resolve(ours)) return true;
126
+ let oursStat;
127
+ let theirsStat;
128
+ try {
129
+ oursStat = fs.statSync(path.resolve(ours));
130
+ theirsStat = fs.statSync(path.resolve(theirs));
131
+ } catch {
132
+ console.error(
133
+ `[daemon] could not verify the database identity (${theirs}) against this command (${ours}).\n`
134
+ + "[daemon] Running the graph locally instead, so the work cannot land in a different store.",
135
+ );
136
+ return false;
137
+ }
138
+ if (
139
+ oursStat.isFile() && theirsStat.isFile() &&
140
+ String(oursStat.dev) === String(theirsStat.dev) &&
141
+ String(oursStat.ino) === String(theirsStat.ino)
142
+ ) return true;
114
143
  console.error(
115
144
  `[daemon] the daemon opened a different database (${theirs}) than this command (${ours}).\n`
116
145
  + "[daemon] Running the graph locally instead, so the work cannot land in a different store.",
@@ -118,4 +147,4 @@ function sharesOurStore(pong) {
118
147
  return false;
119
148
  }
120
149
 
121
- module.exports = { daemonSocketPath, callDaemon, daemonAvailable, sharesOurStore };
150
+ module.exports = { daemonSocketPath, callDaemon, daemonAvailable, sharesOurStore, DAEMON_MAX_RESPONSE_BYTES };
@@ -14,6 +14,7 @@
14
14
  * 정직하게 거절한다(승급은 여전히 데스크탑의 일이다).
15
15
  */
16
16
  const fs = require("node:fs");
17
+ const { pathToFileURL } = require("node:url");
17
18
  const { configureSqliteConnection } = require("../agentlas-sqlite-policy.cjs");
18
19
  const { parseSemVer, compareSemVer } = require("../semver.cjs");
19
20
  const { dbPath } = require("./paths.cjs");
@@ -38,13 +39,16 @@ function loadNodeSqliteQuietly() {
38
39
  function openRaw(file) {
39
40
  try {
40
41
  const Database = require("better-sqlite3");
41
- const db = new Database(file);
42
+ const db = new Database(file, { fileMustExist: true });
42
43
  configureSqliteConnection(db);
43
44
  db.__driver = "better-sqlite3";
44
45
  return db;
45
46
  } catch { /* optional dep 미설치/ABI 불일치 → node:sqlite */ }
46
47
  const { DatabaseSync } = loadNodeSqliteQuietly();
47
- const db = new DatabaseSync(file);
48
+ // DatabaseSync does not expose better-sqlite3's `fileMustExist` option. A
49
+ // SQLite URI with mode=rw opens an existing file read/write but refuses to
50
+ // create it when an existsSync check races with deletion.
51
+ const db = new DatabaseSync(`${pathToFileURL(file).href}?mode=rw`);
48
52
  configureSqliteConnection(db);
49
53
  db.__driver = "node:sqlite";
50
54
  return db;
@@ -125,9 +129,13 @@ function columnExists(db, table, col) {
125
129
  }
126
130
 
127
131
  function runWriteTransaction(db, fn) {
132
+ if (!db || typeof fn !== "function") throw new TypeError("SQLite connection and transaction callback are required");
128
133
  db.exec("BEGIN IMMEDIATE");
129
134
  try {
130
135
  const result = fn();
136
+ if (result && typeof result.then === "function") {
137
+ throw new TypeError("SQLite write transactions must be synchronous");
138
+ }
131
139
  db.exec("COMMIT");
132
140
  return result;
133
141
  } catch (e) {