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
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,107 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.0.34 — 2026-08-06
|
|
4
|
+
|
|
5
|
+
Telegram, standalone. The terminal can now connect a Telegram bot with no desktop app.
|
|
6
|
+
|
|
7
|
+
- `connect telegram <agent|firm>` reads a bot token from stdin (never argv), verifies it
|
|
8
|
+
against api.telegram.org, stores it 0600, polls getUpdates and pairs the first private
|
|
9
|
+
chat, then sends a confirmation.
|
|
10
|
+
- `connect test <id>` / `connect remove <id>` / `connect status`. The connection core is
|
|
11
|
+
plain HTTPS ported from the desktop; no Electron, no plugin, no raw JSON dump.
|
|
12
|
+
|
|
13
|
+
Not yet standalone: auto-creating the bot by piloting BotFather in a browser (the CDP
|
|
14
|
+
browser hardpoint makes this a tractable next layer; it needs a live Telegram web session).
|
|
15
|
+
|
|
16
|
+
## 1.0.33 — 2026-08-06
|
|
17
|
+
|
|
18
|
+
Defect sweep: ran every command with a real prompt and fixed what dumped or stalled.
|
|
19
|
+
|
|
20
|
+
- `connect telegram` / `connect status` no longer dump the raw Hephaestus router JSON —
|
|
21
|
+
they show the local Telegram binding table and honestly note that bot issuance/pairing
|
|
22
|
+
still live in Desktop Connect.
|
|
23
|
+
- `route "<request>"` shows a progress spinner during its ~13s Hub round-trip instead of
|
|
24
|
+
sitting silent.
|
|
25
|
+
|
|
26
|
+
## 1.0.32 — 2026-08-06
|
|
27
|
+
|
|
28
|
+
Standalone: the terminal no longer requires Desktop or the plugin for its core flows.
|
|
29
|
+
(They share artifacts and settings; they are not a prerequisite.)
|
|
30
|
+
|
|
31
|
+
- `project use <agent>` / `project team <agent>…` connect the current folder as a
|
|
32
|
+
project and set an ordered team, entirely from the terminal — so `run "<task>"` and
|
|
33
|
+
plain REPL input work without ever opening Desktop. `project status` shows the team.
|
|
34
|
+
- `build "<request>"` now builds locally: the terminal runtime produces an installable
|
|
35
|
+
agent package (AGENTS.md + manifest.md + README.md) and auto-installs it, instead of
|
|
36
|
+
printing "open the Claude Code / Codex plugin and run /hep-build".
|
|
37
|
+
- Honest-stops in a project-less folder point at `project use`, not "open Desktop".
|
|
38
|
+
|
|
39
|
+
Verified standalone end-to-end: project use → run answered correctly; build produced and
|
|
40
|
+
installed an agent that then ran correctly.
|
|
41
|
+
|
|
42
|
+
## 1.0.31 — 2026-08-06
|
|
43
|
+
|
|
44
|
+
Interactive UX, measured against first-class REPLs with a real PTY.
|
|
45
|
+
|
|
46
|
+
- The empty prompt now guides: a dim ghost hint ("type a task · / commands · @ files
|
|
47
|
+
· ? shortcuts"), `?` prints a shortcuts card, a second empty Enter points the way.
|
|
48
|
+
- Tab-completing a command that takes arguments appends the space, so you can type the
|
|
49
|
+
argument immediately; no-arg commands are unchanged.
|
|
50
|
+
- A plain-language task in a folder with no connected project now says exactly why and how
|
|
51
|
+
to run anyway (localized), instead of a single "recovering…" line that hid the reason.
|
|
52
|
+
Every controller honest-stop carries a machine code so this can never be swallowed again.
|
|
53
|
+
- New PTY-driven gates (repl-guidance, honest-stop-not-swallowed) — these paths live inside
|
|
54
|
+
the readline session and are invisible to spawnSync tests.
|
|
55
|
+
|
|
56
|
+
## 1.0.30 — 2026-08-06
|
|
57
|
+
|
|
58
|
+
CLI-conventions hardening, measured against clig.dev and first-class CLIs.
|
|
59
|
+
|
|
60
|
+
- A closed pipe is a reader saying stop: `agentlas … | head` no longer crashes with EPIPE.
|
|
61
|
+
- Unexpected crashes now print a one-line summary and a pre-filled GitHub issue URL, not just a raw stack.
|
|
62
|
+
- `TERM=dumb` disables ANSI colors (editor shells, some CI).
|
|
63
|
+
- Secrets stop landing in shell history: `creds save --value -` reads the secret from stdin;
|
|
64
|
+
passing it via argv now prints an exposure notice.
|
|
65
|
+
- `list --json`, `doctor --json`, `roles --json` — machine contracts for scripts.
|
|
66
|
+
- Workforce staffing survives transient API failures: a typed transient error
|
|
67
|
+
(connection closed mid-response, timeouts, overload) on a no-authority/read-only stage
|
|
68
|
+
is retried exactly once; write-capable stages are never retried. A 40-minute, 2.1M-token
|
|
69
|
+
live run previously died on the final re-verification call for exactly this.
|
|
70
|
+
- New gate: clig-conventions-contract; retry contract added to the workforce runtime gate.
|
|
71
|
+
|
|
72
|
+
## 1.0.29 — 2026-08-05
|
|
73
|
+
|
|
74
|
+
Terminal-wide audit release. Every command was executed for real; what follows fixes what that audit found.
|
|
75
|
+
|
|
76
|
+
- Native federated staffing: `hep-network` / `hep-local` / `hep-cloud` / `hep-hub` now run this
|
|
77
|
+
terminal's own workforce loop with the local Agentlas-OS core federating the declared source scope.
|
|
78
|
+
(They previously passed through to an external CLI stub that always answered exit 3.)
|
|
79
|
+
Honest stop with install guidance when the local core is missing — no silent fallback to the public Hub.
|
|
80
|
+
- `workforce` now declares its sourceScope ("hub") explicitly instead of relying on the server default.
|
|
81
|
+
- `doctor` distinguishes installed from signed-in: local sign-in evidence per runtime, a warning
|
|
82
|
+
(not "all clear") when the active runtime has none.
|
|
83
|
+
- New `roles` command: view and set orchestrator/worker model roles from the terminal
|
|
84
|
+
(`roles set <role> <runtime> [--model id] [--effort lv]`, `roles set worker --inherit`).
|
|
85
|
+
REPL `/model`·`/runtime` now say they are session-scoped and point to `agentlas roles`.
|
|
86
|
+
- Setup wizard prints install/sign-in guidance when the chosen runtime is missing or unauthenticated.
|
|
87
|
+
- `creds list` (names and stores only — values never printed), `mcp list`, Korean `help` body.
|
|
88
|
+
- The graph command group ships in the npm package for the first time (it landed after 1.0.28 was published).
|
|
89
|
+
- New gates: user-scenarios (93 real CLI invocations), local-core transport wire contract,
|
|
90
|
+
doctor auth-evidence, roles round-trip, onboarding guidance, EN/KO help sync.
|
|
91
|
+
- `agentlas <command> --help` reaches the command's own help. It printed a two-line stub
|
|
92
|
+
scraped from the help table, so `graph --help` never showed the eight lines `graph help` has —
|
|
93
|
+
and that is the spelling people try first. (The gate had pinned the stub as correct; its
|
|
94
|
+
contract now asks whether real help was shown.)
|
|
95
|
+
- `graph install --name "<new name>"` works. The documented flag had never worked: its value was
|
|
96
|
+
appended to the file path, so the install died with "no such file".
|
|
97
|
+
- `graph show` stops indenting a straight chain deeper at every step — fourteen steps meant
|
|
98
|
+
twenty-eight columns. Depth now marks real branches (a fork, a failure exit).
|
|
99
|
+
- Building a graph follows your language setting. One Korean character anywhere in the request
|
|
100
|
+
forced the interview to Korean while `graph show`, the list, and errors stayed English.
|
|
101
|
+
- Graph steps written as code declare the pip packages they import, and a verification step is
|
|
102
|
+
now required whenever a step that changes something outside sends out a value an earlier step
|
|
103
|
+
computed — an unattended run must not ship an empty or invented result.
|
|
104
|
+
|
|
3
105
|
## 1.0.26 — 2026-08-03
|
|
4
106
|
|
|
5
107
|
- **`agentlas list` stops letting the terminal cut its own output.** Slugs were
|
package/README.md
CHANGED
|
@@ -94,10 +94,13 @@ agentlas variant resolve --base-release <id> # Preview local variant compatibili
|
|
|
94
94
|
```sh
|
|
95
95
|
agentlas storm "<goal>" # Goal + UltraCode harness: plan -> assign -> execute -> verify [--research]
|
|
96
96
|
agentlas swarm "<goal>" # Emergent multi-agent swarm [--parallel N]
|
|
97
|
-
agentlas workforce "<prompt>" # Route through Agent Workforce Ontology
|
|
97
|
+
agentlas workforce "<prompt>" # Route through Agent Workforce Ontology (public Hub menu)
|
|
98
98
|
agentlas network "<prompt>" # Alias for workforce
|
|
99
99
|
agentlas taskforce "<prompt>" # Alias for workforce
|
|
100
|
-
agentlas
|
|
100
|
+
agentlas hep-network "<prompt>" # Staff across Local + owner Cloud + public Hub (local Core federation)
|
|
101
|
+
agentlas hep-local "<prompt>" # Same staffing, registered Local agents only
|
|
102
|
+
agentlas hep-cloud "<prompt>" # Same staffing, owner Agent Cloud only
|
|
103
|
+
agentlas hep-hub "<prompt>" # Same staffing, public Hub only
|
|
101
104
|
agentlas call "a,b" "<context>" # Call explicitly named Hub or Cloud agents
|
|
102
105
|
agentlas browser [...] # Real browser hardpoint launcher
|
|
103
106
|
agentlas route "<prompt>" [--json] # Preview routing decisions without execution
|
package/bin/agentlas.cjs
CHANGED
|
@@ -18,6 +18,21 @@
|
|
|
18
18
|
*/
|
|
19
19
|
"use strict";
|
|
20
20
|
|
|
21
|
+
/*
|
|
22
|
+
* EPIPE 방어 — 발행본 실설치 검증에서 발견(2026-08-06): `agentlas version | head -1`
|
|
23
|
+
* 처럼 파이프 소비자가 먼저 닫히면 stdout write가 EPIPE를 던져 스택트레이스로
|
|
24
|
+
* 크래시했다. `| head` `| less` `| grep -m1`은 CLI의 일상 사용 패턴이다.
|
|
25
|
+
* 파이프 단절은 오류가 아니라 "그만 읽겠다"는 신호 — 조용히 성공 종료한다.
|
|
26
|
+
* (시나리오 게이트가 못 잡았던 이유: spawnSync는 파이프를 끝까지 읽는다.
|
|
27
|
+
* test/user-scenarios-contract.cjs 의 파이프 시나리오가 이 계약을 잠근다.)
|
|
28
|
+
*/
|
|
29
|
+
for (const stream of [process.stdout, process.stderr]) {
|
|
30
|
+
stream.on("error", (error) => {
|
|
31
|
+
if (error && error.code === "EPIPE") process.exit(0);
|
|
32
|
+
throw error;
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
21
36
|
const fs = require("node:fs");
|
|
22
37
|
const os = require("node:os");
|
|
23
38
|
const path = require("node:path");
|
|
@@ -38,11 +38,56 @@ function collectFiles(root) {
|
|
|
38
38
|
return files.sort((a, b) => a.path.localeCompare(b.path));
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
// Local sourcePackage identity — the wizard manifest's `packageHash`.
|
|
42
|
+
//
|
|
43
|
+
// This is NOT the delivered Agent Cloud artifact hash. That one is
|
|
44
|
+
// `path-sha256-executable-v2` and lives in engine/cloud-assets/package.cjs,
|
|
45
|
+
// byte-identical with Desktop's hashPackage and Agentlas-OS upload.py. The two
|
|
46
|
+
// are separate contracts on purpose (upload.py: "distinct from agentlas.json's
|
|
47
|
+
// local sourcePackage hash contract").
|
|
48
|
+
//
|
|
49
|
+
// The canonical definition of THIS hash is the kernel's
|
|
50
|
+
// `canonical_package_hash_hex` in Agentlas-OS/agentlas_cloud/runtime.py. This
|
|
51
|
+
// file mirrors it and must produce the same digest for the same folder; the
|
|
52
|
+
// two used to disagree on every input because this copy had no version prefix
|
|
53
|
+
// and skipped only agentlas.json. Keep the three constants below in step with
|
|
54
|
+
// the kernel: PACKAGE_HASH_VERSION, PACKAGE_HASH_EXCLUDED_PATHS, and the
|
|
55
|
+
// experience-lineage rule.
|
|
56
|
+
const PACKAGE_HASH_VERSION = "agentlas-package-hash/v2";
|
|
57
|
+
const LOCAL_EXPERIENCE_LINEAGE_PATH = ".agentlas/experience-relations.jsonl";
|
|
58
|
+
const PACKAGE_HASH_EXCLUDED_PATHS = new Set([
|
|
59
|
+
"agentlas.json",
|
|
60
|
+
".agentlas/brief.json",
|
|
61
|
+
".agentlas/security-scan.json",
|
|
62
|
+
".agentlas/security-llm-judgment.json",
|
|
63
|
+
".agentlas/field-test-report.json",
|
|
64
|
+
LOCAL_EXPERIENCE_LINEAGE_PATH,
|
|
65
|
+
]);
|
|
66
|
+
|
|
67
|
+
function isLocalExperienceLineagePath(filePath) {
|
|
68
|
+
const normalized = String(filePath || "").replaceAll("\\", "/");
|
|
69
|
+
return (
|
|
70
|
+
normalized === LOCAL_EXPERIENCE_LINEAGE_PATH ||
|
|
71
|
+
normalized.startsWith(`${LOCAL_EXPERIENCE_LINEAGE_PATH}.`) ||
|
|
72
|
+
normalized.startsWith(".agentlas/.experience-relations.jsonl.")
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function packageHashIncludes(filePath) {
|
|
77
|
+
const normalized = String(filePath || "").replaceAll("\\", "/");
|
|
78
|
+
return !PACKAGE_HASH_EXCLUDED_PATHS.has(normalized) && !isLocalExperienceLineagePath(normalized);
|
|
79
|
+
}
|
|
80
|
+
|
|
41
81
|
function hashPackage(files) {
|
|
42
82
|
const h = crypto.createHash("sha256");
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
83
|
+
h.update(PACKAGE_HASH_VERSION);
|
|
84
|
+
h.update("\0");
|
|
85
|
+
// Codepoint order, not localeCompare: the kernel sorts by raw string order.
|
|
86
|
+
const ordered = [...files].sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0));
|
|
87
|
+
for (const file of ordered) {
|
|
88
|
+
const normalized = String(file.path || "").replaceAll("\\", "/");
|
|
89
|
+
if (!packageHashIncludes(normalized)) continue;
|
|
90
|
+
h.update(normalized);
|
|
46
91
|
h.update("\0");
|
|
47
92
|
h.update(file.content);
|
|
48
93
|
h.update("\0");
|
|
@@ -55,9 +100,14 @@ function inferEntry(files) {
|
|
|
55
100
|
return ["AGENTS.md", "agent.md", "CLAUDE.md", "README.md"].find((candidate) => paths.has(candidate)) || files[0]?.path || "AGENTS.md";
|
|
56
101
|
}
|
|
57
102
|
|
|
103
|
+
// Skills actually present in the package. An empty result stays empty.
|
|
104
|
+
// A package with no skills used to be given a literal placeholder skill id.
|
|
105
|
+
// Once skills live outside the core that placeholder fires on every modular
|
|
106
|
+
// agent and fills the Workforce index with a skill nobody has.
|
|
107
|
+
// An absent value is an empty list, never a stand-in.
|
|
58
108
|
function inferSkills(files) {
|
|
59
109
|
const skills = files.map((file) => file.path.match(/(?:^|\/)skills\/([^/]+)\/SKILL\.md$/)?.[1]).filter(Boolean);
|
|
60
|
-
return [...new Set(skills)].sort()
|
|
110
|
+
return [...new Set(skills)].sort();
|
|
61
111
|
}
|
|
62
112
|
|
|
63
113
|
function buildManifest(root, options = {}) {
|
package/engine/agentlas-i18n.cjs
CHANGED
|
@@ -74,7 +74,6 @@ const STRINGS = {
|
|
|
74
74
|
"effortUsage": "usage: /effort low|medium|high|max|off|auto",
|
|
75
75
|
"permSet": "permission → %s",
|
|
76
76
|
"permUsage": "usage: /permission read|write|full",
|
|
77
|
-
"legacyNetworkUsage": "usage: /legacy-network <request>",
|
|
78
77
|
"stormUsage": "usage: /storm <goal> [--research]",
|
|
79
78
|
"buildUsage": "usage: /build <agent-or-team request>",
|
|
80
79
|
"routeUsage": "usage: /route <request> [--json]",
|
|
@@ -190,7 +189,6 @@ const STRINGS = {
|
|
|
190
189
|
"help.search": "discover agents in the Hub",
|
|
191
190
|
"help.install": "install an agent from the Hub by slug",
|
|
192
191
|
"help.network": "let the host LLM staff and execute an ontology-grounded exact-release task force",
|
|
193
|
-
"help.legacyNetwork": "run the explicit compatibility-only Hephaestus network route",
|
|
194
192
|
"help.browser": "real browser execution hardpoint",
|
|
195
193
|
"help.connect": "wire Telegram / platforms to an agent team",
|
|
196
194
|
"help.swarm": "fan out an emergent agent swarm on a goal",
|
|
@@ -251,6 +249,8 @@ const STRINGS = {
|
|
|
251
249
|
"wiz.runtimeAuto": "Use the app's active runtime",
|
|
252
250
|
"wiz.runtimeInstalled": "installed",
|
|
253
251
|
"wiz.runtimeMissing": "not installed",
|
|
252
|
+
"wiz.runtimeInstallHint": "This runtime is not installed yet. Install it first: %s",
|
|
253
|
+
"wiz.runtimeLoginHint": "No local sign-in evidence for this runtime. Sign in before your first run (run: %s, then follow its login flow).",
|
|
254
254
|
"wiz.permQ": "How much should agents be allowed to do by default?",
|
|
255
255
|
"wiz.permRead": "read — inspect only; workspace writes blocked",
|
|
256
256
|
"wiz.permWrite": "write — workspace + runtime temp writes; external MCP off (recommended)",
|
|
@@ -323,7 +323,6 @@ const STRINGS = {
|
|
|
323
323
|
"effortUsage": "사용법: /effort low|medium|high|max|off|auto",
|
|
324
324
|
"permSet": "권한 → %s",
|
|
325
325
|
"permUsage": "사용법: /permission read|write|full",
|
|
326
|
-
"legacyNetworkUsage": "사용법: /legacy-network <요청>",
|
|
327
326
|
"stormUsage": "사용법: /storm <목표> [--research]",
|
|
328
327
|
"buildUsage": "사용법: /build <만들 에이전트·팀 설명>",
|
|
329
328
|
"routeUsage": "사용법: /route <요청> [--json]",
|
|
@@ -438,7 +437,6 @@ const STRINGS = {
|
|
|
438
437
|
"help.search": "Hub에서 에이전트 발견",
|
|
439
438
|
"help.install": "식별자로 Hub 에이전트 설치",
|
|
440
439
|
"help.network": "상위 LLM이 온톨로지에서 정확한 릴리스 TF를 선발·실행",
|
|
441
|
-
"help.legacyNetwork": "호환성 전용 Hephaestus 네트워크 경로를 명시적으로 실행",
|
|
442
440
|
"help.browser": "실제 브라우저 실행 하드포인트",
|
|
443
441
|
"help.connect": "Telegram/플랫폼을 에이전트 팀에 연결",
|
|
444
442
|
"help.swarm": "목표에 창발형 에이전트 스웜 전개",
|
|
@@ -497,6 +495,8 @@ const STRINGS = {
|
|
|
497
495
|
"wiz.runtimeAuto": "앱의 활성 런타임 사용",
|
|
498
496
|
"wiz.runtimeInstalled": "설치됨",
|
|
499
497
|
"wiz.runtimeMissing": "미설치",
|
|
498
|
+
"wiz.runtimeInstallHint": "이 런타임은 아직 설치되어 있지 않습니다. 먼저 설치하세요: %s",
|
|
499
|
+
"wiz.runtimeLoginHint": "이 런타임의 로그인 흔적이 없습니다. 첫 실행 전에 로그인하세요 (%s 실행 후 로그인 절차 진행).",
|
|
500
500
|
"wiz.permQ": "에이전트가 기본적으로 어디까지 할 수 있게 할까요?",
|
|
501
501
|
"wiz.permRead": "read — 조회만; 작업 공간 쓰기 차단",
|
|
502
502
|
"wiz.permWrite": "write — 작업 공간·런타임 임시 경로 쓰기; 외부 MCP 꺼짐 (권장)",
|
|
@@ -300,7 +300,6 @@ const SLASH_COMMAND_META = [
|
|
|
300
300
|
{ command: "/search", description: "Discover agents in the Hub", category: "Hub", usage: "/search <what you need>", detail: "Search the Agentlas Hub + local for an agent that fits the task (hep-search)." },
|
|
301
301
|
{ command: "/install", description: "Install an agent from the Hub by slug", category: "Hub", usage: "/install <slug>", detail: "Install a marketplace agent into this terminal." },
|
|
302
302
|
{ command: "/network", description: "Staff and execute an ontology-grounded task force", category: "Engine", usage: "/network <request> [--benchmark]", detail: "The active top host LLM creates the work order, searches the Hub workforce ontology, selects exact releases, and executes a receipt-backed task force.", aliases: ["/taskforce", "/workforce"] },
|
|
303
|
-
{ command: "/legacy-network", description: "Run the compatibility Hephaestus network route", category: "Engine", usage: "/legacy-network <request>", detail: "Explicit compatibility escape hatch; never used as a fallback by /network." },
|
|
304
303
|
{ command: "/browser", description: "Real browser execution hardpoint", category: "Engine", usage: "/browser [sub]", detail: "Runs the Agentlas browser hardpoint (hep-browser)." },
|
|
305
304
|
{ command: "/connect", description: "Wire Telegram / platforms to an agent team", category: "Hub", usage: "/connect", detail: "Runs Hephaestus hep-connect for platform integration." },
|
|
306
305
|
{ command: "/doctor", description: "Check runtimes and local data", category: "Health", usage: "/doctor", detail: "Run local checks for runtimes, data, credentials, and setup." },
|
|
@@ -351,7 +350,6 @@ const HELP_KEY_BY_COMMAND = {
|
|
|
351
350
|
"/research": "help.research",
|
|
352
351
|
"/search": "help.search",
|
|
353
352
|
"/network": "help.network",
|
|
354
|
-
"/legacy-network": "help.legacyNetwork",
|
|
355
353
|
"/browser": "help.browser",
|
|
356
354
|
"/connect": "help.connect",
|
|
357
355
|
"/doctor": "help.doctor",
|
|
@@ -706,7 +704,16 @@ function attachSlashPalette(rl, opts = {}) {
|
|
|
706
704
|
const list = rows();
|
|
707
705
|
if (!list.length) return false;
|
|
708
706
|
if (state.selected < 0 || state.selected >= list.length) state.selected = 0;
|
|
709
|
-
|
|
707
|
+
const row = list[state.selected];
|
|
708
|
+
/*
|
|
709
|
+
* 인자를 받는 명령은 확정 즉시 스페이스까지 넣는다 (2026-08-06, 레퍼런스
|
|
710
|
+
* 대조): Tab 후 바로 인자를 타이핑하게 — 스페이스를 손으로 넣는 한 박자가
|
|
711
|
+
* 모든 인자형 명령에서 반복되는 마찰이었다. 인자 없는 명령(/help 등)은
|
|
712
|
+
* 그대로 — Enter 로 즉시 실행하는 흐름을 깨지 않는다.
|
|
713
|
+
*/
|
|
714
|
+
const takesArgs = Boolean(String(row.usage || row.args || "").trim())
|
|
715
|
+
&& String(row.usage || `${row.command} ${row.args || ""}`).trim() !== row.command;
|
|
716
|
+
state.selectedCommand = row.command + (takesArgs ? " " : "");
|
|
710
717
|
replaceLine(state.selectedCommand);
|
|
711
718
|
clear();
|
|
712
719
|
return true;
|
|
Binary file
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
* 스키마는 실측으로 확인됨 (cli/agentlas.cjs 상단 주석 참고).
|
|
14
14
|
*/
|
|
15
15
|
const { execFileSync, spawn } = require("node:child_process");
|
|
16
|
+
const { detectRuntimeRefusal } = require("./runtime-refusal.cjs");
|
|
16
17
|
const crypto = require("node:crypto");
|
|
17
18
|
const fs = require("node:fs");
|
|
18
19
|
const os = require("node:os");
|
|
@@ -421,11 +422,26 @@ function handleClaudeLine(line, st, ui) {
|
|
|
421
422
|
cost_usd: obj.total_cost_usd,
|
|
422
423
|
duration_ms: obj.duration_ms,
|
|
423
424
|
};
|
|
424
|
-
if (obj.is_error)
|
|
425
|
+
if (obj.is_error) {
|
|
426
|
+
st.error = obj.result || "claude error";
|
|
427
|
+
// api_error_status:429·error:"rate_limit"이 실려 오는 실측 형태 — 한도는 quota.
|
|
428
|
+
st.errorKind = obj.api_error_status === 429 || obj.terminal_reason === "api_error"
|
|
429
|
+
? "quota" : "exit";
|
|
430
|
+
st.errorSource = "marker";
|
|
431
|
+
}
|
|
425
432
|
return;
|
|
426
433
|
case "rate_limit_event":
|
|
434
|
+
/*
|
|
435
|
+
* ★한도 거절은 **표식이다** — 경고만 찍고 버리면 안 된다.
|
|
436
|
+
* 실측(2026-08-06): 이 이벤트가 왔는데도 error가 비어 있어, 뒤따르는 거절문
|
|
437
|
+
* ("You've hit your weekly limit")이 정상 답으로 세어졌다. 살아 있는 다른
|
|
438
|
+
* 런타임으로 폴백이 안 걸린 진범. status:rejected면 그 자체로 실패다.
|
|
439
|
+
*/
|
|
427
440
|
if (obj.rate_limit_info && obj.rate_limit_info.status === "rejected") {
|
|
428
441
|
ui.warn(uiText(ui, "runtime.rateLimit", "Claude"));
|
|
442
|
+
if (!st.error) st.error = "claude rate limit rejected";
|
|
443
|
+
st.errorKind = "quota";
|
|
444
|
+
st.errorSource = "marker";
|
|
429
445
|
}
|
|
430
446
|
return;
|
|
431
447
|
default:
|
|
@@ -501,6 +517,8 @@ function handleCodexLine(line, st, ui) {
|
|
|
501
517
|
case "turn.failed":
|
|
502
518
|
case "error":
|
|
503
519
|
st.error = (obj.error && (obj.error.message || obj.error)) || "codex error";
|
|
520
|
+
st.errorKind = "exit";
|
|
521
|
+
st.errorSource = "marker";
|
|
504
522
|
ui.error(String(st.error));
|
|
505
523
|
st.errorShown = true;
|
|
506
524
|
return;
|
|
@@ -756,9 +774,24 @@ function handleGeminiLine(line, st, ui) {
|
|
|
756
774
|
duration_ms: s.duration_ms,
|
|
757
775
|
};
|
|
758
776
|
st.finalText = st.text;
|
|
759
|
-
|
|
777
|
+
// error 이벤트가 이미 구체 사유를 남겼으면 뭉뚱그린 상태 문자열로 덮지 않는다.
|
|
778
|
+
if (obj.status && obj.status !== "success" && !st.error) {
|
|
779
|
+
st.error = `gemini ${obj.status}`;
|
|
780
|
+
st.errorKind = "exit";
|
|
781
|
+
st.errorSource = "marker";
|
|
782
|
+
}
|
|
760
783
|
return;
|
|
761
784
|
}
|
|
785
|
+
case "error":
|
|
786
|
+
/*
|
|
787
|
+
* ★프로토콜이 선언하는 이벤트인데 핸들러가 없어 조용히 버려졌다
|
|
788
|
+
* (capture.cjs는 목록에 적어 두고도 안 읽었다). 인증 실패("IneligibleTierError")
|
|
789
|
+
* 같은 것이 여기로 온다 — 버리면 빈 성공이 된다.
|
|
790
|
+
*/
|
|
791
|
+
st.error = (obj.error && (obj.error.message || obj.error)) || "gemini error";
|
|
792
|
+
st.errorKind = /auth|login|credential|tier|eligib/i.test(String(st.error)) ? "auth" : "exit";
|
|
793
|
+
st.errorSource = "marker";
|
|
794
|
+
return;
|
|
762
795
|
default:
|
|
763
796
|
return;
|
|
764
797
|
}
|
|
@@ -806,8 +839,20 @@ function runNativeTurn(req) {
|
|
|
806
839
|
} else if (kind === "gemini") {
|
|
807
840
|
args = geminiArgs(launchReq);
|
|
808
841
|
lineHandler = (l) => handleGeminiLine(l, st, ui);
|
|
842
|
+
} else if (kind === "agy") {
|
|
843
|
+
/*
|
|
844
|
+
* Antigravity CLI — stream-json이 없다(실측 1.1.10). 평문 stdout을 그대로 텍스트로.
|
|
845
|
+
* ★--prompt는 값 플래그가 아니라 --print의 별칭이다(실측: 프롬프트가 조용히 유실됐던
|
|
846
|
+
* 사고) — 프롬프트는 반드시 위치 인자로 넘긴다. 시스템 프롬프트는 본문에 앞세운다.
|
|
847
|
+
*/
|
|
848
|
+
const agyPrompt = launchReq.systemPrompt
|
|
849
|
+
? `${launchReq.systemPrompt}\n\n---\n\n${launchReq.prompt}`
|
|
850
|
+
: launchReq.prompt;
|
|
851
|
+
args = ["--print", agyPrompt, ...(launchReq.model ? ["--model", launchReq.model] : [])];
|
|
852
|
+
plainStream = true;
|
|
853
|
+
lineHandler = null;
|
|
809
854
|
} else {
|
|
810
|
-
return Promise.resolve({ text: "", session: st.session, error: `unknown runtime: ${kind}
|
|
855
|
+
return Promise.resolve({ text: "", session: st.session, error: `unknown runtime: ${kind}`, errorKind: "unsupported", errorSource: "marker" });
|
|
811
856
|
}
|
|
812
857
|
} catch (error) {
|
|
813
858
|
const message = error && error.message ? error.message : String(error);
|
|
@@ -883,6 +928,8 @@ function runNativeTurn(req) {
|
|
|
883
928
|
session: st.session,
|
|
884
929
|
usage: st.usage,
|
|
885
930
|
error: termination ? termination.message : "native runtime stopped",
|
|
931
|
+
errorKind: "timeout",
|
|
932
|
+
errorSource: "marker",
|
|
886
933
|
terminationVerified: Boolean(termination?.verified),
|
|
887
934
|
});
|
|
888
935
|
};
|
|
@@ -976,13 +1023,31 @@ function runNativeTurn(req) {
|
|
|
976
1023
|
ui.stopSpinner();
|
|
977
1024
|
const text = (st.finalText || st.text || "").trim();
|
|
978
1025
|
if (st.usage) ui.cost(st.usage);
|
|
1026
|
+
/*
|
|
1027
|
+
* ★표식 없이 완주했는데 산출물이 거절 고지문인 경우 — 실측: codex 한도는
|
|
1028
|
+
* 거절문이 agent_message로 오고 turn.completed로 끝난다(표식 0, exit 0).
|
|
1029
|
+
* 이 한 자리에서만 텍스트 판별을 허용하고, 출처를 heuristic으로 남긴다
|
|
1030
|
+
* (판별 규칙은 runtime-refusal.cjs 한 곳 — 여기서 정규식을 다시 쓰지 않는다).
|
|
1031
|
+
*/
|
|
1032
|
+
if (code === 0 && !st.error) {
|
|
1033
|
+
const refusal = detectRuntimeRefusal(text);
|
|
1034
|
+
if (refusal) {
|
|
1035
|
+
st.error = refusal.message;
|
|
1036
|
+
st.errorKind = refusal.kind;
|
|
1037
|
+
st.errorSource = "heuristic";
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
979
1040
|
const exitError = code === 0
|
|
980
1041
|
? st.error
|
|
981
1042
|
: st.error || [
|
|
982
1043
|
`${kind} exited with code ${code == null ? "unknown" : code}`,
|
|
983
1044
|
stripAnsi(stderrBuf).slice(-4000),
|
|
984
1045
|
].filter(Boolean).join("\n");
|
|
985
|
-
|
|
1046
|
+
if (exitError && !st.errorKind) { st.errorKind = "exit"; st.errorSource = st.errorSource || "exit"; }
|
|
1047
|
+
finish({
|
|
1048
|
+
text, session: st.session, usage: st.usage, error: exitError,
|
|
1049
|
+
...(exitError ? { errorKind: st.errorKind, errorSource: st.errorSource } : {}),
|
|
1050
|
+
});
|
|
986
1051
|
});
|
|
987
1052
|
|
|
988
1053
|
armIdle();
|
|
@@ -142,6 +142,26 @@ async function runOnboard({ ui, rl, helpers, persist }) {
|
|
|
142
142
|
rtOpts.forEach((o, i) => optionLine(i + 1, o.label, i === 0));
|
|
143
143
|
const ri = await pickNum(rtOpts.length);
|
|
144
144
|
const runtime = rtOpts[ri - 1].value;
|
|
145
|
+
// missing인 런타임을 골라도 저장은 한다(미리 설정) — 하지만 조용히 저장하면
|
|
146
|
+
// 첫 실행 실패가 배신이 된다(2026-08-05 감사 결함 A). 설치 명령을 그 자리에서
|
|
147
|
+
// 알려주고, 로그인 흔적이 없으면 로그인 절차까지 말한다.
|
|
148
|
+
if (runtime !== "auto") {
|
|
149
|
+
const installHint = {
|
|
150
|
+
"claude-code": "npm i -g @anthropic-ai/claude-code",
|
|
151
|
+
codex: "npm i -g @openai/codex",
|
|
152
|
+
gemini: "npm i -g @google/gemini-cli",
|
|
153
|
+
}[runtime];
|
|
154
|
+
if (!H.which(H.RUNTIME_BIN[runtime])) {
|
|
155
|
+
if (installHint) printIndented(ui.t("wiz.runtimeInstallHint", installHint), c.dim);
|
|
156
|
+
} else {
|
|
157
|
+
try {
|
|
158
|
+
const { runtimeAuthEvidence } = require("./runtimes/auth-evidence.cjs");
|
|
159
|
+
if (runtimeAuthEvidence(runtime).status === "none") {
|
|
160
|
+
printIndented(ui.t("wiz.runtimeLoginHint", H.RUNTIME_BIN[runtime]), c.dim);
|
|
161
|
+
}
|
|
162
|
+
} catch { /* evidence unavailable — say nothing rather than guess */ }
|
|
163
|
+
}
|
|
164
|
+
}
|
|
145
165
|
|
|
146
166
|
// Step 3 — default permission
|
|
147
167
|
ui.line("");
|
package/engine/agentlas-ui.cjs
CHANGED
|
@@ -15,6 +15,8 @@ const RESET = "\x1b[0m";
|
|
|
15
15
|
|
|
16
16
|
function colorEnabled() {
|
|
17
17
|
if (process.env.NO_COLOR != null && process.env.NO_COLOR !== "") return false;
|
|
18
|
+
// clig.dev: TERM=dumb 인 터미널(에디터 내장 셸, 일부 CI)은 ANSI를 렌더하지 못한다.
|
|
19
|
+
if (process.env.TERM === "dumb") return false;
|
|
18
20
|
if (process.env.FORCE_COLOR === "1" || process.env.FORCE_COLOR === "true") return true;
|
|
19
21
|
if (process.env.AGENTLAS_NO_COLOR === "1") return false;
|
|
20
22
|
return !!process.stdout.isTTY;
|