agentlas 1.0.45 → 1.0.47

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +7 -7
  3. package/engine/agentlas-capabilities.cjs +3 -2
  4. package/engine/agentlas-core-harness.cjs +18 -0
  5. package/engine/agentlas-i18n.cjs +8 -8
  6. package/engine/agentlas-input.cjs +2 -2
  7. package/engine/agentlas-native-host.cjs +124 -11
  8. package/engine/agentlas-onboard.cjs +8 -3
  9. package/engine/agentlas-permissions.cjs +5 -1
  10. package/engine/agentlas-workforce.cjs +81 -24
  11. package/engine/agents/router.cjs +4 -2
  12. package/engine/architecture.data.json +6 -30
  13. package/engine/automation/daemon.cjs +1 -1
  14. package/engine/bootstrap-schema.sql +216 -191
  15. package/engine/browser/cdp.cjs +10 -4
  16. package/engine/cloud-assets/commands.cjs +1 -1
  17. package/engine/cloud-assets/package.cjs +161 -45
  18. package/engine/commands/context.cjs +14 -3
  19. package/engine/commands/doctor.cjs +7 -4
  20. package/engine/commands/graph.cjs +62 -64
  21. package/engine/commands/search.cjs +8 -3
  22. package/engine/core/desktop-core.cjs +39 -1
  23. package/engine/graph/interview.cjs +2 -11
  24. package/engine/graph/vocabulary.generated.cjs +1 -1
  25. package/engine/hephaestus/runtime.cjs +2 -6
  26. package/engine/project/memory-context.cjs +20 -7
  27. package/engine/project/seed.cjs +46 -31
  28. package/engine/project/state.cjs +8 -1
  29. package/engine/runtimes/auth-evidence.cjs +6 -0
  30. package/engine/runtimes/detect.cjs +1 -1
  31. package/engine/runtimes/resolve.cjs +27 -7
  32. package/engine/sessions/prompt.cjs +2 -2
  33. package/engine/ui/palette.cjs +1 -1
  34. package/engine/ui/repl.cjs +2 -2
  35. package/engine/ui/shell.cjs +108 -1
  36. package/engine/workforce/capture.cjs +52 -3
  37. package/engine/workforce/deps.cjs +2 -2
  38. package/engine/workforce/local-core-transport.cjs +13 -19
  39. package/package.json +1 -1
  40. package/engine/project/super-ontology-seed.json +0 -3288
package/CHANGELOG.md CHANGED
@@ -1,5 +1,35 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.0.47 — 2026-08-14
4
+
5
+ Antigravity and the shared runtime contracts now reach the independent
6
+ Terminal surface.
7
+
8
+ - `agy` is recognized as a first-class runtime in capabilities, detection,
9
+ resolution, permissions, and the interactive shell.
10
+ - Terminal model and runtime choices use the same runtime contract as Desktop,
11
+ including honest no-runtime stops and project-scoped execution.
12
+ - Workforce capture, local Core transport, graph commands, and the native host
13
+ preserve the synchronized Agentlas architecture without copying Desktop-only
14
+ SaaS state into Terminal.
15
+
16
+ Verification: the local smoke suite passed 100 cases with 0 failures. The npm
17
+ publication gate remains the authority for whether this tag is visible in the
18
+ registry.
19
+
20
+ ## 1.0.46 — 2026-08-11
21
+
22
+ Pick from a list instead of retyping a slug.
23
+
24
+ - `/search` in the shell now shows its results as a list you move through with the
25
+ arrow keys; Enter installs the one you chose. `/graph` does the same and runs the
26
+ graph you pick. Escape cancels either.
27
+ - Search results say what the listing actually means for you — "callable without
28
+ installing" or "install to use" — rather than repeating the server's own enum.
29
+ - Commands now know which surface you are standing on, so the next step they print is
30
+ one you can actually type there. Inside the shell, `search` ends with `/install <slug>`
31
+ instead of `agentlas install <slug>`, which the shell would have refused.
32
+
3
33
  ## 1.0.45 — 2026-08-11
4
34
 
5
35
  The command surface was rebuilt from one catalog, and failures stopped printing JSON.
package/README.md CHANGED
@@ -9,7 +9,7 @@
9
9
  ╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═══╝ ╚═╝ ╚══════╝╚═╝ ╚═╝╚══════╝
10
10
  ```
11
11
 
12
- **Agentlas Terminal CLI** — Independent AI agent runtime installed via `npm install -g agentlas` and launched with `agentlas`. Run exact installed agents, teams, and parallel sessions directly from your shell without keeping Desktop open. When Desktop is installed, Terminal reads the same local project, agent, and runtime state. Bring your own model — use your existing Claude Code, Codex, or Gemini CLI subscriptions or BYOK API keys.
12
+ **Agentlas Terminal CLI** — Independent AI agent runtime installed via `npm install -g agentlas` and launched with `agentlas`. Run exact installed agents, teams, and parallel sessions directly from your shell without keeping Desktop open. When Desktop is installed, Terminal reads the same local project, agent, and runtime state. Bring your own model — use Antigravity (`agy`), Claude Code, Codex, legacy Gemini CLI, or BYOK API keys.
13
13
 
14
14
  Use this existing independent Terminal as the command-line runtime: inspect owner-private packages with `agentlas cloud list`, restore one with `agentlas cloud restore <slug>`, or install an eligible public package with `agentlas install <slug>`.
15
15
 
@@ -24,10 +24,10 @@ Agent Trust is our product principle: agent packages are treated as portable, ow
24
24
  | Category | Requirement |
25
25
  | --- | --- |
26
26
  | **Node.js** | **Node 22+ recommended.** `package.json` specifies `engines: ">=20"`, but if native optional dependency `better-sqlite3` build fails, the launcher falls back strictly to `node:sqlite` in Node 22+. Node 20 works when `better-sqlite3` native build succeeds. |
27
- | **Agent CLI** | Requires at least one supported runtime CLI (`claude`, `codex`, or `gemini`) in your `PATH`. Halts honestly with `no_runtime` if none are found (no fake model responses). |
27
+ | **Agent CLI** | Requires at least one supported runtime CLI: `agy` (Antigravity, preferred), `claude`, `codex`, or legacy `gemini` in your `PATH`. Halts honestly with `no_runtime` if none are found (no fake model responses). |
28
28
  | **OS** | macOS is verified by the current local release gate. Linux is covered by the public adapter/CI contract. A Windows launcher is provided, but this release does not claim independent end-to-end Windows verification. |
29
29
 
30
- *Note: `kimi`, `grok`, and `cursor-agent` are detected by diagnostics (`doctor`) but not yet executable (`has no v2 streaming driver yet`). Supported active runtimes are `claude-code`, `codex`, and `gemini`.*
30
+ *Note: `kimi`, `grok`, and `cursor-agent` are detected by diagnostics (`doctor`) but not yet executable (`has no v2 streaming driver yet`). Supported active runtimes are `claude-code`, `codex`, `agy` (Antigravity), and legacy `gemini`.*
31
31
 
32
32
  ## Installation
33
33
 
@@ -143,7 +143,7 @@ agentlas netadmin <sub> # Local network administration (init|status|re
143
143
  agentlas version | help
144
144
  ```
145
145
 
146
- Common flags across subcommands: `-p|--print`, `--runtime claude-code|codex|gemini`, `--permission read|write|full`.
146
+ Common flags across subcommands: `-p|--print`, `--runtime claude-code|codex|agy|gemini`, `--permission read|write|full`.
147
147
 
148
148
  ### Typo Guard & Desktop Surface Redirection
149
149
 
@@ -183,7 +183,7 @@ Executing `agentlas` with no arguments resolves the current folder to an Agentla
183
183
  | `/agents` · `/list` | List installed agents |
184
184
  | `/mcp` | List active MCP servers |
185
185
  | `/doctor` | Run runtime & database diagnostics |
186
- | `/runtime <kind>` | Set runtime for new sessions (`claude-code` \| `codex` \| `gemini`) |
186
+ | `/runtime <kind>` | Set runtime for new sessions (`claude-code` \| `codex` \| `agy` (Antigravity) \| legacy `gemini`) |
187
187
  | `/permission <level>` | Set permission level for new sessions (`read` \| `write` \| `full`) |
188
188
  | `/quit` · `/exit` | Exit REPL |
189
189
 
@@ -276,8 +276,8 @@ agentlas doctor # Checks database, PATH runtimes, active CLI drivers, and c
276
276
  agentlas --where # Outputs JSON diagnostic of launcher, engine, DB paths, driver, and Node version
277
277
  ```
278
278
 
279
- - **`no_runtime: no agent CLI found`**: Install `claude`, `codex`, or `gemini` CLI and add to `PATH`. Note that `kimi`/`grok`/`cursor-agent` are detected by `doctor` but do not yet have streaming execution drivers.
280
- - **`runtime '<kind>' has no v2 streaming driver yet`**: Specified `--runtime` is not supported for active execution. Supported values: `claude-code`, `codex`, `gemini`.
279
+ - **`no_runtime: no agent CLI found`**: Connect Antigravity and put `agy` on `PATH` first, or install `claude`/`codex`; `gemini` remains available as a legacy CLI. Note that `kimi`/`grok`/`cursor-agent` are detected by `doctor` but do not yet have streaming execution drivers.
280
+ - **`runtime '<kind>' has no v2 streaming driver yet`**: Specified `--runtime` is not supported for active execution. Supported values: `claude-code`, `codex`, `agy` (Antigravity), `gemini` (legacy).
281
281
  - **`Node vX — Node 22+ (node:sqlite) is required when better-sqlite3 is unavailable`**: `better-sqlite3` native build failed on Node 20/21. Upgrade to Node 22+ or install build tools for native compilation.
282
282
  - **`storm`/`context`/`hep` halting due to missing runtime**: Agentlas OS core runtime is missing. Install Agentlas OS or set `HEPHAESTUS_BIN=<path>`.
283
283
  - **`'xxx' is not an agentlas command`**: Typo guard intercepted an unrecognized command. Use `agentlas run -p "xxx"` to run it as a prompt.
@@ -15,6 +15,7 @@ const RUNTIME_CAPS = {
15
15
  "claude-code": { code: true, image: false, label: "claude" },
16
16
  codex: { code: true, image: true, label: "codex" }, // Imagen
17
17
  gemini: { code: true, image: true, label: "gemini" }, // nano-banana
18
+ agy: { code: true, image: true, label: "antigravity" },
18
19
  grok: { code: true, image: true, label: "grok" }, // Grok Imagine (generate_image/generate_video, 구독 키리스)
19
20
  anthropic: { code: true, image: false, label: "anthropic" },
20
21
  openai: { code: true, image: true, label: "openai" }, // gpt-image
@@ -25,7 +26,7 @@ const RUNTIME_CAPS = {
25
26
 
26
27
  // NOTE: grok은 CAPS(멀티모달 능력 인지)만 등록 — 터미널 스폰 러너(RUNTIME_BIN)가 아직 없어
27
28
  // CLI_KINDS에 넣으면 repl의 which(RUNTIME_BIN[k]) 탐지가 깨진다. 러너 추가 시 함께 확장할 것.
28
- const CLI_KINDS = ["claude-code", "codex", "gemini"];
29
+ const CLI_KINDS = ["claude-code", "codex", "agy", "gemini"];
29
30
 
30
31
  function capsFor(spec) {
31
32
  return RUNTIME_CAPS[spec] || { code: true, image: false, label: spec || "?" };
@@ -115,7 +116,7 @@ function clearImageJudgments() {
115
116
  function autoRuntimeFor(agent, { installedKinds, activeSpec }) {
116
117
  if (needsImage(agent)) {
117
118
  if (capsFor(activeSpec).image) return activeSpec;
118
- for (const k of ["gemini", "codex"]) if ((installedKinds || []).includes(k)) return k;
119
+ for (const k of ["agy", "gemini", "codex"]) if ((installedKinds || []).includes(k)) return k;
119
120
  }
120
121
  return activeSpec;
121
122
  }
@@ -17,6 +17,10 @@ const CORE_RUNTIME_MARKERS = [
17
17
  ["schemas", "workforce-work-order.schema.json"],
18
18
  ["schemas", "workforce-selection.schema.json"],
19
19
  ];
20
+ const CONTEXT_MAP_V3_RUNTIME_MARKERS = [
21
+ ["agentlas_cloud", "project_bootstrap.py"],
22
+ ["schemas", "context-index-policy.schema.json"],
23
+ ];
20
24
 
21
25
  const PY_BOOTSTRAP =
22
26
  "import os, runpy, sys; " +
@@ -116,6 +120,18 @@ function resolveCoreRuntimeRoot(explicitRoot, requiredMarkers = [], options = {}
116
120
  return resolveCoreRuntimeRootFromCandidates(runtimeRoots(explicitRoot), requiredMarkers, options);
117
121
  }
118
122
 
123
+ // Context Map is a versioned Core capability. Every Terminal caller that
124
+ // injects a slice must use the same marker and minimum-version gate as the
125
+ // explicit `agentlas context` command; otherwise a stale runtime can silently
126
+ // supply a pre-v3 map to prompts, memory, or Workforce.
127
+ function resolveContextMapCoreRoot(explicitRoot) {
128
+ return resolveCoreRuntimeRoot(
129
+ explicitRoot,
130
+ CONTEXT_MAP_V3_RUNTIME_MARKERS,
131
+ { minVersion: CONTEXT_MAP_MIN_CORE_VERSION },
132
+ );
133
+ }
134
+
119
135
  function pythonCandidates() {
120
136
  return [...new Set([
121
137
  process.env.HEPHAESTUS_PYTHON,
@@ -262,10 +278,12 @@ module.exports = {
262
278
  HARNESS_ID,
263
279
  HARNESS_MODE,
264
280
  CONTEXT_MAP_MIN_CORE_VERSION,
281
+ CONTEXT_MAP_V3_RUNTIME_MARKERS,
265
282
  PY_BOOTSTRAP,
266
283
  readCoreRuntimeVersion,
267
284
  resolveCoreRuntimeRootFromCandidates,
268
285
  resolveCoreRuntimeRoot,
286
+ resolveContextMapCoreRoot,
269
287
  resolvePython,
270
288
  spawnCoreModule,
271
289
  parseJsonOutput,
@@ -62,9 +62,9 @@ const STRINGS = {
62
62
  "noKey": "No %s API key. Add one in the app (Settings → BYOK), or switch with /runtime.",
63
63
  "runtimeSet": "runtime → %s",
64
64
  "runtimeNotInstalled": "%s CLI is not installed.",
65
- "runtimeUnknown": "Unknown runtime: %s (claude-code|codex|gemini)",
66
- "runtimeUnavailable": "No runtime is available. Install a CLI (claude/codex/gemini) or configure an API key/Ollama in the app.",
67
- "runtimeUsage": "usage: /runtime claude-code|codex|gemini|anthropic|openai|google|ollama|upstage",
65
+ "runtimeUnknown": "Unknown runtime: %s (claude-code|codex|agy|gemini)",
66
+ "runtimeUnavailable": "No runtime is available. Install a CLI (claude/codex/agy; legacy gemini is supported) or configure an API key/Ollama in the app.",
67
+ "runtimeUsage": "usage: /runtime claude-code|codex|agy|gemini|anthropic|openai|google|ollama|upstage",
68
68
  "modelOnlyApi": "/model only applies to BYOK/Ollama (api) runtimes.",
69
69
  "modelSet": "model → %s",
70
70
  "modelCurrent": "current model: %s",
@@ -166,7 +166,7 @@ const STRINGS = {
166
166
  "help.team": "view/assign each agent's LLM (auto-routed by capability)",
167
167
  "help.agent": "switch to another agent",
168
168
  "help.firms": "list companies / switch to one",
169
- "help.runtime": "switch runtime (claude-code|codex|gemini|anthropic|openai|google|ollama|upstage)",
169
+ "help.runtime": "switch runtime (claude-code|codex|agy|legacy gemini|anthropic|openai|google|ollama|upstage)",
170
170
  "help.model": "set the model (claude/codex/gemini alias or BYOK/Ollama id)",
171
171
  "help.effort": "set reasoning effort (low|medium|high|max|off|auto)",
172
172
  "help.permission": "what it may do (read|write|full)",
@@ -311,9 +311,9 @@ const STRINGS = {
311
311
  "noKey": "%s API 키가 없습니다. 앱 설정 → BYOK에서 등록하거나 /runtime으로 전환하세요.",
312
312
  "runtimeSet": "런타임 → %s",
313
313
  "runtimeNotInstalled": "%s CLI가 설치돼 있지 않습니다.",
314
- "runtimeUnknown": "알 수 없는 런타임: %s (claude-code|codex|gemini)",
315
- "runtimeUnavailable": "사용 가능한 런타임이 없습니다. CLI(claude/codex/gemini)를 설치하거나 앱에서 API 키/Ollama를 설정하세요.",
316
- "runtimeUsage": "사용법: /runtime claude-code|codex|gemini|anthropic|openai|google|ollama|upstage",
314
+ "runtimeUnknown": "알 수 없는 런타임: %s (claude-code|codex|agy|gemini)",
315
+ "runtimeUnavailable": "사용 가능한 런타임이 없습니다. CLI(claude/codex/agy, 레거시 gemini 지원)를 설치하거나 앱에서 API 키/Ollama를 설정하세요.",
316
+ "runtimeUsage": "사용법: /runtime claude-code|codex|agy|gemini|anthropic|openai|google|ollama|upstage",
317
317
  "modelOnlyApi": "/model은 BYOK/Ollama(api) 런타임에서만 적용됩니다.",
318
318
  "modelSet": "모델 → %s",
319
319
  "modelCurrent": "현재 모델: %s",
@@ -414,7 +414,7 @@ const STRINGS = {
414
414
  "help.team": "에이전트별 LLM 보기/지정 (능력 기반 자동)",
415
415
  "help.agent": "다른 에이전트로 전환",
416
416
  "help.firms": "회사 목록 / 전환",
417
- "help.runtime": "런타임 전환 (claude-code|codex|gemini|anthropic|openai|google|ollama|upstage)",
417
+ "help.runtime": "런타임 전환 (claude-code|codex|agy|레거시 gemini|anthropic|openai|google|ollama|upstage)",
418
418
  "help.model": "모델 지정 (claude/codex/gemini 별칭 또는 BYOK/Ollama id)",
419
419
  "help.effort": "추론 강도 지정 (low|medium|high|max|off|auto)",
420
420
  "help.permission": "허용 범위 (read|write|full)",
@@ -270,7 +270,7 @@ const SLASH_COMMAND_META = [
270
270
  { command: "/agent", description: "Switch to another agent", category: "Routing", usage: "/agent <name>", detail: "Switch the current conversation to an installed agent." },
271
271
  { command: "/firms", description: "List installed companies", category: "Routing", usage: "/firms", detail: "Show company CEOs available in this terminal." },
272
272
  { command: "/firm", description: "Switch to a company CEO", category: "Routing", usage: "/firm <name>", detail: "Switch the current conversation to a company CEO agent." },
273
- { command: "/runtime", description: "Switch runtime: claude-code, codex, gemini, BYOK, or Ollama", category: "Settings", usage: "/runtime codex", detail: "Change the engine Agentlas uses for subsequent turns." },
273
+ { command: "/runtime", description: "Switch runtime: claude-code, codex, agy, legacy gemini, BYOK, or Ollama", category: "Settings", usage: "/runtime agy", detail: "Change the engine Agentlas uses for subsequent turns." },
274
274
  { command: "/model", description: "Pin a model or return to auto allocation", category: "Settings", usage: "/model <id|auto>", detail: "An id is an explicit session pin; auto lets the higher-level allocator choose a provider-compatible tier." },
275
275
  { command: "/effort", description: "Pin reasoning effort or return to auto", category: "Settings", usage: "/effort low|medium|high|max|off|auto", detail: "A level is an explicit pin; auto lets the higher-level allocator choose per task; off is an explicit no-effort pin." },
276
276
  { command: "/permission", description: "Set read/write/full permission", category: "Settings", usage: "/permission full", detail: "No argument shows what read, write, and full mean.", aliases: ["/perm"] },
@@ -306,7 +306,7 @@ const SLASH_COMMAND_META = [
306
306
  { command: "/exit", description: "Quit Agentlas", category: "Session", usage: "/exit", detail: "Close the terminal session.", aliases: ["/quit"] },
307
307
  ];
308
308
  const SLASH_COMMANDS = SLASH_COMMAND_META.flatMap((entry) => [entry.command].concat(entry.aliases || []));
309
- const RUNTIME_SPECS = ["claude-code", "codex", "gemini", "anthropic", "openai", "google", "ollama", "upstage"];
309
+ const RUNTIME_SPECS = ["claude-code", "codex", "agy", "gemini", "anthropic", "openai", "google", "ollama", "upstage"];
310
310
  const PERM_LEVELS = ["read", "write", "full"];
311
311
 
312
312
  const HELP_KEY_BY_COMMAND = {
@@ -700,6 +700,118 @@ function geminiArgs({ prompt, systemPrompt, permission, model, mcpServers, mcpAl
700
700
  ];
701
701
  }
702
702
 
703
+ function agyPermissionArgs(permission) {
704
+ const level = permissions.normalize(permission);
705
+ if (level === "full") return ["--dangerously-skip-permissions"];
706
+ return [
707
+ "--mode", level === "write" ? "accept-edits" : "plan",
708
+ "--sandbox",
709
+ ];
710
+ }
711
+
712
+ function agyArgs({ prompt, systemPrompt, permission, model, addDirectories = [] }) {
713
+ const body = systemPrompt ? `${systemPrompt}\n\n---\n\n${prompt}` : prompt;
714
+ return [
715
+ ...(model ? ["--model", model] : []),
716
+ ...[...new Set(addDirectories.filter(Boolean))].flatMap((dir) => ["--add-dir", dir]),
717
+ ...agyPermissionArgs(permission),
718
+ "--output-format", "stream-json",
719
+ "--print-timeout", "30m",
720
+ "--prompt", body,
721
+ ];
722
+ }
723
+
724
+ const AGY_WINDOWS_ARGV_PROMPT_LIMIT = 6_000;
725
+
726
+ function agyPromptBootstrap(promptFile) {
727
+ return `Read the complete Agentlas request from ${JSON.stringify(promptFile)}, follow it exactly, and do not reveal the file path.`;
728
+ }
729
+
730
+ /**
731
+ * Windows npm CLI shims pass through cmd.exe's much smaller command-line
732
+ * ceiling. Move only oversized agy prompts into a private one-shot file and
733
+ * keep argv limited to a short bootstrap. The caller owns cleanup and must run
734
+ * it on every process terminal path (close, spawn error, timeout, and abort).
735
+ */
736
+ function prepareAgyLaunch(request, options = {}) {
737
+ const body = request.systemPrompt
738
+ ? `${request.systemPrompt}\n\n---\n\n${request.prompt}`
739
+ : request.prompt;
740
+ const platform = options.platform || process.platform;
741
+ const promptLimit = Number.isFinite(options.promptLimit)
742
+ ? Math.max(1, Math.trunc(options.promptLimit))
743
+ : AGY_WINDOWS_ARGV_PROMPT_LIMIT;
744
+ if (platform !== "win32" || body.length <= promptLimit) {
745
+ return { args: agyArgs(request), promptFile: null, cleanup: () => {} };
746
+ }
747
+
748
+ let directory = null;
749
+ try {
750
+ directory = fs.mkdtempSync(path.join(os.tmpdir(), "agentlas-agy-prompt-"));
751
+ try { fs.chmodSync(directory, 0o700); } catch { /* Windows/best-effort */ }
752
+ const promptFile = path.join(directory, "request.txt");
753
+ fs.writeFileSync(promptFile, body, { encoding: "utf8", mode: 0o600, flag: "wx" });
754
+ try { fs.chmodSync(promptFile, 0o600); } catch { /* Windows/best-effort */ }
755
+ let cleaned = false;
756
+ return {
757
+ args: agyArgs({
758
+ ...request,
759
+ systemPrompt: "",
760
+ prompt: agyPromptBootstrap(promptFile),
761
+ addDirectories: [directory, ...(request.addDirectories || [])],
762
+ }),
763
+ promptFile,
764
+ cleanup: () => {
765
+ if (cleaned) return;
766
+ cleaned = true;
767
+ try { fs.rmSync(directory, { recursive: true, force: true }); } catch { /* OS temp cleanup fallback */ }
768
+ },
769
+ };
770
+ } catch (error) {
771
+ if (directory) {
772
+ try { fs.rmSync(directory, { recursive: true, force: true }); } catch { /* best-effort */ }
773
+ }
774
+ throw error;
775
+ }
776
+ }
777
+
778
+ function handleAgyLine(line, st, ui) {
779
+ let obj;
780
+ try { obj = JSON.parse(line); } catch { return; }
781
+ if (obj.event === "result") {
782
+ if (st.geminiStreaming) { ui.streamEnd(); st.geminiStreaming = false; }
783
+ if (obj.result && typeof obj.result.response === "string") st.finalText = obj.result.response;
784
+ if (obj.result?.status && !["success", "completed", "done"].includes(String(obj.result.status).toLowerCase())) {
785
+ st.error = `agy ${obj.result.status}`;
786
+ st.errorKind = "exit";
787
+ st.errorSource = "marker";
788
+ }
789
+ return;
790
+ }
791
+ if (obj.event !== "step_update" || !obj.step_update) {
792
+ if (obj.event) ui.status(`agy: ${obj.event}`);
793
+ return;
794
+ }
795
+ const step = obj.step_update;
796
+ if (step.usage) {
797
+ st.usage = {
798
+ input_tokens: step.usage.input_tokens,
799
+ output_tokens: step.usage.output_tokens,
800
+ ...(step.usage.duration_ms != null ? { duration_ms: step.usage.duration_ms } : {}),
801
+ };
802
+ }
803
+ if (step.step_type === "agent_response") {
804
+ const delta = typeof step.text_delta === "string" ? step.text_delta : "";
805
+ if (!delta) return;
806
+ if (!st.geminiStreaming) { ui.streamStart(); st.geminiStreaming = true; }
807
+ ui.streamDelta(delta);
808
+ st.text += delta;
809
+ return;
810
+ }
811
+ if (st.geminiStreaming) { ui.streamEnd(); st.geminiStreaming = false; }
812
+ ui.status(`agy: ${step.step_type || "step"}${step.state ? ` (${step.state})` : ""}`);
813
+ }
814
+
703
815
  // gemini 툴명 → 친숙한 표시명 (claude/codex 표기와 통일)
704
816
  const GEMINI_TOOL_NAMES = {
705
817
  run_shell_command: "Bash",
@@ -829,6 +941,7 @@ function runNativeTurn(req) {
829
941
  let args;
830
942
  let lineHandler;
831
943
  let plainStream = false;
944
+ let launchCleanup = () => {};
832
945
  try {
833
946
  if (kind === "claude-code") {
834
947
  args = claudeArgs(launchReq);
@@ -840,17 +953,10 @@ function runNativeTurn(req) {
840
953
  args = geminiArgs(launchReq);
841
954
  lineHandler = (l) => handleGeminiLine(l, st, ui);
842
955
  } 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;
956
+ const prepared = prepareAgyLaunch(launchReq);
957
+ args = prepared.args;
958
+ launchCleanup = prepared.cleanup;
959
+ lineHandler = (l) => handleAgyLine(l, st, ui);
854
960
  } else {
855
961
  return Promise.resolve({ text: "", session: st.session, error: `unknown runtime: ${kind}`, errorKind: "unsupported", errorSource: "marker" });
856
962
  }
@@ -885,6 +991,7 @@ function runNativeTurn(req) {
885
991
  try { req.onSpawn(child); } catch { /* observer 실패가 턴을 죽이면 안 됨 */ }
886
992
  }
887
993
  } catch (e) {
994
+ launchCleanup();
888
995
  ui.error(uiText(ui, "runtime.failed", kind, e.message));
889
996
  return resolve({ text: "", session: st.session, error: e.message });
890
997
  }
@@ -911,6 +1018,7 @@ function runNativeTurn(req) {
911
1018
  removeLineReader();
912
1019
  child.stderr?.removeListener("data", onStderr);
913
1020
  if (req.signal) req.signal.removeEventListener?.("abort", onAbort);
1021
+ launchCleanup();
914
1022
  };
915
1023
  const finish = (result) => {
916
1024
  if (settled) return;
@@ -1212,6 +1320,11 @@ module.exports = {
1212
1320
  codexPermissionArgs,
1213
1321
  geminiArgs,
1214
1322
  geminiPermissionArgs,
1323
+ agyArgs,
1324
+ agyPermissionArgs,
1325
+ agyPromptBootstrap,
1326
+ prepareAgyLaunch,
1327
+ handleAgyLine,
1215
1328
  claudeMcpIsolationArgs,
1216
1329
  geminiMcpIsolationArgs,
1217
1330
  prepareCodexRuntimeEnv,
@@ -133,11 +133,12 @@ async function runOnboard({ ui, rl, helpers, persist }) {
133
133
  // Step 2 — default runtime
134
134
  ui.line("");
135
135
  printIndented(ui.t("wiz.runtimeQ"), c.bold);
136
- const cliKinds = ["claude-code", "codex", "gemini"];
136
+ const cliKinds = ["claude-code", "codex", "agy", "gemini"];
137
137
  const rtOpts = [{ value: "auto", label: ui.t("wiz.runtimeAuto") }];
138
138
  for (const k of cliKinds) {
139
139
  const has = !!H.which(H.RUNTIME_BIN[k]);
140
- rtOpts.push({ value: k, label: `${k} (${has ? ui.t("wiz.runtimeInstalled") : ui.t("wiz.runtimeMissing")})` });
140
+ const runtimeLabel = k === "agy" ? "agy · Antigravity" : k === "gemini" ? "gemini · legacy" : k;
141
+ rtOpts.push({ value: k, label: `${runtimeLabel} (${has ? ui.t("wiz.runtimeInstalled") : ui.t("wiz.runtimeMissing")})` });
141
142
  }
142
143
  rtOpts.forEach((o, i) => optionLine(i + 1, o.label, i === 0));
143
144
  const ri = await pickNum(rtOpts.length);
@@ -149,6 +150,7 @@ async function runOnboard({ ui, rl, helpers, persist }) {
149
150
  const installHint = {
150
151
  "claude-code": "npm i -g @anthropic-ai/claude-code",
151
152
  codex: "npm i -g @openai/codex",
153
+ agy: "Install Antigravity from https://antigravity.google/ and put agy on PATH",
152
154
  gemini: "npm i -g @google/gemini-cli",
153
155
  }[runtime];
154
156
  if (!H.which(H.RUNTIME_BIN[runtime])) {
@@ -156,7 +158,10 @@ async function runOnboard({ ui, rl, helpers, persist }) {
156
158
  } else {
157
159
  try {
158
160
  const { runtimeAuthEvidence } = require("./runtimes/auth-evidence.cjs");
159
- if (runtimeAuthEvidence(runtime).status === "none") {
161
+ // Antigravity and legacy Gemini currently share Google's local OAuth
162
+ // evidence root, but remain distinct executable/runtime selections.
163
+ const evidenceKind = runtime === "agy" ? "gemini" : runtime;
164
+ if (runtimeAuthEvidence(evidenceKind).status === "none") {
160
165
  printIndented(ui.t("wiz.runtimeLoginHint", H.RUNTIME_BIN[runtime]), c.dim);
161
166
  }
162
167
  } catch { /* evidence unavailable — say nothing rather than guess */ }
@@ -9,6 +9,10 @@
9
9
 
10
10
  const LEVELS = ["read", "write", "full"];
11
11
 
12
+ function isLevel(value) {
13
+ return LEVELS.includes(String(value || "").trim().toLowerCase());
14
+ }
15
+
12
16
  const COPY = {
13
17
  en: {
14
18
  read: {
@@ -94,4 +98,4 @@ function createCycleController(options = {}) {
94
98
  };
95
99
  }
96
100
 
97
- module.exports = { LEVELS, normalize, persistent, next, copy, createCycleController };
101
+ module.exports = { LEVELS, isLevel, normalize, persistent, next, copy, createCycleController };