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,96 @@
1
+ "use strict";
2
+ /*
3
+ * billing — 크레딧 잔액 조회: agentlas billing
4
+ *
5
+ * 데스크탑 electron/billing.ts 와 같은 엔드포인트를 읽는다:
6
+ * GET {web}/api/billing/credits — 두 계좌 정책:
7
+ * · 구독 계좌(A): remainingCredits — 월 초기화 + 톱업 + 전송받은 렌트수익. 사용 가능.
8
+ * · 렌트수익 계좌(B): earningsCredits — 내 업로드를 남이 빌려 쓸 때만 쌓임.
9
+ * · 전송은 B → A 한 방향뿐이며 터미널에는 전송 명령이 없다(데스크탑 전용) —
10
+ * 조용히 숨기지 않고 help/출력에 명시한다.
11
+ *
12
+ * 인증: cloud/hub-client.cjs 의 세션 쿠키. 미로그인/세션 만료는 정직 exit 1 —
13
+ * 빈 잔액(0)으로 위장 출력하지 않는다(조용한 기본값 안티패턴 금지).
14
+ */
15
+ const { cloudSessionCookie, fetchHub, webBaseUrl, parseHubJson } = require("../cloud/hub-client.cjs");
16
+
17
+ function fmtCredits(value) {
18
+ const n = Number(value);
19
+ return Number.isFinite(n) ? n.toLocaleString("en-US") : "—";
20
+ }
21
+
22
+ function usage(ko) {
23
+ return [
24
+ ko ? "사용법: agentlas billing" : "Usage: agentlas billing",
25
+ ko
26
+ ? " 구독 계좌(A)와 렌트수익 계좌(B) 잔액을 표시합니다."
27
+ : " Shows the subscription account (A) and rental-earnings account (B) balances.",
28
+ ko
29
+ ? " 참고: 렌트수익(B) → 구독(A) 전송은 Agentlas Desktop 에서만 가능합니다 (터미널 전송 명령 없음)."
30
+ : " Note: earnings (B) → subscription (A) transfer is Desktop-only (no transfer command in the terminal).",
31
+ ].join("\n");
32
+ }
33
+
34
+ async function run(ctx, args) {
35
+ const ko = ctx.lang === "ko";
36
+ if (args.some((a) => a === "--help" || a === "-h" || a === "help")) {
37
+ ctx.out(usage(ko));
38
+ return 0;
39
+ }
40
+
41
+ const cookie = await cloudSessionCookie();
42
+ if (!cookie) {
43
+ ctx.err(ko
44
+ ? "로그인이 필요합니다. `agentlas login` 을 먼저 실행하세요."
45
+ : "Not signed in. Run `agentlas login` first.");
46
+ return 1;
47
+ }
48
+
49
+ let resp;
50
+ try {
51
+ resp = await fetchHub(`${webBaseUrl()}/api/billing/credits`, { headers: { cookie } });
52
+ } catch (e) {
53
+ ctx.err((ko ? "크레딧 조회 실패: " : "Failed to fetch credits: ") + ((e && e.message) || e));
54
+ return 1;
55
+ }
56
+ // 401 = 세션 무효 — 데스크탑과 동일하게 미인증으로 강등한다(만료 세션으로 잔액 표시 금지).
57
+ if (resp.status === 401) {
58
+ ctx.err(ko
59
+ ? "세션이 만료되었습니다. `agentlas login` 으로 다시 로그인하세요."
60
+ : "Session expired. Sign in again with `agentlas login`.");
61
+ return 1;
62
+ }
63
+ if (!resp.ok) {
64
+ ctx.err((ko ? "크레딧 조회 실패: " : "Failed to fetch credits: ") + `HTTP ${resp.status}`);
65
+ return 1;
66
+ }
67
+
68
+ let balance;
69
+ try {
70
+ balance = parseHubJson(resp, "billing/credits");
71
+ } catch (e) {
72
+ ctx.err(String((e && e.message) || e));
73
+ return 1;
74
+ }
75
+ if (!balance || balance.authenticated === false) {
76
+ ctx.err(ko
77
+ ? "세션이 유효하지 않습니다. `agentlas login` 으로 다시 로그인하세요."
78
+ : "Session is not valid. Sign in again with `agentlas login`.");
79
+ return 1;
80
+ }
81
+
82
+ const a = ctx.ui.accent;
83
+ const dim = ctx.ui.dim;
84
+ if (balance.plan) ctx.out(`${ko ? "플랜" : "Plan"}: ${balance.plan}`);
85
+ ctx.out(`${a(ko ? "구독 계좌 (A)" : "Subscription account (A)")}: ${fmtCredits(balance.remainingCredits)} ${ko ? "크레딧" : "credits"}`);
86
+ if (balance.limitCredits != null || balance.usedCredits != null) {
87
+ ctx.out(dim(` ${ko ? "사용" : "used"}: ${fmtCredits(balance.usedCredits)} / ${ko ? "한도" : "limit"}: ${fmtCredits(balance.limitCredits != null ? balance.limitCredits : balance.planCreditLimit)}${balance.topUpCredits ? ` (+${ko ? "톱업" : "top-up"} ${fmtCredits(balance.topUpCredits)})` : ""}`));
88
+ }
89
+ ctx.out(`${a(ko ? "렌트수익 계좌 (B)" : "Rental earnings account (B)")}: ${fmtCredits(balance.earningsCredits)} ${ko ? "크레딧" : "credits"}`);
90
+ ctx.out(dim(ko
91
+ ? "B → A 전송은 Agentlas Desktop 에서만 가능합니다 (터미널 전송 명령 없음)."
92
+ : "B → A transfer is Desktop-only (no transfer command in the terminal)."));
93
+ return 0;
94
+ }
95
+
96
+ module.exports = { run };
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ /*
3
+ * browser — 실제 브라우저 실행 하드포인트 (hep-browser 라우트).
4
+ *
5
+ * v1 디스패처 매핑 그대로:
6
+ * `agentlas browser <url-or-query|sub…>` → cmdHep(["hep-browser", ...rest])
7
+ * v1은 browser에 무인자 가드가 없었다(missingArgumentUsage 미포함) —
8
+ * 무인자도 hep-browser 패스스루로 넘어가 네이티브 usage가 나온다. 보존.
9
+ */
10
+ const { create, usageFor, isHelpToken } = require("../hephaestus/runtime.cjs");
11
+
12
+ async function run(ctx, args) {
13
+ if (args.some(isHelpToken)) {
14
+ ctx.out(usageFor("browser", ctx.lang));
15
+ return 0;
16
+ }
17
+ return create(ctx).cmdHep(["hep-browser", ...args]);
18
+ }
19
+
20
+ module.exports = { run };
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ /*
3
+ * build — 에이전트/팀 빌드·수리·패키징 (hep-build 라우트).
4
+ *
5
+ * v1 디스패처 검증 메모 (legacy-v1-engine-snapshot engine/agentlas.cjs ~13097):
6
+ * v1의 `agentlas build`는 hep-build 단순 패스스루가 아니라 터미널 소유
7
+ * 빌더(terminalAssets.cmdBuild: 시스템 MCP 메타데이터 프리플라이트 → 1회
8
+ * 동의 → Meta-Agent 실행)로 갔다. 그 프리플라이트/빌더 체인은 engine/mcp/*
9
+ * 와 빌더 서브시스템 소유라 이 클러스터의 범위 밖이다.
10
+ * v2의 이 파일은 v1 도움말이 계약으로 명시한 표면 —
11
+ * `build "<request>" … (hep-build)` — 즉 Agentlas OS hep-build 라우트를
12
+ * 그대로 노출한다. 터미널 소유 MCP-동의 빌더가 v2에 재구축되면 그 모듈이
13
+ * 이 명령을 대체(또는 선행)해야 한다.
14
+ *
15
+ * v1 인자 가드 그대로:
16
+ * - help 토큰 → usage 출력, exit 0
17
+ * - 무인자 → usage 실패, exit 1 (요청 문자열이 라우터로 새는 것 방지)
18
+ */
19
+ const { create, usageFor, isHelpToken } = require("../hephaestus/runtime.cjs");
20
+
21
+ async function run(ctx, args) {
22
+ if (args.some(isHelpToken)) {
23
+ ctx.out(usageFor("build", ctx.lang));
24
+ return 0;
25
+ }
26
+ if (!args.length) {
27
+ ctx.err("✖ " + usageFor("build", ctx.lang));
28
+ return 1;
29
+ }
30
+ return create(ctx).cmdHep(["hep-build", ...args]);
31
+ }
32
+
33
+ module.exports = { run };
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ /*
3
+ * call — 지정한 Hub/Cloud 에이전트 호출·준비 (hep-call 라우트).
4
+ *
5
+ * v1 디스패처 매핑 그대로:
6
+ * `agentlas call "a,b" "<맥락>"` → cmdHep(["hep-call", ...rest])
7
+ * 무인자 → usage 실패 exit 1 (missingArgumentUsage 가드 — 슬러그 없는
8
+ * 호출이 자연어 라우팅으로 새는 것 방지).
9
+ */
10
+ const { create, usageFor, isHelpToken } = require("../hephaestus/runtime.cjs");
11
+
12
+ async function run(ctx, args) {
13
+ if (args.some(isHelpToken)) {
14
+ ctx.out(usageFor("call", ctx.lang));
15
+ return 0;
16
+ }
17
+ if (!args.length) {
18
+ ctx.err("✖ " + usageFor("call", ctx.lang));
19
+ return 1;
20
+ }
21
+ return create(ctx).cmdHep(["hep-call", ...args]);
22
+ }
23
+
24
+ module.exports = { run };
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ /*
3
+ * career-graph — 커리어 그래프 상태/소스 등록 + 인덱스 실행 위임 (v1 cmdCareerGraph 포팅).
4
+ *
5
+ * ingest|query|verify|trace|public-card 는 파생 인덱스 실행이며 Agentlas OS /
6
+ * Hephaestus 런타임(career_graph 파이썬 모듈)이 소유한다 — 런타임이 있으면
7
+ * 그대로 위임 실행하고, 없으면 정직 정지(대신 계산하는 척 금지).
8
+ */
9
+ const { runCareerGraphCli } = require("../project/career-graph.cjs");
10
+ const { resolveCoreRuntimeRoot, resolvePython, spawnCoreModule } = require("../agentlas-core-harness.cjs");
11
+
12
+ const INDEX_SUBCOMMANDS = new Set(["ingest", "query", "verify", "trace", "public-card"]);
13
+
14
+ async function run(ctx, args) {
15
+ const sub = String((args && args[0]) || "status");
16
+ if (INDEX_SUBCOMMANDS.has(sub)) {
17
+ const coreRoot = resolveCoreRuntimeRoot();
18
+ if (!coreRoot || !resolvePython()) {
19
+ ctx.err(ctx.lang === "ko"
20
+ ? "Career Graph 인덱스 실행은 Agentlas OS / Hephaestus 런타임이 필요합니다 (~/.agentlas/runtime/current). 런타임 없이 결과를 지어내지 않습니다."
21
+ : "Career Graph index execution requires the Agentlas OS / Hephaestus runtime (~/.agentlas/runtime/current). No runtime — no fabricated result.");
22
+ return 1;
23
+ }
24
+ const graphArgs = args.slice();
25
+ if (!graphArgs.includes("--project")) graphArgs.push("--project", process.cwd());
26
+ const child = spawnCoreModule("career_graph", graphArgs, { cwd: process.cwd(), stdio: "inherit" }, coreRoot);
27
+ if (!child) {
28
+ ctx.err("Agentlas Core runtime or Python 3.9+ is unavailable.");
29
+ return 1;
30
+ }
31
+ return await new Promise((resolve) => {
32
+ child.on("error", (e) => { ctx.err(String((e && e.message) || e)); resolve(1); });
33
+ child.on("close", (code) => resolve(code == null ? 1 : code));
34
+ });
35
+ }
36
+ try {
37
+ const lines = runCareerGraphCli(args, {
38
+ cwd: process.cwd(),
39
+ projectPath: process.cwd(),
40
+ lang: ctx.lang,
41
+ notify: (line) => ctx.out(line),
42
+ });
43
+ for (const line of lines) ctx.out(line);
44
+ return 0;
45
+ } catch (e) {
46
+ ctx.err(String((e && e.message) || e));
47
+ return 1;
48
+ }
49
+ }
50
+
51
+ module.exports = { run };
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ /* cd — 에이전트의 로컬 폴더 경로만 출력 (읽기 전용; cd "$(agentlas cd <agent>)" 용). */
3
+ const { findAgent } = require("../agents/registry.cjs");
4
+ const { agentFolder } = require("../agents/files.cjs");
5
+
6
+ function run(ctx, args) {
7
+ const ko = ctx.lang === "ko";
8
+ if (!args[0]) {
9
+ ctx.err(ko ? "사용법: agentlas cd <agent>" : "Usage: agentlas cd <agent>");
10
+ return 1;
11
+ }
12
+ const agent = findAgent(ctx.db(), args[0]);
13
+ if (!agent) {
14
+ ctx.err((ko ? "에이전트를 찾을 수 없음: " : "agent not found: ") + args[0]);
15
+ return 1;
16
+ }
17
+ // 경로 조회 전용 — cd "$(agentlas cd seo)" 가 소스 패키지를 변형/재분류하면 안 된다.
18
+ ctx.out(agentFolder(agent));
19
+ return 0;
20
+ }
21
+
22
+ module.exports = { run };
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ /* chat — 에이전트 지정 REPL 진입 별칭: agentlas chat <agent> (= agentlas <agent>) */
3
+ function run(ctx, args) {
4
+ const ko = ctx.lang === "ko";
5
+ if (!args[0]) {
6
+ ctx.err(ko ? "사용법: agentlas chat <agent>" : "Usage: agentlas chat <agent>");
7
+ return 1;
8
+ }
9
+ const { startRepl } = require("../ui/repl.cjs");
10
+ return startRepl(ctx, { agent: args[0] });
11
+ }
12
+ module.exports = { run };
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ /* chats [n] — 최근 대화 목록 (공유 DB, 데스크탑과 동일 데이터). */
3
+
4
+ function run(ctx, args) {
5
+ const n = Math.max(1, Math.min(100, Number(args[0]) || 15));
6
+ const db = ctx.db();
7
+ if (!ctx.tableExists(db, "chats")) {
8
+ ctx.out(ctx.lang === "en" ? "No chats yet." : "대화가 아직 없습니다.");
9
+ return 0;
10
+ }
11
+ const rows = db.prepare(
12
+ `SELECT c.id, c.title, c.updated_at, a.slug AS agent_slug
13
+ FROM chats c LEFT JOIN installed_agents a ON a.id = c.agent_id
14
+ WHERE c.archived_at IS NULL AND (c.kind IS NULL OR c.kind = 'user')
15
+ ORDER BY c.updated_at DESC LIMIT ?`,
16
+ ).all(n);
17
+ if (!rows.length) {
18
+ ctx.out(ctx.lang === "en" ? "No chats yet." : "대화가 아직 없습니다.");
19
+ return 0;
20
+ }
21
+ for (const r of rows) {
22
+ const when = String(r.updated_at || "").replace("T", " ").slice(0, 16);
23
+ ctx.out(` ${ctx.ui.dim(when)} ${ctx.ui.accent((r.agent_slug || "?").padEnd(20))} ${r.title}`);
24
+ }
25
+ return 0;
26
+ }
27
+
28
+ module.exports = { run };
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ /*
3
+ * cloud — `agentlas cloud <sub> …`: Agent Cloud 자산 표면.
4
+ * 기능 로직은 전부 cloud-assets/ 에 있다. 여기서는 위임 + 오류 → ctx.err + 1.
5
+ */
6
+ const { runCloud } = require("../cloud-assets/commands.cjs");
7
+
8
+ async function run(ctx, args) {
9
+ try {
10
+ return await runCloud(ctx, args);
11
+ } catch (e) {
12
+ ctx.err(String((e && e.message) || e));
13
+ return 1;
14
+ }
15
+ }
16
+
17
+ module.exports = { run };
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ /*
3
+ * connect — Telegram 등 플랫폼 연결 (hep-connect 라우트).
4
+ *
5
+ * v1 디스패처 매핑 그대로:
6
+ * `agentlas connect <sub…>` → cmdHep(["hep-connect", ...rest])
7
+ * 무인자 connect는 v1에서 fail이 아니라 usage 안내 후 exit 0이었다
8
+ * (topLevelCommandUsage("connect") 특례) — 그대로 보존.
9
+ */
10
+ const { create, usageFor, isHelpToken } = require("../hephaestus/runtime.cjs");
11
+
12
+ async function run(ctx, args) {
13
+ if (args.some(isHelpToken) || !args.length) {
14
+ ctx.out(usageFor("connect", ctx.lang));
15
+ return 0;
16
+ }
17
+ return create(ctx).cmdHep(["hep-connect", ...args]);
18
+ }
19
+
20
+ module.exports = { run };
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ /*
3
+ * context — 의존성 컨텍스트 맵 패스스루 (v1 monolith 13224–13234 포팅).
4
+ *
5
+ * refresh|locate|refs|slice|impact|verify 를 Agentlas Core 런타임
6
+ * (agentlas_cloud context …)에 그대로 넘긴다. v1은 Hephaestus parity 셸을 거쳤지만
7
+ * 최종 실행 주체는 같은 Core CLI다 (engine/agentlas-core-harness.cjs 가 스폰).
8
+ *
9
+ * 정직 정지: Core 런타임(또는 Python 3.9+)이 없으면 가짜 맵을 만들지 않고
10
+ * 무엇이 없는지 보고하며 exit 1 한다.
11
+ */
12
+ const { projectCwd } = require("../project/paths.cjs");
13
+ const { ensureTerminalProjectForExecutionCli } = require("../project/state.cjs");
14
+ const {
15
+ CONTEXT_MAP_MIN_CORE_VERSION,
16
+ resolveCoreRuntimeRoot,
17
+ resolvePython,
18
+ spawnCoreModule,
19
+ } = require("../agentlas-core-harness.cjs");
20
+
21
+ const CONTEXT_SUBCOMMANDS = new Set(["refresh", "locate", "refs", "slice", "impact", "verify"]);
22
+
23
+ function usage(ctx) {
24
+ ctx.err("Usage: agentlas context <refresh|locate|refs|slice|impact|verify> [args…] [--project <path>]");
25
+ return 1;
26
+ }
27
+
28
+ async function run(ctx, args) {
29
+ if (!args[0]) return usage(ctx);
30
+ if (!CONTEXT_SUBCOMMANDS.has(String(args[0]))) return usage(ctx);
31
+ const cwd = projectCwd();
32
+ // 수동 검사만 — context 명령은 프로젝트를 초기화하지 않는다 (0.9.10 경계).
33
+ ensureTerminalProjectForExecutionCli(ctx.db(), cwd, "read", "terminal-context");
34
+
35
+ const coreRoot = resolveCoreRuntimeRoot(null, [], { minVersion: CONTEXT_MAP_MIN_CORE_VERSION });
36
+ if (!coreRoot) {
37
+ // 정직 정지: 맵을 지어내지 않는다.
38
+ ctx.err(ctx.lang === "ko"
39
+ ? `Agentlas Core 런타임(≥ ${CONTEXT_MAP_MIN_CORE_VERSION})을 찾지 못했습니다. 컨텍스트 맵은 Core가 소유하므로 여기서 대신 만들지 않습니다.`
40
+ : `Agentlas Core runtime (>= ${CONTEXT_MAP_MIN_CORE_VERSION}) was not found. The context map is owned by Core; this command will not fabricate one.`);
41
+ ctx.err(ctx.lang === "ko"
42
+ ? "설치: Agentlas Desktop 최신 버전 또는 `hephaestus` 런타임(~/.agentlas/runtime/current)을 설치하세요."
43
+ : "Install the latest Agentlas Desktop or the `hephaestus` runtime (~/.agentlas/runtime/current), then retry.");
44
+ return 1;
45
+ }
46
+ if (!resolvePython()) {
47
+ ctx.err(ctx.lang === "ko"
48
+ ? "Python 3.9+ 를 찾지 못했습니다. Core 컨텍스트 맵 실행에 필요합니다."
49
+ : "Python 3.9+ was not found; it is required to run the Core context map.");
50
+ return 1;
51
+ }
52
+
53
+ const contextArgs = args.slice();
54
+ if (!contextArgs.includes("--project")) contextArgs.push("--project", cwd);
55
+ const child = spawnCoreModule("agentlas_cloud", ["context", ...contextArgs], { cwd, stdio: "inherit" }, coreRoot);
56
+ if (!child) {
57
+ ctx.err("Agentlas Core runtime or Python 3.9+ is unavailable.");
58
+ return 1;
59
+ }
60
+ return await new Promise((resolve) => {
61
+ child.on("error", (e) => { ctx.err(String((e && e.message) || e)); resolve(1); });
62
+ child.on("close", (code) => resolve(code == null ? 1 : code));
63
+ });
64
+ }
65
+
66
+ module.exports = { run, CONTEXT_SUBCOMMANDS };
@@ -0,0 +1,203 @@
1
+ "use strict";
2
+ /*
3
+ * creds — 프로젝트 자격증명 저장 (v1 cmdCreds/cmdCredsFile 11210–11368 포팅).
4
+ *
5
+ * 계약:
6
+ * - 값은 .env / credentials.env(0600) / (Electron 한정) keychain vault 에만 저장.
7
+ * soul memory와 local-credentials.map.json 에는 사실(env 이름·상대경로)만 남긴다.
8
+ * - keytar는 Electron 런타임에서만 사용한다. standalone Node에서 서명 없는
9
+ * keytar 호출은 macOS 키체인에 막혀 무한 대기하고 process.exit로도 안 죽는다
10
+ * (v1 실사고) — 절대 우회하지 않는다.
11
+ * - 비밀 값은 어떤 경로로도 stdout/stderr에 출력하지 않는다.
12
+ */
13
+ const fs = require("node:fs");
14
+ const os = require("node:os");
15
+ const path = require("node:path");
16
+ const { userDataDir } = require("../core/paths.cjs");
17
+ const { loadArch } = require("../core/db.cjs");
18
+ const { activeProjectPath } = require("../project/state.cjs");
19
+ const { upsertEnvLine } = require("../project/env-file.cjs");
20
+ const {
21
+ localCredentialConfigCli,
22
+ ensureLocalCredentialStoreCli,
23
+ ensureSoulCredentialIndexCli,
24
+ upsertLocalCredentialMapCli,
25
+ projectScopedGlobalEnvKeyCli,
26
+ safeCredentialDestRelCli,
27
+ } = require("../project/credentials.cjs");
28
+
29
+ // 데스크탑과 공유하는 키체인 서비스/키 접두어 (v1 상수 그대로).
30
+ const SERVICE = "com.agentlas.desktop";
31
+ const ENV_PREFIX = "env:";
32
+
33
+ function isElectronRuntime() {
34
+ return !!(process.versions && process.versions.electron);
35
+ }
36
+ function readKeytar() {
37
+ try {
38
+ return require("keytar");
39
+ } catch {
40
+ return null;
41
+ }
42
+ }
43
+
44
+ function parseCredFlags(args) {
45
+ const f = {};
46
+ for (let i = 0; i < args.length; i++) {
47
+ const a = args[i];
48
+ if (a && a.startsWith("--")) {
49
+ const next = args[i + 1];
50
+ if (next !== undefined && !String(next).startsWith("--")) {
51
+ f[a.slice(2)] = next;
52
+ i++;
53
+ } else {
54
+ f[a.slice(2)] = true;
55
+ }
56
+ }
57
+ }
58
+ return f;
59
+ }
60
+
61
+ // `agentlas creds file`은 일반 CLI 명령이므로 상대경로 기준은 사용자가 명령을 실행한
62
+ // 셸 cwd다. 런타임 격리용 agent-cwd를 쓰면 실제 프로젝트 파일을 조용히 못 찾는다.
63
+ function resolveCredentialSourcePath(source, cwd) {
64
+ return path.resolve(cwd || process.cwd(), source);
65
+ }
66
+
67
+ async function cmdCredsFile(ctx, args) {
68
+ const fail = (msg) => { ctx.err(msg); return 1; };
69
+ const f = parseCredFlags(args);
70
+ const source = typeof f.source === "string" ? f.source : typeof f.path === "string" ? f.path : "";
71
+ if (!source) return fail("usage: agentlas creds file --source <path> [--provider <name>] [--env <ENV_NAME>] [--dest <relative-path>] [--project <path>] [--force]");
72
+ const project = typeof f.project === "string" && f.project ? f.project : activeProjectPath(ctx.db());
73
+ if (!project) return fail("creds file requires a project path");
74
+ const provider = typeof f.provider === "string" && f.provider ? f.provider : "credential_file";
75
+ const envKey = typeof f.env === "string" && f.env ? f.env.trim() : "";
76
+ if (envKey && !/^[A-Z][A-Z0-9_]*$/.test(envKey)) return fail("credential env name must look like ENV_NAME");
77
+
78
+ const arch = loadArch();
79
+ const cfg = localCredentialConfigCli(arch);
80
+ const projectName = path.basename(project) || "Project";
81
+ ensureLocalCredentialStoreCli(project, projectName, arch);
82
+ ensureSoulCredentialIndexCli(project, projectName, arch);
83
+
84
+ const sourceAbs = resolveCredentialSourcePath(source);
85
+ let stat;
86
+ try { stat = fs.statSync(sourceAbs); } catch { return fail(`credential source not found: ${source}`); }
87
+ if (!stat.isFile()) return fail(`credential source is not a file: ${source}`);
88
+
89
+ const base = path.basename(sourceAbs);
90
+ const lower = base.toLowerCase();
91
+ const defaultDir = lower.includes("google-services") || lower.includes("googleservice-info")
92
+ ? cfg.credentialsDir
93
+ : cfg.signingDir;
94
+ let destRel;
95
+ try {
96
+ destRel = safeCredentialDestRelCli(
97
+ typeof f.dest === "string" && f.dest ? f.dest : path.join(defaultDir, base),
98
+ );
99
+ } catch (e) {
100
+ return fail(String((e && e.message) || e));
101
+ }
102
+ const destAbs = path.join(project, destRel);
103
+ if (!path.resolve(destAbs).startsWith(path.resolve(project) + path.sep)) {
104
+ return fail("credential destination must stay inside the project");
105
+ }
106
+ if (fs.existsSync(destAbs) && !f.force) return fail(`credential destination already exists: ${destRel} (use --force to replace)`);
107
+
108
+ fs.mkdirSync(path.dirname(destAbs), { recursive: true });
109
+ fs.copyFileSync(sourceAbs, destAbs);
110
+ try { fs.chmodSync(destAbs, 0o600); } catch { /* best-effort */ }
111
+
112
+ const targets = [destRel];
113
+ if (envKey) {
114
+ try { upsertEnvLine(path.join(project, ".env"), envKey, destRel); targets.push("project .env"); }
115
+ catch (e) { ctx.err(".env write failed: " + e.message); }
116
+ const scopedKey = projectScopedGlobalEnvKeyCli(project, envKey);
117
+ try { upsertEnvLine(path.join(userDataDir(), "credentials.env"), scopedKey, destAbs); targets.push("global project env"); } catch { /* best-effort */ }
118
+ try { upsertEnvLine(path.join(os.homedir(), ".agentlas", "credentials.env"), scopedKey, destAbs); } catch { /* best-effort */ }
119
+ }
120
+
121
+ upsertLocalCredentialMapCli(project, projectName, arch, {
122
+ id: typeof f.id === "string" && f.id ? f.id : `${provider}:${envKey || destRel}`,
123
+ provider,
124
+ env: envKey ? [envKey] : [],
125
+ localFiles: [destRel],
126
+ owner: "project",
127
+ valueMaterialized: true,
128
+ storage: envKey ? ["project_file", "project_env", "global_project_env"] : ["project_file"],
129
+ requiredFor: typeof f.requiredFor === "string" && f.requiredFor ? [f.requiredFor] : [],
130
+ staleCheck: typeof f.staleCheck === "string" && f.staleCheck ? f.staleCheck : "Validate access before release or deploy.",
131
+ });
132
+
133
+ ctx.out(`✓ saved credential file for ${provider} — ${targets.join(", ")}.`);
134
+ return 0;
135
+ }
136
+
137
+ async function run(ctx, args) {
138
+ const fail = (msg) => { ctx.err(msg); return 1; };
139
+ const sub = args[0];
140
+ if (sub === "file") return cmdCredsFile(ctx, args.slice(1));
141
+ if (sub !== "save") {
142
+ return fail('usage: agentlas creds save --provider <name> --key <ENV_NAME> --value <value> [--project <path>] OR agentlas creds file --source <path> [--env <ENV_NAME>]');
143
+ }
144
+ const f = parseCredFlags(args.slice(1));
145
+ const key = typeof f.key === "string" ? f.key.trim() : "";
146
+ const value = f.value === undefined || f.value === true ? "" : String(f.value);
147
+ if (!key || !value) return fail("creds save requires --key and --value");
148
+ const provider = typeof f.provider === "string" && f.provider ? f.provider : key;
149
+ const project = typeof f.project === "string" && f.project ? f.project : activeProjectPath(ctx.db());
150
+ const targets = [];
151
+ const arch = loadArch();
152
+ const projectName = project ? path.basename(project) || "Project" : "Project";
153
+ if (project) {
154
+ ensureLocalCredentialStoreCli(project, projectName, arch);
155
+ ensureSoulCredentialIndexCli(project, projectName, arch);
156
+ }
157
+
158
+ // 1) keychain vault — project-scoped when a project is active.
159
+ // standalone(비-Electron)에서는 키체인 쓰기가 프롬프트로 멈출 수 있어 건너뛴다;
160
+ // 값은 아래 .env/credentials.env 파일에 저장되므로 런타임 주입에 지장 없다.
161
+ const keytar = isElectronRuntime() ? readKeytar() : null;
162
+ if (keytar) {
163
+ const vaultKey = project ? projectScopedGlobalEnvKeyCli(project, key) : key;
164
+ try { await keytar.setPassword(SERVICE, ENV_PREFIX + vaultKey, value); targets.push(project ? "project vault" : "vault"); }
165
+ catch (e) { ctx.err("vault save failed: " + e.message); }
166
+ }
167
+ // 2) 프로젝트 .env (평문)
168
+ if (project) {
169
+ try { upsertEnvLine(path.join(project, ".env"), key, value); targets.push("project .env"); }
170
+ catch (e) { ctx.err(".env write failed: " + e.message); }
171
+ // 3) 프로젝트 메모리 노트 (.agentlas/project-soul-memory.md) — 값 자체는 .env/vault에, 여기엔 사실만
172
+ try {
173
+ const soulDir = path.join(project, ".agentlas");
174
+ fs.mkdirSync(soulDir, { recursive: true });
175
+ fs.appendFileSync(
176
+ path.join(soulDir, "project-soul-memory.md"),
177
+ `\n- Connected ${provider}: ${key} saved in local credential store during first setup.\n`,
178
+ "utf8",
179
+ );
180
+ } catch { /* best-effort */ }
181
+ try {
182
+ upsertLocalCredentialMapCli(project, projectName, arch, {
183
+ id: `${provider}:${key}`,
184
+ provider,
185
+ env: [key],
186
+ localFiles: [],
187
+ owner: "project",
188
+ valueMaterialized: true,
189
+ storage: ["project_env", "project_vault", "global_project_env"],
190
+ staleCheck: "Validate access before release or deploy.",
191
+ });
192
+ } catch { /* best-effort */ }
193
+ }
194
+ // 4) 전역 로컬 env — 프로젝트가 있으면 프로젝트 이름이 붙은 키로 저장
195
+ const globalKey = project ? projectScopedGlobalEnvKeyCli(project, key) : key;
196
+ try { upsertEnvLine(path.join(userDataDir(), "credentials.env"), globalKey, value); targets.push(project ? "global project env" : "global memory"); } catch { /* best-effort */ }
197
+ try { upsertEnvLine(path.join(os.homedir(), ".agentlas", "credentials.env"), globalKey, value); } catch { /* best-effort */ }
198
+
199
+ ctx.out(`✓ connected ${provider} — saved ${key} to ${targets.join(", ") || "(nowhere — check keytar)"}.`);
200
+ return 0;
201
+ }
202
+
203
+ module.exports = { run, resolveCredentialSourcePath };