@quantiya/codevibe-antigravity-plugin 2.0.77 → 2.0.79

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/server.js +157 -99
  2. package/package.json +2 -2
package/dist/server.js CHANGED
@@ -59,7 +59,7 @@ var fs7 = __toESM(require("fs"));
59
59
  var os7 = __toESM(require("os"));
60
60
  var import_child_process3 = require("child_process");
61
61
  var import_util3 = require("util");
62
- var import_codevibe_core6 = require("@quantiya/codevibe-core");
62
+ var import_codevibe_core7 = require("@quantiya/codevibe-core");
63
63
 
64
64
  // src/logger.ts
65
65
  var import_os = __toESM(require("os"));
@@ -400,6 +400,7 @@ var fs2 = __toESM(require("fs"));
400
400
  var os3 = __toESM(require("os"));
401
401
  var path3 = __toESM(require("path"));
402
402
  var import_chokidar = require("chokidar");
403
+ var import_codevibe_core4 = require("@quantiya/codevibe-core");
403
404
 
404
405
  // src/shutdown-bounds.ts
405
406
  var TEARDOWN_STEP_TIMEOUT_MS = 3e3;
@@ -466,7 +467,12 @@ function readAdmittedTranscript(options) {
466
467
  return parsed && typeof parsed === "object" && !Array.isArray(parsed) && Number.isFinite(parsed.step_index) && typeof parsed.type === "string" ? parsed : null;
467
468
  },
468
469
  admission: {
469
- restore: (source, initial) => options.admission.restore(stream(source), initial),
470
+ restore: (source, initial) => options.admission.restore(stream(source), initial, () => {
471
+ const expected = options.initialFileIdentity;
472
+ if (expected && (source.fileIdentity.dev !== expected.dev || source.fileIdentity.ino !== expected.ino)) {
473
+ throw Error("SYNC_TOOL_INITIAL_SOURCE_CHANGED");
474
+ }
475
+ }),
470
476
  skip: (gap, source) => options.admission.skip(gap, stream(source)),
471
477
  admit: (event, source) => options.admission.admit({
472
478
  conversationId: options.conversationId,
@@ -553,6 +559,11 @@ var TranscriptTailer = class extends import_events.EventEmitter {
553
559
  /** Last swept stat of each unfollowed conversation's transcript (null when
554
560
  * absent), for the resume sweep. */
555
561
  this.transcriptSnapshots = /* @__PURE__ */ new Map();
562
+ /** Immutable startup boundary; discovery snapshots keep moving. */
563
+ this.nativeLaunchBaselines = /* @__PURE__ */ new Map();
564
+ this.nativeLaunchTime = null;
565
+ this.nativeInitialBoundaries = /* @__PURE__ */ new Map();
566
+ this.nativeSeededPaths = /* @__PURE__ */ new Set();
556
567
  this.rootMtimeMs = 0;
557
568
  this.discoveryTimer = null;
558
569
  this.discoveryTickCount = 0;
@@ -590,12 +601,34 @@ var TranscriptTailer = class extends import_events.EventEmitter {
590
601
  * snapshots the brain, then runs the discovery tick. Opens no directory
591
602
  * watch (see the file header).
592
603
  */
604
+ /** Capture only; no readers, listeners, timers or cloud activity. The server
605
+ * calls this before its first startup await, then activates the tailer later. */
606
+ captureLaunchBaselines() {
607
+ this.nativeLaunchTime = Date.now();
608
+ this.nativeLaunchBaselines.clear();
609
+ this.nativeSeededPaths.clear();
610
+ for (const id of this.listConversationDirs() ?? []) {
611
+ this.nativeLaunchBaselines.set(id, this.snapshotTranscript(this.transcriptPathFor(id)));
612
+ }
613
+ }
614
+ /** Called after the retired owner's readers are joined, before its successor
615
+ * starts cloud bootstrap. Keep old scoped journals; only fresh seeds change. */
616
+ refreshNativeOwnerBoundary() {
617
+ this.captureLaunchBaselines();
618
+ this.nativeInitialBoundaries.clear();
619
+ for (const timer of this.retryTimers.values()) clearTimeout(timer);
620
+ this.retryTimers.clear();
621
+ this.readGeneration++;
622
+ this.activeReads.clear();
623
+ this.pendingReads.clear();
624
+ }
593
625
  start() {
594
626
  if (this.isWatching) {
595
627
  logger.warn("TranscriptTailer.start called while already watching");
596
628
  return;
597
629
  }
598
- this.startTime = Date.now();
630
+ if (this.nativeLaunchTime === null) this.captureLaunchBaselines();
631
+ this.startTime = this.nativeLaunchTime;
599
632
  this.readGeneration++;
600
633
  for (const timer of this.retryTimers.values()) clearTimeout(timer);
601
634
  this.retryTimers.clear();
@@ -615,15 +648,14 @@ var TranscriptTailer = class extends import_events.EventEmitter {
615
648
  this.knownConversationDirs.clear();
616
649
  this.pendingTranscripts.clear();
617
650
  this.transcriptSnapshots.clear();
651
+ this.nativeInitialBoundaries.clear();
652
+ this.nativeSeededPaths.clear();
618
653
  this.releasedConversations.clear();
619
654
  this.discoveryTickCount = 0;
620
655
  this.rootMtimeMs = this.statMtimeMs(this.brainRoot) ?? 0;
621
656
  for (const conversationId of this.listConversationDirs() ?? []) {
622
657
  this.knownConversationDirs.add(conversationId);
623
- this.transcriptSnapshots.set(
624
- conversationId,
625
- this.snapshotTranscript(this.transcriptPathFor(conversationId))
626
- );
658
+ this.transcriptSnapshots.set(conversationId, this.nativeLaunchBaselines.get(conversationId) ?? null);
627
659
  }
628
660
  logger.info("Starting transcript tailer", {
629
661
  brainRoot: this.brainRoot,
@@ -677,6 +709,10 @@ var TranscriptTailer = class extends import_events.EventEmitter {
677
709
  * Idempotent.
678
710
  */
679
711
  async stop() {
712
+ this.nativeLaunchBaselines.clear();
713
+ this.nativeLaunchTime = null;
714
+ this.nativeInitialBoundaries.clear();
715
+ this.nativeSeededPaths.clear();
680
716
  if (!this.isWatching) return;
681
717
  this.isShuttingDown = true;
682
718
  this.readGeneration++;
@@ -1034,7 +1070,7 @@ var TranscriptTailer = class extends import_events.EventEmitter {
1034
1070
  snapshotTranscript(transcriptPath) {
1035
1071
  try {
1036
1072
  const stat = fs2.statSync(transcriptPath);
1037
- return stat.isFile() ? { size: stat.size, mtimeMs: stat.mtimeMs, ino: stat.ino } : null;
1073
+ return stat.isFile() ? { size: stat.size, mtimeMs: stat.mtimeMs, ino: stat.ino, dev: stat.dev } : null;
1038
1074
  } catch {
1039
1075
  return null;
1040
1076
  }
@@ -1225,6 +1261,7 @@ var TranscriptTailer = class extends import_events.EventEmitter {
1225
1261
  }
1226
1262
  async readNewLines(filePath, conversationId, generation) {
1227
1263
  if (generation !== this.readGeneration) return;
1264
+ if (this.admission && !this.nativeSeededPaths.has(filePath)) this.ensureOffset(filePath);
1228
1265
  const entry = this.offsets.get(filePath);
1229
1266
  if (!entry) {
1230
1267
  logger.warn("No offset entry \u2014 skipping read", { filePath });
@@ -1235,6 +1272,7 @@ var TranscriptTailer = class extends import_events.EventEmitter {
1235
1272
  filePath,
1236
1273
  conversationId,
1237
1274
  initialOffset: entry.byteOffset,
1275
+ initialFileIdentity: this.nativeInitialBoundaries.get(filePath)?.fileIdentity,
1238
1276
  admission: this.admission,
1239
1277
  isCurrent: () => generation === this.readGeneration && !this.isShuttingDown
1240
1278
  });
@@ -1361,8 +1399,8 @@ var TranscriptTailer = class extends import_events.EventEmitter {
1361
1399
  }
1362
1400
  // ─── Offset persistence ─────────────────────────────────────────────────
1363
1401
  ensureOffset(filePath) {
1364
- if (this.offsets.has(filePath)) return;
1365
- if (this.offsets.size >= LRU_CAP) {
1402
+ if (this.offsets.has(filePath) && (!this.admission || this.nativeSeededPaths.has(filePath))) return;
1403
+ if (!this.offsets.has(filePath) && this.offsets.size >= LRU_CAP) {
1366
1404
  this.evictOldestOffset();
1367
1405
  }
1368
1406
  let stat = null;
@@ -1370,12 +1408,24 @@ var TranscriptTailer = class extends import_events.EventEmitter {
1370
1408
  stat = fs2.statSync(filePath);
1371
1409
  } catch {
1372
1410
  }
1411
+ const conversationId = this.extractConversationId(filePath);
1412
+ const baseline = conversationId ? this.nativeLaunchBaselines.get(conversationId) : void 0;
1413
+ let initialOffset = 0;
1414
+ if (this.admission && stat && baseline && baseline.dev === stat.dev && baseline.ino === stat.ino && stat.size >= baseline.size) {
1415
+ const boundary = (0, import_codevibe_core4.captureToolReplayBoundary)(filePath, baseline.size);
1416
+ if (boundary.fileIdentity.dev !== baseline.dev || boundary.fileIdentity.ino !== baseline.ino) {
1417
+ throw Error("SYNC_TOOL_INITIAL_SOURCE_CHANGED");
1418
+ }
1419
+ initialOffset = boundary.byteOffset;
1420
+ this.nativeInitialBoundaries.set(filePath, boundary);
1421
+ }
1373
1422
  this.offsets.set(filePath, {
1374
- byteOffset: 0,
1423
+ byteOffset: initialOffset,
1375
1424
  carryover: "",
1376
1425
  lastKnownSize: stat?.size ?? 0,
1377
1426
  lastModifiedMs: stat?.mtimeMs ?? Date.now()
1378
1427
  });
1428
+ this.nativeSeededPaths.add(filePath);
1379
1429
  }
1380
1430
  /**
1381
1431
  * Pick the oldest-mtime offset entry that is NOT for a currently-active
@@ -4835,7 +4885,7 @@ function fireDaemonBeacon(name, params) {
4835
4885
 
4836
4886
  // src/event-mapper.ts
4837
4887
  var import_uuid2 = require("uuid");
4838
- var import_codevibe_core4 = require("@quantiya/codevibe-core");
4888
+ var import_codevibe_core5 = require("@quantiya/codevibe-core");
4839
4889
  var CONTENT_MAX = 150 * 1024;
4840
4890
  var TOOL_OUTPUT_MAX = 50 * 1024;
4841
4891
  var TOOL_DIFF_MAX = 100 * 1024;
@@ -4843,10 +4893,10 @@ function mapTranscriptEvent(emit, sessionId, notBeforeMs) {
4843
4893
  const { event } = emit;
4844
4894
  const base = {
4845
4895
  sessionId,
4846
- source: import_codevibe_core4.EventSource.DESKTOP
4896
+ source: import_codevibe_core5.EventSource.DESKTOP
4847
4897
  };
4848
4898
  const orderingKey = `${sessionId}:${emit.conversationId}`;
4849
- const nextTimestamp = () => (0, import_codevibe_core4.prepareEventTimestamp)({ orderingKey, agentClock: event.created_at, notBeforeMs });
4899
+ const nextTimestamp = () => (0, import_codevibe_core5.prepareEventTimestamp)({ orderingKey, agentClock: event.created_at, notBeforeMs });
4850
4900
  const baseMetadata = {
4851
4901
  step_index: event.step_index,
4852
4902
  agy_source: event.source,
@@ -4886,7 +4936,7 @@ function mapTranscriptEvent(emit, sessionId, notBeforeMs) {
4886
4936
  {
4887
4937
  ...base,
4888
4938
  timestamp: nextTimestamp(),
4889
- type: import_codevibe_core4.EventType.USER_PROMPT,
4939
+ type: import_codevibe_core5.EventType.USER_PROMPT,
4890
4940
  content: truncate(cleaned, CONTENT_MAX),
4891
4941
  metadata: { ...baseMetadata }
4892
4942
  }
@@ -4901,7 +4951,7 @@ function mapTranscriptEvent(emit, sessionId, notBeforeMs) {
4901
4951
  events.push({
4902
4952
  ...base,
4903
4953
  timestamp: nextTimestamp(),
4904
- type: import_codevibe_core4.EventType.REASONING,
4954
+ type: import_codevibe_core5.EventType.REASONING,
4905
4955
  content: truncate(event.thinking, CONTENT_MAX),
4906
4956
  metadata: { ...baseMetadata }
4907
4957
  });
@@ -4910,7 +4960,7 @@ function mapTranscriptEvent(emit, sessionId, notBeforeMs) {
4910
4960
  events.push({
4911
4961
  ...base,
4912
4962
  timestamp: nextTimestamp(),
4913
- type: import_codevibe_core4.EventType.ASSISTANT_RESPONSE,
4963
+ type: import_codevibe_core5.EventType.ASSISTANT_RESPONSE,
4914
4964
  content: truncate(event.content, CONTENT_MAX),
4915
4965
  metadata: { ...baseMetadata }
4916
4966
  });
@@ -4947,7 +4997,7 @@ function mapTranscriptEvent(emit, sessionId, notBeforeMs) {
4947
4997
  {
4948
4998
  ...base,
4949
4999
  timestamp: nextTimestamp(),
4950
- type: import_codevibe_core4.EventType.NOTIFICATION,
5000
+ type: import_codevibe_core5.EventType.NOTIFICATION,
4951
5001
  content: truncate(content, CONTENT_MAX),
4952
5002
  metadata: {
4953
5003
  ...baseMetadata,
@@ -4967,7 +5017,7 @@ function mapTranscriptEvent(emit, sessionId, notBeforeMs) {
4967
5017
  {
4968
5018
  ...base,
4969
5019
  timestamp: nextTimestamp(),
4970
- type: import_codevibe_core4.EventType.TOOL_USE,
5020
+ type: import_codevibe_core5.EventType.TOOL_USE,
4971
5021
  content: formatToolResultContent(event.type, toolName, truncatedContent, isErrorStatus),
4972
5022
  metadata: {
4973
5023
  ...baseMetadata,
@@ -5125,7 +5175,7 @@ function truncate(s, maxBytes) {
5125
5175
  }
5126
5176
 
5127
5177
  // src/tool-activity-integration.ts
5128
- var import_codevibe_core5 = require("@quantiya/codevibe-core");
5178
+ var import_codevibe_core6 = require("@quantiya/codevibe-core");
5129
5179
  var TOOL_ACTIVITY_CONTENT = "tool_activity";
5130
5180
  var DEFAULT_WINDOW_MS = 1e4;
5131
5181
  var DEFAULT_MAX_OCCURRENCES = 50;
@@ -5192,9 +5242,9 @@ function agyOccurrenceId(emit, matchedCall) {
5192
5242
  createdAt: emit.event.created_at,
5193
5243
  stepIndex: emit.event.step_index,
5194
5244
  type: emit.event.type,
5195
- contentDigest: (0, import_codevibe_core5.digestOf)(emit.event.content ?? "")
5245
+ contentDigest: (0, import_codevibe_core6.digestOf)(emit.event.content ?? "")
5196
5246
  };
5197
- return `agy:${(0, import_codevibe_core5.digestOf)(identity).slice("sha256:".length)}`;
5247
+ return `agy:${(0, import_codevibe_core6.digestOf)(identity).slice("sha256:".length)}`;
5198
5248
  }
5199
5249
  var AgyToolActivityIntegration = class {
5200
5250
  constructor(deps) {
@@ -5209,12 +5259,12 @@ var AgyToolActivityIntegration = class {
5209
5259
  async start(sessionId) {
5210
5260
  if (this.consolidator && this.backendSessionId === sessionId) return;
5211
5261
  if (this.consolidator) await this.stop();
5212
- const outbox = new import_codevibe_core5.ToolActivityOutbox({
5262
+ const outbox = new import_codevibe_core6.ToolActivityOutbox({
5213
5263
  agent: "agy",
5214
5264
  logger: this.deps.logger,
5215
5265
  root: this.deps.root
5216
5266
  });
5217
- const ledger = new import_codevibe_core5.ToolActivityLedger({
5267
+ const ledger = new import_codevibe_core6.ToolActivityLedger({
5218
5268
  agent: "agy",
5219
5269
  sessionId,
5220
5270
  logger: this.deps.logger,
@@ -5224,7 +5274,7 @@ var AgyToolActivityIntegration = class {
5224
5274
  const legacyTransport = this.buildTransport();
5225
5275
  const transport = this.deps.selectTransport ? await this.deps.selectTransport(sessionId, legacyTransport) : legacyTransport;
5226
5276
  if (transport.protocol !== "SYNC_V2") await this.rehomePendingWindows(outbox, sessionId);
5227
- const consolidator = new import_codevibe_core5.ToolActivityConsolidator({
5277
+ const consolidator = new import_codevibe_core6.ToolActivityConsolidator({
5228
5278
  agent: "agy",
5229
5279
  sessionId,
5230
5280
  logger: this.deps.logger,
@@ -5262,7 +5312,7 @@ var AgyToolActivityIntegration = class {
5262
5312
  ...target ? { normalizedTarget: target } : {},
5263
5313
  ts: emit.event.created_at,
5264
5314
  byteOffset: emit.byteOffset,
5265
- ...inputIdentity ? { digest: (0, import_codevibe_core5.digestOf)(inputIdentity) } : {}
5315
+ ...inputIdentity ? { digest: (0, import_codevibe_core6.digestOf)(inputIdentity) } : {}
5266
5316
  });
5267
5317
  }
5268
5318
  async flush() {
@@ -5332,7 +5382,7 @@ var AgyToolActivityIntegration = class {
5332
5382
  if (!session || session.sessionId !== sessionId) {
5333
5383
  throw terminalSessionError(sessionId);
5334
5384
  }
5335
- const encrypted = (0, import_codevibe_core5.encryptForEmit)(
5385
+ const encrypted = (0, import_codevibe_core6.encryptForEmit)(
5336
5386
  override?.sessionKey ?? session.sessionKey ?? null,
5337
5387
  session.sessionIsEncrypted ?? false,
5338
5388
  TOOL_ACTIVITY_CONTENT,
@@ -5344,8 +5394,8 @@ var AgyToolActivityIntegration = class {
5344
5394
  const sessionKeyGen = override?.sessionKeyGen ?? session.sessionKeyGen;
5345
5395
  const input = {
5346
5396
  sessionId,
5347
- type: import_codevibe_core5.EventType.TOOL_ACTIVITY,
5348
- source: import_codevibe_core5.EventSource.DESKTOP,
5397
+ type: import_codevibe_core6.EventType.TOOL_ACTIVITY,
5398
+ source: import_codevibe_core6.EventSource.DESKTOP,
5349
5399
  content: encrypted.content,
5350
5400
  metadata: encrypted.metadata,
5351
5401
  timestamp: envelope.windowStart,
@@ -5360,10 +5410,10 @@ var AgyToolActivityIntegration = class {
5360
5410
  try {
5361
5411
  await sendOnce(sessionId, envelope);
5362
5412
  } catch (error) {
5363
- if ((0, import_codevibe_core5.isTerminalSessionError)(error)) {
5413
+ if ((0, import_codevibe_core6.isTerminalSessionError)(error)) {
5364
5414
  throw new Error(`[tool-activity] Agy session ${sessionId} retired; awaiting replacement`);
5365
5415
  }
5366
- if ((0, import_codevibe_core5.isSessionKeyStaleError)(error) && this.deps.refreshSessionKey) {
5416
+ if ((0, import_codevibe_core6.isSessionKeyStaleError)(error) && this.deps.refreshSessionKey) {
5367
5417
  const refreshed = await this.deps.refreshSessionKey(sessionId);
5368
5418
  if (refreshed) {
5369
5419
  await sendOnce(sessionId, envelope, refreshed);
@@ -5472,7 +5522,7 @@ var McpServer = class _McpServer {
5472
5522
  * under this single sessionId. /resume does NOT create a new
5473
5523
  * session — same row. */
5474
5524
  this.session = null;
5475
- this.promptPublications = new import_codevibe_core6.PromptPublicationTracker();
5525
+ this.promptPublications = new import_codevibe_core7.PromptPublicationTracker();
5476
5526
  this.transcriptHandlers = /* @__PURE__ */ new Set();
5477
5527
  this.nativeSourceSelection = null;
5478
5528
  this.nativeSources = /* @__PURE__ */ new Map();
@@ -5636,7 +5686,7 @@ var McpServer = class _McpServer {
5636
5686
  this.wrapperPid = options.wrapperPid ?? null;
5637
5687
  this.cliLogPath = options.cliLogPath ?? null;
5638
5688
  this.launchSettleTimeoutMs = options.launchSettleTimeoutMs ?? LAUNCH_SETTLE_TIMEOUT_MS;
5639
- this.appSyncClient = options.appSyncClient ?? new import_codevibe_core6.AppSyncClient();
5689
+ this.appSyncClient = options.appSyncClient ?? new import_codevibe_core7.AppSyncClient();
5640
5690
  this.toolActivity = options.toolActivityIntegration === void 0 ? new AgyToolActivityIntegration({
5641
5691
  logger,
5642
5692
  selectTransport: async (sessionId, legacyTransport) => {
@@ -5669,7 +5719,7 @@ var McpServer = class _McpServer {
5669
5719
  this.approvalDetector = options.approvalDetector ?? new ApprovalDetector(options.detectorOptions);
5670
5720
  this.paneObserver = options.paneObserver ?? new TmuxPaneObserver();
5671
5721
  this.transcriptTailer = options.transcriptTailer ?? new TranscriptTailer({ admission: {
5672
- restore: (source, initial) => this.restoreNativeSource(source, initial),
5722
+ restore: (source, initial, validateInitial) => this.restoreNativeSource(source, initial, validateInitial),
5673
5723
  admit: (emit, source) => this.admitNativeSource(emit, source),
5674
5724
  skip: (gap, source) => this.skipNativeSource(gap, source)
5675
5725
  } });
@@ -5714,6 +5764,7 @@ var McpServer = class _McpServer {
5714
5764
  // ─── Lifecycle ──────────────────────────────────────────────────────────
5715
5765
  async start() {
5716
5766
  if (this.started) throw new Error("McpServer.start() called twice");
5767
+ this.transcriptTailer.captureLaunchBaselines();
5717
5768
  this.stopPromise = null;
5718
5769
  this.stopTmuxLifecycleMonitor();
5719
5770
  this.tmuxLifecycleObservedAlive = false;
@@ -5725,7 +5776,7 @@ var McpServer = class _McpServer {
5725
5776
  const authed = await this.appSyncClient.authenticateWithStoredTokens();
5726
5777
  if (!authed) {
5727
5778
  const kind = this.appSyncClient.getLastAuthFailureKind();
5728
- const failure = (0, import_codevibe_core6.describeStoredAuthFailure)(
5779
+ const failure = (0, import_codevibe_core7.describeStoredAuthFailure)(
5729
5780
  kind,
5730
5781
  this.appSyncClient.getLastAuthFailureDetail()
5731
5782
  );
@@ -5767,9 +5818,9 @@ var McpServer = class _McpServer {
5767
5818
  logger.warn("Standalone Companion sync status unavailable; cloud admission remains authoritative");
5768
5819
  }
5769
5820
  if (!this.started) return { httpPort: 0 };
5770
- await (0, import_codevibe_core6.registerDeviceEncryptionKey)(this.appSyncClient, logger);
5821
+ await (0, import_codevibe_core7.registerDeviceEncryptionKey)(this.appSyncClient, logger);
5771
5822
  if (!this.started) return { httpPort: 0 };
5772
- (0, import_codevibe_core6.startDeviceKeyWatcher)(this.appSyncClient, logger);
5823
+ (0, import_codevibe_core7.startDeviceKeyWatcher)(this.appSyncClient, logger);
5773
5824
  try {
5774
5825
  const swept = await this.appSyncClient.sweepOrphanSessions({
5775
5826
  agentType: "ANTIGRAVITY",
@@ -5842,7 +5893,10 @@ var McpServer = class _McpServer {
5842
5893
  }
5843
5894
  async stop() {
5844
5895
  if (this.stopPromise) return this.stopPromise;
5845
- if (!this.started) return;
5896
+ if (!this.started) {
5897
+ await this.transcriptTailer.stop();
5898
+ return;
5899
+ }
5846
5900
  this.stopPromise = this.doStop();
5847
5901
  try {
5848
5902
  await this.stopPromise;
@@ -6015,7 +6069,10 @@ var McpServer = class _McpServer {
6015
6069
  try {
6016
6070
  const retired = await this.appSyncClient.updateSession({ sessionId, status: "INACTIVE" });
6017
6071
  if (quiescentSession && retired?.sessionGenerationId) {
6018
- await this.appSyncClient.completeDesktopSyncRetirement({ sessionId }, retired, async () => {
6072
+ await this.appSyncClient.completeDesktopSyncRetirement({
6073
+ sessionId,
6074
+ toolOutbox: new import_codevibe_core7.ToolActivityOutbox({ agent: "agy", logger })
6075
+ }, retired, async () => {
6019
6076
  await Promise.allSettled([...this.transcriptHandlers]);
6020
6077
  await this.nativeAdmissionChain;
6021
6078
  await this.stopNativeSources(quiescentSession);
@@ -6064,7 +6121,7 @@ var McpServer = class _McpServer {
6064
6121
  let sessionKey = null;
6065
6122
  let sessionKeyGen = null;
6066
6123
  try {
6067
- const result = await (0, import_codevibe_core6.resumeOrCreateSession)(
6124
+ const result = await (0, import_codevibe_core7.resumeOrCreateSession)(
6068
6125
  {
6069
6126
  sessionId,
6070
6127
  userId,
@@ -6152,7 +6209,7 @@ var McpServer = class _McpServer {
6152
6209
  (evt) => {
6153
6210
  return this.handleMobileEvent(evt).catch((err) => {
6154
6211
  logger.error("handleMobileEvent failed", { error: String(err) });
6155
- if ((0, import_codevibe_core6.requiresSyncInputDeliveryReceipt)(evt)) throw err;
6212
+ if ((0, import_codevibe_core7.requiresSyncInputDeliveryReceipt)(evt)) throw err;
6156
6213
  });
6157
6214
  },
6158
6215
  (err) => logger.warn("AppSync subscription error", { error: String(err) }),
@@ -6428,11 +6485,11 @@ var McpServer = class _McpServer {
6428
6485
  this.approvalDetector.registerPendingCall(reg);
6429
6486
  }
6430
6487
  for (const [index, input] of mapped.events.entries()) {
6431
- if (input.type === import_codevibe_core6.EventType.USER_PROMPT || input.type === import_codevibe_core6.EventType.ASSISTANT_RESPONSE || input.type === import_codevibe_core6.EventType.NOTIFICATION) {
6488
+ if (input.type === import_codevibe_core7.EventType.USER_PROMPT || input.type === import_codevibe_core7.EventType.ASSISTANT_RESPONSE || input.type === import_codevibe_core7.EventType.NOTIFICATION) {
6432
6489
  if (admission) await this.toolActivity.flush();
6433
6490
  else await this.flushToolActivityAtBoundary(input.type);
6434
6491
  }
6435
- if (input.type === import_codevibe_core6.EventType.TOOL_USE && typeof input.metadata === "object" && input.metadata) {
6492
+ if (input.type === import_codevibe_core7.EventType.TOOL_USE && typeof input.metadata === "object" && input.metadata) {
6436
6493
  const meta = input.metadata;
6437
6494
  const resultStep = typeof meta.step_index === "number" ? meta.step_index : void 0;
6438
6495
  const agyType = typeof meta.agy_type === "string" ? meta.agy_type : void 0;
@@ -6459,7 +6516,7 @@ var McpServer = class _McpServer {
6459
6516
  }
6460
6517
  }
6461
6518
  }
6462
- if (input.type === import_codevibe_core6.EventType.USER_PROMPT && input.source === import_codevibe_core6.EventSource.DESKTOP) {
6519
+ if (input.type === import_codevibe_core7.EventType.USER_PROMPT && input.source === import_codevibe_core7.EventSource.DESKTOP) {
6463
6520
  const inputObservedAtMs = this.transcriptObservedAt.get(emit);
6464
6521
  const clearedPromptIds = this.approvalDetector.onPanePromptCleared(inputObservedAtMs);
6465
6522
  await this.resolveAcceptedInputPrompts(session, clearedPromptIds, inputObservedAtMs);
@@ -6549,10 +6606,10 @@ var McpServer = class _McpServer {
6549
6606
  this.nativeSources.set(key, owner);
6550
6607
  return owner;
6551
6608
  }
6552
- async restoreNativeSource(source, initial) {
6609
+ async restoreNativeSource(source, initial, validateInitial) {
6553
6610
  const owner = await this.nativeOwner(source);
6554
6611
  if (!owner) return null;
6555
- const position = await owner.cursor.open(initial);
6612
+ const position = await owner.cursor.open(initial, validateInitial);
6556
6613
  this.assertNativeOwner(owner);
6557
6614
  await owner.selection.writer.mobileEchoes("agy").reconcile(owner.streamSha256, position.byteOffset);
6558
6615
  this.drainNativeSource(owner);
@@ -6583,7 +6640,7 @@ var McpServer = class _McpServer {
6583
6640
  const echoes = owner.selection.writer.mobileEchoes("agy");
6584
6641
  for (let index = 0; index < admission.outputs.length; index++) {
6585
6642
  const input = admission.outputs[index];
6586
- if (input?.type === import_codevibe_core6.EventType.USER_PROMPT && await echoes.claim(echoFrame, input.content, emit.event.created_at)) admission.outputs[index] = null;
6643
+ if (input?.type === import_codevibe_core7.EventType.USER_PROMPT && await echoes.claim(echoFrame, input.content, emit.event.created_at)) admission.outputs[index] = null;
6587
6644
  }
6588
6645
  const factory = (index) => {
6589
6646
  const input = admission.outputs[index];
@@ -6675,18 +6732,18 @@ var McpServer = class _McpServer {
6675
6732
  const expectedSession = this.session;
6676
6733
  try {
6677
6734
  const session = await this.appSyncClient.getSession(sessionId);
6678
- if (session?.status === import_codevibe_core6.SessionStatus.INACTIVE) {
6735
+ if (session?.status === import_codevibe_core7.SessionStatus.INACTIVE) {
6679
6736
  const terminal = new Error(`Antigravity session is no longer active: ${sessionId}`);
6680
6737
  terminal.errorType = "SessionTerminal";
6681
6738
  throw terminal;
6682
6739
  }
6683
- if (!session || session.status !== import_codevibe_core6.SessionStatus.ACTIVE || !session.isEncrypted) {
6740
+ if (!session || session.status !== import_codevibe_core7.SessionStatus.ACTIVE || !session.isEncrypted) {
6684
6741
  return null;
6685
6742
  }
6686
6743
  const sessionKeyGen = session.sessionKeyGen ?? null;
6687
6744
  const encryptedKeys = session.encryptedKeys ?? [];
6688
6745
  if (encryptedKeys.length === 0) return null;
6689
- const sessionKey = await import_codevibe_core6.keychainManager.getSessionKey(
6746
+ const sessionKey = await import_codevibe_core7.keychainManager.getSessionKey(
6690
6747
  sessionId,
6691
6748
  encryptedKeys,
6692
6749
  sessionKeyGen
@@ -6699,7 +6756,7 @@ var McpServer = class _McpServer {
6699
6756
  liveSession.sessionIsEncrypted = true;
6700
6757
  return { sessionKey, sessionKeyGen };
6701
6758
  } catch (error) {
6702
- if ((0, import_codevibe_core6.isTerminalSessionError)(error)) throw error;
6759
+ if ((0, import_codevibe_core7.isTerminalSessionError)(error)) throw error;
6703
6760
  logger.warn("[tool-activity] Agy session-key refresh failed; window remains retryable", {
6704
6761
  sessionId,
6705
6762
  error: String(error)
@@ -6719,7 +6776,7 @@ var McpServer = class _McpServer {
6719
6776
  * an encrypted keyless one (drop).
6720
6777
  */
6721
6778
  encryptOutbound(session, input) {
6722
- const enc = (0, import_codevibe_core6.encryptForEmit)(
6779
+ const enc = (0, import_codevibe_core7.encryptForEmit)(
6723
6780
  session.sessionKey ?? null,
6724
6781
  session.sessionIsEncrypted ?? false,
6725
6782
  input.content,
@@ -6749,7 +6806,7 @@ var McpServer = class _McpServer {
6749
6806
  const promptId = input.producerKind === "PLUGIN_APPROVAL" ? input.promptId : void 0;
6750
6807
  const promptEntry = promptId ? this.e1PromptRaises.get(promptId) : void 0;
6751
6808
  const sendOnce = async () => {
6752
- if (promptId && !(0, import_codevibe_core6.isOpenPromptRaise)(
6809
+ if (promptId && !(0, import_codevibe_core7.isOpenPromptRaise)(
6753
6810
  promptEntry,
6754
6811
  this.e1PromptRaises.get(promptId),
6755
6812
  this.e1NeedsResolution.has(promptId)
@@ -6762,7 +6819,7 @@ var McpServer = class _McpServer {
6762
6819
  try {
6763
6820
  return await sendOnce();
6764
6821
  } catch (error) {
6765
- if (!(0, import_codevibe_core6.isSessionKeyStaleError)(error)) throw error;
6822
+ if (!(0, import_codevibe_core7.isSessionKeyStaleError)(error)) throw error;
6766
6823
  const refreshed = await this.refreshToolActivitySessionKey(session.sessionId);
6767
6824
  if (!refreshed) throw error;
6768
6825
  return sendOnce();
@@ -6783,7 +6840,7 @@ var McpServer = class _McpServer {
6783
6840
  * NOTIFICATION carrier, no fabricated options).
6784
6841
  */
6785
6842
  newE1Raise(sessionId, mobileActionable, title) {
6786
- const { record } = (0, import_codevibe_core6.newPromptRaise)({
6843
+ const { record } = (0, import_codevibe_core7.newPromptRaise)({
6787
6844
  sessionId,
6788
6845
  producerKind: "PLUGIN_APPROVAL",
6789
6846
  mobileActionable,
@@ -6883,26 +6940,26 @@ var McpServer = class _McpServer {
6883
6940
  const bannerText = customBannerText || "\u26A0\uFE0F A prompt is waiting in your desktop terminal, but its options could not be shown here. Please answer it on your desktop.";
6884
6941
  const input = {
6885
6942
  sessionId: session.sessionId,
6886
- type: import_codevibe_core6.EventType.NOTIFICATION,
6887
- source: import_codevibe_core6.EventSource.DESKTOP,
6943
+ type: import_codevibe_core7.EventType.NOTIFICATION,
6944
+ source: import_codevibe_core7.EventSource.DESKTOP,
6888
6945
  content: bannerText,
6889
6946
  metadata: {
6890
6947
  e1SuppressedPrompt: true
6891
6948
  },
6892
- ...(0, import_codevibe_core6.raiseFieldsFromRecord)(record),
6949
+ ...(0, import_codevibe_core7.raiseFieldsFromRecord)(record),
6893
6950
  notificationText: bannerText,
6894
- timestamp: (0, import_codevibe_core6.prepareEventTimestamp)({ orderingKey: session.sessionId })
6951
+ timestamp: (0, import_codevibe_core7.prepareEventTimestamp)({ orderingKey: session.sessionId })
6895
6952
  };
6896
- await this.flushToolActivityAtBoundary(import_codevibe_core6.EventType.NOTIFICATION);
6953
+ await this.flushToolActivityAtBoundary(import_codevibe_core7.EventType.NOTIFICATION);
6897
6954
  return this.publishE1Prompt(session, input, reRaiseToken);
6898
6955
  }
6899
6956
  async publishE1Prompt(session, input, reRaiseToken) {
6900
6957
  const promptId = input.promptId, entry = promptId ? this.e1PromptRaises.get(promptId) : void 0;
6901
- if (!promptId || !(0, import_codevibe_core6.isOpenPromptRaise)(entry, this.e1PromptRaises.get(promptId), this.e1NeedsResolution.has(promptId))) return "CLOSED";
6958
+ if (!promptId || !(0, import_codevibe_core7.isOpenPromptRaise)(entry, this.e1PromptRaises.get(promptId), this.e1NeedsResolution.has(promptId))) return "CLOSED";
6902
6959
  if (!this.started || this.session !== session || input.sessionId !== session.sessionId) return "RETRY";
6903
6960
  const { notificationText: _legacyHint, ...plain } = input;
6904
6961
  const settle = (disposition) => {
6905
- if ((0, import_codevibe_core6.isOpenPromptRaise)(entry, this.e1PromptRaises.get(promptId), this.e1NeedsResolution.has(promptId))) {
6962
+ if ((0, import_codevibe_core7.isOpenPromptRaise)(entry, this.e1PromptRaises.get(promptId), this.e1NeedsResolution.has(promptId))) {
6906
6963
  if (disposition === "RETRY") this.e1NeedsReRaise.add(promptId);
6907
6964
  else if (disposition === "RERAISED" || disposition === "OMITTED") this.e1NeedsReRaise.delete(promptId);
6908
6965
  }
@@ -7077,7 +7134,7 @@ var McpServer = class _McpServer {
7077
7134
  async reRaiseOneE1(session, entry, opts) {
7078
7135
  const rec = entry.record;
7079
7136
  if (this.e1NeedsResolution.has(rec.promptId)) return "CLOSED";
7080
- if (!(0, import_codevibe_core6.canRecoverPromptRaise)(entry, this.promptPublications.isPublishing(rec.promptId))) {
7137
+ if (!(0, import_codevibe_core7.canRecoverPromptRaise)(entry, this.promptPublications.isPublishing(rec.promptId))) {
7081
7138
  return "RETRY";
7082
7139
  }
7083
7140
  const actionable = rec.mobileActionable && entry.contentPlain !== void 0;
@@ -7085,7 +7142,7 @@ var McpServer = class _McpServer {
7085
7142
  const gen = opts?.gen;
7086
7143
  const MAX_ATTEMPTS = 4;
7087
7144
  for (let attempt = 1; ; attempt++) {
7088
- if (!(0, import_codevibe_core6.isOpenPromptRaise)(
7145
+ if (!(0, import_codevibe_core7.isOpenPromptRaise)(
7089
7146
  entry,
7090
7147
  this.e1PromptRaises.get(rec.promptId),
7091
7148
  this.e1NeedsResolution.has(rec.promptId)
@@ -7103,15 +7160,15 @@ var McpServer = class _McpServer {
7103
7160
  if (actionable) {
7104
7161
  const input = {
7105
7162
  sessionId: session.sessionId,
7106
- type: import_codevibe_core6.EventType.INTERACTIVE_PROMPT,
7107
- source: import_codevibe_core6.EventSource.DESKTOP,
7163
+ type: import_codevibe_core7.EventType.INTERACTIVE_PROMPT,
7164
+ source: import_codevibe_core7.EventSource.DESKTOP,
7108
7165
  content: entry.contentPlain,
7109
7166
  metadata: entry.metadataPlain ?? {},
7110
- ...(0, import_codevibe_core6.raiseFieldsFromRecord)(rec),
7111
- timestamp: (0, import_codevibe_core6.prepareEventTimestamp)({ orderingKey: session.sessionId })
7167
+ ...(0, import_codevibe_core7.raiseFieldsFromRecord)(rec),
7168
+ timestamp: (0, import_codevibe_core7.prepareEventTimestamp)({ orderingKey: session.sessionId })
7112
7169
  };
7113
- await this.flushToolActivityAtBoundary(import_codevibe_core6.EventType.INTERACTIVE_PROMPT);
7114
- if (!(0, import_codevibe_core6.isOpenPromptRaise)(
7170
+ await this.flushToolActivityAtBoundary(import_codevibe_core7.EventType.INTERACTIVE_PROMPT);
7171
+ if (!(0, import_codevibe_core7.isOpenPromptRaise)(
7115
7172
  entry,
7116
7173
  this.e1PromptRaises.get(rec.promptId),
7117
7174
  this.e1NeedsResolution.has(rec.promptId)
@@ -7191,7 +7248,7 @@ var McpServer = class _McpServer {
7191
7248
  const session = this.session;
7192
7249
  if (!session) return;
7193
7250
  const sid = session.sessionId;
7194
- const promptIds = [...this.e1PromptRaises.values()].filter((e) => e.record.sessionId === sid && !this.e1NeedsResolution.has(e.record.promptId) && (0, import_codevibe_core6.canRecoverPromptRaise)(e, this.promptPublications.isPublishing(e.record.promptId))).map((e) => e.record.promptId);
7251
+ const promptIds = [...this.e1PromptRaises.values()].filter((e) => e.record.sessionId === sid && !this.e1NeedsResolution.has(e.record.promptId) && (0, import_codevibe_core7.canRecoverPromptRaise)(e, this.promptPublications.isPublishing(e.record.promptId))).map((e) => e.record.promptId);
7195
7252
  if (promptIds.length === 0) return;
7196
7253
  try {
7197
7254
  await this.appSyncClient.refreshSessionOpenPromptTtl({ sessionId: sid, promptIds }, async (promptId, reRaiseToken) => {
@@ -7268,6 +7325,7 @@ var McpServer = class _McpServer {
7268
7325
  error: String(error)
7269
7326
  });
7270
7327
  }
7328
+ this.transcriptTailer.refreshNativeOwnerBoundary();
7271
7329
  this.session = null;
7272
7330
  await this.ensureLaunchSession();
7273
7331
  if (this.session) await this.drainE1RetirementPark();
@@ -7302,10 +7360,10 @@ var McpServer = class _McpServer {
7302
7360
  }
7303
7361
  const result = { ...evt };
7304
7362
  try {
7305
- result.content = import_codevibe_core6.cryptoService.decryptContent(evt.content, session.sessionKey);
7363
+ result.content = import_codevibe_core7.cryptoService.decryptContent(evt.content, session.sessionKey);
7306
7364
  const rawMeta = parseMaybeJson(evt.metadata);
7307
7365
  if (rawMeta && typeof rawMeta === "object" && typeof rawMeta.encrypted === "string") {
7308
- const decryptedMeta = import_codevibe_core6.cryptoService.decryptMetadata(
7366
+ const decryptedMeta = import_codevibe_core7.cryptoService.decryptMetadata(
7309
7367
  rawMeta.encrypted,
7310
7368
  session.sessionKey
7311
7369
  );
@@ -7438,25 +7496,25 @@ var McpServer = class _McpServer {
7438
7496
  const content = state.paneDisplayHeader || state.matchedPaneHeader || state.pendingCall?.command || state.pendingCall?.filePath || "approval requested";
7439
7497
  const input = {
7440
7498
  sessionId: session.sessionId,
7441
- type: import_codevibe_core6.EventType.INTERACTIVE_PROMPT,
7442
- source: import_codevibe_core6.EventSource.DESKTOP,
7499
+ type: import_codevibe_core7.EventType.INTERACTIVE_PROMPT,
7500
+ source: import_codevibe_core7.EventSource.DESKTOP,
7443
7501
  content,
7444
7502
  metadata: optionsForMobile,
7445
7503
  // E1 (§4) — raise identity top-level: promptId + ownerToken/producerKind/
7446
7504
  // mobileActionable (the backend's classifyRaise upserts the open-prompt row).
7447
- ...(0, import_codevibe_core6.raiseFieldsFromRecord)(e1rec),
7505
+ ...(0, import_codevibe_core7.raiseFieldsFromRecord)(e1rec),
7448
7506
  // Per-conversation monotonic timestamp (event-timestamp-ordering fix
7449
7507
  // v5.4, 2026-05-24). orderingKey scopes the counter to this conv so
7450
7508
  // INTERACTIVE_PROMPT can't be forced to lastMs+1 by a newer event
7451
7509
  // from a sibling conversation under v9's multi-conv-per-session
7452
7510
  // model.
7453
- timestamp: (0, import_codevibe_core6.prepareEventTimestamp)({
7511
+ timestamp: (0, import_codevibe_core7.prepareEventTimestamp)({
7454
7512
  orderingKey: `${session.sessionId}:${state.conversationId}`
7455
7513
  })
7456
7514
  };
7457
7515
  try {
7458
7516
  this.stashE1RaiseContent(e1rec.promptId, content, optionsForMobile);
7459
- await this.flushToolActivityAtBoundary(import_codevibe_core6.EventType.INTERACTIVE_PROMPT);
7517
+ await this.flushToolActivityAtBoundary(import_codevibe_core7.EventType.INTERACTIVE_PROMPT);
7460
7518
  if (this.e1NeedsResolution.has(e1rec.promptId) || this.e1PromptRaises.get(e1rec.promptId)?.record !== e1rec) return;
7461
7519
  await this.publishE1Prompt(session, input);
7462
7520
  } catch (err) {
@@ -7504,7 +7562,7 @@ var McpServer = class _McpServer {
7504
7562
  if (shouldDecrypt && sessionKey) {
7505
7563
  try {
7506
7564
  logger.info("Decrypting attachment", { id: attachment.id });
7507
- buffer = import_codevibe_core6.cryptoService.decryptData(buffer, sessionKey);
7565
+ buffer = import_codevibe_core7.cryptoService.decryptData(buffer, sessionKey);
7508
7566
  logger.info("Attachment decrypted successfully", {
7509
7567
  id: attachment.id,
7510
7568
  decryptedSize: buffer.length
@@ -7560,7 +7618,7 @@ var McpServer = class _McpServer {
7560
7618
  await this.ensureLaunchSession();
7561
7619
  if (!this.session) return;
7562
7620
  const session = this.session;
7563
- if (evt.source !== import_codevibe_core6.EventSource.MOBILE) return;
7621
+ if (evt.source !== import_codevibe_core7.EventSource.MOBILE) return;
7564
7622
  if (evt.sessionId !== session.sessionId) {
7565
7623
  logger.warn("Dropping mobile event with mismatched sessionId", {
7566
7624
  expected: session.sessionId,
@@ -7572,19 +7630,19 @@ var McpServer = class _McpServer {
7572
7630
  try {
7573
7631
  decrypted = this.decryptInbound(session, evt);
7574
7632
  } catch (error) {
7575
- if ((0, import_codevibe_core6.requiresSyncInputDeliveryReceipt)(evt)) throw error;
7633
+ if ((0, import_codevibe_core7.requiresSyncInputDeliveryReceipt)(evt)) throw error;
7576
7634
  return;
7577
7635
  }
7578
7636
  evt = decrypted;
7579
7637
  if (!await this.markDelivered(evt)) return;
7580
- if (evt.type === import_codevibe_core6.EventType.USER_PROMPT || evt.type === import_codevibe_core6.EventType.PROMPT_RESPONSE) {
7638
+ if (evt.type === import_codevibe_core7.EventType.USER_PROMPT || evt.type === import_codevibe_core7.EventType.PROMPT_RESPONSE) {
7581
7639
  const mobileFloorMs = Date.parse(evt.timestamp);
7582
7640
  this.mobilePromptFloorBySession.set(session.sessionId, {
7583
7641
  floorMs: Number.isNaN(mobileFloorMs) ? Date.now() : mobileFloorMs,
7584
7642
  setAtWallMs: Date.now()
7585
7643
  });
7586
7644
  }
7587
- if (evt.type === import_codevibe_core6.EventType.USER_PROMPT || evt.type === import_codevibe_core6.EventType.PROMPT_RESPONSE) {
7645
+ if (evt.type === import_codevibe_core7.EventType.USER_PROMPT || evt.type === import_codevibe_core7.EventType.PROMPT_RESPONSE) {
7588
7646
  let promptContent = evt.content;
7589
7647
  const attachments = evt.attachments ?? [];
7590
7648
  if (attachments.length > 0) {
@@ -7625,16 +7683,16 @@ var McpServer = class _McpServer {
7625
7683
  const rawMeta = parseMaybeJson(evt.metadata);
7626
7684
  const meta = rawMeta && typeof rawMeta === "object" ? rawMeta : {};
7627
7685
  const evtAny = evt;
7628
- const responsePromptId = evt.type === import_codevibe_core6.EventType.PROMPT_RESPONSE ? typeof meta.promptId === "string" && meta.promptId || typeof meta.prompt_id === "string" && meta.prompt_id || typeof evtAny.promptId === "string" && evtAny.promptId || typeof evtAny.prompt_id === "string" && evtAny.prompt_id || null : null;
7686
+ const responsePromptId = evt.type === import_codevibe_core7.EventType.PROMPT_RESPONSE ? typeof meta.promptId === "string" && meta.promptId || typeof meta.prompt_id === "string" && meta.prompt_id || typeof evtAny.promptId === "string" && evtAny.promptId || typeof evtAny.prompt_id === "string" && evtAny.prompt_id || null : null;
7629
7687
  const advertisedOptionNumbers = Array.from(new Set(
7630
7688
  pendingPrompts.flatMap((prompt) => Object.keys(prompt.submitMap))
7631
7689
  ));
7632
- const intent = (0, import_codevibe_core6.classifyMobilePromptInput)(
7690
+ const intent = (0, import_codevibe_core7.classifyMobilePromptInput)(
7633
7691
  promptContent,
7634
7692
  advertisedOptionNumbers
7635
7693
  );
7636
7694
  if (intent.kind === "option") {
7637
- const activePrompt = evt.type === import_codevibe_core6.EventType.PROMPT_RESPONSE ? pendingPrompts.find((prompt) => prompt.promptId === responsePromptId) ?? null : pendingPrompts.length === 1 ? pendingPrompts[0] : null;
7695
+ const activePrompt = evt.type === import_codevibe_core7.EventType.PROMPT_RESPONSE ? pendingPrompts.find((prompt) => prompt.promptId === responsePromptId) ?? null : pendingPrompts.length === 1 ? pendingPrompts[0] : null;
7638
7696
  if (!activePrompt || !Object.prototype.hasOwnProperty.call(activePrompt.submitMap, intent.option)) {
7639
7697
  logger.warn("Numeric input does not identify one current advertised prompt; dropping", {
7640
7698
  sessionId: session.sessionId,
@@ -7644,7 +7702,7 @@ var McpServer = class _McpServer {
7644
7702
  });
7645
7703
  return;
7646
7704
  }
7647
- if (evt.type === import_codevibe_core6.EventType.PROMPT_RESPONSE) {
7705
+ if (evt.type === import_codevibe_core7.EventType.PROMPT_RESPONSE) {
7648
7706
  if (responsePromptId !== activePrompt.promptId) {
7649
7707
  logger.warn("PROMPT_RESPONSE does not identify the current advertised prompt; dropping", {
7650
7708
  sessionId: session.sessionId,
@@ -7660,7 +7718,7 @@ var McpServer = class _McpServer {
7660
7718
  intent.option
7661
7719
  );
7662
7720
  if (!optionResult.ok) {
7663
- if (!(0, import_codevibe_core6.requiresSyncInputDeliveryReceipt)(evt)) this.mobileDeduper.forget(session.sessionId, intent.option);
7721
+ if (!(0, import_codevibe_core7.requiresSyncInputDeliveryReceipt)(evt)) this.mobileDeduper.forget(session.sessionId, intent.option);
7664
7722
  return;
7665
7723
  }
7666
7724
  await this.resolveE1PluginApproval(session.sessionId, activePrompt.promptId);
@@ -7687,7 +7745,7 @@ var McpServer = class _McpServer {
7687
7745
  () => this.trackDurableMobileEcho(session, evt, promptContent, "free_form")
7688
7746
  );
7689
7747
  if (!result.ok) {
7690
- if (!(0, import_codevibe_core6.requiresSyncInputDeliveryReceipt)(evt)) this.mobileDeduper.forget(session.sessionId, promptContent);
7748
+ if (!(0, import_codevibe_core7.requiresSyncInputDeliveryReceipt)(evt)) this.mobileDeduper.forget(session.sessionId, promptContent);
7691
7749
  logger.warn("sendFreeForm failed", { reason: result.reason, details: result.details });
7692
7750
  return;
7693
7751
  }
@@ -7696,7 +7754,7 @@ var McpServer = class _McpServer {
7696
7754
  }
7697
7755
  }
7698
7756
  async trackDurableMobileEcho(session, event, content, lane) {
7699
- if (!(0, import_codevibe_core6.requiresSyncInputDeliveryReceipt)(event)) {
7757
+ if (!(0, import_codevibe_core7.requiresSyncInputDeliveryReceipt)(event)) {
7700
7758
  this.mobileDeduper.track(session.sessionId, content);
7701
7759
  return;
7702
7760
  }
@@ -7712,13 +7770,13 @@ var McpServer = class _McpServer {
7712
7770
  async emitPromptSafetyNotification(session, content) {
7713
7771
  const input = {
7714
7772
  sessionId: session.sessionId,
7715
- type: import_codevibe_core6.EventType.NOTIFICATION,
7716
- source: import_codevibe_core6.EventSource.DESKTOP,
7773
+ type: import_codevibe_core7.EventType.NOTIFICATION,
7774
+ source: import_codevibe_core7.EventSource.DESKTOP,
7717
7775
  content,
7718
7776
  metadata: { promptSafetyBlocked: true },
7719
- timestamp: (0, import_codevibe_core6.prepareEventTimestamp)({ orderingKey: session.sessionId })
7777
+ timestamp: (0, import_codevibe_core7.prepareEventTimestamp)({ orderingKey: session.sessionId })
7720
7778
  };
7721
- await this.flushToolActivityAtBoundary(import_codevibe_core6.EventType.NOTIFICATION);
7779
+ await this.flushToolActivityAtBoundary(import_codevibe_core7.EventType.NOTIFICATION);
7722
7780
  try {
7723
7781
  if (!this.started || this.sessionDisabled || this.session !== session) return;
7724
7782
  const result = await this.appSyncClient.publishCompanionNotice(
@@ -7740,14 +7798,14 @@ var McpServer = class _McpServer {
7740
7798
  */
7741
7799
  async markDelivered(evt) {
7742
7800
  try {
7743
- return await (0, import_codevibe_core6.acknowledgeMobileInputDelivery)(this.appSyncClient.updateEventStatus.bind(this.appSyncClient), evt);
7801
+ return await (0, import_codevibe_core7.acknowledgeMobileInputDelivery)(this.appSyncClient.updateEventStatus.bind(this.appSyncClient), evt);
7744
7802
  } catch (err) {
7745
7803
  logger.warn("updateEventStatus(DELIVERED) failed", {
7746
7804
  eventId: evt.eventId,
7747
7805
  sessionId: evt.sessionId,
7748
7806
  error: String(err)
7749
7807
  });
7750
- if ((0, import_codevibe_core6.requiresSyncInputDeliveryReceipt)(evt)) throw err;
7808
+ if ((0, import_codevibe_core7.requiresSyncInputDeliveryReceipt)(evt)) throw err;
7751
7809
  return true;
7752
7810
  }
7753
7811
  }
@@ -7761,7 +7819,7 @@ var McpServer = class _McpServer {
7761
7819
  */
7762
7820
  async markExecuted(evt) {
7763
7821
  try {
7764
- await (0, import_codevibe_core6.acknowledgeMobileInputExecution)(this.appSyncClient.updateEventStatus.bind(this.appSyncClient), evt);
7822
+ await (0, import_codevibe_core7.acknowledgeMobileInputExecution)(this.appSyncClient.updateEventStatus.bind(this.appSyncClient), evt);
7765
7823
  } catch (err) {
7766
7824
  logger.warn("updateEventStatus(EXECUTED) failed", {
7767
7825
  eventId: evt.eventId,
@@ -7792,7 +7850,7 @@ var McpServer = class _McpServer {
7792
7850
  // orderingKey is session-scoped. Slightly coarser than the
7793
7851
  // per-conv key used by transcript emits, but acceptable because
7794
7852
  // hook-script pushes are off the hot transcript path.
7795
- timestamp: (0, import_codevibe_core6.prepareEventTimestamp)({ orderingKey: payload.sessionId })
7853
+ timestamp: (0, import_codevibe_core7.prepareEventTimestamp)({ orderingKey: payload.sessionId })
7796
7854
  };
7797
7855
  return this.appSyncClient.publishCompanionEvent(input, async () => {
7798
7856
  assertOwner();
@@ -8166,7 +8224,7 @@ async function main() {
8166
8224
  tmuxTarget: process.env.CODEVIBE_AGY_TMUX_TARGET ?? void 0,
8167
8225
  wrapperPid: process.env.CODEVIBE_AGY_WRAPPER_PID ? parseInt(process.env.CODEVIBE_AGY_WRAPPER_PID, 10) : void 0
8168
8226
  });
8169
- (0, import_codevibe_core6.installDaemonProcessGuards)(logger, {
8227
+ (0, import_codevibe_core7.installDaemonProcessGuards)(logger, {
8170
8228
  onFatal: () => {
8171
8229
  void server.stop().finally(() => process.exit(1));
8172
8230
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quantiya/codevibe-antigravity-plugin",
3
- "version": "2.0.77",
3
+ "version": "2.0.79",
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": {
@@ -46,7 +46,7 @@
46
46
  "node": ">=22.0.0"
47
47
  },
48
48
  "dependencies": {
49
- "@quantiya/codevibe-core": "^2.0.71",
49
+ "@quantiya/codevibe-core": "^2.0.73",
50
50
  "chokidar": "^5.0.0",
51
51
  "dotenv": "^16.6.1",
52
52
  "express": "^5.1.0",