agentlas 1.0.46 → 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 +17 -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 +46 -54
  21. package/engine/commands/search.cjs +2 -2
  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 +5 -2
  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
@@ -741,7 +741,7 @@ function handleSlash(ctx, cmdline, api) {
741
741
  }
742
742
 
743
743
  case "runtime": {
744
- if (!rest[0]) throw usageError("Usage: /runtime claude-code|codex|gemini");
744
+ if (!rest[0]) throw usageError("Usage: /runtime claude-code|codex|agy|gemini");
745
745
  // 세션 오버라이드는 저장되지 않는다 — 고지 없이는 사용자가 영구 설정으로
746
746
  // 믿는다(2026-08-05 감사 결함 C). 영구 경로를 같은 줄에서 알려준다.
747
747
  api.setRuntime(rest[0]);
@@ -774,7 +774,7 @@ function handleSlash(ctx, cmdline, api) {
774
774
  return;
775
775
  }
776
776
  case "permission": {
777
- if (!["read", "write", "full"].includes(String(rest[0] || ""))) {
777
+ if (!permissions.isLevel(rest[0])) {
778
778
  throw usageError("Usage: /permission read|write|full");
779
779
  }
780
780
  const level = permissions.normalize(rest[0]);
@@ -386,7 +386,7 @@ async function startShell(ctx, opts = {}) {
386
386
  let result;
387
387
  ui.updateSpinner(en ? "Searching the Hub…" : "Hub 검색 중…");
388
388
  try {
389
- result = await callHubTool("marketplace.search_agents", { q: query, query, limit: 12 });
389
+ result = await callHubTool("marketplace.search_agents", { q: query, limit: 12 });
390
390
  } catch (e) {
391
391
  ui.stopSpinner();
392
392
  ui.error(Object.assign(new Error(e instanceof HubError ? e.message : String((e && e.message) || e)),
@@ -449,8 +449,11 @@ async function startShell(ctx, opts = {}) {
449
449
  return;
450
450
  }
451
451
  if (cmd === "permission") {
452
+ if (!permissions.isLevel(value)) {
453
+ ui.line(ui.c.dim("Usage: /permission read|write|full"));
454
+ return;
455
+ }
452
456
  const next = permissions.normalize(value);
453
- if (!next) { ui.line(ui.c.dim("Usage: /permission read|write|full")); return; }
454
457
  permission = next;
455
458
  ui.line(ui.c.dim(`permission: ${next} · ${en ? "persist: agentlas setup" : "영구 저장: agentlas setup"}`));
456
459
  return;
@@ -29,6 +29,7 @@ const { dbPath, userDataDir } = require("../core/paths.cjs");
29
29
  const RUNTIME_BIN = {
30
30
  "claude-code": "claude",
31
31
  codex: "codex",
32
+ agy: "agy",
32
33
  gemini: "gemini",
33
34
  };
34
35
 
@@ -198,6 +199,14 @@ function buildArgs(kind, systemPrompt, prompt, permission, runtimeOptions = {})
198
199
  const mcp = native.geminiMcpIsolationArgs();
199
200
  return ["--prompt", `[SYSTEM]\n${systemPrompt}\n\n${prompt}`, ...(model ? ["-m", model] : []), ...perm, ...noAuthorityArgs, ...mcp];
200
201
  }
202
+ if (kind === "agy") {
203
+ return native.agyArgs({
204
+ prompt,
205
+ systemPrompt,
206
+ permission: noAuthority ? "read" : level,
207
+ model,
208
+ });
209
+ }
201
210
  return [prompt];
202
211
  }
203
212
 
@@ -287,6 +296,7 @@ function capturedRuntimeUsage(kind, raw) {
287
296
  }
288
297
  const direct =
289
298
  genericUsage(event?.usage) ||
299
+ genericUsage(event?.step_update?.usage) ||
290
300
  genericUsage(event?.usageMetadata) ||
291
301
  genericUsage(event?.stats);
292
302
  if (direct) return direct;
@@ -346,6 +356,12 @@ function capturedRuntimeFailure(kind, raw, text) {
346
356
  return { message: `gemini ${event.status}`, source: "marker" };
347
357
  }
348
358
  }
359
+ if (kind === "agy" && event.event === "result") {
360
+ const status = String(event.result?.status || "").toLowerCase();
361
+ if (status && !["success", "completed", "done"].includes(status)) {
362
+ return { message: `agy ${status}`, source: "marker" };
363
+ }
364
+ }
349
365
  }
350
366
  // 표식이 전혀 없는 케이스(codex 한도) — 휴리스틱 최후 그물, 출처 표기.
351
367
  const refusal = detectRuntimeRefusal(text);
@@ -399,6 +415,21 @@ function capturedRuntimeAgentText(kind, raw) {
399
415
  return final ? String(final.result ?? final.response) : "";
400
416
  }
401
417
 
418
+ if (kind === "agy") {
419
+ const isProtocol = events.some((event) =>
420
+ event?.event === "step_update" || event?.event === "result",
421
+ );
422
+ if (!isProtocol) return text.trim();
423
+ const final = [...events].reverse().find((event) =>
424
+ event?.event === "result" && typeof event.result?.response === "string",
425
+ );
426
+ if (final) return final.result.response;
427
+ return events
428
+ .filter((event) => event?.event === "step_update" && event.step_update?.step_type === "agent_response")
429
+ .map((event) => typeof event.step_update?.text_delta === "string" ? event.step_update.text_delta : "")
430
+ .join("");
431
+ }
432
+
402
433
  return text.trim();
403
434
  }
404
435
 
@@ -423,6 +454,7 @@ function captureRuntime(kind, systemPrompt, prompt, opts) {
423
454
  // 계약 테스트용 실행 파일 주입(가짜 CLI가 픽스처를 cat) — 프로덕션 경로에선 없음.
424
455
  const bin = opts.binOverride || which(RUNTIME_BIN[kind]) || RUNTIME_BIN[kind];
425
456
  let child;
457
+ let launchCleanup = () => {};
426
458
  try {
427
459
  const spawnImpl = opts.spawn || spawn;
428
460
  const env = nativeHost.runtimeEnvForKind(kind, opts.env || process.env, {
@@ -431,13 +463,28 @@ function captureRuntime(kind, systemPrompt, prompt, opts) {
431
463
  mcpAllowlistMode: kind === "gemini" ? "exact" : undefined,
432
464
  });
433
465
  const groupedChild = process.platform !== "win32" && spawnImpl === spawn;
434
- child = spawnImpl(bin, buildArgs(kind, systemPrompt, prompt, opts.permission, {
466
+ const runtimeOptions = {
435
467
  model: opts.model,
436
468
  effort: opts.effort,
437
469
  authorityMode: opts.authorityMode,
438
470
  noToolsPolicyPath: opts.noToolsPolicyPath,
439
471
  allowedNativeTools: opts.allowedNativeTools,
440
- }), {
472
+ };
473
+ let childArgs = buildArgs(kind, systemPrompt, prompt, opts.permission, runtimeOptions);
474
+ if (kind === "agy") {
475
+ const prepared = nativeHost.prepareAgyLaunch({
476
+ prompt,
477
+ systemPrompt,
478
+ permission: opts.authorityMode === "no-authority" ? "read" : opts.permission,
479
+ model: opts.model,
480
+ }, {
481
+ platform: opts.platform,
482
+ promptLimit: opts.agyPromptLimit,
483
+ });
484
+ childArgs = prepared.args;
485
+ launchCleanup = prepared.cleanup;
486
+ }
487
+ child = spawnImpl(bin, childArgs, {
441
488
  cwd,
442
489
  stdio: ["ignore", "pipe", "pipe"],
443
490
  env,
@@ -446,6 +493,7 @@ function captureRuntime(kind, systemPrompt, prompt, opts) {
446
493
  });
447
494
  child.__agentlasGroupedChild = groupedChild;
448
495
  } catch (error) {
496
+ launchCleanup();
449
497
  reject(error);
450
498
  return;
451
499
  }
@@ -479,6 +527,7 @@ function captureRuntime(kind, systemPrompt, prompt, opts) {
479
527
  child.removeListener("error", onError);
480
528
  child.removeListener("close", onClose);
481
529
  if (opts.signal) opts.signal.removeEventListener?.("abort", onAbort);
530
+ launchCleanup();
482
531
  };
483
532
  const finishReject = (error) => {
484
533
  if (settled) return;
@@ -562,7 +611,7 @@ function captureRuntime(kind, systemPrompt, prompt, opts) {
562
611
  let text;
563
612
  if (kind === "codex" && opts.authorityMode === "no-authority") {
564
613
  text = codexCaptureAgentText(raw);
565
- } else if (kind === "claude-code" || kind === "gemini") {
614
+ } else if (kind === "claude-code" || kind === "gemini" || kind === "agy") {
566
615
  text = capturedRuntimeAgentText(kind, raw);
567
616
  } else {
568
617
  text = raw;
@@ -109,7 +109,7 @@ function legacyWorkforceRuntime(db, override) {
109
109
  }
110
110
  }
111
111
  const error = new Error(
112
- "no_runtime: no agent CLI or connected API runtime found (claude / codex / gemini / BYOK / Ollama).",
112
+ "no_runtime: no agent CLI or connected API runtime found (claude / codex / Antigravity agy / legacy gemini / BYOK / Ollama).",
113
113
  );
114
114
  error.code = "no_runtime";
115
115
  throw error;
@@ -513,7 +513,7 @@ function projectContextSlice(projectPath, task) {
513
513
  if (!projectPath || !String(task || "").trim()) return "";
514
514
  try {
515
515
  const core = coreHarness();
516
- const coreRoot = core.resolveCoreRuntimeRoot();
516
+ const coreRoot = core.resolveContextMapCoreRoot();
517
517
  if (!coreRoot) return "";
518
518
  const result = core.captureCoreJsonSync(
519
519
  "agentlas_cloud",
@@ -7,16 +7,14 @@
7
7
  * search_candidates 요청 {workOrder, sourceScope}
8
8
  * 응답 agentlas.workforce-federation-result.v1 봉투
9
9
  * → 루프에는 봉투를 벗긴 candidateSet만 준다.
10
- * validate_selection 요청 {workOrder, selection, candidateSet}
11
- * (federationResult를 실으면 invalid_federation_result
12
- * Core는 자기 선택 세션에서 연합을 이미 안다)
10
+ * validate_selection 요청 {workOrder, selection}
11
+ * (Core는 selectionSessionId로 자기 핀 세션을 복원한다)
13
12
  * 응답 안의 selectionValidation이 정확히
14
13
  * agentlas.workforce-selection-validation.v1 — 루프 검증기와
15
14
  * 동일 계약이라 그대로 돌려준다. 원본 응답은 여기 상태로
16
15
  * 붙잡아 둔다(prepare가 요구).
17
- * prepare_execution 요청 {workOrder, selection, candidateSet,
18
- * federatedSelection: <validate 원본 응답>,
19
- * validationReceipt: <동일>, projectDir}
16
+ * prepare_execution 요청 {workOrder, selection,
17
+ * federatedSelection: <validate 원본 응답>, projectDir}
20
18
  * 응답 안의 executionPlan이 정확히
21
19
  * agentlas.workforce-execution-plan.v5 (roster에
22
20
  * directiveBundle·permissionPolicy 동봉) — 그대로 돌려준다.
@@ -115,7 +113,7 @@ function createLocalCoreHubTool({ sourceScope, projectDir, cwd, client } = {}) {
115
113
  const core = client || createLocalCoreClient({ cwd: cwd || projectDir });
116
114
  // 편성 계보 상태 — 전부 "Core 어휘"(opaque id) 원본이다:
117
115
  // maps: 마지막 search 의 id 지도. 재검색(refinement)마다 재구성된다.
118
- // coreCandidateSet: Core 가 준 원본 CandidateSet (validate/prepare 무수정 반송).
116
+ // coreCandidateSet: Core 가 준 요약 메뉴. 로컬 계보 확인에만 쓰며 반송하지 않는다.
119
117
  // lastValidationEnvelope: validate 원본 응답. prepare 의 federatedSelection 은
120
118
  // 이것이어야 한다 — 루프가 들고 있는 것은 벗겨낸 selectionValidation 뿐이다.
121
119
  let maps = { forward: new Map(), reverse: new Map() };
@@ -137,12 +135,11 @@ function createLocalCoreHubTool({ sourceScope, projectDir, cwd, client } = {}) {
137
135
  maps = buildIdMaps(args.workOrder);
138
136
  coreCandidateSet = null;
139
137
  lastValidationEnvelope = null;
140
- // fullDossier: 터미널 루프의 후보 검증기는 legacy full-echo 계약이다
141
- // (qualificationEvidence·packageHash·contentDigest 필수 실측: 기본
142
- // reference-first 메뉴는 candidate_set_invalid 로 거절된다).
138
+ // Current Core keeps the full dossier in its pinned session and returns a
139
+ // numbered decision menu. Do not request the legacy full-echo form.
143
140
  let envelope;
144
141
  try {
145
- envelope = await core.call(name, { workOrder: mapDeep(args.workOrder, maps.forward), sourceScope, fullDossier: true });
142
+ envelope = await core.call(name, { workOrder: mapDeep(args.workOrder, maps.forward), sourceScope });
146
143
  } catch (error) {
147
144
  // 반응형 정규화(1회): 경계가 지목한 finite 값만 opaque 로 바꿔 재시도.
148
145
  const issues = error.code === "work_order_hub_boundary_rejected" ? boundaryIssues(error) : null;
@@ -161,7 +158,7 @@ function createLocalCoreHubTool({ sourceScope, projectDir, cwd, client } = {}) {
161
158
  repaired += 1;
162
159
  }
163
160
  if (!repaired) throw error;
164
- envelope = await core.call(name, { workOrder: mapDeep(args.workOrder, maps.forward), sourceScope, fullDossier: true });
161
+ envelope = await core.call(name, { workOrder: mapDeep(args.workOrder, maps.forward), sourceScope });
165
162
  }
166
163
  const candidateSet = envelope && envelope.candidateSet;
167
164
  if (!candidateSet || typeof candidateSet !== "object") throw invalid("local Core federation returned no candidateSet");
@@ -174,9 +171,10 @@ function createLocalCoreHubTool({ sourceScope, projectDir, cwd, client } = {}) {
174
171
  error.code = "local_core_lineage_missing";
175
172
  throw error;
176
173
  }
177
- // 루프의 candidateSet(역치환본)과 보관본의 계보 일치를 다이제스트로 확인한다.
178
- if (args.candidateSet?.candidateSetDigest !== coreCandidateSet.candidateSetDigest) {
179
- throw invalid("candidateSet lineage mismatch between the loop and the local Core session");
174
+ // The host-authored selection must point at the exact summary menu just
175
+ // returned. Core independently reloads and verifies the full pinned set.
176
+ if (args.selection?.candidateSetDigest !== coreCandidateSet.candidateSetDigest) {
177
+ throw invalid("selection lineage mismatch between the loop and the local Core session");
180
178
  }
181
179
  let envelope;
182
180
  let coreSelection = mapDeep(args.selection, maps.forward);
@@ -184,7 +182,6 @@ function createLocalCoreHubTool({ sourceScope, projectDir, cwd, client } = {}) {
184
182
  envelope = await core.call(name, {
185
183
  workOrder: mapDeep(args.workOrder, maps.forward),
186
184
  selection: coreSelection,
187
- candidateSet: coreCandidateSet,
188
185
  });
189
186
  } catch (error) {
190
187
  /*
@@ -205,7 +202,6 @@ function createLocalCoreHubTool({ sourceScope, projectDir, cwd, client } = {}) {
205
202
  envelope = await core.call(name, {
206
203
  workOrder: mapDeep(args.workOrder, maps.forward),
207
204
  selection: repairedSelection,
208
- candidateSet: coreCandidateSet,
209
205
  });
210
206
  coreSelection = repairedSelection;
211
207
  }
@@ -224,9 +220,7 @@ function createLocalCoreHubTool({ sourceScope, projectDir, cwd, client } = {}) {
224
220
  workOrder: mapDeep(args.workOrder, maps.forward),
225
221
  // validate 가 수락한 정확한 본 — 반응형 reasonCode 수리를 반영한다.
226
222
  selection: lastCoreSelection || mapDeep(args.selection, maps.forward),
227
- candidateSet: coreCandidateSet,
228
223
  federatedSelection: lastValidationEnvelope,
229
- validationReceipt: lastValidationEnvelope,
230
224
  projectDir,
231
225
  });
232
226
  if (!envelope || typeof envelope.executionPlan !== "object") throw invalid("local Core preparation returned no executionPlan");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentlas",
3
- "version": "1.0.46",
3
+ "version": "1.0.47",
4
4
  "description": "Agentlas project terminal — run project controllers and task-scoped agent teams from the terminal. Standalone: no desktop app process required.",
5
5
  "bin": {
6
6
  "agentlas": "bin/agentlas.cjs"