agentlas 1.0.46 → 1.0.48

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 (51) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/README.md +7 -7
  3. package/engine/acp/server.cjs +279 -0
  4. package/engine/agentlas-capabilities.cjs +4 -2
  5. package/engine/agentlas-core-harness.cjs +18 -0
  6. package/engine/agentlas-i18n.cjs +8 -8
  7. package/engine/agentlas-input.cjs +3 -2
  8. package/engine/agentlas-native-host.cjs +130 -11
  9. package/engine/agentlas-onboard.cjs +9 -3
  10. package/engine/agentlas-permissions.cjs +5 -1
  11. package/engine/agentlas-workforce.cjs +81 -24
  12. package/engine/agents/router.cjs +4 -2
  13. package/engine/architecture.data.json +6 -30
  14. package/engine/automation/daemon.cjs +3 -7
  15. package/engine/bootstrap-schema.sql +216 -191
  16. package/engine/browser/cdp.cjs +10 -4
  17. package/engine/cloud-assets/commands.cjs +1 -1
  18. package/engine/cloud-assets/package.cjs +161 -45
  19. package/engine/commands/acp.cjs +45 -0
  20. package/engine/commands/billing.cjs +2 -2
  21. package/engine/commands/call.cjs +4 -0
  22. package/engine/commands/context.cjs +14 -3
  23. package/engine/commands/doctor.cjs +8 -4
  24. package/engine/commands/graph.cjs +46 -54
  25. package/engine/commands/index.cjs +2 -0
  26. package/engine/commands/search.cjs +2 -2
  27. package/engine/commands/workforce.cjs +11 -0
  28. package/engine/core/desktop-core.cjs +93 -1
  29. package/engine/firms/orchestrate.cjs +32 -1
  30. package/engine/graph/interview.cjs +2 -11
  31. package/engine/graph/vocabulary.generated.cjs +1 -1
  32. package/engine/hephaestus/runtime.cjs +2 -6
  33. package/engine/project/memory-context.cjs +20 -7
  34. package/engine/project/seed.cjs +46 -31
  35. package/engine/project/state.cjs +8 -1
  36. package/engine/runtimes/acp-driver.cjs +96 -0
  37. package/engine/runtimes/auth-evidence.cjs +6 -0
  38. package/engine/runtimes/detect.cjs +3 -13
  39. package/engine/runtimes/kinds.cjs +84 -0
  40. package/engine/runtimes/resolve.cjs +67 -14
  41. package/engine/sessions/prompt.cjs +2 -2
  42. package/engine/ui/commands-catalog.cjs +2 -0
  43. package/engine/ui/palette.cjs +2 -1
  44. package/engine/ui/repl.cjs +4 -3
  45. package/engine/ui/shell.cjs +43 -5
  46. package/engine/vendor/desktop-core.manifest.json +5 -5
  47. package/engine/workforce/capture.cjs +55 -10
  48. package/engine/workforce/deps.cjs +2 -2
  49. package/engine/workforce/local-core-transport.cjs +13 -19
  50. package/package.json +2 -1
  51. package/engine/project/super-ontology-seed.json +0 -3288
@@ -24,13 +24,10 @@ const path = require("node:path");
24
24
  const { spawn } = require("node:child_process");
25
25
  const { dbPath, userDataDir } = require("../core/paths.cjs");
26
26
 
27
- // 캡처 드라이버가 검증된 런타임만. v2 detect.cjs의 RUNTIME_BIN에는 kimi/grok/cursor도
28
- // 있지만 buildArgs/텍스트 추출 계약이 없으므로 여기 목록에 절대 조용히 추가하지 않는다.
29
- const RUNTIME_BIN = {
30
- "claude-code": "claude",
31
- codex: "codex",
32
- gemini: "gemini",
33
- };
27
+ // 캡처 드라이버가 검증된 런타임만. 정본(runtimes/kinds.cjs)의 RUNTIME_BIN에는 kimi/grok/cursor도
28
+ // 있지만 buildArgs/텍스트 추출 계약이 없으므로 캡처 검증 파생본만 쓴다 새 kind 를
29
+ // 정본에 추가해도 capture:true 를 명시하기 전엔 여기 조용히 들어오지 않는다.
30
+ const { CAPTURE_RUNTIME_BIN: RUNTIME_BIN } = require("../runtimes/kinds.cjs");
34
31
 
35
32
  const SERVICE = "com.agentlas.desktop";
36
33
 
@@ -198,6 +195,14 @@ function buildArgs(kind, systemPrompt, prompt, permission, runtimeOptions = {})
198
195
  const mcp = native.geminiMcpIsolationArgs();
199
196
  return ["--prompt", `[SYSTEM]\n${systemPrompt}\n\n${prompt}`, ...(model ? ["-m", model] : []), ...perm, ...noAuthorityArgs, ...mcp];
200
197
  }
198
+ if (kind === "agy") {
199
+ return native.agyArgs({
200
+ prompt,
201
+ systemPrompt,
202
+ permission: noAuthority ? "read" : level,
203
+ model,
204
+ });
205
+ }
201
206
  return [prompt];
202
207
  }
203
208
 
@@ -287,6 +292,7 @@ function capturedRuntimeUsage(kind, raw) {
287
292
  }
288
293
  const direct =
289
294
  genericUsage(event?.usage) ||
295
+ genericUsage(event?.step_update?.usage) ||
290
296
  genericUsage(event?.usageMetadata) ||
291
297
  genericUsage(event?.stats);
292
298
  if (direct) return direct;
@@ -346,6 +352,12 @@ function capturedRuntimeFailure(kind, raw, text) {
346
352
  return { message: `gemini ${event.status}`, source: "marker" };
347
353
  }
348
354
  }
355
+ if (kind === "agy" && event.event === "result") {
356
+ const status = String(event.result?.status || "").toLowerCase();
357
+ if (status && !["success", "completed", "done"].includes(status)) {
358
+ return { message: `agy ${status}`, source: "marker" };
359
+ }
360
+ }
349
361
  }
350
362
  // 표식이 전혀 없는 케이스(codex 한도) — 휴리스틱 최후 그물, 출처 표기.
351
363
  const refusal = detectRuntimeRefusal(text);
@@ -399,6 +411,21 @@ function capturedRuntimeAgentText(kind, raw) {
399
411
  return final ? String(final.result ?? final.response) : "";
400
412
  }
401
413
 
414
+ if (kind === "agy") {
415
+ const isProtocol = events.some((event) =>
416
+ event?.event === "step_update" || event?.event === "result",
417
+ );
418
+ if (!isProtocol) return text.trim();
419
+ const final = [...events].reverse().find((event) =>
420
+ event?.event === "result" && typeof event.result?.response === "string",
421
+ );
422
+ if (final) return final.result.response;
423
+ return events
424
+ .filter((event) => event?.event === "step_update" && event.step_update?.step_type === "agent_response")
425
+ .map((event) => typeof event.step_update?.text_delta === "string" ? event.step_update.text_delta : "")
426
+ .join("");
427
+ }
428
+
402
429
  return text.trim();
403
430
  }
404
431
 
@@ -423,6 +450,7 @@ function captureRuntime(kind, systemPrompt, prompt, opts) {
423
450
  // 계약 테스트용 실행 파일 주입(가짜 CLI가 픽스처를 cat) — 프로덕션 경로에선 없음.
424
451
  const bin = opts.binOverride || which(RUNTIME_BIN[kind]) || RUNTIME_BIN[kind];
425
452
  let child;
453
+ let launchCleanup = () => {};
426
454
  try {
427
455
  const spawnImpl = opts.spawn || spawn;
428
456
  const env = nativeHost.runtimeEnvForKind(kind, opts.env || process.env, {
@@ -431,13 +459,28 @@ function captureRuntime(kind, systemPrompt, prompt, opts) {
431
459
  mcpAllowlistMode: kind === "gemini" ? "exact" : undefined,
432
460
  });
433
461
  const groupedChild = process.platform !== "win32" && spawnImpl === spawn;
434
- child = spawnImpl(bin, buildArgs(kind, systemPrompt, prompt, opts.permission, {
462
+ const runtimeOptions = {
435
463
  model: opts.model,
436
464
  effort: opts.effort,
437
465
  authorityMode: opts.authorityMode,
438
466
  noToolsPolicyPath: opts.noToolsPolicyPath,
439
467
  allowedNativeTools: opts.allowedNativeTools,
440
- }), {
468
+ };
469
+ let childArgs = buildArgs(kind, systemPrompt, prompt, opts.permission, runtimeOptions);
470
+ if (kind === "agy") {
471
+ const prepared = nativeHost.prepareAgyLaunch({
472
+ prompt,
473
+ systemPrompt,
474
+ permission: opts.authorityMode === "no-authority" ? "read" : opts.permission,
475
+ model: opts.model,
476
+ }, {
477
+ platform: opts.platform,
478
+ promptLimit: opts.agyPromptLimit,
479
+ });
480
+ childArgs = prepared.args;
481
+ launchCleanup = prepared.cleanup;
482
+ }
483
+ child = spawnImpl(bin, childArgs, {
441
484
  cwd,
442
485
  stdio: ["ignore", "pipe", "pipe"],
443
486
  env,
@@ -446,6 +489,7 @@ function captureRuntime(kind, systemPrompt, prompt, opts) {
446
489
  });
447
490
  child.__agentlasGroupedChild = groupedChild;
448
491
  } catch (error) {
492
+ launchCleanup();
449
493
  reject(error);
450
494
  return;
451
495
  }
@@ -479,6 +523,7 @@ function captureRuntime(kind, systemPrompt, prompt, opts) {
479
523
  child.removeListener("error", onError);
480
524
  child.removeListener("close", onClose);
481
525
  if (opts.signal) opts.signal.removeEventListener?.("abort", onAbort);
526
+ launchCleanup();
482
527
  };
483
528
  const finishReject = (error) => {
484
529
  if (settled) return;
@@ -562,7 +607,7 @@ function captureRuntime(kind, systemPrompt, prompt, opts) {
562
607
  let text;
563
608
  if (kind === "codex" && opts.authorityMode === "no-authority") {
564
609
  text = codexCaptureAgentText(raw);
565
- } else if (kind === "claude-code" || kind === "gemini") {
610
+ } else if (kind === "claude-code" || kind === "gemini" || kind === "agy") {
566
611
  text = capturedRuntimeAgentText(kind, raw);
567
612
  } else {
568
613
  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,11 +1,12 @@
1
1
  {
2
2
  "name": "agentlas",
3
- "version": "1.0.46",
3
+ "version": "1.0.48",
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"
7
7
  },
8
8
  "scripts": {
9
+ "test": "sh test/smoke.sh",
9
10
  "smoke": "sh test/smoke.sh",
10
11
  "test:release-contracts": "npm run smoke",
11
12
  "sync:architecture": "node scripts/sync-architecture-from-desktop.cjs",