@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.
- package/dist/server.js +157 -99
- 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
|
|
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.
|
|
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:
|
|
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
|
|
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:
|
|
4896
|
+
source: import_codevibe_core5.EventSource.DESKTOP
|
|
4847
4897
|
};
|
|
4848
4898
|
const orderingKey = `${sessionId}:${emit.conversationId}`;
|
|
4849
|
-
const nextTimestamp = () => (0,
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
|
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,
|
|
5245
|
+
contentDigest: (0, import_codevibe_core6.digestOf)(emit.event.content ?? "")
|
|
5196
5246
|
};
|
|
5197
|
-
return `agy:${(0,
|
|
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
|
|
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
|
|
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
|
|
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,
|
|
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,
|
|
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:
|
|
5348
|
-
source:
|
|
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,
|
|
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,
|
|
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
|
|
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
|
|
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,
|
|
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,
|
|
5821
|
+
await (0, import_codevibe_core7.registerDeviceEncryptionKey)(this.appSyncClient, logger);
|
|
5771
5822
|
if (!this.started) return { httpPort: 0 };
|
|
5772
|
-
(0,
|
|
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)
|
|
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({
|
|
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,
|
|
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,
|
|
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 ===
|
|
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 ===
|
|
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 ===
|
|
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 ===
|
|
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 ===
|
|
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 !==
|
|
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
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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:
|
|
6887
|
-
source:
|
|
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,
|
|
6949
|
+
...(0, import_codevibe_core7.raiseFieldsFromRecord)(record),
|
|
6893
6950
|
notificationText: bannerText,
|
|
6894
|
-
timestamp: (0,
|
|
6951
|
+
timestamp: (0, import_codevibe_core7.prepareEventTimestamp)({ orderingKey: session.sessionId })
|
|
6895
6952
|
};
|
|
6896
|
-
await this.flushToolActivityAtBoundary(
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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:
|
|
7107
|
-
source:
|
|
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,
|
|
7111
|
-
timestamp: (0,
|
|
7167
|
+
...(0, import_codevibe_core7.raiseFieldsFromRecord)(rec),
|
|
7168
|
+
timestamp: (0, import_codevibe_core7.prepareEventTimestamp)({ orderingKey: session.sessionId })
|
|
7112
7169
|
};
|
|
7113
|
-
await this.flushToolActivityAtBoundary(
|
|
7114
|
-
if (!(0,
|
|
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,
|
|
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 =
|
|
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 =
|
|
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:
|
|
7442
|
-
source:
|
|
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,
|
|
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,
|
|
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(
|
|
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 =
|
|
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 !==
|
|
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,
|
|
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 ===
|
|
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 ===
|
|
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 ===
|
|
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,
|
|
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 ===
|
|
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 ===
|
|
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,
|
|
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,
|
|
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,
|
|
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:
|
|
7716
|
-
source:
|
|
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,
|
|
7777
|
+
timestamp: (0, import_codevibe_core7.prepareEventTimestamp)({ orderingKey: session.sessionId })
|
|
7720
7778
|
};
|
|
7721
|
-
await this.flushToolActivityAtBoundary(
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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.
|
|
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.
|
|
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",
|