@ycodium-ai/agent-acp 0.2.2130 → 0.2.2143

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 (2) hide show
  1. package/dist/index.js +260 -152
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -23633,6 +23633,7 @@ function createAcpConnection(options) {
23633
23633
  options.readable.off("data", onData);
23634
23634
  options.readable.off("end", onEnd);
23635
23635
  options.readable.off("error", onError);
23636
+ options.writable.off("error", onWritableError);
23636
23637
  try {
23637
23638
  await byteWriter.close();
23638
23639
  } catch {
@@ -23771,8 +23772,17 @@ function createAcpConnection(options) {
23771
23772
  endInboundBatch();
23772
23773
  }
23773
23774
  };
23775
+ const failInbound = (error62) => {
23776
+ if (closedError !== void 0) return;
23777
+ options.onInboundFailure?.(error62);
23778
+ void shutdown(
23779
+ new AcpConnectionClosedError(
23780
+ `ACP inbound handling failed: ${error62 instanceof Error ? error62.message : String(error62)}`
23781
+ )
23782
+ );
23783
+ };
23774
23784
  const enqueueInbound = (work) => {
23775
- inboundTail = inboundTail.then(work, work);
23785
+ inboundTail = inboundTail.then(work).catch(failInbound);
23776
23786
  };
23777
23787
  const onData = (chunk) => {
23778
23788
  if (closedError !== void 0) {
@@ -23822,9 +23832,15 @@ function createAcpConnection(options) {
23822
23832
  );
23823
23833
  });
23824
23834
  };
23835
+ const onWritableError = (error62) => {
23836
+ void shutdown(
23837
+ error62 instanceof Error ? error62 : new AcpConnectionClosedError("ACP output stream error")
23838
+ );
23839
+ };
23825
23840
  options.readable.on("data", onData);
23826
23841
  options.readable.on("end", onEnd);
23827
23842
  options.readable.on("error", onError);
23843
+ options.writable.once("error", onWritableError);
23828
23844
  const request = (async (method, params) => {
23829
23845
  failIfClosed();
23830
23846
  const id = nextRequestId;
@@ -23833,7 +23849,7 @@ function createAcpConnection(options) {
23833
23849
  pending.set(String(id), { method, resolve: resolve2, reject });
23834
23850
  const message = params === void 0 ? { jsonrpc: "2.0", id, method } : { jsonrpc: "2.0", id, method, params };
23835
23851
  try {
23836
- await writeMessage(message);
23852
+ await Promise.race([writeMessage(message), promise2]);
23837
23853
  } catch (error62) {
23838
23854
  if (pending.delete(String(id))) {
23839
23855
  reject(error62);
@@ -25691,6 +25707,12 @@ function createAcpExecutor(options) {
25691
25707
  const connection = createAcpConnection({
25692
25708
  readable: options.readable,
25693
25709
  writable: options.writable,
25710
+ onInboundFailure: (error62) => {
25711
+ options.log?.warn?.("acp connection closed: an inbound request could not be answered", {
25712
+ threadId: options.threadId,
25713
+ error: error62 instanceof Error ? error62.message : String(error62)
25714
+ });
25715
+ },
25694
25716
  onNotification: (notification) => {
25695
25717
  if (notification.method === "session/update") {
25696
25718
  handleSessionUpdate(notification.params);
@@ -26328,10 +26350,10 @@ function createAcpExecutor(options) {
26328
26350
  }
26329
26351
 
26330
26352
  // ../../packages/ycodium-acp-executor/src/probe.ts
26331
- function withProbeTimeout(promise2, timeoutMs, method) {
26353
+ function withProbeTimeout(promise2, timeoutMs, what) {
26332
26354
  return new Promise((resolve2, reject) => {
26333
26355
  const timer = setTimeout(() => {
26334
- reject(new Error(`ACP probe request '${method}' timed out after ${timeoutMs}ms`));
26356
+ reject(new Error(`${what} timed out after ${timeoutMs}ms`));
26335
26357
  }, timeoutMs);
26336
26358
  timer.unref?.();
26337
26359
  promise2.then(
@@ -26356,11 +26378,15 @@ async function openAcpProbeHandshake(input2) {
26356
26378
  const initializeResult = await withProbeTimeout(
26357
26379
  connection.request("initialize", acpInitializePayload(input2.clientInfo)),
26358
26380
  input2.requestTimeoutMs,
26359
- "initialize"
26381
+ "ACP probe request 'initialize'"
26360
26382
  );
26361
26383
  return {
26362
26384
  initializeResult,
26363
- request: (method, params) => withProbeTimeout(connection.request(method, params), input2.requestTimeoutMs, method),
26385
+ request: (method, params) => withProbeTimeout(
26386
+ connection.request(method, params),
26387
+ input2.requestTimeoutMs,
26388
+ `ACP probe request '${method}'`
26389
+ ),
26364
26390
  close: () => connection.close()
26365
26391
  };
26366
26392
  } catch (error62) {
@@ -26368,6 +26394,62 @@ async function openAcpProbeHandshake(input2) {
26368
26394
  throw error62;
26369
26395
  }
26370
26396
  }
26397
+ function acpAgentVersion(initializeResult) {
26398
+ if (!isRecord5(initializeResult)) return null;
26399
+ const agentInfo = initializeResult["agentInfo"];
26400
+ return isRecord5(agentInfo) ? asTrimmedString(agentInfo["version"]) ?? null : null;
26401
+ }
26402
+ var CLI_VERSION_PATTERN = /(?<![\d.])(\d+\.\d+\.\d+(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?)/;
26403
+ function parseCliVersion(output2) {
26404
+ return CLI_VERSION_PATTERN.exec(output2)?.[1] ?? null;
26405
+ }
26406
+ async function collectCappedText(stream, maxBytes) {
26407
+ const decoder = new TextDecoder();
26408
+ let text = "";
26409
+ let total = 0;
26410
+ for await (const chunk of stream) {
26411
+ total += chunk.byteLength;
26412
+ if (total <= maxBytes) text += decoder.decode(chunk, { stream: true });
26413
+ }
26414
+ return { text: text + decoder.decode(), overflowed: total > maxBytes };
26415
+ }
26416
+ async function collectProbeProcess(child, input2) {
26417
+ try {
26418
+ await child.closeStdin().catch(() => void 0);
26419
+ const [stdout, stderr, exitCode] = await withProbeTimeout(
26420
+ Promise.all([
26421
+ collectCappedText(child.stdout, input2.maxOutputBytes),
26422
+ collectCappedText(child.stderr, input2.maxOutputBytes),
26423
+ child.exited
26424
+ ]),
26425
+ input2.timeoutMs,
26426
+ input2.what
26427
+ );
26428
+ return { stdout: stdout.overflowed ? void 0 : stdout.text, stderr: stderr.text, exitCode };
26429
+ } finally {
26430
+ await child.kill("SIGTERM").catch(() => void 0);
26431
+ }
26432
+ }
26433
+ var MAX_VERSION_OUTPUT_BYTES = 64 * 1024;
26434
+ async function probeCliVersion(input2) {
26435
+ let child;
26436
+ try {
26437
+ child = await input2.spawn();
26438
+ } catch {
26439
+ return null;
26440
+ }
26441
+ try {
26442
+ const run = await collectProbeProcess(child, {
26443
+ timeoutMs: input2.timeoutMs,
26444
+ maxOutputBytes: MAX_VERSION_OUTPUT_BYTES,
26445
+ what: "--version"
26446
+ });
26447
+ if (run.exitCode !== 0) return null;
26448
+ return parseCliVersion(run.stdout ?? "") ?? parseCliVersion(run.stderr);
26449
+ } catch {
26450
+ return null;
26451
+ }
26452
+ }
26371
26453
 
26372
26454
  // src/card.ts
26373
26455
  var ACP_DRIVER_KIND = "acp";
@@ -26668,118 +26750,17 @@ function readKimiContextWindow(input2) {
26668
26750
  }
26669
26751
 
26670
26752
  // src/kimiModels.ts
26671
- var PROBE_TIMEOUT_MS = 15e3;
26672
- var MAX_OUTPUT_BYTES = 1024 * 1024;
26673
- var KIMI_MODEL_LIST_ARGS = ["provider", "list", "--json"];
26674
- function isRecord8(value) {
26675
- return typeof value === "object" && value !== null && !Array.isArray(value);
26676
- }
26677
- function asString3(value) {
26678
- return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
26679
- }
26680
- function positiveInt2(value) {
26681
- return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.trunc(value) : void 0;
26682
- }
26683
- function kimiProbeModels(stdout) {
26684
- let parsed;
26685
- try {
26686
- parsed = JSON.parse(stdout);
26687
- } catch {
26688
- return void 0;
26689
- }
26690
- if (!isRecord8(parsed)) return void 0;
26691
- const models = parsed["models"];
26692
- if (!isRecord8(models)) return void 0;
26693
- const out = [];
26694
- for (const [slug, entry] of Object.entries(models)) {
26695
- const trimmed = slug.trim();
26696
- if (trimmed.length === 0 || !isRecord8(entry)) continue;
26697
- const name = asString3(entry["displayName"]);
26698
- const contextWindow = positiveInt2(entry["maxContextSize"]);
26699
- out.push({
26700
- slug: trimmed,
26701
- ...name === void 0 ? {} : { name },
26702
- ...contextWindow === void 0 ? {} : { contextWindow }
26703
- });
26704
- }
26705
- return out;
26706
- }
26707
- function withProbeTimeout2(promise2, what) {
26708
- return new Promise((resolve2, reject) => {
26709
- const timer = setTimeout(
26710
- () => reject(new Error(`${what} timed out after ${PROBE_TIMEOUT_MS}ms`)),
26711
- PROBE_TIMEOUT_MS
26712
- );
26713
- timer.unref?.();
26714
- promise2.then(
26715
- (value) => {
26716
- clearTimeout(timer);
26717
- resolve2(value);
26718
- },
26719
- (error62) => {
26720
- clearTimeout(timer);
26721
- reject(error62 instanceof Error ? error62 : new Error(String(error62)));
26722
- }
26723
- );
26724
- });
26725
- }
26726
- function concat(chunks) {
26727
- const total = chunks.reduce((sum, chunk) => sum + chunk.byteLength, 0);
26728
- const out = new Uint8Array(total);
26729
- let offset = 0;
26730
- for (const chunk of chunks) {
26731
- out.set(chunk, offset);
26732
- offset += chunk.byteLength;
26733
- }
26734
- return out;
26735
- }
26736
- async function probeKimiModels(input2) {
26737
- const { recipe, host, env } = input2;
26738
- if (recipe.binaryPath.length === 0) return void 0;
26739
- let handle;
26740
- try {
26741
- handle = await host.process.spawn({
26742
- program: recipe.binaryPath,
26743
- // 实例信封里的启动参数(Kimi 那行预填 `acp`)在这一栏用不上:读配置要换成
26744
- // `provider list --json`,留着 `acp` 就等于让它起 ACP 服务然后什么都不问。
26745
- args: KIMI_MODEL_LIST_ARGS,
26746
- cwd: process.cwd(),
26747
- owner: { bindingId: host.bindingId },
26748
- ...Object.keys(env).length > 0 ? { env } : {}
26749
- });
26750
- const spawned = handle;
26751
- const collect = withProbeTimeout2(
26752
- (async () => {
26753
- const chunks = [];
26754
- let total = 0;
26755
- for await (const chunk of spawned.stdout) {
26756
- total += chunk.byteLength;
26757
- if (total > MAX_OUTPUT_BYTES) return void 0;
26758
- chunks.push(chunk);
26759
- }
26760
- return new TextDecoder().decode(concat(chunks));
26761
- })(),
26762
- "kimi provider list"
26763
- );
26764
- const drain = (async () => {
26765
- for await (const _chunk of spawned.stderr) {
26766
- }
26767
- })().catch(() => void 0);
26768
- const [stdout, , exitCode] = await Promise.all([collect, drain, spawned.exited]);
26769
- if (stdout === void 0) return void 0;
26770
- if (exitCode !== 0) return void 0;
26771
- return kimiProbeModels(stdout);
26772
- } catch {
26773
- return void 0;
26774
- } finally {
26775
- await handle?.kill("SIGTERM").catch(() => void 0);
26776
- }
26777
- }
26753
+ import {
26754
+ ExecutorSpawnRefusedError as ExecutorSpawnRefusedError2
26755
+ } from "@ycodium-ai/plugin-api/executor";
26778
26756
 
26779
26757
  // src/probeModels.ts
26780
26758
  import * as NodeFS2 from "node:fs";
26781
26759
  import * as NodeOS from "node:os";
26782
26760
  import * as NodePath2 from "node:path";
26761
+ import {
26762
+ ExecutorSpawnRefusedError
26763
+ } from "@ycodium-ai/plugin-api/executor";
26783
26764
  import { nodeStreamsFromHandle } from "@ycodium-ai/plugin-api/process-stdin";
26784
26765
  var PROBE_REQUEST_TIMEOUT_MS = 15e3;
26785
26766
  var CLIENT_INFO = { name: "ycodium-agent-acp-probe", version: "0.2.0" };
@@ -26788,18 +26769,18 @@ function acpProbeSessionCwd(instanceId) {
26788
26769
  const safe = instanceId.replace(/[^a-zA-Z0-9_-]/g, "_");
26789
26770
  return NodePath2.join(NodeOS.tmpdir(), `ycodium-acp-probe-${safe}`);
26790
26771
  }
26791
- function isRecord9(value) {
26772
+ function isRecord8(value) {
26792
26773
  return typeof value === "object" && value !== null && !Array.isArray(value);
26793
26774
  }
26794
- function asString4(value) {
26775
+ function asString3(value) {
26795
26776
  return typeof value === "string" ? value : void 0;
26796
26777
  }
26797
26778
  function findAcpProbeSessionId(listed, probeCwd) {
26798
- if (!isRecord9(listed) || !Array.isArray(listed["sessions"])) return void 0;
26779
+ if (!isRecord8(listed) || !Array.isArray(listed["sessions"])) return void 0;
26799
26780
  for (const entry of listed["sessions"]) {
26800
- if (!isRecord9(entry)) continue;
26801
- if (asString4(entry["cwd"]) !== probeCwd) continue;
26802
- const sessionId = asString4(entry["sessionId"]);
26781
+ if (!isRecord8(entry)) continue;
26782
+ if (asString3(entry["cwd"]) !== probeCwd) continue;
26783
+ const sessionId = asString3(entry["sessionId"]);
26803
26784
  if (sessionId !== void 0) return sessionId;
26804
26785
  }
26805
26786
  return void 0;
@@ -26814,7 +26795,7 @@ async function probeSessionSetup(handshake, probeCwd) {
26814
26795
  return handshake.request("session/new", { cwd: probeCwd, mcpServers: [] });
26815
26796
  }
26816
26797
  function acpProbeModels(setup) {
26817
- if (!isRecord9(setup)) return void 0;
26798
+ if (!isRecord8(setup)) return void 0;
26818
26799
  const rawOptions = setup["configOptions"];
26819
26800
  const choices = acpModelChoicesFromConfigOptions(rawOptions) ?? acpModelChoicesFromSessionModels(setup["models"]);
26820
26801
  if (choices === void 0 || choices.length === 0) return void 0;
@@ -26842,14 +26823,16 @@ function acpProbeModels(setup) {
26842
26823
  };
26843
26824
  return models.map((model) => ({ ...model, capabilities }));
26844
26825
  }
26845
- var failureDetail = (error62) => (error62 instanceof Error ? error62.message : String(error62)).trim() || void 0;
26826
+ var probeFailureDetail = (error62) => (error62 instanceof Error ? error62.message : String(error62)).trim() || void 0;
26827
+ var ACP_AUTH_REQUIRED_CODE = RequestError.authRequired().code;
26828
+ var isAcpAuthRequired = (error62) => error62 instanceof RequestError && error62.code === ACP_AUTH_REQUIRED_CODE;
26846
26829
  async function probeAcpModelsViaSession(input2) {
26847
26830
  const { recipe, host, env } = input2;
26848
26831
  const probeCwd = acpProbeSessionCwd(host.instanceId);
26849
26832
  try {
26850
26833
  NodeFS2.mkdirSync(probeCwd, { recursive: true });
26851
26834
  } catch (error62) {
26852
- return { kind: "failed", detail: failureDetail(error62) };
26835
+ return { kind: "failed", detail: probeFailureDetail(error62), version: null };
26853
26836
  }
26854
26837
  let handle;
26855
26838
  try {
@@ -26861,7 +26844,8 @@ async function probeAcpModelsViaSession(input2) {
26861
26844
  ...Object.keys(env).length > 0 ? { env } : {}
26862
26845
  });
26863
26846
  } catch (error62) {
26864
- return { kind: "not-started", detail: failureDetail(error62) };
26847
+ if (error62 instanceof ExecutorSpawnRefusedError) throw error62;
26848
+ return { kind: "not-started", detail: probeFailureDetail(error62) };
26865
26849
  }
26866
26850
  let handshake;
26867
26851
  try {
@@ -26875,6 +26859,7 @@ async function probeAcpModelsViaSession(input2) {
26875
26859
  const setup = await probeSessionSetup(handshake, probeCwd);
26876
26860
  return {
26877
26861
  kind: "answered",
26862
+ version: acpAgentVersion(handshake.initializeResult),
26878
26863
  models: acpProbeModels(setup),
26879
26864
  // 审批档原样上报:宿主落进 provider 快照的 `nativeModes`,composer 直接画这只手
26880
26865
  // 自己的那几档,不再退回宿主四档开关。
@@ -26886,13 +26871,124 @@ async function probeAcpModelsViaSession(input2) {
26886
26871
  currentNativeModeId: acpCurrentModeId(setup)
26887
26872
  };
26888
26873
  } catch (error62) {
26889
- return { kind: "failed", detail: failureDetail(error62) };
26874
+ const version2 = acpAgentVersion(handshake?.initializeResult);
26875
+ if (handshake !== void 0 && isAcpAuthRequired(error62)) {
26876
+ return { kind: "auth-required", version: version2 };
26877
+ }
26878
+ return { kind: "failed", detail: probeFailureDetail(error62), version: version2 };
26890
26879
  } finally {
26891
26880
  await handshake?.close().catch(() => void 0);
26892
26881
  await handle.kill("SIGTERM").catch(() => void 0);
26893
26882
  }
26894
26883
  }
26895
26884
 
26885
+ // src/kimiModels.ts
26886
+ var PROBE_TIMEOUT_MS = 15e3;
26887
+ var MAX_OUTPUT_BYTES = 1024 * 1024;
26888
+ var KIMI_MODEL_LIST_ARGS = ["provider", "list", "--json"];
26889
+ function isRecord9(value) {
26890
+ return typeof value === "object" && value !== null && !Array.isArray(value);
26891
+ }
26892
+ function asString4(value) {
26893
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
26894
+ }
26895
+ function positiveInt2(value) {
26896
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.trunc(value) : void 0;
26897
+ }
26898
+ function kimiProbeModels(stdout) {
26899
+ let parsed;
26900
+ try {
26901
+ parsed = JSON.parse(stdout);
26902
+ } catch {
26903
+ return void 0;
26904
+ }
26905
+ if (!isRecord9(parsed)) return void 0;
26906
+ const models = parsed["models"];
26907
+ if (!isRecord9(models)) return void 0;
26908
+ const out = [];
26909
+ for (const [slug, entry] of Object.entries(models)) {
26910
+ const trimmed = slug.trim();
26911
+ if (trimmed.length === 0 || !isRecord9(entry)) continue;
26912
+ const name = asString4(entry["displayName"]);
26913
+ const contextWindow = positiveInt2(entry["maxContextSize"]);
26914
+ out.push({
26915
+ slug: trimmed,
26916
+ ...name === void 0 ? {} : { name },
26917
+ ...contextWindow === void 0 ? {} : { contextWindow }
26918
+ });
26919
+ }
26920
+ return out;
26921
+ }
26922
+ async function probeKimiModels(input2) {
26923
+ const { recipe, host, env } = input2;
26924
+ let handle;
26925
+ try {
26926
+ handle = await host.process.spawn({
26927
+ program: recipe.binaryPath,
26928
+ // 实例信封里的启动参数(Kimi 那行预填 `acp`)在这一栏用不上:读配置要换成
26929
+ // `provider list --json`,留着 `acp` 就等于让它起 ACP 服务然后什么都不问。
26930
+ args: KIMI_MODEL_LIST_ARGS,
26931
+ cwd: process.cwd(),
26932
+ owner: { bindingId: host.bindingId },
26933
+ ...Object.keys(env).length > 0 ? { env } : {}
26934
+ });
26935
+ } catch (error62) {
26936
+ if (error62 instanceof ExecutorSpawnRefusedError2) throw error62;
26937
+ return { kind: "not-started", detail: probeFailureDetail(error62) };
26938
+ }
26939
+ try {
26940
+ const run = await collectProbeProcess(handle, {
26941
+ timeoutMs: input2.timeoutMs ?? PROBE_TIMEOUT_MS,
26942
+ // 这份 JSON 实测 1.7KB;封顶是防 CLI 抽风刷日志把内存吃掉。
26943
+ maxOutputBytes: MAX_OUTPUT_BYTES,
26944
+ what: "kimi provider list"
26945
+ });
26946
+ if (run.exitCode !== 0) {
26947
+ const stderr = run.stderr.trim();
26948
+ return {
26949
+ kind: "failed",
26950
+ detail: stderr.length > 0 ? stderr : run.exitCode === null ? "kimi provider list was killed by a signal" : `kimi provider list exited with code ${run.exitCode}`
26951
+ };
26952
+ }
26953
+ return {
26954
+ kind: "answered",
26955
+ models: run.stdout === void 0 ? void 0 : kimiProbeModels(run.stdout)
26956
+ };
26957
+ } catch (error62) {
26958
+ return { kind: "failed", detail: probeFailureDetail(error62) };
26959
+ }
26960
+ }
26961
+ async function probeKimiVersion(input2) {
26962
+ const { recipe, host, env } = input2;
26963
+ return probeCliVersion({
26964
+ spawn: () => host.process.spawn({
26965
+ program: recipe.binaryPath,
26966
+ args: ["--version"],
26967
+ cwd: process.cwd(),
26968
+ owner: { bindingId: host.bindingId },
26969
+ ...Object.keys(env).length > 0 ? { env } : {}
26970
+ }),
26971
+ timeoutMs: PROBE_TIMEOUT_MS
26972
+ });
26973
+ }
26974
+ async function probeKimi(input2) {
26975
+ const [listed, version2] = await Promise.all([probeKimiModels(input2), probeKimiVersion(input2)]);
26976
+ switch (listed.kind) {
26977
+ case "not-started":
26978
+ return { kind: "not-started", detail: listed.detail };
26979
+ case "failed":
26980
+ return { kind: "failed", detail: listed.detail, version: version2 };
26981
+ case "answered":
26982
+ return {
26983
+ kind: "answered",
26984
+ version: version2,
26985
+ models: listed.models,
26986
+ nativeModes: [],
26987
+ currentNativeModeId: void 0
26988
+ };
26989
+ }
26990
+ }
26991
+
26896
26992
  // src/runtimeModeApproval.ts
26897
26993
  function acpRuntimeModeAutoApproves(runtimeMode, toolKind) {
26898
26994
  switch (runtimeMode) {
@@ -27028,34 +27124,46 @@ var createAcpInstance = (config2, host) => {
27028
27124
  detail: "ACP program path is not configured"
27029
27125
  };
27030
27126
  }
27031
- const outcome = isKimiInstance(recipe) ? {
27032
- kind: "answered",
27033
- models: await probeKimiModels({
27034
- recipe,
27035
- host,
27036
- env: buildSpawnEnv(recipe, recipe.homePath)
27037
- }),
27038
- nativeModes: void 0,
27039
- currentNativeModeId: void 0
27040
- } : await probeAcpModelsViaSession({
27041
- recipe,
27042
- host,
27043
- env: buildSpawnEnv(recipe, recipe.homePath)
27044
- });
27045
- const models = outcome.kind === "answered" ? outcome.models : void 0;
27046
- const nativeModes = outcome.kind === "answered" && outcome.nativeModes !== void 0 ? outcome.nativeModes : void 0;
27047
- const currentNativeModeId = outcome.kind === "answered" ? outcome.currentNativeModeId : void 0;
27048
- return {
27049
- installed: true,
27050
- version: null,
27051
- readiness: "unchecked",
27052
- auth: { status: "unknown" },
27053
- ...models === void 0 ? {} : { models },
27054
- ...nativeModes === void 0 || nativeModes.length === 0 ? {} : {
27055
- nativeModes,
27056
- ...currentNativeModeId === void 0 ? {} : { currentNativeModeId }
27057
- }
27058
- };
27127
+ const env = buildSpawnEnv(recipe, recipe.homePath);
27128
+ const outcome = isKimiInstance(recipe) ? await probeKimi({ recipe, host, env }) : await probeAcpModelsViaSession({ recipe, host, env });
27129
+ switch (outcome.kind) {
27130
+ case "not-started":
27131
+ return {
27132
+ installed: false,
27133
+ version: null,
27134
+ readiness: "error",
27135
+ auth: { status: "unknown" },
27136
+ ...outcome.detail === void 0 ? {} : { detail: outcome.detail }
27137
+ };
27138
+ case "failed":
27139
+ return {
27140
+ installed: true,
27141
+ version: outcome.version,
27142
+ readiness: "error",
27143
+ auth: { status: "unknown" },
27144
+ ...outcome.detail === void 0 ? {} : { detail: outcome.detail }
27145
+ };
27146
+ case "auth-required":
27147
+ return {
27148
+ installed: true,
27149
+ version: outcome.version,
27150
+ readiness: "ready",
27151
+ auth: { status: "unauthenticated" }
27152
+ };
27153
+ case "answered":
27154
+ return {
27155
+ installed: true,
27156
+ version: outcome.version,
27157
+ readiness: "ready",
27158
+ auth: { status: "unknown" },
27159
+ ...outcome.models === void 0 ? {} : { models: outcome.models },
27160
+ // 清单与当前档必须同进同出:只报清单,界面在清单里找不到当前档会整个不画那一格。
27161
+ ...outcome.nativeModes.length === 0 ? {} : {
27162
+ nativeModes: outcome.nativeModes,
27163
+ ...outcome.currentNativeModeId === void 0 ? {} : { currentNativeModeId: outcome.currentNativeModeId }
27164
+ }
27165
+ };
27166
+ }
27059
27167
  },
27060
27168
  startSession: async (input2, signal) => {
27061
27169
  if (disposed) throw new Error("instance disposed");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ycodium-ai/agent-acp",
3
- "version": "0.2.2130",
3
+ "version": "0.2.2143",
4
4
  "description": "Generic ACP executor: user-supplied CLI over Agent Client Protocol stdio.",
5
5
  "keywords": [
6
6
  "ycodium",
@@ -20,7 +20,7 @@
20
20
  "@types/node": "24.12.4",
21
21
  "esbuild": "0.28.1",
22
22
  "vite-plus": "0.2.2",
23
- "@ycodium-ai/plugin-api": "0.2.2130",
23
+ "@ycodium-ai/plugin-api": "0.2.2143",
24
24
  "ycodium-acp-executor": "0.0.0",
25
25
  "ycodium-acp-protocol": "0.0.0"
26
26
  },