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
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ /*
3
+ * project — 명시적 프로젝트 초기화/점검 (v1 monolith 13199–13223 포팅).
4
+ *
5
+ * 0.9.10 경계: `.agentlas/` 를 만드는 유일한 진입점은 `agentlas project init` 이다.
6
+ * `project status` 는 완전 수동(파일 생성/DB visit 기록 없음)으로 검사만 한다.
7
+ */
8
+ const { projectCwd } = require("../project/paths.cjs");
9
+ const {
10
+ ensureTerminalProjectForExecutionCli,
11
+ initializeTerminalProjectCli,
12
+ } = require("../project/state.cjs");
13
+
14
+ function run(ctx, args) {
15
+ const action = String(args[0] || "status").toLowerCase();
16
+ const cwd = projectCwd();
17
+ const ko = ctx.lang === "ko";
18
+ if (action === "status") {
19
+ const active = ensureTerminalProjectForExecutionCli(ctx.db(), cwd, "read", "terminal-project-status");
20
+ ctx.out(`${ko ? "프로젝트" : "project"}: ${cwd}`);
21
+ ctx.out(`${ko ? "Agentlas 상태" : "Agentlas state"}: ${active
22
+ ? (ko ? "초기화됨" : "initialized")
23
+ : (ko ? "초기화되지 않음" : "not initialized")}`);
24
+ if (!active) ctx.out(ko
25
+ ? "비공개 .agentlas 상태와 로컬 제외 파일을 만들려면 `agentlas project init`을 실행하세요."
26
+ : "Run `agentlas project init` to create private .agentlas state and update local ignore files.");
27
+ return 0;
28
+ }
29
+ if (action === "init") {
30
+ ctx.out(ko
31
+ ? "비공개 Agentlas 프로젝트 상태를 초기화합니다. .agentlas/ 생성, .gitignore 갱신, 로컬 자격증명·서명 템플릿 추가가 포함될 수 있습니다."
32
+ : "Initializing private Agentlas project state. This may create .agentlas/, update .gitignore, and add local credential/signing templates.");
33
+ try {
34
+ initializeTerminalProjectCli(ctx.db(), cwd);
35
+ } catch (e) {
36
+ // fail-closed: 프라이버시 경계(.gitignore/심볼릭 링크)를 보증 못 하면 생성 금지.
37
+ ctx.err(String((e && e.message) || e));
38
+ return 1;
39
+ }
40
+ ctx.out(`${ko ? "초기화됨" : "Initialized"}: ${cwd}`);
41
+ return 0;
42
+ }
43
+ ctx.err("Usage: agentlas project [status|init]");
44
+ return 1;
45
+ }
46
+
47
+ module.exports = { run };
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ /*
3
+ * research — Research Engine (status|gather|search|read|plan).
4
+ *
5
+ * v1 디스패처 매핑 그대로:
6
+ * `agentlas research <sub…>` → cmdHep(["research", ...rest])
7
+ * → runHephaestusInteractive가 research를 사람용 렌더러
8
+ * (runHephaestusResearch, --json 원본 모드 포함)로 넘긴다.
9
+ *
10
+ * v1 가드 그대로:
11
+ * - help 토큰 → 로컬 usage가 아니라 Hephaestus 네이티브 help 패스스루
12
+ * (v1: parity().cmdHep(null, ["research", ...rest]) 특례).
13
+ * - 첫 인자가 status|gather|search|read|plan 밖 → usage 실패 exit 1
14
+ * (자연어가 리서치 서브커맨드 자리로 새는 것 방지; ko 문구 v1 그대로).
15
+ */
16
+ const { create, usageFor, isHelpToken } = require("../hephaestus/runtime.cjs");
17
+
18
+ const RESEARCH_SUBCOMMANDS = ["status", "gather", "search", "read", "plan"];
19
+
20
+ async function run(ctx, args) {
21
+ const runtime = create(ctx);
22
+ if (args.some(isHelpToken)) {
23
+ return runtime.cmdHep(["research", ...args]);
24
+ }
25
+ if (!RESEARCH_SUBCOMMANDS.includes(args[0])) {
26
+ ctx.err(
27
+ "✖ " + (ctx.lang === "ko"
28
+ ? "사용법: agentlas research <status|gather|search|read|plan> [인자]"
29
+ : usageFor("research", ctx.lang)),
30
+ );
31
+ return 1;
32
+ }
33
+ return runtime.cmdHep(["research", ...args]);
34
+ }
35
+
36
+ module.exports = { run };
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ /*
3
+ * route — 라우팅 미리보기, 실행 없음 (사람용 렌더 + --json 원본 모드).
4
+ *
5
+ * v1 디스패처 매핑 그대로 (legacy-v1-engine-snapshot engine/agentlas.cjs ~13160):
6
+ * query 있음 → cmdHep(["route", query, "--project", projectCwd(),
7
+ * "--runtime", "terminal", ...(--json ? ["--json"] : [])])
8
+ * → runHephaestusInteractive가 route를 사람용 렌더러(runHephaestusRoute)로
9
+ * 넘기고, --json이면 human:false 원본 패스스루로 내려간다.
10
+ *
11
+ * v1 인자 가드 그대로:
12
+ * - help 토큰 → usage, exit 0
13
+ * - 인자가 없거나 --json뿐 → usage 실패 exit 1
14
+ * (빈 쿼리가 라우터로 새는 것 방지)
15
+ */
16
+ const { create, usageFor, isHelpToken } = require("../hephaestus/runtime.cjs");
17
+
18
+ async function run(ctx, args) {
19
+ if (args.some(isHelpToken)) {
20
+ ctx.out(usageFor("route", ctx.lang));
21
+ return 0;
22
+ }
23
+ if (!args.some((value) => value !== "--json")) {
24
+ ctx.err("✖ " + usageFor("route", ctx.lang));
25
+ return 1;
26
+ }
27
+ const runtime = create(ctx);
28
+ const raw = args.includes("--json");
29
+ const query = args.filter((value) => value !== "--json").join(" ").trim();
30
+ return runtime.cmdHep(
31
+ query
32
+ ? ["route", query, "--project", runtime.projectCwd(), "--runtime", "terminal", ...(raw ? ["--json"] : [])]
33
+ : ["route"],
34
+ );
35
+ }
36
+
37
+ module.exports = { run };
@@ -0,0 +1,149 @@
1
+ "use strict";
2
+ /*
3
+ * run — 원샷 실행: agentlas run [agent] [prompt…]
4
+ * -p | --print 최종 답만 stdout에 (스트리밍 UI 없음)
5
+ * --runtime <kind> claude-code | codex | gemini
6
+ * --permission <level> read | write | full
7
+ * 프롬프트가 없고 stdin이 TTY가 아니면 stdin을 읽는다.
8
+ *
9
+ * 자동 라우팅(agents/router.cjs): 첫 토큰이 에이전트로 해석되지 않으면 호스트 LLM
10
+ * 판정(resolveAutoRoute)이 최적 에이전트를 고른다 — 어휘 점수는 후보 모집 전용이다.
11
+ * 판정 런타임이 없으면 기본 에이전트로 정직 폴백하되 note를 stderr에 반드시 출력한다
12
+ * (조용한 오라우팅/폴백 금지 — 오너 결정).
13
+ * 런타임 사다리: 명시(--runtime) > 에이전트별 오버라이드(agent_runtime_overrides) >
14
+ * prefs > active_runtime > detected (runtimes/overrides.cjs).
15
+ */
16
+ const { findAgent, listAgents } = require("../agents/registry.cjs");
17
+ const { resolveRuntime } = require("../runtimes/resolve.cjs");
18
+ const { resolveRuntimeForAgent, unavailableOverrideNote } = require("../runtimes/overrides.cjs");
19
+ const { Orchestrator } = require("../sessions/orchestrator.cjs");
20
+ const { Renderer } = require("../ui/renderer.cjs");
21
+ const permissions = require("../agentlas-permissions.cjs");
22
+
23
+ function readStdin() {
24
+ return new Promise((resolve) => {
25
+ let buf = "";
26
+ process.stdin.setEncoding("utf8");
27
+ process.stdin.on("data", (d) => { buf += d; });
28
+ process.stdin.on("end", () => resolve(buf.trim()));
29
+ });
30
+ }
31
+
32
+ function parseArgs(args) {
33
+ const out = { print: false, runtime: null, permission: null, rest: [] };
34
+ for (let i = 0; i < args.length; i++) {
35
+ const a = args[i];
36
+ if (a === "-p" || a === "--print") out.print = true;
37
+ else if (a === "--runtime") out.runtime = args[++i];
38
+ else if (a === "--permission") out.permission = args[++i];
39
+ else out.rest.push(a);
40
+ }
41
+ return out;
42
+ }
43
+
44
+ async function runOnce(ctx, args) {
45
+ const parsed = parseArgs(args);
46
+ // 플래그 검증은 모델을 부르기 전에. normalize는 알 수 없는 값을 read로 fail-closed
47
+ // 강등하는데, 조용히 강등하면 full을 요청한 사용자가 read로 도는 걸 모른다.
48
+ if (parsed.permission && !["read", "write", "full"].includes(String(parsed.permission))) {
49
+ ctx.err(`unknown --permission ${parsed.permission} (use: read | write | full)`);
50
+ return 1;
51
+ }
52
+ const db = ctx.db();
53
+
54
+ let agent = null;
55
+ let promptParts = parsed.rest;
56
+ if (parsed.rest.length) {
57
+ const candidate = findAgent(db, parsed.rest[0]);
58
+ if (candidate) {
59
+ agent = candidate;
60
+ promptParts = parsed.rest.slice(1);
61
+ }
62
+ }
63
+ let prompt = promptParts.join(" ").trim();
64
+ if (!prompt && !process.stdin.isTTY) prompt = await readStdin();
65
+ if (!prompt) {
66
+ ctx.err("Usage: agentlas run [agent] [prompt] (reads stdin if no prompt)");
67
+ return 1;
68
+ }
69
+
70
+ // 기본 런타임을 먼저 확정한다 — 판정 러너(자동 라우팅)도 이 런타임을 쓴다.
71
+ let runtime;
72
+ try {
73
+ runtime = resolveRuntime({ db, prefs: ctx.prefs, explicit: parsed.runtime });
74
+ } catch (e) {
75
+ ctx.err(String((e && e.message) || e));
76
+ return 1;
77
+ }
78
+
79
+ if (!agent) {
80
+ // 자동 라우팅 — 최종 픽은 호스트 LLM 판정. 판정 불가 시 기본 에이전트 정직 폴백 + note.
81
+ const router = require("../agents/router.cjs");
82
+ let choice = null;
83
+ try {
84
+ choice = await router.resolveAutoRoute(db, prompt, { lang: ctx.lang, runtime });
85
+ } catch (e) {
86
+ ctx.err(ctx.lang === "ko"
87
+ ? `자동 라우팅 실패(${(e && e.message) || e}) — 기본 에이전트로 실행합니다`
88
+ : `auto-routing failed (${(e && e.message) || e}) — running with the default agent`);
89
+ }
90
+ if (choice && choice.agent) {
91
+ agent = choice.agent;
92
+ } else {
93
+ const visible = listAgents(db);
94
+ agent = visible[0] || findAgent(db, "agentlas-orchestrator");
95
+ if (!agent) {
96
+ ctx.err(ctx.lang === "en" ? "no installed agent (agentlas search/install first)" : "설치된 에이전트가 없습니다 (agentlas search/install 먼저)");
97
+ return 1;
98
+ }
99
+ // 직답 판정 — 페르소나 오염 없이 기본 에이전트 챗으로, 플레인 프롬프트로 답한다.
100
+ if (choice && choice.direct) agent = { ...agent, systemPrompt: router.directSystemPrompt(ctx.lang) };
101
+ }
102
+ // 조용한 라우팅 금지 — 누가 왜 선택됐는지(또는 왜 판정을 못 했는지) 반드시 출력.
103
+ if (choice && choice.note) ctx.err(ctx.uiInstance.c.dim(choice.note));
104
+ }
105
+
106
+ // 에이전트가 확정된 뒤 에이전트별 런타임 오버라이드를 얹는다(명시 --runtime이 항상 우선).
107
+ if (!parsed.runtime && agent && agent.id) {
108
+ try {
109
+ const layered = resolveRuntimeForAgent({ db, prefs: ctx.prefs, explicit: null, agentId: agent.id });
110
+ if (layered.unavailableOverride) ctx.err(ctx.uiInstance.c.dim(unavailableOverrideNote(layered, ctx.lang)));
111
+ runtime = layered;
112
+ } catch { /* 오버라이드 층 실패 → 이미 확정된 기본 런타임 유지 */ }
113
+ }
114
+
115
+ const orch = new Orchestrator({ db, lang: ctx.lang });
116
+ const session = orch.spawn({
117
+ agent,
118
+ runtime,
119
+ permission: permissions.normalize(parsed.permission || (ctx.prefs && ctx.prefs.permission) || "write"),
120
+ cwd: process.cwd(),
121
+ title: prompt.slice(0, 60),
122
+ });
123
+
124
+ let renderer = null;
125
+ if (!parsed.print) {
126
+ renderer = new Renderer(ctx.uiInstance);
127
+ renderer.attach(session, { replay: false });
128
+ ctx.err(ctx.uiInstance.c.dim(`${agent.slug} · ${runtime.kind}`));
129
+ }
130
+
131
+ const res = await session.send(prompt);
132
+ if (renderer) renderer.detach();
133
+
134
+ if (parsed.print) {
135
+ const finalText = (res && (res.finalText || res.text)) || "";
136
+ if (finalText) process.stdout.write(finalText.trimEnd() + "\n");
137
+ }
138
+ if (session.status === "failed") {
139
+ if (parsed.print && session.lastError) ctx.err(session.lastError);
140
+ return 1;
141
+ }
142
+ return 0;
143
+ }
144
+
145
+ function run(ctx, args) {
146
+ return runOnce(ctx, args);
147
+ }
148
+
149
+ module.exports = { run, parseArgs };
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ /*
3
+ * search — Hub 에이전트 디렉터리 검색 (hep-search 표면).
4
+ * 로그인 없이도 동작한다(쿠키는 있으면 첨부). 결과 위장/폴백 카탈로그 금지 —
5
+ * Hub가 실패하면 그 실패를 그대로 보고한다.
6
+ */
7
+ const { callHubTool, HubError } = require("../cloud/hub-client.cjs");
8
+
9
+ /** 엔진 내부 에이전트는 제품이 아니므로 검색 결과에서 숨긴다 (v1과 동일 규칙). */
10
+ function isInternalAgentSlug(slug) {
11
+ const s = String(slug || "").toLowerCase();
12
+ return /^researcher-\d+/.test(s) || s === "research-intelligence-desk" || s.startsWith("hephaestus-");
13
+ }
14
+
15
+ async function run(ctx, args) {
16
+ let limit = 10;
17
+ const rest = [];
18
+ for (let i = 0; i < args.length; i++) {
19
+ if (args[i] === "--limit") limit = Math.max(1, Math.min(30, Number(args[++i]) || 10));
20
+ else rest.push(args[i]);
21
+ }
22
+ const query = rest.join(" ").trim();
23
+ if (!query) {
24
+ ctx.err('usage: agentlas search "<what you need>" [--limit 10]');
25
+ return 1;
26
+ }
27
+
28
+ let result;
29
+ try {
30
+ // Hub 파라미터 이름은 `q` — 데스크탑 mcp-source.ts와 동일하게 q/query 둘 다 전송.
31
+ result = await callHubTool("marketplace.search_agents", { q: query, query, limit });
32
+ } catch (e) {
33
+ ctx.err(e instanceof HubError ? e.message : `Marketplace connection failed: ${(e && e.message) || e}`);
34
+ return 1;
35
+ }
36
+
37
+ const raw = (result && (result.results || result.agents || result.items)) || (Array.isArray(result) ? result : null);
38
+ const items = Array.isArray(raw) ? raw.filter((it) => !isInternalAgentSlug(it && (it.slug || it.id))) : [];
39
+ if (!items.length) {
40
+ ctx.out(`No results for "${query}"`);
41
+ return 0;
42
+ }
43
+ for (const it of items.slice(0, limit)) {
44
+ const slug = it.slug || it.id || "?";
45
+ const name = it.name || it.title || slug;
46
+ const kind = it.kind || it.entity_kind || "";
47
+ const tagline = it.tagline || it.description || "";
48
+ ctx.out(`${ctx.ui.accent(String(slug).padEnd(34).slice(0, 34))} ${String(name).slice(0, 26).padEnd(27)} ${ctx.ui.dim(String(kind).padEnd(14))} ${String(tagline).slice(0, 60)}`);
49
+ }
50
+ ctx.out("");
51
+ ctx.out(ctx.ui.dim("Install: agentlas install <slug>"));
52
+ return 0;
53
+ }
54
+
55
+ module.exports = { run, isInternalAgentSlug };
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ /*
3
+ * setup — 첫 실행 마법사 재실행 (언어 → 기본 런타임 → 기본 권한).
4
+ * 결과는 cli-prefs.json에 저장된다. REPL은 onboarded가 아니면 이 마법사를 먼저 연다.
5
+ */
6
+ const readline = require("node:readline");
7
+ const { runOnboard } = require("../agentlas-onboard.cjs");
8
+ const { updatePrefs } = require("../agentlas-config.cjs");
9
+ const { userDataDir } = require("../core/paths.cjs");
10
+ const { RUNTIME_BIN, whichSync } = require("../runtimes/detect.cjs");
11
+
12
+ async function runWizard(ctx, rl) {
13
+ const result = await runOnboard({
14
+ ui: ctx.uiInstance,
15
+ rl,
16
+ helpers: { RUNTIME_BIN, which: whichSync },
17
+ });
18
+ if (result && result.onboarded) {
19
+ updatePrefs(userDataDir(), {
20
+ onboarded: true,
21
+ ...(result.lang ? { language: result.lang } : {}),
22
+ ...(result.runtime ? { runtime: result.runtime } : {}),
23
+ ...(result.permission ? { permission: result.permission } : {}),
24
+ });
25
+ }
26
+ return result;
27
+ }
28
+
29
+ async function run(ctx) {
30
+ if (!process.stdin.isTTY) {
31
+ // 비-TTY에서 마법사를 돌리면 EOF로 이벤트 루프가 비어 exit 0으로 "조용히 성공"
32
+ // 하는 함정이 있다 — 정직하게 거부한다.
33
+ ctx.err(ctx.lang === "ko" ? "setup은 대화형 터미널에서만 실행됩니다." : "setup requires an interactive terminal.");
34
+ return 1;
35
+ }
36
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
37
+ try {
38
+ const result = await runWizard(ctx, rl);
39
+ return result && result.onboarded ? 0 : 1;
40
+ } finally {
41
+ rl.close();
42
+ }
43
+ }
44
+
45
+ module.exports = { run, runWizard };
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ /*
3
+ * commands/storm — `agentlas storm <goal> [--research] [--background] [--runtime <kind>]`.
4
+ *
5
+ * v1 모놀리스 디스패치(legacy-v1-engine-snapshot, engine/agentlas.cjs 13074행)의 포팅:
6
+ * case "storm" → parity().cmdStorm(db, rest, runtimeOverride,
7
+ * { cwd, projectPath, permission })
8
+ *
9
+ * 정직 정지 계약: Agentlas Core의 Goal+UltraCode 하네스가 없으면 storm/storm.cjs 가
10
+ * stormbreaker-core-harness-unavailable 로 멈춘다 — 하네스의 로컬 모조 실행 금지.
11
+ * 런타임 부재는 resolveRuntime의 code="no_runtime" throw가 그대로 전파돼 exit 1.
12
+ *
13
+ * projectPath 에 대한 정직한 메모: v1은 ensureTerminalProjectForExecutionCli(db,
14
+ * cwd, permission, "terminal-storm")로 프로젝트 상태 머신을 돌려 활성 프로젝트
15
+ * 경로를 만들었다. 그 프로젝트-상태 기계는 아직 v2로 포팅되지 않았다. storm/swarm 이
16
+ * projectPath 를 쓰는 곳은 buildChildEnv 의 프로젝트 dotenv 스코핑뿐이고 부재 시
17
+ * fail-closed 의존이 없다 — 그래서 여기서는 cwd 를 projectPath 로 넘긴다
18
+ * (commands/workforce.cjs 와 동일한 결정·동일한 근거). 프로젝트-상태 모듈이 v2에
19
+ * 착륙하면 이 자리를 그 결과로 교체한다.
20
+ */
21
+ const { buildStormDeps } = require("../storm/deps.cjs");
22
+ const { projectCwd } = require("../workforce/capture.cjs");
23
+
24
+ function assertPermissionFlag(value) {
25
+ if (value && !["read", "write", "full"].includes(String(value))) {
26
+ throw new Error(`unknown --permission ${value} (use: read | write | full)`);
27
+ }
28
+ }
29
+
30
+ function resolvePermission(ctx) {
31
+ // v1 resolveTerminalPermission 포팅: 저장된 `full` 은 세션 한정 계약이라
32
+ // persistent()가 fail-closed 로 강등한다.
33
+ try {
34
+ const policy = require("../agentlas-permissions.cjs");
35
+ return policy.persistent(ctx && ctx.prefs && ctx.prefs.permission, "write");
36
+ } catch {
37
+ return "write";
38
+ }
39
+ }
40
+
41
+ /** `--runtime <kind>` 만 명령 자체 플래그로 벗겨낸다. 나머지는 cmdStorm 이 파싱. */
42
+ function splitRuntimeOverride(args) {
43
+ const rest = [];
44
+ let runtimeOverride = null;
45
+ for (let i = 0; i < args.length; i += 1) {
46
+ if (args[i] === "--runtime" && args[i + 1]) {
47
+ runtimeOverride = String(args[++i]);
48
+ continue;
49
+ }
50
+ rest.push(args[i]);
51
+ }
52
+ return { rest, runtimeOverride };
53
+ }
54
+
55
+ async function run(ctx, args) {
56
+ const { rest, runtimeOverride } = splitRuntimeOverride(args);
57
+ // usage 경로(목표 텍스트 없음)는 SQLite를 열 이유가 없다.
58
+ if (!rest.some((token) => !["--research", "--research-evidence", "--background"].includes(String(token)))) {
59
+ ctx.err("usage: agentlas storm <goal> [--research] [--background] [--runtime <kind>]");
60
+ return 1;
61
+ }
62
+ const db = ctx.db();
63
+ const cwd = projectCwd();
64
+ const permission = resolvePermission(ctx);
65
+ const storm = require("../storm/storm.cjs").create(buildStormDeps(ctx));
66
+ const r = await storm.cmdStorm(db, rest, runtimeOverride, {
67
+ cwd,
68
+ // v1 ensureTerminalProjectForExecutionCli 미포팅 — 위 파일 머리 주석 참조.
69
+ projectPath: cwd,
70
+ permission,
71
+ });
72
+ return r && r.ok ? 0 : 1;
73
+ }
74
+
75
+ module.exports = { run, splitRuntimeOverride };
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ /*
3
+ * commands/swarm — `agentlas swarm <goal> [--parallel N] [--runtime <kind>]`.
4
+ *
5
+ * v1 모놀리스 디스패치(legacy-v1-engine-snapshot, engine/agentlas.cjs 13079행)의 포팅:
6
+ * case "swarm" → parity().cmdSwarm(db, rest, runtimeOverride,
7
+ * { cwd, projectPath, permission })
8
+ *
9
+ * 워커 실행은 storm/swarm.cjs 를 통해 engine/workforce/capture.cjs 의 headless
10
+ * 캡처로만 이뤄진다(제2의 스폰 경로 금지). 워커의 workload allocation은
11
+ * agentlas-workload-routing 이 검증만 하고, 거부 시 fail-closed 다.
12
+ * 런타임 부재는 resolveRuntime의 code="no_runtime" throw가 그대로 전파돼 exit 1.
13
+ *
14
+ * projectPath: v1 ensureTerminalProjectForExecutionCli 미포팅 —
15
+ * commands/storm.cjs 파일 머리 주석과 동일한 결정·동일한 근거로 cwd 를 넘긴다.
16
+ */
17
+ const { buildStormDeps } = require("../storm/deps.cjs");
18
+ const { projectCwd } = require("../workforce/capture.cjs");
19
+
20
+ function assertPermissionFlag(value) {
21
+ if (value && !["read", "write", "full"].includes(String(value))) {
22
+ throw new Error(`unknown --permission ${value} (use: read | write | full)`);
23
+ }
24
+ }
25
+
26
+ function resolvePermission(ctx) {
27
+ // v1 resolveTerminalPermission 포팅: 저장된 `full` 은 세션 한정 계약이라
28
+ // persistent()가 fail-closed 로 강등한다.
29
+ try {
30
+ const policy = require("../agentlas-permissions.cjs");
31
+ return policy.persistent(ctx && ctx.prefs && ctx.prefs.permission, "write");
32
+ } catch {
33
+ return "write";
34
+ }
35
+ }
36
+
37
+ /** `--runtime <kind>` 만 명령 자체 플래그로 벗겨낸다. 나머지는 cmdSwarm 이 파싱. */
38
+ function splitRuntimeOverride(args) {
39
+ const rest = [];
40
+ let runtimeOverride = null;
41
+ for (let i = 0; i < args.length; i += 1) {
42
+ if (args[i] === "--runtime" && args[i + 1]) {
43
+ runtimeOverride = String(args[++i]);
44
+ continue;
45
+ }
46
+ rest.push(args[i]);
47
+ }
48
+ return { rest, runtimeOverride };
49
+ }
50
+
51
+ async function run(ctx, args) {
52
+ const { rest, runtimeOverride } = splitRuntimeOverride(args);
53
+ // usage 경로(목표 텍스트 없음)는 SQLite를 열 이유가 없다 — cmdSwarm 의 플래그
54
+ // (--parallel/-n <N>)만 있는 호출은 빈 목표다.
55
+ const hasGoal = rest.some((token, i) =>
56
+ !["--parallel", "-n"].includes(String(token))
57
+ && !(i > 0 && ["--parallel", "-n"].includes(String(rest[i - 1]))));
58
+ if (!hasGoal) {
59
+ ctx.err("usage: agentlas swarm <goal> [--parallel N] [--runtime <kind>]");
60
+ return 1;
61
+ }
62
+ const db = ctx.db();
63
+ const cwd = projectCwd();
64
+ const permission = resolvePermission(ctx);
65
+ const swarm = require("../storm/swarm.cjs").create(buildStormDeps(ctx));
66
+ const r = await swarm.cmdSwarm(db, rest, runtimeOverride, {
67
+ cwd,
68
+ // v1 ensureTerminalProjectForExecutionCli 미포팅 — commands/storm.cjs 주석 참조.
69
+ projectPath: cwd,
70
+ permission,
71
+ });
72
+ return r && r.ok ? 0 : 1;
73
+ }
74
+
75
+ module.exports = { run, splitRuntimeOverride };
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ /* telegram — 바인딩 현황 (읽기 전용). 페어링·봇 발급은 Desktop Connect 소관. */
3
+
4
+ function run(ctx) {
5
+ const ko = ctx.lang === "ko";
6
+ const db = ctx.db();
7
+ let rows;
8
+ try {
9
+ rows = db.prepare("SELECT * FROM telegram_bindings ORDER BY rowid DESC").all();
10
+ } catch {
11
+ rows = [];
12
+ }
13
+ if (!rows.length) {
14
+ ctx.out(ko
15
+ ? "Telegram 연결이 없습니다. Desktop Connect에서 기기를 연결하세요."
16
+ : "No Telegram bindings. Pair devices from Desktop Connect.");
17
+ return 0;
18
+ }
19
+ for (const r of rows) {
20
+ const bot = r.bot_username ? "@" + r.bot_username : "(bot not set)";
21
+ const chat = r.telegram_chat_title || r.telegram_chat_id || "(chat not connected)";
22
+ const status = r.status || (r.telegram_chat_id ? "paired" : "pending");
23
+ ctx.out(`${String(r.id).slice(0, 8)} ${r.target_kind}:${String(r.target_id).slice(0, 20).padEnd(21)} ${String(bot).padEnd(24)} ${String(chat).slice(0, 28).padEnd(29)} ${status}`);
24
+ }
25
+ ctx.out("");
26
+ ctx.out(ctx.ui.dim(ko
27
+ ? "연결과 봇 발급은 Desktop Connect에서 수행하며, 이 명령은 상태만 보여줍니다."
28
+ : "Pairing and bot issuance happen in Desktop Connect; this command only shows status."));
29
+ return 0;
30
+ }
31
+
32
+ module.exports = { run };
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ /*
3
+ * uninstall — 설치 에이전트 제거 (데스크탑 registry.uninstallAgent 동형).
4
+ * 게이트: 설치된 회사(firm)에 속한 에이전트는 회사 관계를 먼저 정리해야 한다
5
+ * (에이전트/챗은 그대로 남는다는 안내 포함 — 데스크탑 문구 동일).
6
+ * 로컬 임포트 라우트도 정리하되 원본 폴더는 건드리지 않는다. 빌트인은 거부.
7
+ */
8
+ const { findAgent } = require("../agents/registry.cjs");
9
+ const { routesMap, saveRoutes } = require("../agents/routes.cjs");
10
+ const { runWriteTransaction } = require("../agentlas-sqlite-policy.cjs");
11
+
12
+ function run(ctx, args) {
13
+ const ko = ctx.lang === "ko";
14
+ const token = args[0];
15
+ if (!token) {
16
+ ctx.err(ko ? "사용법: agentlas uninstall <agent>" : "Usage: agentlas uninstall <agent>");
17
+ return 1;
18
+ }
19
+ const db = ctx.db();
20
+ const agent = findAgent(db, token);
21
+ if (!agent) {
22
+ ctx.err((ko ? "에이전트를 찾을 수 없음: " : "agent not found: ") + token);
23
+ return 1;
24
+ }
25
+ if (agent.builtin) {
26
+ ctx.err(ko ? "빌트인 아키텍처 에이전트는 제거할 수 없습니다." : "Built-in architecture agents cannot be uninstalled.");
27
+ return 1;
28
+ }
29
+
30
+ if (ctx.tableExists(db, "firms")) {
31
+ const firmRows = db.prepare("SELECT id, name, ceo_agent_id, org_chart_json FROM firms").all();
32
+ const membership = firmRows.find((firm) => {
33
+ if (firm.ceo_agent_id === agent.id) return true;
34
+ try {
35
+ return JSON.parse(firm.org_chart_json || "[]").some((node) => node && node.agentId === agent.id);
36
+ } catch {
37
+ return false;
38
+ }
39
+ });
40
+ if (membership) {
41
+ ctx.err(ko
42
+ ? `설치된 회사 "${membership.name}"에 속한 에이전트입니다. 회사 관계를 먼저 정리하세요; 에이전트와 대화는 그대로 남습니다.`
43
+ : `Agent belongs to installed firm "${membership.name}". Remove the firm relationship first; the agent and its chats will stay installed.`);
44
+ return 1;
45
+ }
46
+ }
47
+
48
+ let deleted = false;
49
+ runWriteTransaction(db, () => {
50
+ deleted = db.prepare("DELETE FROM installed_agents WHERE id=?").run(agent.id).changes > 0;
51
+ });
52
+ if (deleted) {
53
+ // 로컬 임포트 라우팅도 정리 (원본 폴더는 건드리지 않음) — 데스크탑 removeRoute 동형.
54
+ try {
55
+ const routes = routesMap();
56
+ if (routes[agent.id]) {
57
+ delete routes[agent.id];
58
+ saveRoutes(routes);
59
+ }
60
+ } catch { /* 라우트 정리는 best-effort */ }
61
+ ctx.out(`${ctx.ui.green("✓")} ${ko ? "제거됨" : "Uninstalled"}: ${agent.slug}`);
62
+ return 0;
63
+ }
64
+ ctx.err(ko ? "제거하지 못했습니다." : "Nothing was uninstalled.");
65
+ return 1;
66
+ }
67
+
68
+ module.exports = { run };