agentlas 1.0.28 → 1.0.35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +102 -0
- package/README.md +5 -2
- package/bin/agentlas.cjs +15 -0
- package/engine/agentlas-cloud-runtime.cjs +54 -4
- package/engine/agentlas-i18n.cjs +4 -4
- package/engine/agentlas-input.cjs +10 -3
- package/engine/agentlas-judgment.cjs +0 -0
- package/engine/agentlas-native-host.cjs +69 -4
- package/engine/agentlas-onboard.cjs +20 -0
- package/engine/agentlas-ui.cjs +2 -0
- package/engine/agentlas-workforce.cjs +69 -13
- package/engine/agentlas.cjs +71 -3
- package/engine/agents/builder.cjs +84 -0
- package/engine/agents/router.cjs +8 -2
- package/engine/automation/launchd.cjs +131 -0
- package/engine/bootstrap-schema.sql +6 -44
- package/engine/browser/cdp.cjs +188 -0
- package/engine/browser/vault.cjs +124 -0
- package/engine/cli-output.cjs +262 -0
- package/engine/cloud-assets/package.cjs +5 -1
- package/engine/commands/automation.cjs +37 -1
- package/engine/commands/billing.cjs +3 -0
- package/engine/commands/browser.cjs +166 -8
- package/engine/commands/build.cjs +101 -20
- package/engine/commands/connect.cjs +162 -9
- package/engine/commands/creds.cjs +65 -3
- package/engine/commands/doctor.cjs +66 -4
- package/engine/commands/document.cjs +79 -0
- package/engine/commands/graph.cjs +1190 -0
- package/engine/commands/help.cjs +87 -9
- package/engine/commands/hep-cloud.cjs +9 -23
- package/engine/commands/hep-hub.cjs +9 -22
- package/engine/commands/hep-local.cjs +9 -24
- package/engine/commands/hep-network.cjs +9 -35
- package/engine/commands/index.cjs +50 -25
- package/engine/commands/list.cjs +10 -1
- package/engine/commands/mcp.cjs +6 -2
- package/engine/commands/native.cjs +18 -2
- package/engine/commands/plugin.cjs +22 -0
- package/engine/commands/project.cjs +79 -16
- package/engine/commands/roles.cjs +210 -0
- package/engine/commands/telegram.cjs +23 -16
- package/engine/commands/workforce.cjs +63 -12
- package/engine/core/desktop-core-fetch.cjs +98 -0
- package/engine/core/desktop-core.cjs +170 -0
- package/engine/graph/ask-model.cjs +159 -0
- package/engine/graph/interview.cjs +960 -0
- package/engine/graph/layout.cjs +139 -0
- package/engine/graph/package.cjs +223 -0
- package/engine/graph/vocabulary.generated.cjs +30 -0
- package/engine/hephaestus/local-core.cjs +159 -0
- package/engine/hephaestus/runtime.cjs +14 -10
- package/engine/project/controller.cjs +8 -8
- package/engine/project/team.cjs +99 -0
- package/engine/runtime-refusal.cjs +71 -0
- package/engine/runtimes/auth-evidence.cjs +78 -0
- package/engine/runtimes/detect.cjs +3 -0
- package/engine/runtimes/resolve.cjs +1 -1
- package/engine/sessions/prompt.cjs +16 -0
- package/engine/sessions/session.cjs +24 -2
- package/engine/telegram/connect.cjs +202 -0
- package/engine/tools/access-notice.cjs +86 -0
- package/engine/ui/palette.cjs +7 -3
- package/engine/ui/repl.cjs +120 -3
- package/engine/vendor/desktop-core.manifest.json +7 -0
- package/engine/workforce/capture.cjs +51 -1
- package/engine/workforce/deps.cjs +13 -0
- package/engine/workforce/local-core-transport.cjs +298 -0
- package/package.json +4 -2
- package/engine/commands/legacy-network.cjs +0 -29
|
@@ -9,6 +9,7 @@ const fs = require("node:fs");
|
|
|
9
9
|
const path = require("node:path");
|
|
10
10
|
const { dbPath, userDataDir } = require("../core/paths.cjs");
|
|
11
11
|
const { listAvailableCliRuntimes, activeRuntimeRow } = require("../runtimes/detect.cjs");
|
|
12
|
+
const { runtimeAuthEvidence } = require("../runtimes/auth-evidence.cjs");
|
|
12
13
|
const { resolvedModelRole } = require("../runtimes/roles.cjs");
|
|
13
14
|
|
|
14
15
|
function roleDetail(selection, role, en) {
|
|
@@ -23,11 +24,32 @@ function roleDetail(selection, role, en) {
|
|
|
23
24
|
].filter(Boolean).join(" · ");
|
|
24
25
|
}
|
|
25
26
|
|
|
26
|
-
function run(ctx) {
|
|
27
|
+
function run(ctx, args = []) {
|
|
27
28
|
const en = ctx.lang === "en";
|
|
29
|
+
// clig.dev: 스크립트 소비자를 위한 기계 계약. 사람용 줄과 같은 사실만 담는다.
|
|
30
|
+
if (args.includes("--json")) {
|
|
31
|
+
const db = ctx.db();
|
|
32
|
+
const clis = listAvailableCliRuntimes().map((c) => ({ kind: c.kind, path: c.path, authEvidence: runtimeAuthEvidence(c.kind).status }));
|
|
33
|
+
const active = activeRuntimeRow(db);
|
|
34
|
+
return (() => {
|
|
35
|
+
ctx.out(JSON.stringify({
|
|
36
|
+
database: { path: dbPath(), exists: fs.existsSync(dbPath()) },
|
|
37
|
+
runtimes: clis,
|
|
38
|
+
activeRuntime: active ? { ...active, authEvidence: runtimeAuthEvidence(active.kind).status } : null,
|
|
39
|
+
modelRoles: {
|
|
40
|
+
orchestrator: resolvedModelRole(db, "orchestrator"),
|
|
41
|
+
worker: resolvedModelRole(db, "worker"),
|
|
42
|
+
},
|
|
43
|
+
cloudSession: Boolean(process.env.AGENTLAS_SESSION) || fs.existsSync(path.join(userDataDir(), "auth", "cli-session.v1.json")),
|
|
44
|
+
}, null, 2));
|
|
45
|
+
return 0;
|
|
46
|
+
})();
|
|
47
|
+
}
|
|
28
48
|
let failures = 0;
|
|
49
|
+
let warnings = 0;
|
|
29
50
|
const ok = (label, detail) => ctx.out(` ${ctx.ui.green("✓")} ${label}${detail ? ctx.ui.dim(" — " + detail) : ""}`);
|
|
30
51
|
const bad = (label, detail) => { failures += 1; ctx.out(` ${ctx.ui.red("✗")} ${label}${detail ? ctx.ui.dim(" — " + detail) : ""}`); };
|
|
52
|
+
const warn = (label, detail) => { warnings += 1; ctx.out(` ${ctx.ui.yellow ? ctx.ui.yellow("!") : "!"} ${label}${detail ? ctx.ui.dim(" — " + detail) : ""}`); };
|
|
31
53
|
|
|
32
54
|
// 1) 데이터
|
|
33
55
|
const p = dbPath();
|
|
@@ -43,10 +65,28 @@ function run(ctx) {
|
|
|
43
65
|
bad(en ? "database" : "데이터베이스", (en ? "missing: " : "없음: ") + p);
|
|
44
66
|
}
|
|
45
67
|
|
|
46
|
-
// 2) 런타임
|
|
68
|
+
// 2) 런타임 — 설치 여부와 인증 흔적은 다른 축이다. which()만 보면 로그아웃
|
|
69
|
+
// 상태에서도 all clear가 나간다(2026-08-05 실측). 각 CLI가 로그인 시 남기는
|
|
70
|
+
// 로컬 산출물을 증거로 관측하고, 증거≠증명이므로 문구도 단정하지 않는다.
|
|
47
71
|
const clis = listAvailableCliRuntimes();
|
|
48
72
|
if (clis.length) {
|
|
49
|
-
|
|
73
|
+
const evidences = clis.map((c) => ({ kind: c.kind, evidence: runtimeAuthEvidence(c.kind) }));
|
|
74
|
+
const annotated = evidences.map(({ kind, evidence }) => {
|
|
75
|
+
if (evidence.status === "none") return `${kind}(${en ? "no sign-in evidence" : "로그인 흔적 없음"})`;
|
|
76
|
+
return kind; // evidence 또는 unknown — 검사법이 없는 런타임을 미로그인으로 표시하지 않는다
|
|
77
|
+
});
|
|
78
|
+
ok(en ? "runtimes" : "런타임", annotated.join(", "));
|
|
79
|
+
// 신규 설치 상태: 검사 가능한 런타임 전부가 흔적 없음이면 첫 실행이 거의
|
|
80
|
+
// 확실히 실패한다 — 활성 런타임 행이 아직 없어도 여기서 경고한다.
|
|
81
|
+
const checkable = evidences.filter(({ evidence }) => evidence.status !== "unknown");
|
|
82
|
+
if (checkable.length && checkable.every(({ evidence }) => evidence.status === "none")) {
|
|
83
|
+
warn(
|
|
84
|
+
en ? "runtime sign-in" : "런타임 로그인",
|
|
85
|
+
en
|
|
86
|
+
? "no detected runtime has local sign-in evidence — sign in to one before running (e.g. claude / codex login / gemini)"
|
|
87
|
+
: "감지된 어떤 런타임에도 로그인 흔적이 없습니다 — 실행 전에 하나는 로그인하세요 (예: claude / codex login / gemini)",
|
|
88
|
+
);
|
|
89
|
+
}
|
|
50
90
|
} else {
|
|
51
91
|
bad(en ? "runtimes" : "런타임", en
|
|
52
92
|
? "no agent CLI on PATH (claude / codex / gemini / kimi / grok / cursor-agent)"
|
|
@@ -57,7 +97,23 @@ function run(ctx) {
|
|
|
57
97
|
try {
|
|
58
98
|
const db = ctx.db();
|
|
59
99
|
const active = activeRuntimeRow(db);
|
|
60
|
-
if (active)
|
|
100
|
+
if (active) {
|
|
101
|
+
const detail = `${active.kind}${active.model ? ` (${active.model})` : ""}`;
|
|
102
|
+
// 활성 런타임은 모든 실행이 지나는 문이다 — 로그인 흔적이 없으면 all clear
|
|
103
|
+
// 가 아니라 경고다. 흔적 없음 = 미로그인 "가능성"이므로 단정하지 않는다.
|
|
104
|
+
const evidence = runtimeAuthEvidence(active.kind);
|
|
105
|
+
if (evidence.status === "none") {
|
|
106
|
+
const bin = { "claude-code": "claude", codex: "codex", gemini: "gemini" }[active.kind] || active.kind;
|
|
107
|
+
warn(
|
|
108
|
+
en ? "active runtime" : "활성 런타임",
|
|
109
|
+
en
|
|
110
|
+
? `${detail} — no local sign-in evidence; runs may fail until you sign in (try: ${bin} login)`
|
|
111
|
+
: `${detail} — 로그인 흔적이 없습니다. 로그인 전에는 실행이 실패할 수 있습니다 (시도: ${bin} login)`,
|
|
112
|
+
);
|
|
113
|
+
} else {
|
|
114
|
+
ok(en ? "active runtime" : "활성 런타임", detail);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
61
117
|
const orchestrator = resolvedModelRole(db, "orchestrator");
|
|
62
118
|
const worker = resolvedModelRole(db, "worker");
|
|
63
119
|
if (orchestrator && worker) {
|
|
@@ -83,6 +139,12 @@ function run(ctx) {
|
|
|
83
139
|
ctx.out(en ? `doctor: ${failures} problem(s) found` : `doctor: 문제 ${failures}건`);
|
|
84
140
|
return 1;
|
|
85
141
|
}
|
|
142
|
+
if (warnings) {
|
|
143
|
+
// 경고가 있으면 "이상 없음"이라고 말하지 않는다 — 그 문구가 첫 실행 실패를
|
|
144
|
+
// 배신으로 만든다. 경고는 실행을 막지 않으므로 exit 0.
|
|
145
|
+
ctx.out(en ? `doctor: ${warnings} warning(s) — runnable, but check the lines above` : `doctor: 경고 ${warnings}건 — 실행은 가능하나 위 항목을 확인하세요`);
|
|
146
|
+
return 0;
|
|
147
|
+
}
|
|
86
148
|
ctx.out(en ? "doctor: all clear" : "doctor: 이상 없음");
|
|
87
149
|
return 0;
|
|
88
150
|
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* document — 문서 산출(2026-08-06). 지금은 PDF 내보내기.
|
|
4
|
+
*
|
|
5
|
+
* 오너 원칙("터미널인데 모든 기능이 다 돼야"): 데스크탑 document/export-pdf.ts 는 offscreen
|
|
6
|
+
* BrowserWindow.printToPDF 로 HTML/URL 을 PDF 로 굽는다. 터미널은 같은 메커니즘을 CDP
|
|
7
|
+
* Page.printToPDF(engine/browser/cdp.cjs)로 한다 — GUI 창 없이 Agentlas 전용 Chrome 에서.
|
|
8
|
+
*
|
|
9
|
+
* document pdf <html-file|url> [-o out.pdf] [--landscape]
|
|
10
|
+
*
|
|
11
|
+
* 로컬 HTML 파일은 file:// 로, http(s) 는 그대로 연다. 브라우저(CDP)가 없으면 정직하게
|
|
12
|
+
* 멈추고 먼저 띄우도록 안내한다(조용히 안 되는 척하지 않는다).
|
|
13
|
+
*/
|
|
14
|
+
const path = require("node:path");
|
|
15
|
+
const fs = require("node:fs");
|
|
16
|
+
const cdp = require("../browser/cdp.cjs");
|
|
17
|
+
|
|
18
|
+
function usage(ko) {
|
|
19
|
+
return ko
|
|
20
|
+
? "사용법: agentlas document pdf <html파일|url> [-o 출력.pdf] [--landscape]"
|
|
21
|
+
: "Usage: agentlas document pdf <html-file|url> [-o out.pdf] [--landscape]";
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function toUrl(src) {
|
|
25
|
+
if (/^[a-z][a-z0-9+.-]*:\/\//i.test(src)) return src; // http(s):// · file:// · data:
|
|
26
|
+
return "file://" + path.resolve(src); // 로컬 파일
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async function toPdf(ctx, args) {
|
|
30
|
+
const ko = ctx.lang === "ko";
|
|
31
|
+
const flags = { landscape: args.includes("--landscape") };
|
|
32
|
+
const oi = args.indexOf("-o");
|
|
33
|
+
const out = oi >= 0 && args[oi + 1] ? args[oi + 1] : null;
|
|
34
|
+
const src = args.find((a, i) => a && !String(a).startsWith("-") && (oi < 0 || i !== oi + 1));
|
|
35
|
+
if (!src) { ctx.err(usage(ko)); return 1; }
|
|
36
|
+
|
|
37
|
+
// 로컬 파일이면 존재 확인(없는 걸 조용히 빈 PDF 로 굽지 않는다).
|
|
38
|
+
if (!/^[a-z][a-z0-9+.-]*:\/\//i.test(src) && !fs.existsSync(path.resolve(src))) {
|
|
39
|
+
ctx.err((ko ? "파일이 없습니다: " : "no such file: ") + src);
|
|
40
|
+
return 1;
|
|
41
|
+
}
|
|
42
|
+
const url = toUrl(src);
|
|
43
|
+
const outPath = path.resolve(out || (src.replace(/^https?:\/\//, "").replace(/[^\w.-]+/g, "_").replace(/\.(html?|md)$/i, "") || "document") + ".pdf");
|
|
44
|
+
|
|
45
|
+
if (!(await cdp.cdpReady())) {
|
|
46
|
+
ctx.err(ko
|
|
47
|
+
? `Agentlas 브라우저가 실행 중이 아닙니다. 먼저 띄우세요: agentlas browser ${url}`
|
|
48
|
+
: `The Agentlas browser is not running. Start it first: agentlas browser ${url}`);
|
|
49
|
+
return 1;
|
|
50
|
+
}
|
|
51
|
+
let page;
|
|
52
|
+
try {
|
|
53
|
+
if (typeof ctx.ui.startSpinner === "function") ctx.ui.startSpinner(ko ? "PDF 굽는 중…" : "Rendering PDF…");
|
|
54
|
+
page = await cdp.attachPage();
|
|
55
|
+
await page.navigate(url, { waitMs: 1800 });
|
|
56
|
+
await page.waitFor("document.readyState === 'complete'", { timeoutMs: 8000 });
|
|
57
|
+
const r = await page.printPdf(outPath, { landscape: flags.landscape });
|
|
58
|
+
if (typeof ctx.ui.stopSpinner === "function") ctx.ui.stopSpinner();
|
|
59
|
+
ctx.out(`${ctx.ui.green("✓")} ${ko ? "PDF 를 만들었습니다" : "wrote PDF"}: ${r.path} ${ctx.ui.dim(`(${Math.round(r.bytes / 1024)} KB)`)}`);
|
|
60
|
+
return 0;
|
|
61
|
+
} catch (e) {
|
|
62
|
+
if (typeof ctx.ui.stopSpinner === "function") ctx.ui.stopSpinner();
|
|
63
|
+
ctx.err(`${ctx.ui.red("✖")} ${String((e && e.message) || e)}`);
|
|
64
|
+
return 1;
|
|
65
|
+
} finally {
|
|
66
|
+
if (page) page.close();
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async function run(ctx, args) {
|
|
71
|
+
const ko = ctx.lang === "ko";
|
|
72
|
+
const sub = String(args[0] || "").toLowerCase();
|
|
73
|
+
if (!sub || sub === "help" || sub === "-h" || sub === "--help") { ctx.out(usage(ko)); return 0; }
|
|
74
|
+
if (sub === "pdf") return toPdf(ctx, args.slice(1));
|
|
75
|
+
ctx.err(usage(ko));
|
|
76
|
+
return 1;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
module.exports = { run };
|