@quantiya/codevibe-antigravity-plugin 2.0.81 → 2.0.82

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.
package/dist/agy-hook.js CHANGED
@@ -97,7 +97,9 @@ function buildBody(raw) {
97
97
  const kept = {};
98
98
  for (const key of FORWARDED_TOOL_ARG_KEYS) {
99
99
  const value = source[key];
100
- if (typeof value === "string") kept[key] = value.slice(0, MAX_TOOL_ARG_CHARS);
100
+ if (typeof value === "string") {
101
+ kept[key] = value.slice(0, MAX_TOOL_ARG_CHARS);
102
+ }
101
103
  }
102
104
  body.toolArgs = kept;
103
105
  }
@@ -230,8 +232,9 @@ function finishProcess() {
230
232
  process.exit(0);
231
233
  }
232
234
  if (require.main === module) {
233
- setTimeout(finishProcess, HARD_DEADLINE_MS);
234
- runHook({ event: process.argv[2], env: process.env, stdin: process.stdin }).then(finishProcess, finishProcess);
235
+ const exitHandler = () => finishProcess();
236
+ setTimeout(exitHandler, HARD_DEADLINE_MS);
237
+ runHook({ event: process.argv[2], env: process.env, stdin: process.stdin }).then(exitHandler, exitHandler);
235
238
  }
236
239
  // Annotate the CommonJS export names for ESM import in node:
237
240
  0 && (module.exports = {
package/dist/server.js CHANGED
@@ -30,6 +30,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/server.ts
31
31
  var server_exports = {};
32
32
  __export(server_exports, {
33
+ ApprovalDetector: () => ApprovalDetector,
33
34
  McpServer: () => McpServer,
34
35
  SessionNotFoundError: () => SessionNotFoundError,
35
36
  StoredAuthFailureError: () => StoredAuthFailureError,
@@ -47,13 +48,15 @@ __export(server_exports, {
47
48
  isAgyStatusFooterLine: () => isAgyStatusFooterLine,
48
49
  isComposedStatusFooter: () => isComposedStatusFooter,
49
50
  isPaneInputSafetyBlocked: () => isPaneInputSafetyBlocked,
51
+ isQuestionFooterLine: () => isQuestionFooterLine,
50
52
  isSystemErrorActiveFromIndex: () => isSystemErrorActiveFromIndex,
51
53
  looksLikePromptSnapshot: () => looksLikePromptSnapshot,
52
54
  parseApprovalSnapshot: () => parseApprovalSnapshot,
53
55
  parseMaybeJson: () => parseMaybeJson,
54
56
  readTranscriptFirstType: () => readTranscriptFirstType,
55
57
  reconstructFooter: () => reconstructFooter,
56
- runForeignSpawnIdle: () => runForeignSpawnIdle
58
+ runForeignSpawnIdle: () => runForeignSpawnIdle,
59
+ safeIsoTimestamp: () => safeIsoTimestamp
57
60
  });
58
61
  module.exports = __toCommonJS(server_exports);
59
62
  var crypto3 = __toESM(require("crypto"));
@@ -4586,23 +4589,31 @@ var ApprovalDetector = class extends import_events3.EventEmitter {
4586
4589
  return null;
4587
4590
  }
4588
4591
  const promptId = forcedPromptId ?? (0, import_uuid.v4)();
4592
+ const matchingCall = candidate.kind === "question" ? this.findMatchingPendingCall(candidate, conversationId) : null;
4593
+ if (matchingCall) {
4594
+ matchingCall.matchedPromptId = promptId;
4595
+ }
4589
4596
  const syntheticCall = {
4590
4597
  conversationId,
4591
- intentStepIndex: -1,
4598
+ intentStepIndex: matchingCall?.intentStepIndex ?? -1,
4592
4599
  // sentinel: "no transcript origin"
4593
- toolCallIndex: 0,
4594
- intentByteOffset: 0,
4600
+ toolCallIndex: matchingCall?.toolCallIndex ?? 0,
4601
+ intentByteOffset: matchingCall?.intentByteOffset ?? 0,
4595
4602
  // Best-effort tool-type inference from the candidate. For shell
4596
4603
  // commands → RUN_COMMAND. For edit-style headers with a file
4597
4604
  // path → CODE_ACTION. For questions → ASK_QUESTION. Default: GENERIC.
4598
- toolType: guessToolTypeFromIdentity(candidate),
4599
- command: candidate.command,
4600
- filePath: candidate.filePath,
4601
- rawToolName: candidate.kind === "question" ? "ask_question" : candidate.command ?? candidate.filePath ?? "unknown",
4602
- questionText: candidate.kind === "question" ? candidate.headerText : void 0,
4605
+ toolType: matchingCall?.toolType ?? guessToolTypeFromIdentity(candidate),
4606
+ command: matchingCall?.command ?? candidate.command,
4607
+ filePath: matchingCall?.filePath ?? candidate.filePath,
4608
+ rawToolName: matchingCall?.rawToolName ?? (candidate.kind === "question" ? "ask_question" : candidate.command ?? candidate.filePath ?? "unknown"),
4609
+ questionText: candidate.kind === "question" && candidate.headerText ? candidate.headerText : matchingCall?.questionText,
4610
+ // NOTE (Codex R3-F1 / Claude R3-F2): Pane options are authoritative ground truth
4611
+ // that directly correspond to desktop keystrokes (submitMap). Transcript options
4612
+ // serve solely as fallback when pane options cannot be parsed.
4613
+ questionOptions: candidate.kind === "question" && candidate.options && candidate.options.length > 0 ? candidate.options : matchingCall?.questionOptions,
4603
4614
  promptId,
4604
- startedAt: Date.now(),
4605
- intentCreatedAt: (/* @__PURE__ */ new Date()).toISOString()
4615
+ startedAt: matchingCall?.startedAt ?? Date.now(),
4616
+ intentCreatedAt: matchingCall?.intentCreatedAt ?? (/* @__PURE__ */ new Date()).toISOString()
4606
4617
  };
4607
4618
  const state = {
4608
4619
  promptId,
@@ -4896,6 +4907,11 @@ var ApprovalDetector = class extends import_events3.EventEmitter {
4896
4907
  if (state.pendingCall.promptId === promptId) {
4897
4908
  state.pendingCall.promptId = void 0;
4898
4909
  }
4910
+ for (const call of this.pendingCalls.values()) {
4911
+ if (call.matchedPromptId === promptId) {
4912
+ call.matchedPromptId = void 0;
4913
+ }
4914
+ }
4899
4915
  this.paneOnlyEmittedHashes.clear();
4900
4916
  return state;
4901
4917
  }
@@ -4922,7 +4938,11 @@ var ApprovalDetector = class extends import_events3.EventEmitter {
4922
4938
  }
4923
4939
  findMatchingPendingCall(candidate, conversationId) {
4924
4940
  if (candidate.kind === "question") {
4925
- const questionCalls = Array.from(this.pendingCalls.values()).filter((c) => c.conversationId === conversationId).filter(
4941
+ const questionCalls = Array.from(this.pendingCalls.values()).filter((c) => c.conversationId === conversationId).filter((c) => c.resultStepIndex === void 0).filter((c) => {
4942
+ const associatedPromptId = c.matchedPromptId || c.promptId;
4943
+ if (!associatedPromptId) return true;
4944
+ return !this.resolvedPrompts.has(associatedPromptId) && !this.pendingPrompts.has(associatedPromptId);
4945
+ }).filter(
4926
4946
  (c) => c.toolType === "ASK_QUESTION" || c.rawToolName?.toLowerCase() === "ask_question"
4927
4947
  ).sort((a, b) => a.intentStepIndex - b.intentStepIndex);
4928
4948
  if (questionCalls.length > 0 && candidate.headerText) {
@@ -5642,6 +5662,7 @@ function mapTranscriptEvent(emit, sessionId, notBeforeMs) {
5642
5662
  command: extractCommandFromArgs(name, args),
5643
5663
  filePath: extractFilePathFromArgs(name, args),
5644
5664
  questionText: extractQuestionFromArgs(name, args),
5665
+ questionOptions: extractQuestionOptionsFromArgs(name, args),
5645
5666
  cwd: extractCwdFromArgs(args),
5646
5667
  rawToolName: name,
5647
5668
  startedAt: Date.now(),
@@ -5793,8 +5814,15 @@ function extractQuestionFromArgs(toolName, args) {
5793
5814
  if (typeof a.prompt === "string" && a.prompt.trim().length > 0) {
5794
5815
  return stripWrappingQuotes2(a.prompt.trim());
5795
5816
  }
5796
- if (Array.isArray(a.questions) && a.questions.length > 0) {
5797
- const first = a.questions[0];
5817
+ let questions = a.questions;
5818
+ if (typeof questions === "string") {
5819
+ try {
5820
+ questions = JSON.parse(questions.trim());
5821
+ } catch {
5822
+ }
5823
+ }
5824
+ if (Array.isArray(questions) && questions.length > 0) {
5825
+ const first = questions[0];
5798
5826
  if (typeof first === "string" && first.trim().length > 0) {
5799
5827
  return stripWrappingQuotes2(first.trim());
5800
5828
  }
@@ -5807,6 +5835,40 @@ function extractQuestionFromArgs(toolName, args) {
5807
5835
  }
5808
5836
  return void 0;
5809
5837
  }
5838
+ function extractQuestionOptionsFromArgs(toolName, args) {
5839
+ if (!args || typeof args !== "object") return void 0;
5840
+ const tn = (toolName || "").toLowerCase().trim();
5841
+ const isQuestionTool = tn === "ask_question" || tn === "question" || tn === "ask";
5842
+ if (!isQuestionTool) return void 0;
5843
+ const a = args;
5844
+ let questions = a.questions;
5845
+ if (typeof questions === "string") {
5846
+ try {
5847
+ questions = JSON.parse(questions.trim());
5848
+ } catch {
5849
+ }
5850
+ }
5851
+ if (Array.isArray(questions) && questions.length > 0) {
5852
+ const first = questions[0];
5853
+ if (first && typeof first === "object" && Array.isArray(first.options)) {
5854
+ const rawOptions = first.options;
5855
+ const result = [];
5856
+ for (let i = 0; i < rawOptions.length; i++) {
5857
+ const opt = rawOptions[i];
5858
+ if (typeof opt === "string" && opt.trim().length > 0) {
5859
+ result.push({ number: String(i + 1), text: stripWrappingQuotes2(opt.trim()) });
5860
+ } else if (opt && typeof opt === "object" && typeof opt.text === "string") {
5861
+ result.push({
5862
+ number: String(opt.number ?? i + 1),
5863
+ text: stripWrappingQuotes2(String(opt.text).trim())
5864
+ });
5865
+ }
5866
+ }
5867
+ if (result.length > 0) return result;
5868
+ }
5869
+ }
5870
+ return void 0;
5871
+ }
5810
5872
  function extractCwdFromArgs(args) {
5811
5873
  if (!args || typeof args !== "object") return void 0;
5812
5874
  const a = args;
@@ -5912,6 +5974,15 @@ function friendlyHookToolName(rawName, resultType) {
5912
5974
  return transcriptTypeToFriendlyToolName(resultType);
5913
5975
  }
5914
5976
  }
5977
+ function safeIsoTimestamp(rawTimestamp) {
5978
+ if (typeof rawTimestamp === "string" && rawTimestamp.trim().length > 0) {
5979
+ const parsed = Date.parse(rawTimestamp);
5980
+ if (!Number.isNaN(parsed)) {
5981
+ return new Date(parsed).toISOString();
5982
+ }
5983
+ }
5984
+ return (/* @__PURE__ */ new Date()).toISOString();
5985
+ }
5915
5986
  function commandTarget(command) {
5916
5987
  return command?.trim().split(/\s+/)[0] || void 0;
5917
5988
  }
@@ -5998,7 +6069,7 @@ var AgyToolActivityIntegration = class {
5998
6069
  id: agyOccurrenceId(emit, matchedCall),
5999
6070
  tool: friendlyHookToolName(matchedCall?.rawToolName, resultType),
6000
6071
  ...target ? { normalizedTarget: target } : {},
6001
- ts: emit.event.created_at,
6072
+ ts: safeIsoTimestamp(emit.event.created_at),
6002
6073
  byteOffset: emit.byteOffset,
6003
6074
  ...inputIdentity ? { digest: (0, import_codevibe_core6.digestOf)(inputIdentity) } : {}
6004
6075
  });
@@ -8153,7 +8224,8 @@ var McpServer = class _McpServer {
8153
8224
  const e1existing = this.e1PromptRaises.get(state.promptId);
8154
8225
  const e1rec = e1existing ? e1existing.record : this.newE1Raise(session.sessionId, !isDisplayOnly);
8155
8226
  if (!e1existing) state.promptId = e1rec.promptId;
8156
- const optionsArr = isDisplayOnly ? [] : state.paneOptions ? state.paneOptions.map((o) => ({ number: o.number, text: o.text })) : Object.keys(state.submitMap).map((n) => ({ number: n }));
8227
+ const resolvedOptions = state.paneOptions && state.paneOptions.length > 0 ? state.paneOptions : state.pendingCall?.questionOptions && state.pendingCall.questionOptions.length > 0 ? state.pendingCall.questionOptions : void 0;
8228
+ const optionsArr = isDisplayOnly ? [] : resolvedOptions ? resolvedOptions.map((o) => ({ number: o.number, text: o.text })) : Object.keys(state.submitMap).map((n) => ({ number: n }));
8157
8229
  const diffParsed = parseFencedDiffFromBody(
8158
8230
  state.body,
8159
8231
  state.paneDisplayHeader
@@ -8183,7 +8255,14 @@ var McpServer = class _McpServer {
8183
8255
  command: state.pendingCall.command,
8184
8256
  file_path: filePath,
8185
8257
  options: optionsArr,
8186
- ...toolInput ? { tool_input: toolInput } : {}
8258
+ ...toolInput ? { tool_input: toolInput } : {},
8259
+ ...state.kind === "question" && resolvedOptions && resolvedOptions.length > 0 ? {
8260
+ questions: [{
8261
+ question: state.pendingCall?.questionText || state.matchedPaneHeader || state.paneDisplayHeader || "Question",
8262
+ options: resolvedOptions,
8263
+ ...isDisplayOnly ? { instructions: "Answer this question in your desktop terminal" } : {}
8264
+ }]
8265
+ } : {}
8187
8266
  } : { promptId: state.promptId };
8188
8267
  const content = state.paneDisplayHeader || state.matchedPaneHeader || state.pendingCall?.command || state.pendingCall?.filePath || "approval requested";
8189
8268
  const input = {
@@ -9088,6 +9167,7 @@ var __testing = {
9088
9167
  };
9089
9168
  // Annotate the CommonJS export names for ESM import in node:
9090
9169
  0 && (module.exports = {
9170
+ ApprovalDetector,
9091
9171
  McpServer,
9092
9172
  SessionNotFoundError,
9093
9173
  StoredAuthFailureError,
@@ -9105,11 +9185,13 @@ var __testing = {
9105
9185
  isAgyStatusFooterLine,
9106
9186
  isComposedStatusFooter,
9107
9187
  isPaneInputSafetyBlocked,
9188
+ isQuestionFooterLine,
9108
9189
  isSystemErrorActiveFromIndex,
9109
9190
  looksLikePromptSnapshot,
9110
9191
  parseApprovalSnapshot,
9111
9192
  parseMaybeJson,
9112
9193
  readTranscriptFirstType,
9113
9194
  reconstructFooter,
9114
- runForeignSpawnIdle
9195
+ runForeignSpawnIdle,
9196
+ safeIsoTimestamp
9115
9197
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quantiya/codevibe-antigravity-plugin",
3
- "version": "2.0.81",
3
+ "version": "2.0.82",
4
4
  "description": "Control Antigravity CLI from your iPhone and Android — real-time sync, approve file edits, send prompts by voice. Part of CodeVibe.",
5
5
  "main": "dist/server.js",
6
6
  "codevibe": {