@ycodium-ai/agent-antigravity 0.2.3122 → 0.2.3158

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 +331 -148
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -1626,9 +1626,6 @@ function registerAntigravityAuthCommands(ctx) {
1626
1626
  // src/antigravityInstance.ts
1627
1627
  import * as NodeCrypto6 from "node:crypto";
1628
1628
 
1629
- // src/agentProcess.ts
1630
- import { nodeStreamsFromHandle } from "@ycodium-ai/plugin-api/process-stdin";
1631
-
1632
1629
  // ../../packages/ycodium-acp-executor/src/executor.ts
1633
1630
  import * as NodeCrypto from "node:crypto";
1634
1631
 
@@ -26478,7 +26475,10 @@ function createAcpConnection(options2) {
26478
26475
  }
26479
26476
  pending.delete(key);
26480
26477
  try {
26481
- options2.onResponse?.(waiter.method);
26478
+ options2.onResponse?.(
26479
+ waiter,
26480
+ Object.hasOwn(message, "error") ? { error: message["error"] } : { result: message["result"] }
26481
+ );
26482
26482
  } catch {
26483
26483
  }
26484
26484
  if (Object.hasOwn(message, "error")) {
@@ -26611,12 +26611,17 @@ function createAcpConnection(options2) {
26611
26611
  options2.readable.on("end", onEnd);
26612
26612
  options2.readable.on("error", onError);
26613
26613
  options2.writable.once("error", onWritableError);
26614
- const begin = (method, params) => {
26614
+ const begin = (method, params, promptId) => {
26615
26615
  failIfClosed();
26616
26616
  const id = nextRequestId;
26617
26617
  nextRequestId += 1;
26618
26618
  const { promise: promise2, resolve: resolve6, reject } = Promise.withResolvers();
26619
- pending.set(String(id), { method, resolve: resolve6, reject });
26619
+ pending.set(String(id), {
26620
+ method,
26621
+ ...promptId === void 0 ? {} : { promptId },
26622
+ resolve: resolve6,
26623
+ reject
26624
+ });
26620
26625
  const message = params === void 0 ? { jsonrpc: "2.0", id, method } : { jsonrpc: "2.0", id, method, params };
26621
26626
  const written = Promise.race([writeMessage(message), promise2]).then(
26622
26627
  () => void 0,
@@ -26686,12 +26691,14 @@ function createExecutorLifecycle({
26686
26691
  notifyPromptSettled,
26687
26692
  eventStream,
26688
26693
  onInputDead,
26689
- shared
26694
+ shared,
26695
+ promptResults
26690
26696
  }) {
26691
26697
  const cancel = async (turnId) => {
26692
26698
  failIfDisposed();
26693
26699
  const started = requireStarted();
26694
26700
  const targetTurnId = turnId ?? shared.activeTurnId;
26701
+ promptResults.stop(targetTurnId);
26695
26702
  if (targetTurnId !== void 0) {
26696
26703
  interruptedTurnIds.add(targetTurnId);
26697
26704
  }
@@ -26702,6 +26709,9 @@ function createExecutorLifecycle({
26702
26709
  if (shared.sessionId) {
26703
26710
  await connection.notify("session/cancel", { sessionId: shared.sessionId });
26704
26711
  }
26712
+ await promptResults.wait(targetTurnId);
26713
+ if (targetTurnId !== void 0 && shared.activeTurnId !== targetTurnId && !interruptedTurnIds.has(targetTurnId))
26714
+ return;
26705
26715
  const settled = await waitForPromptIdle(cancelGraceMs);
26706
26716
  if (!settled) {
26707
26717
  throw new AcpExecutorCancelTimeoutError();
@@ -26722,6 +26732,7 @@ function createExecutorLifecycle({
26722
26732
  payload: { state: "cancelled", stopReason: "cancelled" }
26723
26733
  });
26724
26734
  interruptedTurnIds.delete(targetTurnId);
26735
+ promptResults.forget(targetTurnId);
26725
26736
  }
26726
26737
  }
26727
26738
  }
@@ -26796,33 +26807,39 @@ function createExecutorLifecycle({
26796
26807
  if (!shared.disposed) emitSessionState("ready");
26797
26808
  }
26798
26809
  };
26799
- const dispose = async () => {
26800
- if (shared.disposed) {
26801
- return;
26802
- }
26810
+ let disposing;
26811
+ const dispose = () => {
26812
+ if (disposing) return disposing;
26813
+ shared.disposing = true;
26814
+ promptResults.stop();
26803
26815
  settleAllApprovals("cancel");
26804
26816
  settleAllUserInputs();
26805
26817
  abortPendingSettlement("executor disposed");
26806
26818
  notifyPromptSettled();
26807
26819
  shared.abortLocalPrompt?.();
26808
- emit({
26809
- type: "session.exited",
26810
- ...stamp(),
26811
- provider: options2.provider,
26812
- threadId: options2.threadId,
26813
- payload: { reason: "disposed" }
26814
- });
26815
- shared.disposed = true;
26816
- shared.generation += 1;
26817
- shared.status = "disposed";
26818
- eventStream.close();
26819
- options2.readable.off("end", onInputDead);
26820
- options2.readable.off("error", onInputDead);
26821
- options2.readable.pause();
26822
- if (!shared.connectionClosed) {
26823
- await connection.awaitInboundIdle().catch(() => void 0);
26824
- await connection.close().catch(() => void 0);
26825
- }
26820
+ disposing = (async () => {
26821
+ promptResults.finishUnreceived();
26822
+ await promptResults.wait();
26823
+ emit({
26824
+ type: "session.exited",
26825
+ ...stamp(),
26826
+ provider: options2.provider,
26827
+ threadId: options2.threadId,
26828
+ payload: { reason: "disposed" }
26829
+ });
26830
+ shared.disposed = true;
26831
+ shared.generation += 1;
26832
+ shared.status = "disposed";
26833
+ eventStream.close();
26834
+ options2.readable.off("end", onInputDead);
26835
+ options2.readable.off("error", onInputDead);
26836
+ options2.readable.pause();
26837
+ if (!shared.connectionClosed) {
26838
+ await connection.awaitInboundIdle().catch(() => void 0);
26839
+ await connection.close().catch(() => void 0);
26840
+ }
26841
+ })();
26842
+ return disposing;
26826
26843
  };
26827
26844
  return { cancel, compact, dispose };
26828
26845
  }
@@ -26926,12 +26943,14 @@ function createExecutorPrompt({
26926
26943
  promptMutex,
26927
26944
  applyRequestedModel,
26928
26945
  notifyPromptSettled,
26929
- shared
26946
+ shared,
26947
+ promptResults
26930
26948
  }) {
26931
26949
  const settleTurn = (input2) => {
26932
- if (!isLive(input2.expectedGeneration)) {
26950
+ if (!isLive(input2.expectedGeneration) || input2.record.finished) {
26933
26951
  return false;
26934
26952
  }
26953
+ promptResults.complete(input2.record);
26935
26954
  if (!acpPromptSettlementBelongsToContext({
26936
26955
  liveAcpSessionId: shared.sessionId ?? "",
26937
26956
  expectedAcpSessionId: input2.expectedSessionId,
@@ -26948,6 +26967,7 @@ function createExecutorPrompt({
26948
26967
  if (shared.status !== "disposed") {
26949
26968
  shared.status = "ready";
26950
26969
  }
26970
+ const interrupted = promptResults.hasInterrupted(input2.turnId);
26951
26971
  emit({
26952
26972
  type: "turn.completed",
26953
26973
  ...stamp(),
@@ -26955,30 +26975,44 @@ function createExecutorPrompt({
26955
26975
  threadId: options2.threadId,
26956
26976
  turnId: input2.turnId,
26957
26977
  payload: {
26958
- state: input2.state,
26959
- stopReason: input2.stopReason,
26978
+ state: interrupted ? "cancelled" : input2.state,
26979
+ stopReason: interrupted ? "cancelled" : input2.stopReason,
26960
26980
  ...input2.errorMessage === void 0 ? {} : { errorMessage: input2.errorMessage },
26961
26981
  ...input2.state === "failed" ? failureCategoryField(input2.failureCategory) : {}
26962
26982
  }
26963
26983
  });
26964
26984
  interruptedTurnIds.delete(input2.turnId);
26985
+ promptResults.forget(input2.turnId);
26965
26986
  return true;
26966
26987
  };
26967
- const sendPromptRpc = async (sessionId, promptParts, onWritten) => {
26988
+ const sendPromptRpc = async (sessionId, promptParts, onWritten, record2) => {
26968
26989
  const settlementHooks = hooks.promptSettlement;
26969
26990
  const promptKey = settlementHooks === void 0 ? void 0 : randomId();
26970
- const pending = connection.begin("session/prompt", {
26971
- sessionId,
26972
- prompt: promptParts,
26973
- ...settlementHooks !== void 0 && promptKey !== void 0 ? settlementHooks.requestFields(promptKey) : {}
26974
- });
26991
+ const pending = connection.begin(
26992
+ "session/prompt",
26993
+ {
26994
+ sessionId,
26995
+ prompt: promptParts,
26996
+ ...settlementHooks !== void 0 && promptKey !== void 0 ? settlementHooks.requestFields(promptKey) : {}
26997
+ },
26998
+ record2?.promptId
26999
+ );
26975
27000
  void pending.written.then(onWritten, () => void 0);
26976
27001
  const promptRpc = pending.response;
26977
27002
  if (settlementHooks === void 0 || promptKey === void 0) {
26978
27003
  return await promptRpc;
26979
27004
  } else {
26980
27005
  const { promise: early, resolve: settleEarly } = Promise.withResolvers();
26981
- shared.pendingSettlement = { promptKey, sessionId, settle: settleEarly };
27006
+ shared.pendingSettlement = {
27007
+ promptKey,
27008
+ sessionId,
27009
+ settle: settleEarly,
27010
+ ...record2 === void 0 ? {} : {
27011
+ onResponse: (response) => promptResults.receive(record2.promptId, response),
27012
+ onError: () => promptResults.reject(record2.promptId),
27013
+ hasResult: () => record2.response !== void 0
27014
+ }
27015
+ };
26982
27016
  try {
26983
27017
  const outcome = await Promise.race([
26984
27018
  promptRpc.then((value) => {
@@ -26999,9 +27033,11 @@ function createExecutorPrompt({
26999
27033
  const prompt = async (input2) => {
27000
27034
  failIfDisposed();
27001
27035
  const started = requireStarted();
27036
+ let record2;
27002
27037
  const settle2 = (rest) => settleTurn({
27003
27038
  expectedGeneration: started.generation,
27004
27039
  expectedSessionId: started.sessionId,
27040
+ record: record2,
27005
27041
  ...rest
27006
27042
  });
27007
27043
  let turnId;
@@ -27014,6 +27050,17 @@ function createExecutorPrompt({
27014
27050
  randomId
27015
27051
  );
27016
27052
  shared.promptsInFlight += 1;
27053
+ record2 = promptResults.add(
27054
+ {
27055
+ promptId: randomId(),
27056
+ sessionId: started.sessionId,
27057
+ generation: started.generation,
27058
+ turnId
27059
+ },
27060
+ () => {
27061
+ finishPrompt();
27062
+ }
27063
+ );
27017
27064
  shared.activeTurnId = turnId;
27018
27065
  shared.status = "running";
27019
27066
  if (shared.promptsInFlight === 1) {
@@ -27030,6 +27077,42 @@ function createExecutorPrompt({
27030
27077
  threadMutex.release();
27031
27078
  }
27032
27079
  const promptParts = input2.prompt ?? (input2.text !== void 0 ? [{ type: "text", text: input2.text }] : [{ type: "text", text: "" }]);
27080
+ let contextWindow;
27081
+ const finishPrompt = () => {
27082
+ if (!isLive(started.generation) || record2.finished) throw new AcpExecutorDisposedError();
27083
+ const response2 = record2.response;
27084
+ if (record2.interrupted || response2 === void 0) {
27085
+ settle2({ turnId, stopReason: "cancelled", state: "cancelled" });
27086
+ return { threadId: options2.threadId, turnId, stopReason: "cancelled" };
27087
+ }
27088
+ const stopReason = hooks.completedStopReason?.(response2) ?? response2.stopReason;
27089
+ if (contextWindow !== void 0) {
27090
+ emit({
27091
+ type: "thread.token-usage.updated",
27092
+ ...stamp(),
27093
+ provider: options2.provider,
27094
+ threadId: options2.threadId,
27095
+ turnId,
27096
+ payload: {
27097
+ usage: {
27098
+ usedTokens: contextWindow.usedTokens,
27099
+ ...contextWindow.maxTokens === void 0 ? {} : { maxTokens: contextWindow.maxTokens }
27100
+ }
27101
+ }
27102
+ });
27103
+ }
27104
+ settle2({
27105
+ turnId,
27106
+ stopReason,
27107
+ state: response2.stopReason === "cancelled" ? "cancelled" : "completed"
27108
+ });
27109
+ return {
27110
+ threadId: options2.threadId,
27111
+ turnId,
27112
+ stopReason,
27113
+ ...response2.usage !== void 0 && response2.usage !== null ? { usage: response2.usage } : {}
27114
+ };
27115
+ };
27033
27116
  await promptMutex.acquire();
27034
27117
  let response;
27035
27118
  try {
@@ -27044,6 +27127,7 @@ function createExecutorPrompt({
27044
27127
  expectedGeneration: started.generation
27045
27128
  });
27046
27129
  }
27130
+ failIfDisposed();
27047
27131
  if (isStale()) {
27048
27132
  settle2({ turnId, stopReason: "cancelled", state: "cancelled" });
27049
27133
  return { threadId: options2.threadId, turnId, stopReason: "cancelled" };
@@ -27051,10 +27135,15 @@ function createExecutorPrompt({
27051
27135
  closeActiveAssistantSegment(turnId);
27052
27136
  let written = false;
27053
27137
  try {
27054
- response = await sendPromptRpc(started.sessionId, promptParts, () => {
27055
- written = true;
27056
- input2.onDispatched?.(turnId);
27057
- });
27138
+ response = await sendPromptRpc(
27139
+ started.sessionId,
27140
+ promptParts,
27141
+ () => {
27142
+ written = true;
27143
+ input2.onDispatched?.(turnId);
27144
+ },
27145
+ record2
27146
+ );
27058
27147
  } catch (error62) {
27059
27148
  if (shared.disposed) {
27060
27149
  throw new AcpExecutorDisposedError();
@@ -27093,8 +27182,7 @@ function createExecutorPrompt({
27093
27182
  if (turnId === void 0) {
27094
27183
  throw new AcpExecutorError("internal", "ACP prompt settled without a turn id");
27095
27184
  }
27096
- const settledTurnId = turnId;
27097
- let contextWindow;
27185
+ if (record2.finished) throw new AcpExecutorDisposedError();
27098
27186
  if (hooks.readContextWindow !== void 0) {
27099
27187
  try {
27100
27188
  contextWindow = await hooks.readContextWindow({
@@ -27105,43 +27193,6 @@ function createExecutorPrompt({
27105
27193
  contextWindow = void 0;
27106
27194
  }
27107
27195
  }
27108
- const finishPrompt = () => {
27109
- if (interruptedTurnIds.has(settledTurnId)) {
27110
- settle2({ turnId: settledTurnId, stopReason: "cancelled", state: "cancelled" });
27111
- return {
27112
- threadId: options2.threadId,
27113
- turnId: settledTurnId,
27114
- stopReason: "cancelled"
27115
- };
27116
- }
27117
- const stopReason = hooks.completedStopReason?.(response) ?? response.stopReason;
27118
- if (contextWindow !== void 0) {
27119
- emit({
27120
- type: "thread.token-usage.updated",
27121
- ...stamp(),
27122
- provider: options2.provider,
27123
- threadId: options2.threadId,
27124
- turnId: settledTurnId,
27125
- payload: {
27126
- usage: {
27127
- usedTokens: contextWindow.usedTokens,
27128
- ...contextWindow.maxTokens === void 0 ? {} : { maxTokens: contextWindow.maxTokens }
27129
- }
27130
- }
27131
- });
27132
- }
27133
- settle2({
27134
- turnId: settledTurnId,
27135
- stopReason,
27136
- state: response.stopReason === "cancelled" ? "cancelled" : "completed"
27137
- });
27138
- return {
27139
- threadId: options2.threadId,
27140
- turnId: settledTurnId,
27141
- stopReason,
27142
- ...response.usage !== void 0 && response.usage !== null ? { usage: response.usage } : {}
27143
- };
27144
- };
27145
27196
  if (threadMutex.tryAcquire()) {
27146
27197
  try {
27147
27198
  return finishPrompt();
@@ -27159,6 +27210,91 @@ function createExecutorPrompt({
27159
27210
  return { sendPromptRpc, prompt };
27160
27211
  }
27161
27212
 
27213
+ // ../../packages/ycodium-acp-executor/src/executor/prompt-results.ts
27214
+ function createPromptResults({
27215
+ options: options2,
27216
+ shared
27217
+ }) {
27218
+ const prompts = /* @__PURE__ */ new Map();
27219
+ const add = (identity, finish) => {
27220
+ const { promise: done, resolve: resolve6 } = Promise.withResolvers();
27221
+ const record2 = {
27222
+ ...identity,
27223
+ finish,
27224
+ done,
27225
+ resolve: resolve6,
27226
+ rejected: false,
27227
+ interrupted: false,
27228
+ finished: false
27229
+ };
27230
+ prompts.set(record2.promptId, record2);
27231
+ return record2;
27232
+ };
27233
+ const receive = (promptId, response) => {
27234
+ const record2 = prompts.get(promptId);
27235
+ if (!record2 || record2.finished || record2.rejected || record2.response !== void 0) return;
27236
+ if (shared.disposed || shared.generation !== record2.generation || shared.sessionId !== record2.sessionId)
27237
+ return;
27238
+ record2.response = response;
27239
+ };
27240
+ const reject = (promptId) => {
27241
+ const record2 = prompts.get(promptId);
27242
+ if (record2 && record2.response === void 0) record2.rejected = true;
27243
+ };
27244
+ const stop = (turnId) => {
27245
+ for (const record2 of prompts.values()) {
27246
+ if (!record2.finished && (turnId === void 0 || record2.turnId === turnId) && record2.response === void 0) {
27247
+ record2.interrupted = true;
27248
+ }
27249
+ }
27250
+ };
27251
+ const complete = (record2) => {
27252
+ record2.finished = true;
27253
+ record2.resolve();
27254
+ };
27255
+ const hasInterrupted = (turnId) => [...prompts.values()].some((record2) => record2.turnId === turnId && record2.interrupted);
27256
+ const forget = (turnId) => {
27257
+ for (const [id, record2] of prompts) {
27258
+ if (record2.turnId === turnId) {
27259
+ complete(record2);
27260
+ prompts.delete(id);
27261
+ }
27262
+ }
27263
+ };
27264
+ const wait = async (turnId) => {
27265
+ const claimed = [...prompts.values()].filter(
27266
+ (record2) => !record2.finished && record2.response !== void 0 && (turnId === void 0 || record2.turnId === turnId)
27267
+ );
27268
+ if (claimed.length === 0) return;
27269
+ let timer;
27270
+ try {
27271
+ const drained = await Promise.race([
27272
+ Promise.all(claimed.map((record2) => record2.done)).then(() => true),
27273
+ new Promise((resolve6) => {
27274
+ timer = setTimeout(() => resolve6(false), options2.resultDrainTimeoutMs ?? 2e3);
27275
+ })
27276
+ ]);
27277
+ if (drained) return;
27278
+ options2.log?.warn?.("ACP result settlement timed out", { threadId: options2.threadId });
27279
+ for (const record2 of claimed) if (!record2.finished) record2.finish();
27280
+ } finally {
27281
+ clearTimeout(timer);
27282
+ }
27283
+ };
27284
+ const finishUnreceived = () => {
27285
+ const claimedTurns = new Set(
27286
+ [...prompts.values()].filter((record2) => !record2.finished && record2.response !== void 0).map((record2) => record2.turnId)
27287
+ );
27288
+ for (const record2 of prompts.values()) {
27289
+ if (!record2.finished && record2.response === void 0) {
27290
+ if (claimedTurns.has(record2.turnId)) record2.finish();
27291
+ else complete(record2);
27292
+ }
27293
+ }
27294
+ };
27295
+ return { add, receive, reject, stop, complete, hasInterrupted, forget, wait, finishUnreceived };
27296
+ }
27297
+
27162
27298
  // ../../packages/ycodium-acp-executor/src/user-input-pending.ts
27163
27299
  var userInputAnswerOptionId = (question, answers) => {
27164
27300
  const answer = answers[question.id];
@@ -27465,7 +27601,7 @@ function createExecutorRuntime({
27465
27601
  turnId: () => shared.activeTurnId
27466
27602
  });
27467
27603
  const failIfDisposed = () => {
27468
- if (shared.disposed) {
27604
+ if (shared.disposed || shared.disposing) {
27469
27605
  throw new AcpExecutorDisposedError();
27470
27606
  }
27471
27607
  };
@@ -28057,6 +28193,7 @@ function createExecutorSettlement({
28057
28193
  const abortPendingSettlement = (reason, failureCategory) => {
28058
28194
  const waiting = shared.pendingSettlement;
28059
28195
  if (waiting === void 0) return;
28196
+ if (waiting.hasResult?.()) return;
28060
28197
  shared.pendingSettlement = void 0;
28061
28198
  waiting.settle({
28062
28199
  error: withFailureCategory(
@@ -28078,6 +28215,7 @@ function createExecutorSettlement({
28078
28215
  shared.pendingSettlement = void 0;
28079
28216
  rememberSettledPromptKey(waiting.promptKey);
28080
28217
  if (signal.outcome === "error") {
28218
+ waiting.onError?.();
28081
28219
  waiting.settle({
28082
28220
  error: withFailureCategory(
28083
28221
  new AcpExecutorRequestError(
@@ -28088,8 +28226,10 @@ function createExecutorSettlement({
28088
28226
  )
28089
28227
  });
28090
28228
  } else {
28229
+ const response = { stopReason: signal.stopReason ?? "end_turn" };
28230
+ waiting.onResponse?.(response);
28091
28231
  waiting.settle({
28092
- response: { stopReason: signal.stopReason ?? "end_turn" }
28232
+ response
28093
28233
  });
28094
28234
  }
28095
28235
  return true;
@@ -28419,6 +28559,7 @@ function createAcpExecutor(options2) {
28419
28559
  const shared = {
28420
28560
  generation: 0,
28421
28561
  disposed: false,
28562
+ disposing: false,
28422
28563
  status: "idle",
28423
28564
  sessionId: void 0,
28424
28565
  modelSelectionState: {
@@ -28506,6 +28647,7 @@ function createAcpExecutor(options2) {
28506
28647
  shared
28507
28648
  });
28508
28649
  const { rememberSettledPromptKey, abortPendingSettlement, settleFromNotification } = createExecutorSettlement({ hooks, shared });
28650
+ const promptResults = createPromptResults({ options: options2, shared });
28509
28651
  const connection = createAcpConnection({
28510
28652
  readable: options2.readable,
28511
28653
  writable: options2.writable,
@@ -28516,8 +28658,12 @@ function createAcpExecutor(options2) {
28516
28658
  });
28517
28659
  },
28518
28660
  // 窗口在应答帧到达的那一刻同步收掉:应答之后的通知是真输出,不能再丢。
28519
- onResponse: (method) => {
28661
+ onResponse: ({ method, promptId }, outcome) => {
28520
28662
  if (method === "session/load") shared.sessionLoadInFlight = false;
28663
+ if (promptId !== void 0) {
28664
+ if ("result" in outcome) promptResults.receive(promptId, outcome.result);
28665
+ else promptResults.reject(promptId);
28666
+ }
28521
28667
  },
28522
28668
  onNotification: (notification) => {
28523
28669
  if (notification.method === "session/update") {
@@ -28582,6 +28728,7 @@ function createAcpExecutor(options2) {
28582
28728
  shared
28583
28729
  });
28584
28730
  const { sendPromptRpc, prompt } = createExecutorPrompt({
28731
+ promptResults,
28585
28732
  isLive,
28586
28733
  closeActiveAssistantSegment,
28587
28734
  emit,
@@ -28601,6 +28748,7 @@ function createAcpExecutor(options2) {
28601
28748
  shared
28602
28749
  });
28603
28750
  const { cancel, compact, dispose } = createExecutorLifecycle({
28751
+ promptResults,
28604
28752
  failIfDisposed,
28605
28753
  requireStarted,
28606
28754
  interruptedTurnIds,
@@ -28652,6 +28800,27 @@ function createAcpExecutor(options2) {
28652
28800
  };
28653
28801
  }
28654
28802
 
28803
+ // ../../packages/ycodium-acp-executor/src/session-registry.ts
28804
+ function createAcpSessionRegistry(threads, stopBooked) {
28805
+ const requireThread = (threadId) => {
28806
+ const booked = threads.get(threadId);
28807
+ if (!booked) throw new Error(`unknown thread ${threadId}`);
28808
+ if (booked.closing) throw new Error(`thread ${threadId} is closing`);
28809
+ return booked;
28810
+ };
28811
+ const stopSession = (threadId, booked = threads.get(threadId)) => {
28812
+ if (!booked) return Promise.resolve();
28813
+ booked.closing ??= Promise.resolve().then(() => stopBooked(booked)).then(() => {
28814
+ if (threads.get(threadId) === booked) threads.delete(threadId);
28815
+ });
28816
+ return booked.closing;
28817
+ };
28818
+ const stopAll = () => Promise.all([...threads].map(([threadId, booked]) => stopSession(threadId, booked))).then(
28819
+ () => void 0
28820
+ );
28821
+ return { requireThread, stopSession, stopAll };
28822
+ }
28823
+
28655
28824
  // ../../packages/ycodium-acp-executor/src/start-abort.ts
28656
28825
  function throwIfStartAborted(signal) {
28657
28826
  if (signal?.aborted) throw new Error("aborted");
@@ -28742,6 +28911,21 @@ function acpAgentVersion(initializeResult) {
28742
28911
  }
28743
28912
  var MAX_VERSION_OUTPUT_BYTES = 64 * 1024;
28744
28913
 
28914
+ // src/agentProcess.ts
28915
+ import { nodeStreamsFromHandle } from "@ycodium-ai/plugin-api/process-stdin";
28916
+
28917
+ // src/clock.ts
28918
+ var realAgentClock = {
28919
+ now: () => Date.now(),
28920
+ delay(ms, callback) {
28921
+ const timer = setTimeout(callback, ms);
28922
+ timer.unref?.();
28923
+ return () => {
28924
+ clearTimeout(timer);
28925
+ };
28926
+ }
28927
+ };
28928
+
28745
28929
  // src/profile.ts
28746
28930
  import * as NodeCrypto2 from "node:crypto";
28747
28931
  import * as NodeFSP from "node:fs/promises";
@@ -29000,36 +29184,36 @@ async function* watchAgentStderr(source, onLoginPrompt, onBrowserHelperLine) {
29000
29184
  }
29001
29185
 
29002
29186
  // src/agentProcess.ts
29003
- async function waitForExit(handle, timeoutMs) {
29004
- let timer;
29187
+ async function waitForExit(handle, timeoutMs, clock) {
29188
+ let cancel = () => {
29189
+ };
29005
29190
  const exited = await Promise.race([
29006
29191
  handle.exited.then(
29007
29192
  () => true,
29008
29193
  () => true
29009
29194
  ),
29010
29195
  new Promise((resolve6) => {
29011
- timer = setTimeout(() => resolve6(false), timeoutMs);
29012
- timer.unref?.();
29196
+ cancel = clock.delay(timeoutMs, () => resolve6(false));
29013
29197
  })
29014
29198
  ]);
29015
- clearTimeout(timer);
29199
+ cancel();
29016
29200
  return exited;
29017
29201
  }
29018
- function stopAgentProcess(handle, exitWaitMs, log) {
29202
+ function stopAgentProcess(handle, exitWaitMs, log, clock = realAgentClock) {
29019
29203
  let stopping = stoppingByHandle.get(handle);
29020
29204
  if (stopping === void 0) {
29021
- stopping = terminate(handle, exitWaitMs, log);
29205
+ stopping = terminate(handle, exitWaitMs, log, clock);
29022
29206
  stoppingByHandle.set(handle, stopping);
29023
29207
  }
29024
29208
  return stopping;
29025
29209
  }
29026
29210
  var stoppingByHandle = /* @__PURE__ */ new WeakMap();
29027
- async function terminate(handle, exitWaitMs, log) {
29211
+ async function terminate(handle, exitWaitMs, log, clock) {
29028
29212
  await handle.kill("SIGTERM").catch(() => void 0);
29029
- if (await waitForExit(handle, exitWaitMs)) return;
29213
+ if (await waitForExit(handle, exitWaitMs, clock)) return;
29030
29214
  log.warn("the agent process ignored SIGTERM; killing it", { pid: handle.pid, exitWaitMs });
29031
29215
  await handle.kill("SIGKILL").catch(() => void 0);
29032
- if (await waitForExit(handle, exitWaitMs)) return;
29216
+ if (await waitForExit(handle, exitWaitMs, clock)) return;
29033
29217
  log.error("the agent process is still running after SIGKILL; leaving it behind", {
29034
29218
  pid: handle.pid,
29035
29219
  exitWaitMs
@@ -29062,6 +29246,7 @@ async function openAgentProcess(input2) {
29062
29246
  await removeRuntimeTempDir(directory);
29063
29247
  throw error62;
29064
29248
  }
29249
+ const clock = input2.clock ?? realAgentClock;
29065
29250
  const { readable, writable } = nodeStreamsFromHandle({
29066
29251
  stdout: filterAgentStdout(handle.stdout, { onLoginPrompt: input2.onLoginPrompt }),
29067
29252
  stderr: watchAgentStderr(handle.stderr, input2.onLoginPrompt, input2.onBrowserHelperLine),
@@ -29073,22 +29258,21 @@ async function openAgentProcess(input2) {
29073
29258
  const pending = connection.request(method, params);
29074
29259
  if (timeoutMs === void 0) return pending;
29075
29260
  return new Promise((resolve6, reject) => {
29076
- const timer = setTimeout(() => {
29261
+ const cancel = clock.delay(timeoutMs, () => {
29077
29262
  reject(
29078
29263
  new AntigravityAuthError(
29079
29264
  "agent-timeout",
29080
29265
  `Antigravity did not answer '${method}' in time. It may still be starting up; try again.`
29081
29266
  )
29082
29267
  );
29083
- }, timeoutMs);
29084
- timer.unref?.();
29268
+ });
29085
29269
  pending.then(
29086
29270
  (value) => {
29087
- clearTimeout(timer);
29271
+ cancel();
29088
29272
  resolve6(value);
29089
29273
  },
29090
29274
  (error62) => {
29091
- clearTimeout(timer);
29275
+ cancel();
29092
29276
  reject(error62);
29093
29277
  }
29094
29278
  );
@@ -29098,7 +29282,7 @@ async function openAgentProcess(input2) {
29098
29282
  const close = () => {
29099
29283
  closing ??= (async () => {
29100
29284
  await connection.close().catch(() => void 0);
29101
- await stopAgentProcess(handle, input2.exitWaitMs, input2.host.log);
29285
+ await stopAgentProcess(handle, input2.exitWaitMs, input2.host.log, clock);
29102
29286
  await removeRuntimeTempDir(directory);
29103
29287
  })();
29104
29288
  return closing;
@@ -30054,13 +30238,14 @@ function createAntigravitySession({
30054
30238
  platform: platform2,
30055
30239
  processEnv,
30056
30240
  exitWaitMs,
30241
+ clock,
30057
30242
  userHome,
30058
30243
  dirs,
30059
30244
  events,
30060
30245
  threads,
30061
30246
  mutable,
30062
30247
  resolveInput,
30063
- stopBooked,
30248
+ stopSession,
30064
30249
  login,
30065
30250
  noteSession,
30066
30251
  recordCatalog,
@@ -30075,8 +30260,8 @@ function createAntigravitySession({
30075
30260
  if (cwd.trim() === "") throw new Error("workspace path missing");
30076
30261
  const existing = threads.get(input2.threadId);
30077
30262
  if (existing !== void 0) {
30078
- threads.delete(input2.threadId);
30079
- await stopBooked(existing);
30263
+ await stopSession(input2.threadId, existing);
30264
+ if (mutable.disposed) throw new Error("instance disposed");
30080
30265
  throwIfStartAborted(signal);
30081
30266
  }
30082
30267
  const lease = await deps.runtime.acquire(resolveInput);
@@ -30135,7 +30320,7 @@ function createAntigravitySession({
30135
30320
  if (sessionReady) {
30136
30321
  void noteSession(() => login.noteSessionSignedOut());
30137
30322
  host.log.warn("antigravity asked to sign in during a session; stopping the process");
30138
- void stopAgentProcess(handle, exitWaitMs, host.log);
30323
+ void stopAgentProcess(handle, exitWaitMs, host.log, clock);
30139
30324
  }
30140
30325
  };
30141
30326
  const { readable, writable, stderrTail } = nodeStreamsFromHandle2({
@@ -30282,7 +30467,7 @@ function createAntigravitySession({
30282
30467
  return session;
30283
30468
  } catch (error62) {
30284
30469
  await executor.dispose().catch(() => void 0);
30285
- await stopAgentProcess(handle, exitWaitMs, host.log);
30470
+ await stopAgentProcess(handle, exitWaitMs, host.log, clock);
30286
30471
  await forwarding.catch(() => void 0);
30287
30472
  await removeRuntimeTempDir(runtimeTemp);
30288
30473
  if (live.signInRequired || isSignInRequiredError(error62)) {
@@ -30300,10 +30485,9 @@ import * as NodeCrypto4 from "node:crypto";
30300
30485
  function createAntigravityTurn({
30301
30486
  deps,
30302
30487
  events,
30303
- threads,
30304
30488
  mutable,
30305
30489
  requireThread,
30306
- stopBooked,
30490
+ stopSession,
30307
30491
  login,
30308
30492
  pushTaskEvents
30309
30493
  }) {
@@ -30340,8 +30524,7 @@ function createAntigravityTurn({
30340
30524
  ...base,
30341
30525
  payload: { state: "completed", stopReason: "end_turn" }
30342
30526
  });
30343
- threads.delete(input2.threadId);
30344
- await stopBooked(booked);
30527
+ await stopSession(input2.threadId, booked);
30345
30528
  return { threadId: input2.threadId, turnId };
30346
30529
  };
30347
30530
  return {
@@ -30876,6 +31059,7 @@ function createLoginController(deps) {
30876
31059
  const { host } = deps;
30877
31060
  const authDeadlineMs = deps.authDeadlineMs ?? AUTH_DEADLINE_MS;
30878
31061
  const startupMs = deps.startupTimeoutMs ?? AGENT_STARTUP_TIMEOUT_MS;
31062
+ const clock = deps.clock ?? realAgentClock;
30879
31063
  const forward = deps.forward ?? forwardCallback;
30880
31064
  const markerFile = signedInMarkerFile(deps.dirs.profile);
30881
31065
  const browserCommand = buildBrowserCommand({ nodePath: deps.nodePath, platform: deps.platform });
@@ -30944,6 +31128,7 @@ function createLoginController(deps) {
30944
31128
  platform: deps.platform,
30945
31129
  processEnv: deps.processEnv,
30946
31130
  exitWaitMs: deps.exitWaitMs,
31131
+ clock,
30947
31132
  clientInfo: deps.clientInfo,
30948
31133
  browserCommand: hooks.browser ? browserCommand : void 0,
30949
31134
  onLoginPrompt: hooks.onLoginPrompt,
@@ -31039,13 +31224,12 @@ function createLoginController(deps) {
31039
31224
  };
31040
31225
  const runSignIn = async (target) => {
31041
31226
  const guard = (promise2) => Promise.race([promise2, target.interrupted]);
31042
- const deadline = setTimeout(() => {
31227
+ const cancelDeadline = clock.delay(authDeadlineMs, () => {
31043
31228
  abortFlow(target, {
31044
31229
  kind: "failed",
31045
31230
  failure: failure2("expired", "Google sign-in expired. Start sign-in again.")
31046
31231
  });
31047
- }, authDeadlineMs);
31048
- deadline.unref?.();
31232
+ });
31049
31233
  const opening = open4({
31050
31234
  browser: true,
31051
31235
  onLoginPrompt: (detail) => receiveAuthorizationUrl(target, detail),
@@ -31089,7 +31273,7 @@ function createLoginController(deps) {
31089
31273
  });
31090
31274
  }
31091
31275
  } finally {
31092
- clearTimeout(deadline);
31276
+ cancelDeadline();
31093
31277
  const agent = await opening.catch(() => void 0);
31094
31278
  if (agent !== void 0) await release(agent);
31095
31279
  if (refreshAfter) requestRefresh();
@@ -31116,7 +31300,7 @@ function createLoginController(deps) {
31116
31300
  phase = "starting";
31117
31301
  authorizationUrl = null;
31118
31302
  error62 = null;
31119
- expiresAt = new Date(Date.now() + authDeadlineMs).toISOString();
31303
+ expiresAt = new Date(clock.now() + authDeadlineMs).toISOString();
31120
31304
  publish();
31121
31305
  target.done = track(runSignIn(target));
31122
31306
  return snapshot();
@@ -31812,6 +31996,7 @@ var TextGenerationRejection = class extends Error {
31812
31996
  };
31813
31997
  function createAntigravityTextGeneration(deps) {
31814
31998
  const timeoutMs = deps.timeoutMs ?? DEFAULT_TIMEOUT_MS;
31999
+ const clock = deps.clock ?? realAgentClock;
31815
32000
  const running = /* @__PURE__ */ new Set();
31816
32001
  const runJson = async (request2) => {
31817
32002
  const { operation, signal } = request2;
@@ -31839,7 +32024,8 @@ function createAntigravityTextGeneration(deps) {
31839
32024
  const closeAll = async () => {
31840
32025
  stopped = true;
31841
32026
  await executor?.dispose().catch(() => void 0);
31842
- if (handle !== void 0) await stopAgentProcess(handle, deps.exitWaitMs, deps.host.log);
32027
+ if (handle !== void 0)
32028
+ await stopAgentProcess(handle, deps.exitWaitMs, deps.host.log, clock);
31843
32029
  await pump?.catch(() => void 0);
31844
32030
  if (runtimeTemp !== void 0) await removeRuntimeTempDir(runtimeTemp);
31845
32031
  if (workspace !== void 0) {
@@ -32133,6 +32319,7 @@ async function createAntigravityInstance(config2, host, deps) {
32133
32319
  const platform2 = deps.platform ?? HOST_PLATFORM;
32134
32320
  const processEnv = deps.processEnv ?? process.env;
32135
32321
  const exitWaitMs = deps.exitWaitMs ?? DEFAULT_EXIT_WAIT_MS;
32322
+ const clock = deps.clock ?? realAgentClock;
32136
32323
  const userHome = deps.userHome ?? resolveAntigravityUserHome(platform2, { ...processEnv, ...recipe.environment });
32137
32324
  const dirs = resolveAntigravityDirectories({
32138
32325
  dataDir: deps.dataDir,
@@ -32145,6 +32332,7 @@ async function createAntigravityInstance(config2, host, deps) {
32145
32332
  const events = new EventBus();
32146
32333
  const threads = /* @__PURE__ */ new Map();
32147
32334
  const mutable = { disposed: false };
32335
+ let disposeTask;
32148
32336
  const unregister = deps.runtime.registerInstance({
32149
32337
  instanceId: host.instanceId,
32150
32338
  host,
@@ -32157,15 +32345,10 @@ async function createAntigravityInstance(config2, host, deps) {
32157
32345
  processEnv
32158
32346
  };
32159
32347
  const resolveExecutable = () => deps.runtime.resolve(resolveInput);
32160
- const requireThread = (threadId) => {
32161
- const booked = threads.get(threadId);
32162
- if (!booked) throw new Error(`unknown thread ${threadId}`);
32163
- return booked;
32164
- };
32165
32348
  const stopBooked = async (booked) => {
32166
32349
  for (const stopped of booked.background.finish()) events.push(stopped);
32167
32350
  await booked.executor.dispose().catch(() => void 0);
32168
- await stopAgentProcess(booked.handle, exitWaitMs, host.log);
32351
+ await stopAgentProcess(booked.handle, exitWaitMs, host.log, clock);
32169
32352
  await booked.forwarding.catch(() => void 0);
32170
32353
  if (!await removeRuntimeTempDir(booked.runtimeTemp)) {
32171
32354
  host.log.warn("could not remove a runtime temp directory; it is swept on the next start", {
@@ -32173,6 +32356,7 @@ async function createAntigravityInstance(config2, host, deps) {
32173
32356
  });
32174
32357
  }
32175
32358
  };
32359
+ const { requireThread, stopSession, stopAll } = createAcpSessionRegistry(threads, stopBooked);
32176
32360
  const helpers = createAntigravityTextGeneration({
32177
32361
  host,
32178
32362
  profile: dirs.profile,
@@ -32181,14 +32365,17 @@ async function createAntigravityInstance(config2, host, deps) {
32181
32365
  platform: platform2,
32182
32366
  processEnv,
32183
32367
  exitWaitMs,
32368
+ clock,
32184
32369
  clientInfo: CLIENT_INFO,
32185
32370
  acquireExecutable: () => deps.runtime.acquire(resolveInput),
32186
32371
  ...deps.textGenerationTimeoutMs === void 0 ? {} : { timeoutMs: deps.textGenerationTimeoutMs }
32187
32372
  });
32188
32373
  const stopAllSessions = async (keepThreadId) => {
32189
32374
  const targets = [...threads].filter(([threadId]) => threadId !== keepThreadId);
32190
- for (const [threadId] of targets) threads.delete(threadId);
32191
- await Promise.all([...targets.map(([, booked]) => stopBooked(booked)), helpers.stopRunning()]);
32375
+ await Promise.all([
32376
+ ...targets.map(([threadId, booked]) => stopSession(threadId, booked)),
32377
+ helpers.stopRunning()
32378
+ ]);
32192
32379
  };
32193
32380
  const login = createLoginController({
32194
32381
  host,
@@ -32200,6 +32387,7 @@ async function createAntigravityInstance(config2, host, deps) {
32200
32387
  acquireExecutable: () => deps.runtime.acquire(resolveInput),
32201
32388
  stopSessions: stopAllSessions,
32202
32389
  exitWaitMs,
32390
+ clock,
32203
32391
  clientInfo: CLIENT_INFO,
32204
32392
  nodePath: deps.nodePath ?? process.execPath,
32205
32393
  ...deps.authDeadlineMs === void 0 ? {} : { authDeadlineMs: deps.authDeadlineMs },
@@ -32278,13 +32466,14 @@ async function createAntigravityInstance(config2, host, deps) {
32278
32466
  platform: platform2,
32279
32467
  processEnv,
32280
32468
  exitWaitMs,
32469
+ clock,
32281
32470
  userHome,
32282
32471
  dirs,
32283
32472
  events,
32284
32473
  threads,
32285
32474
  mutable,
32286
32475
  resolveInput,
32287
- stopBooked,
32476
+ stopSession,
32288
32477
  login,
32289
32478
  noteSession,
32290
32479
  recordCatalog,
@@ -32294,10 +32483,9 @@ async function createAntigravityInstance(config2, host, deps) {
32294
32483
  const turn = createAntigravityTurn({
32295
32484
  deps,
32296
32485
  events,
32297
- threads,
32298
32486
  mutable,
32299
32487
  requireThread,
32300
- stopBooked,
32488
+ stopSession,
32301
32489
  login,
32302
32490
  pushTaskEvents
32303
32491
  });
@@ -32344,11 +32532,10 @@ async function createAntigravityInstance(config2, host, deps) {
32344
32532
  sendTurn: turn.sendTurn,
32345
32533
  interruptTurn: async (threadId, turnId) => {
32346
32534
  const booked = threads.get(threadId);
32347
- if (booked === void 0) return;
32535
+ if (booked === void 0 || booked.closing) return;
32348
32536
  host.log.info("interrupt turn", { threadId, turnId });
32349
32537
  if (booked.session.status !== "running" && booked.background.hasPromoted()) {
32350
- threads.delete(threadId);
32351
- await stopBooked(booked);
32538
+ await stopSession(threadId, booked);
32352
32539
  return;
32353
32540
  }
32354
32541
  await booked.executor.cancel(turnId);
@@ -32380,12 +32567,7 @@ async function createAntigravityInstance(config2, host, deps) {
32380
32567
  };
32381
32568
  if (applied !== void 0) booked.appliedModeId = applied;
32382
32569
  },
32383
- stopSession: async (threadId) => {
32384
- const booked = threads.get(threadId);
32385
- if (booked === void 0) return;
32386
- threads.delete(threadId);
32387
- await stopBooked(booked);
32388
- },
32570
+ stopSession: (threadId) => stopSession(threadId),
32389
32571
  readThread: async (threadId) => {
32390
32572
  const booked = requireThread(threadId);
32391
32573
  return { threadId, turns: booked.turns };
@@ -32393,17 +32575,18 @@ async function createAntigravityInstance(config2, host, deps) {
32393
32575
  events,
32394
32576
  textGeneration: helpers.textGeneration,
32395
32577
  continuationKey: dirs.continuationKey,
32396
- dispose: async () => {
32397
- if (mutable.disposed) return;
32578
+ dispose: () => {
32579
+ if (disposeTask) return disposeTask;
32398
32580
  mutable.disposed = true;
32399
- unregisterLogin();
32400
- unsubscribeRuntime();
32401
- await login.dispose();
32402
- unregister();
32403
- const booked = [...threads.values()];
32404
- threads.clear();
32405
- await Promise.all([...booked.map((entry) => stopBooked(entry)), helpers.stopRunning()]);
32406
- events.close();
32581
+ disposeTask = (async () => {
32582
+ unregisterLogin();
32583
+ unsubscribeRuntime();
32584
+ await login.dispose();
32585
+ unregister();
32586
+ await Promise.all([stopAll(), helpers.stopRunning()]);
32587
+ events.close();
32588
+ })();
32589
+ return disposeTask;
32407
32590
  }
32408
32591
  };
32409
32592
  return instance;
@@ -33478,7 +33661,7 @@ var executors = [
33478
33661
  ];
33479
33662
  var index_default = definePlugin({
33480
33663
  id: "agent-antigravity",
33481
- apiVersion: 13,
33664
+ apiVersion: 15,
33482
33665
  executors,
33483
33666
  activate(ctx) {
33484
33667
  const runtime = createRuntimeManager({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ycodium-ai/agent-antigravity",
3
- "version": "0.2.3122",
3
+ "version": "0.2.3158",
4
4
  "description": "Google Antigravity executor: runs the Antigravity agent over Agent Client Protocol stdio.",
5
5
  "keywords": [
6
6
  "ycodium",
@@ -31,8 +31,8 @@
31
31
  "typescript": "~6.0.3",
32
32
  "vite-plus": "0.2.2",
33
33
  "yauzl": "^3.4.0",
34
- "ycodium-acp-executor": "0.2.3122",
35
- "@ycodium-ai/plugin-api": "0.2.3122",
34
+ "@ycodium-ai/plugin-api": "0.2.3158",
35
+ "ycodium-acp-executor": "0.2.3158",
36
36
  "ycodium-executor-testing": "0.0.0"
37
37
  },
38
38
  "ycodium": {