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.
- package/CHANGELOG.md +78 -0
- package/README.md +6 -4
- package/bin/agentlas.cjs +341 -16
- package/engine/acp/server.cjs +27 -1
- package/engine/agentlas-api-agent.cjs +151 -120
- package/engine/agentlas-banner.cjs +6 -2
- package/engine/agentlas-capabilities.cjs +17 -10
- package/engine/agentlas-cloud-runtime.cjs +4 -5
- package/engine/agentlas-config.cjs +19 -54
- package/engine/agentlas-core-harness.cjs +59 -5
- package/engine/agentlas-desktop-loadout.cjs +17 -3
- package/engine/agentlas-evolution.cjs +75 -18
- package/engine/agentlas-experience-exchange.cjs +145 -14
- package/engine/agentlas-experience-intake.cjs +2 -2
- package/engine/agentlas-i18n.cjs +0 -2
- package/engine/agentlas-input.cjs +273 -20
- package/engine/agentlas-judgment.cjs +0 -0
- package/engine/agentlas-mcp-env.cjs +84 -23
- package/engine/agentlas-mcp-wrapper.cjs +36 -4
- package/engine/agentlas-memory-governance.cjs +2 -1
- package/engine/agentlas-memory-import.cjs +49 -12
- package/engine/agentlas-native-host.cjs +279 -44
- package/engine/agentlas-onboard.cjs +23 -1
- package/engine/agentlas-permissions.cjs +5 -1
- package/engine/agentlas-sqlite-policy.cjs +40 -2
- package/engine/agentlas-tasks.cjs +7 -0
- package/engine/agentlas-tools.cjs +37 -10
- package/engine/agentlas-ui.cjs +26 -4
- package/engine/agentlas-workforce.cjs +29 -5
- package/engine/agentlas-workload-routing.cjs +83 -10
- package/engine/agentlas.cjs +10 -3
- package/engine/agents/builder.cjs +35 -10
- package/engine/agents/files.cjs +81 -10
- package/engine/agents/import-local.cjs +10 -2
- package/engine/agents/registry.cjs +10 -3
- package/engine/agents/router.cjs +7 -7
- package/engine/agents/routes.cjs +31 -9
- package/engine/automation/daemon.cjs +154 -40
- package/engine/automation/launchd.cjs +395 -16
- package/engine/automation/schedule.cjs +90 -3
- package/engine/automation/store.cjs +163 -59
- package/engine/browser/cdp.cjs +190 -17
- package/engine/browser/vault.cjs +1 -0
- package/engine/cli-output.cjs +80 -28
- package/engine/cloud/auth.cjs +131 -13
- package/engine/cloud/hub-client.cjs +41 -16
- package/engine/cloud-assets/cas.cjs +18 -9
- package/engine/cloud-assets/commands.cjs +108 -30
- package/engine/cloud-assets/package.cjs +66 -3
- package/engine/cloud-assets/restore.cjs +12 -9
- package/engine/cloud-assets/state.cjs +308 -113
- package/engine/commands/acp.cjs +13 -2
- package/engine/commands/automation.cjs +75 -24
- package/engine/commands/billing.cjs +6 -1
- package/engine/commands/browser.cjs +61 -29
- package/engine/commands/build.cjs +42 -12
- package/engine/commands/call.cjs +1 -1
- package/engine/commands/cd.cjs +1 -1
- package/engine/commands/cloud.cjs +2 -1
- package/engine/commands/connect.cjs +38 -13
- package/engine/commands/creds.cjs +74 -29
- package/engine/commands/doctor.cjs +17 -1
- package/engine/commands/document.cjs +38 -10
- package/engine/commands/env.cjs +6 -1
- package/engine/commands/firm.cjs +42 -12
- package/engine/commands/graph.cjs +36 -32
- package/engine/commands/help.cjs +11 -1
- package/engine/commands/hep.cjs +1 -1
- package/engine/commands/import.cjs +5 -4
- package/engine/commands/index.cjs +1 -1
- package/engine/commands/install.cjs +6 -4
- package/engine/commands/list.cjs +56 -16
- package/engine/commands/login.cjs +5 -0
- package/engine/commands/logout.cjs +6 -1
- package/engine/commands/mcp.cjs +8 -2
- package/engine/commands/memory.cjs +3 -2
- package/engine/commands/multimodal.cjs +12 -0
- package/engine/commands/native.cjs +5 -1
- package/engine/commands/one.cjs +78 -33
- package/engine/commands/plugin.cjs +13 -2
- package/engine/commands/project.cjs +15 -12
- package/engine/commands/research.cjs +18 -7
- package/engine/commands/roles.cjs +104 -28
- package/engine/commands/route.cjs +2 -2
- package/engine/commands/run.cjs +42 -9
- package/engine/commands/search.cjs +23 -2
- package/engine/commands/setup.cjs +6 -1
- package/engine/commands/storm.cjs +44 -6
- package/engine/commands/swarm.cjs +47 -9
- package/engine/commands/telegram.cjs +6 -1
- package/engine/commands/uninstall.cjs +12 -6
- package/engine/commands/update.cjs +5 -0
- package/engine/commands/upload.cjs +2 -1
- package/engine/commands/usage.cjs +6 -1
- package/engine/commands/version.cjs +6 -1
- package/engine/commands/whoami.cjs +6 -1
- package/engine/commands/workforce.cjs +60 -16
- package/engine/core/capability-grants.cjs +7 -2
- package/engine/core/daemon-client.cjs +36 -7
- package/engine/core/db.cjs +10 -2
- package/engine/core/desktop-core-fetch.cjs +477 -77
- package/engine/core/schema-ensure.cjs +23 -11
- package/engine/experience/build.cjs +5 -1
- package/engine/experience/intents.cjs +29 -82
- package/engine/experience/runtime.cjs +7 -1
- package/engine/experience/variant.cjs +58 -4
- package/engine/firms/orchestrate.cjs +9 -6
- package/engine/graph/ask-model.cjs +22 -11
- package/engine/graph/interview.cjs +74 -23
- package/engine/graph/package.cjs +63 -8
- package/engine/hephaestus/local-core.cjs +18 -5
- package/engine/hephaestus/runtime.cjs +48 -43
- package/engine/hub/install.cjs +230 -61
- package/engine/hub/plugins.cjs +391 -29
- package/engine/mcp/consent.cjs +25 -17
- package/engine/mcp/contract.cjs +229 -24
- package/engine/mcp/inventory.cjs +15 -5
- package/engine/mcp/plan.cjs +5 -1
- package/engine/mcp/probe.cjs +24 -9
- package/engine/memory-cli/curate.cjs +74 -16
- package/engine/oberon/common.cjs +37 -12
- package/engine/oberon/manifest.cjs +25 -2
- package/engine/oberon/outputs.cjs +49 -19
- package/engine/oberon/render.cjs +665 -40
- package/engine/project/career-graph.cjs +15 -2
- package/engine/project/controller.cjs +133 -15
- package/engine/project/credentials.cjs +212 -34
- package/engine/project/env-file.cjs +93 -8
- package/engine/project/memory-context.cjs +11 -57
- package/engine/project/ontology.cjs +66 -25
- package/engine/project/paths.cjs +42 -8
- package/engine/project/seed.cjs +88 -51
- package/engine/project/state.cjs +41 -16
- package/engine/project/team.cjs +26 -1
- package/engine/runtime-refusal.cjs +4 -1
- package/engine/runtimes/acp-driver.cjs +56 -9
- package/engine/runtimes/auth-evidence.cjs +21 -2
- package/engine/runtimes/detect.cjs +28 -8
- package/engine/runtimes/kinds.cjs +12 -4
- package/engine/runtimes/overrides.cjs +4 -3
- package/engine/runtimes/resolve.cjs +8 -7
- package/engine/runtimes/roles.cjs +7 -5
- package/engine/sessions/apply-fences.cjs +396 -56
- package/engine/sessions/fences.cjs +111 -27
- package/engine/sessions/memory-turn.cjs +62 -3
- package/engine/sessions/orchestrator.cjs +11 -1
- package/engine/sessions/prompt.cjs +66 -9
- package/engine/sessions/session.cjs +70 -10
- package/engine/sessions/sink.cjs +78 -12
- package/engine/sessions/store.cjs +29 -7
- package/engine/storm/storm.cjs +26 -3
- package/engine/storm/swarm.cjs +31 -3
- package/engine/telegram/connect.cjs +185 -22
- package/engine/ui/commands-catalog.cjs +1 -1
- package/engine/ui/palette.cjs +12 -2
- package/engine/ui/repl.cjs +57 -9
- package/engine/ui/screens.cjs +2 -4
- package/engine/vendor/desktop-core.manifest.json +5 -5
- package/engine/workforce/capture.cjs +9 -27
- package/engine/workforce/deps.cjs +18 -6
- package/engine/workforce/local-core-transport.cjs +68 -5
- package/package.json +1 -1
- package/engine/commands/career-graph.cjs +0 -51
package/engine/commands/list.cjs
CHANGED
|
@@ -7,6 +7,10 @@
|
|
|
7
7
|
const { activeRuntimeRow, listAvailableCliRuntimes } = require("../runtimes/detect.cjs");
|
|
8
8
|
const { resolvedModelRole } = require("../runtimes/roles.cjs");
|
|
9
9
|
const { listAgents } = require("../agents/registry.cjs");
|
|
10
|
+
const { render, single } = require("../cli-output.cjs");
|
|
11
|
+
|
|
12
|
+
const LIST_OUTPUT_SCHEMA = Object.freeze({ idField: "slug", columns: [] });
|
|
13
|
+
const LIST_OUTPUT_FLAGS = new Set(["--json", "--yaml", "--quiet", "-q", "--no-headers", "--no-color"]);
|
|
10
14
|
|
|
11
15
|
function roleRuntimeLabel(selection, role, en) {
|
|
12
16
|
if (!selection) return en ? "(not set)" : "(미설정)";
|
|
@@ -25,6 +29,12 @@ function roleRuntimeLabel(selection, role, en) {
|
|
|
25
29
|
}
|
|
26
30
|
|
|
27
31
|
function run(ctx, args = []) {
|
|
32
|
+
const invalidArgs = args.filter((arg) => !LIST_OUTPUT_FLAGS.has(arg));
|
|
33
|
+
if (invalidArgs.length) {
|
|
34
|
+
const error = new Error(`Usage: agentlas list [--json|--yaml|--quiet|--no-headers|--no-color]. Unknown argument: ${invalidArgs[0]}`);
|
|
35
|
+
error.code = "INVALID_ARGUMENT";
|
|
36
|
+
throw error;
|
|
37
|
+
}
|
|
28
38
|
const db = ctx.db();
|
|
29
39
|
// 프라이버시 정책(웹 전용/백그라운드 제외)은 registry가 소유한다 — 직접 SQL 금지.
|
|
30
40
|
const agents = listAgents(db).map((a) => ({
|
|
@@ -33,18 +43,40 @@ function run(ctx, args = []) {
|
|
|
33
43
|
const firms = ctx.tableExists(db, "firms")
|
|
34
44
|
? db.prepare("SELECT id, slug, name FROM firms ORDER BY name").all()
|
|
35
45
|
: [];
|
|
46
|
+
const output = ctx.output || {};
|
|
47
|
+
let format = output.format || "table";
|
|
48
|
+
for (const arg of args) {
|
|
49
|
+
if (arg === "--json") format = "json";
|
|
50
|
+
if (arg === "--yaml") format = "yaml";
|
|
51
|
+
}
|
|
52
|
+
const quiet = Boolean(output.quiet) || args.includes("--quiet") || args.includes("-q");
|
|
53
|
+
const noHeaders = Boolean(output.noHeaders) || args.includes("--no-headers");
|
|
54
|
+
const noColor = Boolean(output.noColor) || args.includes("--no-color");
|
|
55
|
+
const payload = () => ({
|
|
56
|
+
agents,
|
|
57
|
+
firms,
|
|
58
|
+
modelRoles: {
|
|
59
|
+
orchestrator: resolvedModelRole(db, "orchestrator"),
|
|
60
|
+
worker: resolvedModelRole(db, "worker"),
|
|
61
|
+
multimodal: resolvedModelRole(db, "multimodal"),
|
|
62
|
+
},
|
|
63
|
+
});
|
|
36
64
|
|
|
37
|
-
// clig.dev: 스크립트 소비자는 사람용 표를 파싱하게 두지 말 것 —
|
|
38
|
-
//
|
|
39
|
-
if (
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
65
|
+
// clig.dev: 스크립트 소비자는 사람용 표를 파싱하게 두지 말 것 — 공통 출력
|
|
66
|
+
// renderer가 quiet 우선과 JSON/YAML 형식을 한 곳에서 해석한다.
|
|
67
|
+
if (quiet) {
|
|
68
|
+
const ids = agents.map((agent) => agent.slug).concat(firms.map((firm) => firm.slug || firm.id));
|
|
69
|
+
if (ids.length) ctx.out(ids.join("\n"));
|
|
70
|
+
return 0;
|
|
71
|
+
}
|
|
72
|
+
if (format === "json" || format === "yaml") {
|
|
73
|
+
ctx.out(render(single(payload(), LIST_OUTPUT_SCHEMA), { ...output, format, quiet: false }));
|
|
43
74
|
return 0;
|
|
44
75
|
}
|
|
45
76
|
|
|
46
77
|
const en = ctx.lang === "en";
|
|
47
|
-
|
|
78
|
+
const paint = (name, value) => noColor ? String(value) : ctx.ui[name](value);
|
|
79
|
+
if (!noHeaders) ctx.out(paint("bold", en ? "Installed agents" : "설치된 에이전트"));
|
|
48
80
|
if (!agents.length) {
|
|
49
81
|
ctx.out(" " + (en ? "(none yet — try: agentlas search \"what you need\")" : " (아직 없음 — agentlas search \"필요한 것\" 으로 찾아보세요)"));
|
|
50
82
|
}
|
|
@@ -104,31 +136,39 @@ function run(ctx, args = []) {
|
|
|
104
136
|
// 2 indent + slug + space + name + " — " + tagline must fit one line.
|
|
105
137
|
const budget = Math.max(20, cols - (2 + slugWidth + 1 + displayWidth(name) + 3));
|
|
106
138
|
const shown = tag ? clampTag(tag, budget) : "";
|
|
107
|
-
ctx.out(` ${
|
|
139
|
+
ctx.out(` ${paint("accent", clampSlug(a.slug))} ${name}${shown ? paint("dim", " — " + shown) : ""}`);
|
|
108
140
|
}
|
|
109
141
|
if (firms.length) {
|
|
110
|
-
|
|
111
|
-
|
|
142
|
+
if (!noHeaders) {
|
|
143
|
+
ctx.out("");
|
|
144
|
+
ctx.out(paint("bold", en ? "Companies" : "회사"));
|
|
145
|
+
}
|
|
112
146
|
for (const f of firms) {
|
|
113
147
|
const callable = String(f.slug || f.id);
|
|
114
|
-
ctx.out(` ${
|
|
148
|
+
ctx.out(` ${paint("accent", callable.padEnd(28))} ${f.name}`);
|
|
115
149
|
}
|
|
116
|
-
ctx.out(
|
|
150
|
+
ctx.out(paint("dim", en
|
|
117
151
|
? " Run one with: agentlas firm <company-key> \"<task>\""
|
|
118
152
|
: " 실행: agentlas firm <회사 키> \"<작업>\""));
|
|
119
153
|
}
|
|
120
154
|
|
|
121
155
|
const active = activeRuntimeRow(db);
|
|
122
156
|
const clis = listAvailableCliRuntimes();
|
|
123
|
-
|
|
124
|
-
|
|
157
|
+
if (!noHeaders) {
|
|
158
|
+
ctx.out("");
|
|
159
|
+
ctx.out(paint("bold", en ? "Model roles" : "모델 역할"));
|
|
160
|
+
}
|
|
125
161
|
const orchestrator = resolvedModelRole(db, "orchestrator");
|
|
126
162
|
const worker = resolvedModelRole(db, "worker");
|
|
163
|
+
const multimodal = resolvedModelRole(db, "multimodal");
|
|
127
164
|
ctx.out(` orchestrator: ${roleRuntimeLabel(orchestrator, "orchestrator", en)}`);
|
|
128
165
|
ctx.out(` worker: ${roleRuntimeLabel(worker, "worker", en)}`);
|
|
166
|
+
ctx.out(` multimodal: ${roleRuntimeLabel(multimodal, "multimodal", en)}`);
|
|
129
167
|
|
|
130
|
-
|
|
131
|
-
|
|
168
|
+
if (!noHeaders) {
|
|
169
|
+
ctx.out("");
|
|
170
|
+
ctx.out(paint("bold", en ? "Legacy runtime compatibility" : "레거시 런타임 호환"));
|
|
171
|
+
}
|
|
132
172
|
if (active) {
|
|
133
173
|
ctx.out(` active: ${active.kind}${active.model ? ` (${active.model})` : ""}${active.backend ? ` via ${active.backend}` : ""}`);
|
|
134
174
|
} else {
|
|
@@ -9,6 +9,11 @@ const auth = require("../cloud/auth.cjs");
|
|
|
9
9
|
|
|
10
10
|
async function run(ctx, args = []) {
|
|
11
11
|
const ko = ctx.lang === "ko";
|
|
12
|
+
if (args.some((arg) => arg !== "--force") || args.filter((arg) => arg === "--force").length > 1) {
|
|
13
|
+
const error = new Error("usage: agentlas login [--force]");
|
|
14
|
+
error.code = "INVALID_ARGUMENT";
|
|
15
|
+
throw error;
|
|
16
|
+
}
|
|
12
17
|
const force = args.includes("--force");
|
|
13
18
|
if (!force) {
|
|
14
19
|
const existing = auth.cloudSessionCookie();
|
|
@@ -5,8 +5,13 @@
|
|
|
5
5
|
*/
|
|
6
6
|
const auth = require("../cloud/auth.cjs");
|
|
7
7
|
|
|
8
|
-
function run(ctx) {
|
|
8
|
+
function run(ctx, args = []) {
|
|
9
9
|
const ko = ctx.lang === "ko";
|
|
10
|
+
if (args.length) {
|
|
11
|
+
const error = new Error("usage: agentlas logout");
|
|
12
|
+
error.code = "INVALID_ARGUMENT";
|
|
13
|
+
throw error;
|
|
14
|
+
}
|
|
10
15
|
let result;
|
|
11
16
|
try {
|
|
12
17
|
result = auth.deleteCliSession();
|
package/engine/commands/mcp.cjs
CHANGED
|
@@ -34,7 +34,7 @@ function list(ctx) {
|
|
|
34
34
|
async function probe(ctx, args) {
|
|
35
35
|
const en = ctx.lang === "en";
|
|
36
36
|
const ref = String(args[0] || "").trim();
|
|
37
|
-
if (!ref) {
|
|
37
|
+
if (!ref || args.length !== 1 || ref.startsWith("-")) {
|
|
38
38
|
ctx.err(en ? "Usage: agentlas mcp probe <server-id|catalog-id>" : "사용법: agentlas mcp probe <server-id|catalog-id>");
|
|
39
39
|
return 1;
|
|
40
40
|
}
|
|
@@ -83,7 +83,13 @@ function run(ctx, args = []) {
|
|
|
83
83
|
// 무인자 기본 동작이 목록인데 이름으로 부르면 거부되는 비대칭이 있었다
|
|
84
84
|
// (2026-08-05 감사 결함 G): 다른 명령들(cloud list, plugin list)이 만든
|
|
85
85
|
// "list를 붙이는" 습관이 여기서만 usage 오류가 됐다.
|
|
86
|
-
if (sub === "list" || sub === "ls")
|
|
86
|
+
if (sub === "list" || sub === "ls") {
|
|
87
|
+
if (rest.length) {
|
|
88
|
+
ctx.err(ctx.lang === "en" ? "Usage: agentlas mcp list" : "사용법: agentlas mcp list");
|
|
89
|
+
return 1;
|
|
90
|
+
}
|
|
91
|
+
return list(ctx);
|
|
92
|
+
}
|
|
87
93
|
if (sub === "probe") return probe(ctx, rest);
|
|
88
94
|
const en = ctx.lang === "en";
|
|
89
95
|
ctx.err(en
|
|
@@ -6,11 +6,12 @@
|
|
|
6
6
|
* engine/agentlas-memory-import.cjs 가 소유한다(여기서는 주입만).
|
|
7
7
|
* v1의 fail(process.exit)은 v2에서 throw 로 바꿔 엔진이 stderr+exit 1 처리한다.
|
|
8
8
|
*/
|
|
9
|
-
const { cmdMemory } = require("../agentlas-memory-import.cjs");
|
|
9
|
+
const { cmdMemory, parseMemoryArgs } = require("../agentlas-memory-import.cjs");
|
|
10
10
|
|
|
11
11
|
function run(ctx, args) {
|
|
12
|
+
const parsed = parseMemoryArgs(args);
|
|
12
13
|
cmdMemory({
|
|
13
|
-
db: ctx.db(),
|
|
14
|
+
db: parsed.help ? null : ctx.db(),
|
|
14
15
|
args,
|
|
15
16
|
out: ctx.out,
|
|
16
17
|
fail: (msg) => { throw new Error(String(msg ?? "")); },
|
|
@@ -51,6 +51,18 @@ function saveSettings(db, patch) {
|
|
|
51
51
|
|
|
52
52
|
function run(ctx, args) {
|
|
53
53
|
const ko = ctx.lang === "ko";
|
|
54
|
+
const usage = ko
|
|
55
|
+
? "사용법: agentlas multimodal [set <image|video|audio> <provider-id>]"
|
|
56
|
+
: "Usage: agentlas multimodal [set <image|video|audio> <provider-id>]";
|
|
57
|
+
if (args.length === 1 && ["help", "--help", "-h"].includes(args[0])) {
|
|
58
|
+
ctx.out(usage);
|
|
59
|
+
return 0;
|
|
60
|
+
}
|
|
61
|
+
if (args.length !== 0 && !(args.length === 3 && args[0] === "set")) {
|
|
62
|
+
const error = new Error(usage);
|
|
63
|
+
error.code = "INVALID_ARGUMENT";
|
|
64
|
+
throw error;
|
|
65
|
+
}
|
|
54
66
|
const db = ctx.db();
|
|
55
67
|
|
|
56
68
|
if (args[0] === "set") {
|
|
@@ -8,6 +8,10 @@ function run(ctx, args) {
|
|
|
8
8
|
const sub = String(args[0] || "help");
|
|
9
9
|
const query = args[1];
|
|
10
10
|
if (sub === "help" || sub === "--help" || sub === "-h") {
|
|
11
|
+
if (args.length > 1) {
|
|
12
|
+
ctx.err(ko ? "사용법: agentlas native help" : "usage: agentlas native help");
|
|
13
|
+
return 1;
|
|
14
|
+
}
|
|
11
15
|
// SELF_HELP_COMMANDS 계약: --help 는 스텁이 아니라 실제 안내여야 한다 —
|
|
12
16
|
// 무엇이 만들어지고 언제 필요한지까지 말한다.
|
|
13
17
|
ctx.out(ko
|
|
@@ -29,7 +33,7 @@ function run(ctx, args) {
|
|
|
29
33
|
].join("\n"));
|
|
30
34
|
return 0;
|
|
31
35
|
}
|
|
32
|
-
if (sub !== "prepare" || !query) {
|
|
36
|
+
if (sub !== "prepare" || !query || args.length !== 2) {
|
|
33
37
|
ctx.err(ko ? "사용법: agentlas native prepare <에이전트>" : "usage: agentlas native prepare <agent>");
|
|
34
38
|
return 1;
|
|
35
39
|
}
|
package/engine/commands/one.cjs
CHANGED
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
* agentlas one --list One 대화 목록
|
|
21
21
|
* agentlas one --new "<프롬프트>" 새 One 대화로 시작
|
|
22
22
|
* agentlas one --chat <id> "<p>" 특정 One 대화에 이어 붙임
|
|
23
|
+
* agentlas one -- "list 같은 옵션 모양의 프롬프트"
|
|
23
24
|
* 공통: -p/--print · --runtime · --model · --effort · --permission
|
|
24
25
|
*/
|
|
25
26
|
const readline = require("node:readline");
|
|
@@ -30,7 +31,7 @@ const { Renderer } = require("../ui/renderer.cjs");
|
|
|
30
31
|
const permissions = require("../agentlas-permissions.cjs");
|
|
31
32
|
const { EFFORTS } = require("../agentlas-workload-routing.cjs");
|
|
32
33
|
const { projectCwd } = require("../project/paths.cjs");
|
|
33
|
-
const {
|
|
34
|
+
const { runWriteTransaction } = require("../core/db.cjs");
|
|
34
35
|
const store = require("../sessions/store.cjs");
|
|
35
36
|
|
|
36
37
|
/** 데스크탑 정본 신원(electron/architecture/manifest.ts + builtinAgentId). */
|
|
@@ -45,13 +46,8 @@ const ONE_ORIGIN_SURFACE = "one";
|
|
|
45
46
|
* 걸러 낸다(설계). One 은 라우팅 후보가 아니라 **신원 행**이므로 직접 읽는다.
|
|
46
47
|
*/
|
|
47
48
|
function resolveOneAgent(db) {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
row = db.prepare("SELECT * FROM installed_agents WHERE id=?").get(ONE_AGENT_ID)
|
|
51
|
-
|| db.prepare("SELECT * FROM installed_agents WHERE slug=?").get(ONE_AGENT_SLUG);
|
|
52
|
-
} catch {
|
|
53
|
-
row = null;
|
|
54
|
-
}
|
|
49
|
+
const row = db.prepare("SELECT * FROM installed_agents WHERE id=?").get(ONE_AGENT_ID)
|
|
50
|
+
|| db.prepare("SELECT * FROM installed_agents WHERE slug=?").get(ONE_AGENT_SLUG);
|
|
55
51
|
return rowToAgent(row);
|
|
56
52
|
}
|
|
57
53
|
|
|
@@ -78,26 +74,22 @@ function desktopOnePersona() {
|
|
|
78
74
|
}
|
|
79
75
|
|
|
80
76
|
function chatsHaveOriginSurface(db) {
|
|
81
|
-
return
|
|
77
|
+
return db.prepare("PRAGMA table_info(chats)").all().some((column) => column.name === "origin_surface");
|
|
82
78
|
}
|
|
83
79
|
|
|
84
80
|
/** One 소유 대화 목록(최근 순). origin_surface 열이 없는 구형 DB 는 에이전트 소유로 폴백. */
|
|
85
81
|
function listOneChats(db, limit = 20) {
|
|
86
82
|
const bounded = Math.max(1, Math.min(Number(limit) || 20, 200));
|
|
87
|
-
|
|
88
|
-
if (chatsHaveOriginSurface(db)) {
|
|
89
|
-
return db.prepare(
|
|
90
|
-
"SELECT id, title, updated_at, origin_surface FROM chats " +
|
|
91
|
-
"WHERE origin_surface = ? ORDER BY updated_at DESC, rowid DESC LIMIT ?",
|
|
92
|
-
).all(ONE_ORIGIN_SURFACE, bounded);
|
|
93
|
-
}
|
|
83
|
+
if (chatsHaveOriginSurface(db)) {
|
|
94
84
|
return db.prepare(
|
|
95
|
-
"SELECT id, title, updated_at FROM chats
|
|
96
|
-
"ORDER BY updated_at DESC, rowid DESC LIMIT ?",
|
|
97
|
-
).all(
|
|
98
|
-
} catch {
|
|
99
|
-
return [];
|
|
85
|
+
"SELECT id, title, updated_at, origin_surface FROM chats " +
|
|
86
|
+
"WHERE origin_surface = ? ORDER BY updated_at DESC, rowid DESC LIMIT ?",
|
|
87
|
+
).all(ONE_ORIGIN_SURFACE, bounded);
|
|
100
88
|
}
|
|
89
|
+
return db.prepare(
|
|
90
|
+
"SELECT id, title, updated_at FROM chats WHERE agent_id IN (?, ?) AND (kind IS NULL OR kind <> 'division') " +
|
|
91
|
+
"ORDER BY updated_at DESC, rowid DESC LIMIT ?",
|
|
92
|
+
).all(ONE_AGENT_ID, ONE_AGENT_SLUG, bounded);
|
|
101
93
|
}
|
|
102
94
|
|
|
103
95
|
/**
|
|
@@ -121,19 +113,48 @@ function createOneChat(db, { agentId, title, workingFolder }) {
|
|
|
121
113
|
}
|
|
122
114
|
|
|
123
115
|
function parseArgs(args) {
|
|
124
|
-
const out = { print: false, list: false, fresh: false, chatId: null, runtime: null, model: null, effort: null, permission: null, rest: [] };
|
|
116
|
+
const out = { print: false, list: false, fresh: false, chatId: null, runtime: null, model: null, effort: null, permission: null, rest: [], error: null };
|
|
117
|
+
const readValue = (index, flag) => {
|
|
118
|
+
const value = args[index + 1];
|
|
119
|
+
if (typeof value !== "string" || !value || value === "--" || value.startsWith("--")) {
|
|
120
|
+
out.error = `${flag} requires a value`;
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
return value;
|
|
124
|
+
};
|
|
125
125
|
for (let i = 0; i < args.length; i++) {
|
|
126
126
|
const a = args[i];
|
|
127
|
+
if (a === "--") {
|
|
128
|
+
out.rest.push(...args.slice(i + 1));
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
127
131
|
if (a === "-p" || a === "--print") out.print = true;
|
|
128
|
-
else if (a === "--list"
|
|
129
|
-
else if (a === "--new"
|
|
130
|
-
else if (
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
132
|
+
else if (a === "--list") out.list = true;
|
|
133
|
+
else if (a === "--new") out.fresh = true;
|
|
134
|
+
else if (["--chat", "--runtime", "--model", "--effort", "--permission"].includes(a)) {
|
|
135
|
+
const value = readValue(i, a);
|
|
136
|
+
if (value === null) break;
|
|
137
|
+
if (a === "--chat") out.chatId = value;
|
|
138
|
+
else if (a === "--runtime") out.runtime = value;
|
|
139
|
+
else if (a === "--model") out.model = value;
|
|
140
|
+
else if (a === "--effort") out.effort = value;
|
|
141
|
+
else out.permission = value;
|
|
142
|
+
i += 1;
|
|
143
|
+
}
|
|
144
|
+
else if (a.startsWith("-")) {
|
|
145
|
+
out.error = `unknown option ${a}`;
|
|
146
|
+
break;
|
|
147
|
+
}
|
|
135
148
|
else out.rest.push(a);
|
|
136
149
|
}
|
|
150
|
+
if (!out.error && out.list && (
|
|
151
|
+
out.fresh || out.chatId || out.runtime || out.model || out.effort || out.permission || out.rest.length > 0
|
|
152
|
+
)) {
|
|
153
|
+
out.error = "--list cannot be combined with a prompt or execution options";
|
|
154
|
+
}
|
|
155
|
+
if (!out.error && out.fresh && out.chatId) {
|
|
156
|
+
out.error = "--new cannot be combined with --chat";
|
|
157
|
+
}
|
|
137
158
|
return out;
|
|
138
159
|
}
|
|
139
160
|
|
|
@@ -153,6 +174,10 @@ function renderList(ctx, rows) {
|
|
|
153
174
|
|
|
154
175
|
async function runOne(ctx, args) {
|
|
155
176
|
const parsed = parseArgs(args);
|
|
177
|
+
if (parsed.error) {
|
|
178
|
+
ctx.err(`invalid one arguments: ${parsed.error}`);
|
|
179
|
+
return 1;
|
|
180
|
+
}
|
|
156
181
|
if (parsed.permission && !permissions.LEVELS.includes(String(parsed.permission))) {
|
|
157
182
|
ctx.err(`unknown --permission ${parsed.permission} (use: ${permissions.LEVELS.join(" | ")})`);
|
|
158
183
|
return 1;
|
|
@@ -163,12 +188,29 @@ async function runOne(ctx, args) {
|
|
|
163
188
|
}
|
|
164
189
|
|
|
165
190
|
const db = ctx.db();
|
|
191
|
+
const readChats = (limit) => {
|
|
192
|
+
try {
|
|
193
|
+
return listOneChats(db, limit);
|
|
194
|
+
} catch (error) {
|
|
195
|
+
ctx.err(`Could not read One conversations: ${String((error && error.message) || error)}`);
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
};
|
|
166
199
|
|
|
167
200
|
// 목록은 신원 행이 없어도 답할 수 있어야 한다 — 대화는 chats 에 있고, One 행은
|
|
168
201
|
// 실행에만 필요하다. 조회를 실행 전제조건 뒤에 두면 "볼 수도 없는" 화면이 된다.
|
|
169
|
-
if (parsed.list)
|
|
202
|
+
if (parsed.list) {
|
|
203
|
+
const rows = readChats(20);
|
|
204
|
+
return rows ? renderList(ctx, rows) : 1;
|
|
205
|
+
}
|
|
170
206
|
|
|
171
|
-
|
|
207
|
+
let agent;
|
|
208
|
+
try {
|
|
209
|
+
agent = resolveOneAgent(db);
|
|
210
|
+
} catch (error) {
|
|
211
|
+
ctx.err(`Could not read the Agentlas One identity: ${String((error && error.message) || error)}`);
|
|
212
|
+
return 1;
|
|
213
|
+
}
|
|
172
214
|
if (!agent) {
|
|
173
215
|
ctx.err(
|
|
174
216
|
"Agentlas One is not present in the shared database yet.\n" +
|
|
@@ -212,14 +254,17 @@ async function runOne(ctx, args) {
|
|
|
212
254
|
let chatId = null;
|
|
213
255
|
let created = false;
|
|
214
256
|
if (parsed.chatId) {
|
|
215
|
-
const
|
|
257
|
+
const rows = readChats(200);
|
|
258
|
+
if (!rows) return 1;
|
|
259
|
+
const row = rows.find((item) => item.id === parsed.chatId);
|
|
216
260
|
if (!row) {
|
|
217
261
|
ctx.err(`No One conversation with id ${parsed.chatId} (see: agentlas one --list)`);
|
|
218
262
|
return 1;
|
|
219
263
|
}
|
|
220
264
|
chatId = row.id;
|
|
221
265
|
} else if (!parsed.fresh) {
|
|
222
|
-
const recent =
|
|
266
|
+
const recent = readChats(1);
|
|
267
|
+
if (!recent) return 1;
|
|
223
268
|
if (recent.length) chatId = recent[0].id;
|
|
224
269
|
}
|
|
225
270
|
if (!chatId) {
|
|
@@ -157,18 +157,29 @@ function parsePluginListFlags(args) {
|
|
|
157
157
|
errors: [],
|
|
158
158
|
positionals: [],
|
|
159
159
|
};
|
|
160
|
+
const seen = new Set();
|
|
160
161
|
for (let i = 0; i < args.length; i++) {
|
|
161
162
|
const arg = args[i];
|
|
162
163
|
if (arg === "--global") {
|
|
164
|
+
if (seen.has("global")) {
|
|
165
|
+
flags.errors.push("duplicate flag: --global");
|
|
166
|
+
return flags;
|
|
167
|
+
}
|
|
168
|
+
seen.add("global");
|
|
163
169
|
flags.global = true;
|
|
164
170
|
continue;
|
|
165
171
|
}
|
|
166
172
|
if (arg === "--project") {
|
|
173
|
+
if (seen.has("project")) {
|
|
174
|
+
flags.errors.push("duplicate flag: --project");
|
|
175
|
+
return flags;
|
|
176
|
+
}
|
|
167
177
|
const next = args[i + 1];
|
|
168
178
|
if (!next || next.startsWith("-")) {
|
|
169
179
|
flags.errors.push("usage: agentlas plugin list --project <path>");
|
|
170
180
|
return flags;
|
|
171
181
|
}
|
|
182
|
+
seen.add("project");
|
|
172
183
|
flags.project = next;
|
|
173
184
|
i += 1;
|
|
174
185
|
continue;
|
|
@@ -207,7 +218,7 @@ function run(ctx, args) {
|
|
|
207
218
|
// SELF_HELP_COMMANDS 계약(index.cjs): `plugin --help` 는 여기로 ["help"] 가 되어
|
|
208
219
|
// 들어온다. help 분기가 없으면 unknown action → usage exit 1 이라, 도움말을
|
|
209
220
|
// 요청한 사용자가 오류 코드를 받는다.
|
|
210
|
-
if (action === "help" || action === "--help" || action === "-h") {
|
|
221
|
+
if ((action === "help" || action === "--help" || action === "-h") && args.length === 1) {
|
|
211
222
|
const ko = ctx.lang !== "en";
|
|
212
223
|
ctx.out(ko
|
|
213
224
|
? [
|
|
@@ -227,7 +238,7 @@ function run(ctx, args) {
|
|
|
227
238
|
return 0;
|
|
228
239
|
}
|
|
229
240
|
if (action === "add") {
|
|
230
|
-
if (args.length !== 2) {
|
|
241
|
+
if (args.length !== 2 || !/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(String(args[1] || ""))) {
|
|
231
242
|
ctx.err("usage: agentlas plugin add <slug> (run agentlas plugin list first)");
|
|
232
243
|
return 1;
|
|
233
244
|
}
|
|
@@ -56,10 +56,21 @@ function run(ctx, args) {
|
|
|
56
56
|
const action = String(args[0] || "status").toLowerCase();
|
|
57
57
|
const cwd = projectCwd();
|
|
58
58
|
const ko = ctx.lang === "ko";
|
|
59
|
+
const invalid = () => {
|
|
60
|
+
const error = new Error(ko
|
|
61
|
+
? "사용법: agentlas project [status | init | use <에이전트> | team <에이전트>...]"
|
|
62
|
+
: "Usage: agentlas project [status | init | use <agent> | team <agent>...]");
|
|
63
|
+
error.code = "INVALID_ARGUMENT";
|
|
64
|
+
throw error;
|
|
65
|
+
};
|
|
59
66
|
|
|
60
|
-
if (action === "status")
|
|
67
|
+
if (action === "status") {
|
|
68
|
+
if (args.length > 1) return invalid();
|
|
69
|
+
return showStatus(ctx, cwd, ko);
|
|
70
|
+
}
|
|
61
71
|
|
|
62
72
|
if (action === "init") {
|
|
73
|
+
if (args.length !== 1) return invalid();
|
|
63
74
|
ctx.out(ko
|
|
64
75
|
? "비공개 Agentlas 프로젝트 상태를 초기화합니다. .agentlas/ 생성, .gitignore 갱신, 로컬 자격증명·서명 템플릿 추가가 포함될 수 있습니다."
|
|
65
76
|
: "Initializing private Agentlas project state. This may create .agentlas/, update .gitignore, and add local credential/signing templates.");
|
|
@@ -79,13 +90,8 @@ function run(ctx, args) {
|
|
|
79
90
|
* 둘 다 데스크탑 없이 동작한다.
|
|
80
91
|
*/
|
|
81
92
|
if (action === "use" || action === "team") {
|
|
82
|
-
const tokens = args.slice(1)
|
|
83
|
-
if (!tokens.length)
|
|
84
|
-
ctx.err(ko
|
|
85
|
-
? `사용법: agentlas project ${action} <에이전트> ${action === "team" ? "[<에이전트>...]" : ""} · 에이전트 목록: agentlas list`
|
|
86
|
-
: `Usage: agentlas project ${action} <agent> ${action === "team" ? "[<agent>...]" : ""} · list agents: agentlas list`);
|
|
87
|
-
return 1;
|
|
88
|
-
}
|
|
93
|
+
const tokens = args.slice(1);
|
|
94
|
+
if (!tokens.length || tokens.some((token) => !token || String(token).startsWith("-")) || (action === "use" && tokens.length !== 1)) return invalid();
|
|
89
95
|
try {
|
|
90
96
|
const result = connectProjectTeam(ctx.db(), cwd, tokens, {});
|
|
91
97
|
reportTeam(ctx, result, ko);
|
|
@@ -101,10 +107,7 @@ function run(ctx, args) {
|
|
|
101
107
|
}
|
|
102
108
|
}
|
|
103
109
|
|
|
104
|
-
|
|
105
|
-
? "사용법: agentlas project [status | init | use <에이전트> | team <에이전트>...]"
|
|
106
|
-
: "Usage: agentlas project [status | init | use <agent> | team <agent>...]");
|
|
107
|
-
return 1;
|
|
110
|
+
return invalid();
|
|
108
111
|
}
|
|
109
112
|
|
|
110
113
|
module.exports = { run };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/*
|
|
3
|
-
* research — Research Engine
|
|
3
|
+
* research — Agentlas OS Research Engine.
|
|
4
4
|
*
|
|
5
5
|
* v1 디스패처 매핑 그대로:
|
|
6
6
|
* `agentlas research <sub…>` → cmdHep(["research", ...rest])
|
|
@@ -10,22 +10,33 @@
|
|
|
10
10
|
* v1 가드 그대로:
|
|
11
11
|
* - help 토큰 → 로컬 usage가 아니라 Hephaestus 네이티브 help 패스스루
|
|
12
12
|
* (v1: parity().cmdHep(null, ["research", ...rest]) 특례).
|
|
13
|
-
* - 첫 인자가
|
|
13
|
+
* - 첫 인자가 현재 Agentlas OS Research 명령 밖 → usage 실패 exit 1
|
|
14
14
|
* (자연어가 리서치 서브커맨드 자리로 새는 것 방지; ko 문구 v1 그대로).
|
|
15
15
|
*/
|
|
16
16
|
const { create, usageFor, isHelpToken } = require("../hephaestus/runtime.cjs");
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
// Agentlas OS 1.2.37의 공개 `hephaestus research --help` 표면. Terminal이
|
|
19
|
+
// 옛 다섯 개만 허용하면 설치된 Core의 진단·검증·하드포인트·loadout 명령이
|
|
20
|
+
// 물리적으로 도달 불가능해진다. 알 수 없는 값은 계속 로컬에서 fail-closed 한다.
|
|
21
|
+
const RESEARCH_SUBCOMMANDS = new Set([
|
|
22
|
+
"doctor", "status", "credentials", "social-fallbacks", "proofs", "verify",
|
|
23
|
+
"hardpoints", "modules", "armory", "profile", "recommend", "preflight",
|
|
24
|
+
"bridge-contract", "browser-candidates", "bridge-check", "platform-contract",
|
|
25
|
+
"platform-check", "loadouts", "plan", "read", "search", "gather",
|
|
26
|
+
]);
|
|
19
27
|
|
|
20
28
|
async function run(ctx, args) {
|
|
21
29
|
const runtime = create(ctx);
|
|
22
30
|
if (args.some(isHelpToken)) {
|
|
23
|
-
|
|
31
|
+
// The top-level router canonicalizes `<command> --help` to the command's
|
|
32
|
+
// `help` branch. argparse behind Agentlas OS expects `--help`, not a
|
|
33
|
+
// positional `help` research subcommand.
|
|
34
|
+
return runtime.cmdHep(["research", ...args.map((arg) => arg === "help" ? "--help" : arg)]);
|
|
24
35
|
}
|
|
25
|
-
if (!RESEARCH_SUBCOMMANDS.
|
|
36
|
+
if (!RESEARCH_SUBCOMMANDS.has(args[0])) {
|
|
26
37
|
ctx.err(
|
|
27
38
|
"✖ " + (ctx.lang === "ko"
|
|
28
|
-
? "사용법: agentlas research
|
|
39
|
+
? "사용법: agentlas research <하위-명령> [인자] (전체 목록: agentlas research --help)"
|
|
29
40
|
: usageFor("research", ctx.lang)),
|
|
30
41
|
);
|
|
31
42
|
return 1;
|
|
@@ -33,4 +44,4 @@ async function run(ctx, args) {
|
|
|
33
44
|
return runtime.cmdHep(["research", ...args]);
|
|
34
45
|
}
|
|
35
46
|
|
|
36
|
-
module.exports = { run };
|
|
47
|
+
module.exports = { run, RESEARCH_SUBCOMMANDS };
|