agentlas 1.0.65 → 1.0.67
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 +94 -0
- package/README.md +12 -4
- package/bin/agentlas.cjs +354 -16
- package/engine/acp/server.cjs +34 -3
- 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 +30 -5
- package/engine/agentlas-workload-routing.cjs +83 -10
- package/engine/agentlas.cjs +21 -4
- 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 +96 -30
- 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 +609 -116
- 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 +72 -14
- 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 +150 -37
- 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 +35 -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 +484 -63
- 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 +46 -10
- package/engine/mcp/plan.cjs +10 -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 +382 -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
|
@@ -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 };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/*
|
|
3
|
-
* roles —
|
|
3
|
+
* roles — 오케스트레이터/워커/멀티모달 모델 역할 조회·설정.
|
|
4
4
|
*
|
|
5
5
|
* 배경(2026-08-05 감사, 결함 C): `list`와 `doctor`는 model_roles를 보여주는데
|
|
6
6
|
* 터미널 어디에도 쓰기 경로가 없었다(전 코드베이스 SELECT만). 바꾸려면 데스크탑을
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
const { RUNTIME_BIN, whichSync } = require("../runtimes/detect.cjs");
|
|
19
19
|
const { runtimeAuthEvidence } = require("../runtimes/auth-evidence.cjs");
|
|
20
20
|
const { canonicalRuntimeKind, storedRuntimeKind } = require("../runtimes/kinds.cjs");
|
|
21
|
-
const { MODEL_ROLE_TABLE, VALID_ROLES, resolvedModelRole, roleMembers } = require("../runtimes/roles.cjs");
|
|
21
|
+
const { MODEL_ROLE_TABLE, MODEL_ROLE_MEMBER_TABLE, VALID_ROLES, resolvedModelRole, roleMembers } = require("../runtimes/roles.cjs");
|
|
22
22
|
const { runWriteTransaction } = require("../agentlas-sqlite-policy.cjs");
|
|
23
23
|
const { EFFORTS } = require("../agentlas-workload-routing.cjs");
|
|
24
24
|
|
|
@@ -43,12 +43,17 @@ function show(ctx, args = []) {
|
|
|
43
43
|
ctx.out(JSON.stringify({
|
|
44
44
|
orchestrator: resolvedModelRole(db, "orchestrator"),
|
|
45
45
|
worker: resolvedModelRole(db, "worker"),
|
|
46
|
-
|
|
46
|
+
multimodal: resolvedModelRole(db, "multimodal"),
|
|
47
|
+
pools: {
|
|
48
|
+
orchestrator: roleMembers(db, "orchestrator"),
|
|
49
|
+
worker: roleMembers(db, "worker"),
|
|
50
|
+
multimodal: roleMembers(db, "multimodal"),
|
|
51
|
+
},
|
|
47
52
|
}, null, 2));
|
|
48
53
|
return 0;
|
|
49
54
|
}
|
|
50
55
|
ctx.out(ctx.ui.bold(en ? "Model roles" : "모델 역할"));
|
|
51
|
-
for (const role of
|
|
56
|
+
for (const role of VALID_ROLES) {
|
|
52
57
|
const resolved = resolvedModelRole(db, role);
|
|
53
58
|
ctx.out(` ${role.padEnd(13)} ${fmt(resolved, en)}`);
|
|
54
59
|
const pool = roleMembers(db, role);
|
|
@@ -58,21 +63,35 @@ function show(ctx, args = []) {
|
|
|
58
63
|
}
|
|
59
64
|
ctx.out("");
|
|
60
65
|
ctx.out(ctx.ui.dim(en
|
|
61
|
-
? 'Change: agentlas roles set <orchestrator|worker> <runtime> [--model <id>] [--effort <level>] · worker inherit: agentlas roles set worker --inherit'
|
|
62
|
-
: '변경: agentlas roles set <orchestrator|worker> <runtime> [--model <id>] [--effort <level>] · 워커 상속: agentlas roles set worker --inherit'));
|
|
66
|
+
? 'Change: agentlas roles set <orchestrator|worker|multimodal> <runtime> [--model <id>] [--effort <level>] · worker inherit: agentlas roles set worker --inherit'
|
|
67
|
+
: '변경: agentlas roles set <orchestrator|worker|multimodal> <runtime> [--model <id>] [--effort <level>] · 워커 상속: agentlas roles set worker --inherit'));
|
|
63
68
|
return 0;
|
|
64
69
|
}
|
|
65
70
|
|
|
66
71
|
function parseSetFlags(args) {
|
|
67
72
|
const rest = [];
|
|
68
73
|
const flags = {};
|
|
74
|
+
const seen = new Set();
|
|
75
|
+
const take = (name, raw) => {
|
|
76
|
+
if (seen.has(name)) throw new Error(`duplicate option: --${name}`);
|
|
77
|
+
const value = String(raw ?? "").trim();
|
|
78
|
+
if (!value || value.startsWith("--")) throw new Error(`missing value: --${name}`);
|
|
79
|
+
seen.add(name);
|
|
80
|
+
return value;
|
|
81
|
+
};
|
|
69
82
|
for (let i = 0; i < args.length; i += 1) {
|
|
70
|
-
const arg = args[i];
|
|
71
|
-
if (arg === "--model") { flags.model =
|
|
72
|
-
if (arg.startsWith("--model=")) { flags.model = arg.slice(8)
|
|
73
|
-
if (arg === "--effort") { flags.effort =
|
|
74
|
-
if (arg.startsWith("--effort=")) { flags.effort = arg.slice(9)
|
|
75
|
-
if (arg === "--inherit") {
|
|
83
|
+
const arg = String(args[i] ?? "");
|
|
84
|
+
if (arg === "--model") { flags.model = take("model", args[++i]); continue; }
|
|
85
|
+
if (arg.startsWith("--model=")) { flags.model = take("model", arg.slice(8)); continue; }
|
|
86
|
+
if (arg === "--effort") { flags.effort = take("effort", args[++i]).toLowerCase(); continue; }
|
|
87
|
+
if (arg.startsWith("--effort=")) { flags.effort = take("effort", arg.slice(9)).toLowerCase(); continue; }
|
|
88
|
+
if (arg === "--inherit") {
|
|
89
|
+
if (seen.has("inherit")) throw new Error("duplicate option: --inherit");
|
|
90
|
+
seen.add("inherit");
|
|
91
|
+
flags.inherit = true;
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
if (arg.startsWith("-")) throw new Error(`unknown option: ${arg}`);
|
|
76
95
|
rest.push(arg);
|
|
77
96
|
}
|
|
78
97
|
return { rest, flags };
|
|
@@ -81,19 +100,33 @@ function parseSetFlags(args) {
|
|
|
81
100
|
function set(ctx, args) {
|
|
82
101
|
const en = ctx.lang === "ko" ? false : true;
|
|
83
102
|
const ko = !en;
|
|
84
|
-
|
|
103
|
+
let parsed;
|
|
104
|
+
try {
|
|
105
|
+
parsed = parseSetFlags(args);
|
|
106
|
+
} catch (error) {
|
|
107
|
+
ctx.err(error instanceof Error ? error.message : String(error));
|
|
108
|
+
return 1;
|
|
109
|
+
}
|
|
110
|
+
const { rest, flags } = parsed;
|
|
85
111
|
const role = String(rest[0] || "").toLowerCase();
|
|
86
112
|
const kindArg = rest[1] ? String(rest[1]).toLowerCase() : null;
|
|
87
113
|
|
|
88
114
|
const usage = ko
|
|
89
|
-
? "사용법: agentlas roles set <orchestrator|worker> <runtime> [--model <id>] [--effort <level>] | agentlas roles set worker --inherit"
|
|
90
|
-
: "Usage: agentlas roles set <orchestrator|worker> <runtime> [--model <id>] [--effort <level>] | agentlas roles set worker --inherit";
|
|
115
|
+
? "사용법: agentlas roles set <orchestrator|worker|multimodal> <runtime> [--model <id>] [--effort <level>] | agentlas roles set worker --inherit"
|
|
116
|
+
: "Usage: agentlas roles set <orchestrator|worker|multimodal> <runtime> [--model <id>] [--effort <level>] | agentlas roles set worker --inherit";
|
|
91
117
|
|
|
92
118
|
if (!VALID_ROLES.has(role)) { ctx.err(usage); return 1; }
|
|
119
|
+
if (rest.length > 2) { ctx.err(usage); return 1; }
|
|
93
120
|
if (flags.inherit && role !== "worker") {
|
|
94
121
|
ctx.err(ko ? "--inherit 는 worker 역할에만 씁니다 (스키마 계약)." : "--inherit applies to the worker role only (schema contract).");
|
|
95
122
|
return 1;
|
|
96
123
|
}
|
|
124
|
+
if (flags.inherit && (kindArg || flags.model !== undefined || flags.effort !== undefined)) {
|
|
125
|
+
ctx.err(ko
|
|
126
|
+
? "--inherit 는 runtime, --model, --effort 와 함께 쓸 수 없습니다. 오케스트레이터 설정 전체를 따릅니다."
|
|
127
|
+
: "--inherit cannot be combined with a runtime, --model, or --effort. It follows the complete orchestrator selection.");
|
|
128
|
+
return 1;
|
|
129
|
+
}
|
|
97
130
|
if (!flags.inherit && !kindArg) { ctx.err(usage); return 1; }
|
|
98
131
|
if (kindArg && !KNOWN_KINDS.has(kindArg)) {
|
|
99
132
|
ctx.err((ko ? "모르는 런타임 종류: " : "unknown runtime kind: ") + kindArg);
|
|
@@ -119,6 +152,7 @@ function set(ctx, args) {
|
|
|
119
152
|
let kind = kindArg;
|
|
120
153
|
let model = flags.model !== undefined ? (flags.model || null) : undefined;
|
|
121
154
|
let inherit = 0;
|
|
155
|
+
let inheritedSelection = null;
|
|
122
156
|
if (flags.inherit) {
|
|
123
157
|
// 상속 = 워커가 오케스트레이터를 따른다. 스키마상 kind NOT NULL이라
|
|
124
158
|
// 현재 오케스트레이터의 좌표를 복사해 두되 inherit=1로 표시한다(리더 부재 시 정직 정지).
|
|
@@ -129,32 +163,72 @@ function set(ctx, args) {
|
|
|
129
163
|
}
|
|
130
164
|
kind = orchestrator.kind;
|
|
131
165
|
if (model === undefined) model = orchestrator.model;
|
|
166
|
+
inheritedSelection = orchestrator;
|
|
132
167
|
inherit = 1;
|
|
133
168
|
}
|
|
134
169
|
|
|
135
170
|
const now = new Date().toISOString();
|
|
136
171
|
runWriteTransaction(db, () => {
|
|
137
172
|
const existing = db.prepare("SELECT * FROM model_roles WHERE role=?").get(role);
|
|
173
|
+
const sameKind = existing && canonicalRuntimeKind(existing.kind) === kind;
|
|
174
|
+
const storedKind = storedRuntimeKind(kind);
|
|
175
|
+
// kind가 바뀌면 이전 모델/백엔드/출처는 새 런타임의 좌표가 아니다
|
|
176
|
+
// (예: kimi에 opus, codex에 google backend). 명시하지 않은 값은 지운다.
|
|
177
|
+
const savedModel = model === undefined ? (sameKind ? existing.model : null) : model;
|
|
178
|
+
const savedEffort = flags.effort === undefined
|
|
179
|
+
? (inheritedSelection ? inheritedSelection.effort : existing?.effort) || null
|
|
180
|
+
: (flags.effort === "none" ? null : flags.effort);
|
|
181
|
+
const savedBackend = inheritedSelection
|
|
182
|
+
? inheritedSelection.backend || null
|
|
183
|
+
: sameKind ? existing.backend || null : null;
|
|
184
|
+
const savedSource = inheritedSelection
|
|
185
|
+
? inheritedSelection.source || null
|
|
186
|
+
: sameKind ? existing.source || null : null;
|
|
187
|
+
const savedLongContext = inheritedSelection
|
|
188
|
+
? (inheritedSelection.longContext ? 1 : 0)
|
|
189
|
+
: sameKind && existing.long_context ? 1 : 0;
|
|
138
190
|
if (existing) {
|
|
139
|
-
// kind가 바뀌면 이전 모델 id는 새 런타임의 어휘가 아니다(예: kimi에 opus).
|
|
140
|
-
// --model 미지정 시 유지가 아니라 초기화 — 무의미한 좌표를 승계하지 않는다.
|
|
141
|
-
const keepModel = canonicalRuntimeKind(existing.kind) === kind ? existing.model : null;
|
|
142
191
|
db.prepare(
|
|
143
|
-
|
|
192
|
+
`UPDATE model_roles
|
|
193
|
+
SET kind=?, backend=?, source=?, model=?, effort=?, long_context=?, inherit=?, updated_at=?
|
|
194
|
+
WHERE role=?`,
|
|
144
195
|
).run(
|
|
145
196
|
// 공유 DB 는 데스크탑 어휘로 적는다(runtimes/kinds.cjs) — 여기서 이 저장소의
|
|
146
197
|
// 이름을 그대로 넣으면 데스크탑이 그 역할을 못 읽는다.
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
198
|
+
storedKind,
|
|
199
|
+
savedBackend,
|
|
200
|
+
savedSource,
|
|
201
|
+
savedModel,
|
|
202
|
+
savedEffort,
|
|
203
|
+
savedLongContext,
|
|
150
204
|
inherit,
|
|
151
205
|
now,
|
|
152
206
|
role,
|
|
153
207
|
);
|
|
154
208
|
} else {
|
|
155
209
|
db.prepare(
|
|
156
|
-
|
|
157
|
-
|
|
210
|
+
`INSERT INTO model_roles
|
|
211
|
+
(role, kind, backend, source, model, effort, long_context, inherit, updated_at)
|
|
212
|
+
VALUES (?,?,?,?,?,?,?,?,?)`,
|
|
213
|
+
).run(role, storedKind, savedBackend, savedSource, savedModel, savedEffort, savedLongContext, inherit, now);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Desktop v80과 같은 단일 설정 계약: model_roles만 바꿔 실제 실행이
|
|
217
|
+
// 계속 옛 pool 1순위를 고르는 split-brain을 만들지 않는다.
|
|
218
|
+
if (ctx.tableExists(db, MODEL_ROLE_MEMBER_TABLE)) {
|
|
219
|
+
const hasMembers = Number(
|
|
220
|
+
db.prepare("SELECT COUNT(*) AS n FROM model_role_members WHERE role=?").get(role)?.n || 0,
|
|
221
|
+
) > 0;
|
|
222
|
+
if (hasMembers && inherit) {
|
|
223
|
+
// 빈 worker 풀 자체가 orchestrator 풀 상속을 뜻한다.
|
|
224
|
+
db.prepare("DELETE FROM model_role_members WHERE role=?").run(role);
|
|
225
|
+
} else if (hasMembers) {
|
|
226
|
+
db.prepare(
|
|
227
|
+
`UPDATE model_role_members
|
|
228
|
+
SET kind=?, backend=?, source=?, model=?, effort=?, long_context=?, updated_at=?
|
|
229
|
+
WHERE role=? AND position=1`,
|
|
230
|
+
).run(storedKind, savedBackend, savedSource, savedModel, savedEffort, savedLongContext, now, role);
|
|
231
|
+
}
|
|
158
232
|
}
|
|
159
233
|
});
|
|
160
234
|
|
|
@@ -188,18 +262,20 @@ function run(ctx, args = []) {
|
|
|
188
262
|
// SELF_HELP_COMMANDS 계약: --help 는 스텁이 아니라 실제 안내여야 한다.
|
|
189
263
|
ctx.out(en
|
|
190
264
|
? [
|
|
191
|
-
"agentlas roles — orchestrator/worker model roles (persisted, shared with Desktop)",
|
|
192
|
-
" roles show
|
|
265
|
+
"agentlas roles — orchestrator/worker/multimodal model roles (persisted, shared with Desktop)",
|
|
266
|
+
" roles show all three roles and their pools",
|
|
193
267
|
" roles set <orchestrator|worker> <runtime> [--model <id>] [--effort <level>]",
|
|
268
|
+
" roles set multimodal <runtime> [--model <id>] [--effort <level>]",
|
|
194
269
|
" roles set worker --inherit worker follows the orchestrator",
|
|
195
270
|
"",
|
|
196
271
|
` runtimes: ${[...KNOWN_KINDS].join(" · ")}`,
|
|
197
272
|
" REPL /model and /runtime are session-scoped — this command is the persistent path.",
|
|
198
273
|
].join("\n")
|
|
199
274
|
: [
|
|
200
|
-
"agentlas roles —
|
|
201
|
-
" roles
|
|
275
|
+
"agentlas roles — 오케스트레이터/워커/멀티모달 모델 역할 (영구 저장, 데스크탑과 공유)",
|
|
276
|
+
" roles 세 역할과 풀 조회",
|
|
202
277
|
" roles set <orchestrator|worker> <runtime> [--model <id>] [--effort <level>]",
|
|
278
|
+
" roles set multimodal <runtime> [--model <id>] [--effort <level>]",
|
|
203
279
|
" roles set worker --inherit 워커가 오케스트레이터를 따름",
|
|
204
280
|
"",
|
|
205
281
|
` 런타임: ${[...KNOWN_KINDS].join(" · ")}`,
|
|
@@ -9,14 +9,14 @@
|
|
|
9
9
|
* 넘기고, --json이면 human:false 원본 패스스루로 내려간다.
|
|
10
10
|
*
|
|
11
11
|
* v1 인자 가드 그대로:
|
|
12
|
-
* - help 토큰 → usage, exit 0
|
|
12
|
+
* - 단독 help 토큰 → usage, exit 0
|
|
13
13
|
* - 인자가 없거나 --json뿐 → usage 실패 exit 1
|
|
14
14
|
* (빈 쿼리가 라우터로 새는 것 방지)
|
|
15
15
|
*/
|
|
16
16
|
const { create, usageFor, isHelpToken } = require("../hephaestus/runtime.cjs");
|
|
17
17
|
|
|
18
18
|
async function run(ctx, args) {
|
|
19
|
-
if (args.
|
|
19
|
+
if (args.length === 1 && isHelpToken(args[0])) {
|
|
20
20
|
ctx.out(usageFor("route", ctx.lang));
|
|
21
21
|
return 0;
|
|
22
22
|
}
|
package/engine/commands/run.cjs
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* --effort <level> none | minimal | low | medium | high | xhigh | max
|
|
8
8
|
* --tier <tier> economy | balanced | frontier (requires --model)
|
|
9
9
|
* --permission <level> read | write | full
|
|
10
|
+
* -- 뒤의 토큰은 옵션처럼 보여도 프롬프트로 전달
|
|
10
11
|
* 프롬프트가 없고 stdin이 TTY가 아니면 stdin을 읽는다.
|
|
11
12
|
*
|
|
12
13
|
* 첫 토큰이 정확한 에이전트이면 고급 직접 호출이다. 그 외 일반 실행은 현재 폴더에
|
|
@@ -48,21 +49,53 @@ function parseArgs(args) {
|
|
|
48
49
|
permission: null,
|
|
49
50
|
rest: [],
|
|
50
51
|
};
|
|
52
|
+
const seen = new Set();
|
|
53
|
+
const valueFlags = new Map([
|
|
54
|
+
["--runtime", "runtime"],
|
|
55
|
+
["--model", "model"],
|
|
56
|
+
["--effort", "effort"],
|
|
57
|
+
["--tier", "tier"],
|
|
58
|
+
["--permission", "permission"],
|
|
59
|
+
]);
|
|
60
|
+
let passthrough = false;
|
|
51
61
|
for (let i = 0; i < args.length; i++) {
|
|
52
|
-
const a = args[i];
|
|
53
|
-
if (
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
62
|
+
const a = String(args[i]);
|
|
63
|
+
if (passthrough) { out.rest.push(a); continue; }
|
|
64
|
+
if (a === "--") { passthrough = true; continue; }
|
|
65
|
+
if (a === "-p" || a === "--print") {
|
|
66
|
+
if (seen.has("print")) throw new Error("duplicate option: --print");
|
|
67
|
+
seen.add("print");
|
|
68
|
+
out.print = true;
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
const equalAt = a.indexOf("=");
|
|
72
|
+
const option = equalAt >= 0 ? a.slice(0, equalAt) : a;
|
|
73
|
+
const field = valueFlags.get(option);
|
|
74
|
+
if (field) {
|
|
75
|
+
if (seen.has(field)) throw new Error(`duplicate option: ${option}`);
|
|
76
|
+
seen.add(field);
|
|
77
|
+
const value = equalAt >= 0 ? a.slice(equalAt + 1) : args[++i];
|
|
78
|
+
if (value === undefined || value === "" || (equalAt < 0 && String(value).startsWith("--"))) {
|
|
79
|
+
throw new Error(`${option} requires a value`);
|
|
80
|
+
}
|
|
81
|
+
out[field] = String(value);
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
if (a.startsWith("-")) {
|
|
85
|
+
throw new Error(`unknown option: ${a} (use -- before a prompt that starts with '-')`);
|
|
86
|
+
}
|
|
87
|
+
out.rest.push(a);
|
|
60
88
|
}
|
|
61
89
|
return out;
|
|
62
90
|
}
|
|
63
91
|
|
|
64
92
|
async function runOnce(ctx, args) {
|
|
65
|
-
|
|
93
|
+
let parsed;
|
|
94
|
+
try { parsed = parseArgs(args); }
|
|
95
|
+
catch (error) {
|
|
96
|
+
ctx.err(String((error && error.message) || error));
|
|
97
|
+
return 1;
|
|
98
|
+
}
|
|
66
99
|
// 플래그 검증은 모델을 부르기 전에. normalize는 알 수 없는 값을 read로 fail-closed
|
|
67
100
|
// 강등하는데, 조용히 강등하면 full을 요청한 사용자가 read로 도는 걸 모른다.
|
|
68
101
|
if (parsed.permission && !["read", "write", "full"].includes(String(parsed.permission))) {
|
|
@@ -15,9 +15,30 @@ function isInternalAgentSlug(slug) {
|
|
|
15
15
|
async function run(ctx, args) {
|
|
16
16
|
let limit = 10;
|
|
17
17
|
const rest = [];
|
|
18
|
+
let seenLimit = false;
|
|
19
|
+
let passthrough = false;
|
|
18
20
|
for (let i = 0; i < args.length; i++) {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
+
const token = String(args[i]);
|
|
22
|
+
if (passthrough) { rest.push(token); continue; }
|
|
23
|
+
if (token === "--") { passthrough = true; continue; }
|
|
24
|
+
if (token === "--limit" || token.startsWith("--limit=")) {
|
|
25
|
+
if (seenLimit) { ctx.err("duplicate option: --limit"); return 1; }
|
|
26
|
+
seenLimit = true;
|
|
27
|
+
const inline = token.startsWith("--limit=");
|
|
28
|
+
const raw = inline ? token.slice(8) : args[++i];
|
|
29
|
+
const parsed = Number(raw);
|
|
30
|
+
if (raw === undefined || raw === "" || !Number.isInteger(parsed) || parsed < 1 || parsed > 30) {
|
|
31
|
+
ctx.err("--limit requires an integer from 1 to 30");
|
|
32
|
+
return 1;
|
|
33
|
+
}
|
|
34
|
+
limit = parsed;
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
if (token.startsWith("-")) {
|
|
38
|
+
ctx.err(`unknown option: ${token} (use -- before a query that starts with '-')`);
|
|
39
|
+
return 1;
|
|
40
|
+
}
|
|
41
|
+
rest.push(token);
|
|
21
42
|
}
|
|
22
43
|
const query = rest.join(" ").trim();
|
|
23
44
|
if (!query) {
|
|
@@ -26,7 +26,12 @@ async function runWizard(ctx, rl) {
|
|
|
26
26
|
});
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
async function run(ctx) {
|
|
29
|
+
async function run(ctx, args = []) {
|
|
30
|
+
if (args.length) {
|
|
31
|
+
const error = new Error("usage: agentlas setup");
|
|
32
|
+
error.code = "INVALID_ARGUMENT";
|
|
33
|
+
throw error;
|
|
34
|
+
}
|
|
30
35
|
if (!process.stdin.isTTY) {
|
|
31
36
|
// 비-TTY에서 마법사를 돌리면 EOF로 이벤트 루프가 비어 exit 0으로 "조용히 성공"
|
|
32
37
|
// 하는 함정이 있다 — 정직하게 거부한다.
|
|
@@ -38,20 +38,58 @@ function resolvePermission(ctx) {
|
|
|
38
38
|
function splitRuntimeOverride(args) {
|
|
39
39
|
const rest = [];
|
|
40
40
|
let runtimeOverride = null;
|
|
41
|
+
let seen = false;
|
|
42
|
+
let passthrough = false;
|
|
41
43
|
for (let i = 0; i < args.length; i += 1) {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
+
const token = String(args[i]);
|
|
45
|
+
if (passthrough) { rest.push(token); continue; }
|
|
46
|
+
if (token === "--") { passthrough = true; rest.push(token); continue; }
|
|
47
|
+
if (token === "--runtime" || token.startsWith("--runtime=")) {
|
|
48
|
+
if (seen) throw new Error("duplicate option: --runtime");
|
|
49
|
+
seen = true;
|
|
50
|
+
const inline = token.startsWith("--runtime=");
|
|
51
|
+
const value = inline ? token.slice(10) : args[++i];
|
|
52
|
+
if (value === undefined || value === "" || (!inline && String(value).startsWith("--"))) {
|
|
53
|
+
throw new Error("--runtime requires a value");
|
|
54
|
+
}
|
|
55
|
+
runtimeOverride = String(value);
|
|
44
56
|
continue;
|
|
45
57
|
}
|
|
46
|
-
rest.push(
|
|
58
|
+
rest.push(token);
|
|
47
59
|
}
|
|
48
60
|
return { rest, runtimeOverride };
|
|
49
61
|
}
|
|
50
62
|
|
|
63
|
+
function validateStormArgs(args) {
|
|
64
|
+
const seen = new Set();
|
|
65
|
+
let passthrough = false;
|
|
66
|
+
let hasGoal = false;
|
|
67
|
+
for (const raw of args) {
|
|
68
|
+
const token = String(raw);
|
|
69
|
+
if (passthrough) { hasGoal = true; continue; }
|
|
70
|
+
if (token === "--") { passthrough = true; continue; }
|
|
71
|
+
if (token === "--research" || token === "--research-evidence") {
|
|
72
|
+
if (seen.has("research")) return { error: "duplicate option: --research", hasGoal };
|
|
73
|
+
seen.add("research");
|
|
74
|
+
} else if (token === "--background") {
|
|
75
|
+
if (seen.has("background")) return { error: "duplicate option: --background", hasGoal };
|
|
76
|
+
seen.add("background");
|
|
77
|
+
} else if (token.startsWith("-")) {
|
|
78
|
+
return { error: `unknown option: ${token} (use -- before a goal token that starts with '-')`, hasGoal };
|
|
79
|
+
} else hasGoal = true;
|
|
80
|
+
}
|
|
81
|
+
return { error: null, hasGoal };
|
|
82
|
+
}
|
|
83
|
+
|
|
51
84
|
async function run(ctx, args) {
|
|
52
|
-
|
|
85
|
+
let parsed;
|
|
86
|
+
try { parsed = splitRuntimeOverride(args); }
|
|
87
|
+
catch (error) { ctx.err(String((error && error.message) || error)); return 1; }
|
|
88
|
+
const { rest, runtimeOverride } = parsed;
|
|
89
|
+
const validation = validateStormArgs(rest);
|
|
90
|
+
if (validation.error) { ctx.err(validation.error); return 1; }
|
|
53
91
|
// usage 경로(목표 텍스트 없음)는 SQLite를 열 이유가 없다.
|
|
54
|
-
if (!
|
|
92
|
+
if (!validation.hasGoal) {
|
|
55
93
|
ctx.err("usage: agentlas storm <goal> [--research] [--background] [--runtime <kind>]");
|
|
56
94
|
return 1;
|
|
57
95
|
}
|
|
@@ -68,4 +106,4 @@ async function run(ctx, args) {
|
|
|
68
106
|
return r && r.ok ? 0 : 1;
|
|
69
107
|
}
|
|
70
108
|
|
|
71
|
-
module.exports = { run, splitRuntimeOverride };
|
|
109
|
+
module.exports = { run, splitRuntimeOverride, validateStormArgs };
|