@agentvault/grok-bridge 0.4.2 → 0.4.4
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/index.js
CHANGED
|
@@ -64589,17 +64589,28 @@ var init_mls_kp_pool = __esm2({
|
|
|
64589
64589
|
}
|
|
64590
64590
|
});
|
|
64591
64591
|
function ownIdentity() {
|
|
64592
|
-
const v2 = true ? "0.23.
|
|
64592
|
+
const v2 = true ? "0.23.31" : FALLBACK;
|
|
64593
64593
|
return `${PACKAGE}@${v2}`;
|
|
64594
64594
|
}
|
|
64595
|
+
function buildSha() {
|
|
64596
|
+
const raw = true ? "3e1243a-dirty" : "";
|
|
64597
|
+
const cleaned = (raw ?? "").trim();
|
|
64598
|
+
return !cleaned || cleaned === "unknown" ? null : cleaned;
|
|
64599
|
+
}
|
|
64600
|
+
function withBuildSha(identity) {
|
|
64601
|
+
const sha = buildSha();
|
|
64602
|
+
if (!sha || identity.includes("+")) return identity;
|
|
64603
|
+
const stamped = `${identity}+${sha}`;
|
|
64604
|
+
return stamped.length <= MAX_LEN ? stamped : identity;
|
|
64605
|
+
}
|
|
64595
64606
|
function buildClientVersion(override) {
|
|
64596
64607
|
try {
|
|
64597
64608
|
const candidate = (override ?? "").trim();
|
|
64598
64609
|
if (candidate) {
|
|
64599
|
-
const cleaned = candidate.replace(DISALLOWED, "").slice(0, MAX_LEN);
|
|
64610
|
+
const cleaned = withBuildSha(candidate.replace(DISALLOWED, "").slice(0, MAX_LEN));
|
|
64600
64611
|
if (cleaned && !cleaned.includes("..")) return cleaned;
|
|
64601
64612
|
}
|
|
64602
|
-
return ownIdentity().replace(DISALLOWED, "").slice(0, MAX_LEN);
|
|
64613
|
+
return withBuildSha(ownIdentity().replace(DISALLOWED, "").slice(0, MAX_LEN));
|
|
64603
64614
|
} catch {
|
|
64604
64615
|
return FALLBACK;
|
|
64605
64616
|
}
|
|
@@ -66330,6 +66341,118 @@ var init_channel = __esm2({
|
|
|
66330
66341
|
* Encrypt and send a message to ALL owner devices (fanout).
|
|
66331
66342
|
* Each session gets the same plaintext encrypted independently.
|
|
66332
66343
|
*/
|
|
66344
|
+
/**
|
|
66345
|
+
* #952 — sends held because MLS is expected for this conversation but the
|
|
66346
|
+
* group is not joined yet.
|
|
66347
|
+
*
|
|
66348
|
+
* ⚠️ IN MEMORY ONLY. These entries hold PLAINTEXT. `_persisted` is written to
|
|
66349
|
+
* disk, and the product's entire premise is that plaintext does not rest
|
|
66350
|
+
* where it does not have to; a crash losing a held greeting is the correct
|
|
66351
|
+
* trade. This is why the existing `outboundQueue` could not be reused — that
|
|
66352
|
+
* one is persisted, and holds already-DR-encrypted bytes, which is exactly
|
|
66353
|
+
* the encryption we are trying not to perform yet.
|
|
66354
|
+
*/
|
|
66355
|
+
_mlsHold = /* @__PURE__ */ new Map();
|
|
66356
|
+
/** How long a send waits for the Welcome. The two measured bursts were each
|
|
66357
|
+
* confined to a single minute, with the group already existing server-side
|
|
66358
|
+
* in the same second, so this is generous rather than tight. */
|
|
66359
|
+
static MLS_HOLD_MS = 3e4;
|
|
66360
|
+
/** Bound on held sends per group — see `_holdForMls`. */
|
|
66361
|
+
static MLS_HOLD_MAX = 50;
|
|
66362
|
+
/**
|
|
66363
|
+
* Should this 1:1 send wait for MLS rather than go out over Double Ratchet?
|
|
66364
|
+
*
|
|
66365
|
+
* The discriminator exists at the moment of the bug: `_sessionGroupIds`
|
|
66366
|
+
* already carries the conversation's group id — the server told us the group
|
|
66367
|
+
* exists — while `_mlsGroups` has no usable manager for it. Group expected,
|
|
66368
|
+
* group not ready.
|
|
66369
|
+
*
|
|
66370
|
+
* The negative case is load-bearing. A conversation with NO group id is
|
|
66371
|
+
* legitimately Double Ratchet, and holding it would break owner-to-agent
|
|
66372
|
+
* messaging outright, which is far worse than the bug this fixes. "Present"
|
|
66373
|
+
* is also not "ready": a manager parked at epoch 0 has not joined (#1092),
|
|
66374
|
+
* and reading presence as readiness is how #991 shipped.
|
|
66375
|
+
*/
|
|
66376
|
+
_shouldHoldForMls(convGroupId, mlsGroup, mlsGroupId) {
|
|
66377
|
+
if (!convGroupId) return false;
|
|
66378
|
+
const ready = Boolean(mlsGroup?.isInitialized) && Boolean(mlsGroupId) && Number(mlsGroup?.epoch) > 0;
|
|
66379
|
+
return !ready;
|
|
66380
|
+
}
|
|
66381
|
+
/** Park a send until the Welcome lands, or until the hold expires. */
|
|
66382
|
+
_holdForMls(convGroupId, convId, plaintext, options) {
|
|
66383
|
+
let entry = this._mlsHold.get(convGroupId);
|
|
66384
|
+
if (!entry) {
|
|
66385
|
+
const timer = setTimeout(() => {
|
|
66386
|
+
void this._releaseHeldOverDr(convGroupId);
|
|
66387
|
+
}, _SecureChannel.MLS_HOLD_MS);
|
|
66388
|
+
timer.unref?.();
|
|
66389
|
+
entry = { items: [], timer };
|
|
66390
|
+
this._mlsHold.set(convGroupId, entry);
|
|
66391
|
+
}
|
|
66392
|
+
if (entry.items.length >= _SecureChannel.MLS_HOLD_MAX) {
|
|
66393
|
+
entry.items.shift();
|
|
66394
|
+
console.warn(
|
|
66395
|
+
`[SecureChannel] MLS hold full for group ${convGroupId.slice(0, 8)} \u2014 dropped the oldest held message`
|
|
66396
|
+
);
|
|
66397
|
+
}
|
|
66398
|
+
entry.items.push({ convId, plaintext, options });
|
|
66399
|
+
console.log(
|
|
66400
|
+
`[SecureChannel] Holding send for group ${convGroupId.slice(0, 8)} until its Welcome lands (held=${entry.items.length})`
|
|
66401
|
+
);
|
|
66402
|
+
}
|
|
66403
|
+
_takeHold(convGroupId) {
|
|
66404
|
+
const entry = this._mlsHold.get(convGroupId);
|
|
66405
|
+
if (!entry) return null;
|
|
66406
|
+
clearTimeout(entry.timer);
|
|
66407
|
+
this._mlsHold.delete(convGroupId);
|
|
66408
|
+
return entry;
|
|
66409
|
+
}
|
|
66410
|
+
/** Re-drive one held send through the normal path, now that MLS is ready. */
|
|
66411
|
+
async _resendHeld(item) {
|
|
66412
|
+
await this.send(item.plaintext, {
|
|
66413
|
+
...item.options ?? {},
|
|
66414
|
+
conversationId: item.convId,
|
|
66415
|
+
bypassMlsHold: true
|
|
66416
|
+
});
|
|
66417
|
+
}
|
|
66418
|
+
/** The Welcome landed — release everything held for this group, in order. */
|
|
66419
|
+
async _flushMlsHold(convGroupId) {
|
|
66420
|
+
const entry = this._takeHold(convGroupId);
|
|
66421
|
+
if (!entry) return;
|
|
66422
|
+
console.log(
|
|
66423
|
+
`[SecureChannel] Welcome landed for group ${convGroupId.slice(0, 8)} \u2014 releasing ${entry.items.length} held message(s) over MLS`
|
|
66424
|
+
);
|
|
66425
|
+
for (const item of entry.items) {
|
|
66426
|
+
try {
|
|
66427
|
+
await this._resendHeld(item);
|
|
66428
|
+
} catch (err) {
|
|
66429
|
+
console.warn("[SecureChannel] Held message failed to send after Welcome:", err);
|
|
66430
|
+
}
|
|
66431
|
+
}
|
|
66432
|
+
}
|
|
66433
|
+
/**
|
|
66434
|
+
* The hold expired. Send over Double Ratchet exactly as before.
|
|
66435
|
+
*
|
|
66436
|
+
* This is deliberately NOT a drop. #853 and #831 are Welcomes that never
|
|
66437
|
+
* arrive; under those an unbounded hold turns a lost minute into an agent
|
|
66438
|
+
* that never speaks again. The hold removes the race — it must not invent a
|
|
66439
|
+
* new failure mode. The warning is the part that is new: today the loss is
|
|
66440
|
+
* silent.
|
|
66441
|
+
*/
|
|
66442
|
+
async _releaseHeldOverDr(convGroupId) {
|
|
66443
|
+
const entry = this._takeHold(convGroupId);
|
|
66444
|
+
if (!entry) return;
|
|
66445
|
+
console.warn(
|
|
66446
|
+
`[SecureChannel] No Welcome for group ${convGroupId.slice(0, 8)} within ${_SecureChannel.MLS_HOLD_MS}ms \u2014 releasing ${entry.items.length} message(s) over Double Ratchet. The recipient may not hold a ratchet with this device, in which case they are undeliverable (#952).`
|
|
66447
|
+
);
|
|
66448
|
+
for (const item of entry.items) {
|
|
66449
|
+
try {
|
|
66450
|
+
await this._resendHeld(item);
|
|
66451
|
+
} catch (err) {
|
|
66452
|
+
console.warn("[SecureChannel] Held message failed on Double Ratchet release:", err);
|
|
66453
|
+
}
|
|
66454
|
+
}
|
|
66455
|
+
}
|
|
66333
66456
|
async send(plaintext, options) {
|
|
66334
66457
|
if (isAbstention(plaintext)) return;
|
|
66335
66458
|
if (this._state === "error" || this._state === "idle") {
|
|
@@ -66491,6 +66614,10 @@ var init_channel = __esm2({
|
|
|
66491
66614
|
);
|
|
66492
66615
|
addressedMlsGroupIds.push(mlsGroupId);
|
|
66493
66616
|
if (convGroupId) sentSharedGroupIds.add(convGroupId);
|
|
66617
|
+
} else if (!options?.bypassMlsHold && this._shouldHoldForMls(convGroupId, mlsGroup, mlsGroupId)) {
|
|
66618
|
+
this._holdForMls(convGroupId, convId, plaintext, options);
|
|
66619
|
+
sentCount++;
|
|
66620
|
+
continue;
|
|
66494
66621
|
} else {
|
|
66495
66622
|
const encrypted = session.ratchet.encrypt(plaintext);
|
|
66496
66623
|
const transport = encryptedMessageToTransport(encrypted);
|
|
@@ -66660,7 +66787,7 @@ var init_channel = __esm2({
|
|
|
66660
66787
|
*/
|
|
66661
66788
|
sendActivitySpan(spanData) {
|
|
66662
66789
|
if (!this._ws || this._ws.readyState !== WebSocket.OPEN) return;
|
|
66663
|
-
const pluginVersion = true ? "0.23.
|
|
66790
|
+
const pluginVersion = true ? "0.23.31" : "0.0.0-dev";
|
|
66664
66791
|
const agentName = this.config.agentName ?? "Agent";
|
|
66665
66792
|
const resource = {
|
|
66666
66793
|
"service.name": "agentvault-agent",
|
|
@@ -68598,7 +68725,7 @@ var init_channel = __esm2({
|
|
|
68598
68725
|
agentVersion: this.config.agentVersion ?? "0.0.0",
|
|
68599
68726
|
// __AV_VERSION__ is injected by esbuild from package.json at build time.
|
|
68600
68727
|
// Falls back to "0.0.0-dev" in non-bundled contexts (tests).
|
|
68601
|
-
pluginVersion: true ? "0.23.
|
|
68728
|
+
pluginVersion: true ? "0.23.31" : "0.0.0-dev"
|
|
68602
68729
|
});
|
|
68603
68730
|
this._telemetryReporter.startAutoFlush(3e4);
|
|
68604
68731
|
}
|
|
@@ -68922,7 +69049,7 @@ var init_channel = __esm2({
|
|
|
68922
69049
|
agentVersion: this.config.agentVersion ?? "0.0.0",
|
|
68923
69050
|
// __AV_VERSION__ is injected by esbuild from package.json at build time.
|
|
68924
69051
|
// Falls back to "0.0.0-dev" in non-bundled contexts (tests).
|
|
68925
|
-
pluginVersion: true ? "0.23.
|
|
69052
|
+
pluginVersion: true ? "0.23.31" : "0.0.0-dev"
|
|
68926
69053
|
});
|
|
68927
69054
|
this._telemetryReporter.startAutoFlush(3e4);
|
|
68928
69055
|
}
|
|
@@ -69338,11 +69465,13 @@ var init_channel = __esm2({
|
|
|
69338
69465
|
let text = plaintext;
|
|
69339
69466
|
let messageType = "text";
|
|
69340
69467
|
let topicId = data.topic_id;
|
|
69468
|
+
let mlsAttachment = null;
|
|
69341
69469
|
try {
|
|
69342
69470
|
const parsed = JSON.parse(plaintext);
|
|
69343
69471
|
text = parsed.text ?? plaintext;
|
|
69344
69472
|
messageType = parsed.type ?? "text";
|
|
69345
69473
|
topicId = parsed.topicId ?? topicId;
|
|
69474
|
+
if (parsed.attachment) mlsAttachment = parsed.attachment;
|
|
69346
69475
|
} catch {
|
|
69347
69476
|
}
|
|
69348
69477
|
if (messageType === "history_catchup_request") {
|
|
@@ -69409,6 +69538,9 @@ var init_channel = __esm2({
|
|
|
69409
69538
|
console.log(`[SecureChannel] Session ${convId.slice(0, 8)} activated via MLS message`);
|
|
69410
69539
|
}
|
|
69411
69540
|
}
|
|
69541
|
+
if (mlsAttachment) {
|
|
69542
|
+
text = await this._augmentWithAttachment(mlsAttachment, text);
|
|
69543
|
+
}
|
|
69412
69544
|
const metadata = {
|
|
69413
69545
|
messageId: data.message_id ?? `mls_${Date.now()}`,
|
|
69414
69546
|
conversationId: convId ?? this._primaryConversationId,
|
|
@@ -69658,6 +69790,65 @@ ${messageText}`;
|
|
|
69658
69790
|
* Download an encrypted attachment blob, decrypt it, verify integrity,
|
|
69659
69791
|
* and save the plaintext file to disk.
|
|
69660
69792
|
*/
|
|
69793
|
+
/** Where an attachment may be written — always directly inside `attachDir` (#1143).
|
|
69794
|
+
*
|
|
69795
|
+
* The filename arrives INSIDE the envelope and is chosen by whoever sent the
|
|
69796
|
+
* message. `join(attachDir, info.filename)` resolves `..` normally, so
|
|
69797
|
+
* `../../agentvault.json` wrote over the device credential store. Only the
|
|
69798
|
+
* final path component is honoured, and anything that is not a usable name
|
|
69799
|
+
* falls back to a fixed one.
|
|
69800
|
+
*/
|
|
69801
|
+
_safeAttachmentPath(attachDir, filename) {
|
|
69802
|
+
const raw = String(filename ?? "");
|
|
69803
|
+
const last = raw.split(/[\\/]/).pop() ?? "";
|
|
69804
|
+
const cleaned = last.replace(/\0/g, "").trim();
|
|
69805
|
+
const safe = cleaned === "" || cleaned === "." || cleaned === ".." ? "attachment.bin" : cleaned;
|
|
69806
|
+
return join4(attachDir, safe);
|
|
69807
|
+
}
|
|
69808
|
+
/** Download an attachment and fold it into the text the agent sees (#1139).
|
|
69809
|
+
*
|
|
69810
|
+
* Extracted so the MLS receive path can use it too. It used to live inline in
|
|
69811
|
+
* `_handleIncomingMessage`, which meant attachments worked on the Double
|
|
69812
|
+
* Ratchet path ONLY — and hermes drops DR by design (`secure_channel.py:594`,
|
|
69813
|
+
* "DR fallback is logged-and-dropped"), so no single transport could serve
|
|
69814
|
+
* both client families. That is why an attachment reached ohtani and never
|
|
69815
|
+
* reached smartcoder2 on 2026-08-31.
|
|
69816
|
+
*
|
|
69817
|
+
* Returns the text unchanged when there is no attachment or the fetch fails —
|
|
69818
|
+
* but a failure is LOGGED and announced in the text, never silent.
|
|
69819
|
+
*/
|
|
69820
|
+
async _augmentWithAttachment(attachmentInfo, baseText) {
|
|
69821
|
+
if (!attachmentInfo) return baseText;
|
|
69822
|
+
try {
|
|
69823
|
+
const { filePath, decrypted } = await this._downloadAndDecryptAttachment(attachmentInfo);
|
|
69824
|
+
const mime = String(attachmentInfo.mime ?? "application/octet-stream");
|
|
69825
|
+
const name = String(attachmentInfo.filename ?? "attachment");
|
|
69826
|
+
const textMimes = ["text/", "application/json", "application/xml", "application/csv"];
|
|
69827
|
+
if (textMimes.some((m2) => mime.startsWith(m2))) {
|
|
69828
|
+
const content = new TextDecoder().decode(decrypted);
|
|
69829
|
+
return `[Attachment: ${name} (${mime}) saved to ${filePath}]
|
|
69830
|
+
---
|
|
69831
|
+
${content}
|
|
69832
|
+
---
|
|
69833
|
+
|
|
69834
|
+
${baseText}`;
|
|
69835
|
+
}
|
|
69836
|
+
if (mime.startsWith("image/")) {
|
|
69837
|
+
return `[Image attachment: ${name} saved to ${filePath}]
|
|
69838
|
+
Use your Read tool to view this image file.
|
|
69839
|
+
|
|
69840
|
+
${baseText}`;
|
|
69841
|
+
}
|
|
69842
|
+
return `[Attachment: ${name} saved to ${filePath}]
|
|
69843
|
+
|
|
69844
|
+
${baseText}`;
|
|
69845
|
+
} catch (err) {
|
|
69846
|
+
console.error("[SecureChannel] Failed to download attachment:", err);
|
|
69847
|
+
return `[Attachment: ${String(attachmentInfo.filename ?? "file")} was sent but could not be retrieved: ${err}]
|
|
69848
|
+
|
|
69849
|
+
${baseText}`;
|
|
69850
|
+
}
|
|
69851
|
+
}
|
|
69661
69852
|
async _downloadAndDecryptAttachment(info) {
|
|
69662
69853
|
const attachDir = join4(this.config.dataDir, "attachments");
|
|
69663
69854
|
await mkdir3(attachDir, { recursive: true });
|
|
@@ -69677,7 +69868,7 @@ ${messageText}`;
|
|
|
69677
69868
|
const fileKey = base64ToBytes(info.fileKey);
|
|
69678
69869
|
const fileNonce = base64ToBytes(info.fileNonce);
|
|
69679
69870
|
const decrypted = decryptFile(encryptedData, fileKey, fileNonce);
|
|
69680
|
-
const filePath =
|
|
69871
|
+
const filePath = this._safeAttachmentPath(attachDir, info.filename);
|
|
69681
69872
|
await writeFile3(filePath, decrypted);
|
|
69682
69873
|
console.log(`[SecureChannel] Attachment saved: ${filePath} (${decrypted.length} bytes)`);
|
|
69683
69874
|
return { filePath, decrypted };
|
|
@@ -71098,6 +71289,7 @@ ${messageText}`;
|
|
|
71098
71289
|
await this._persistState();
|
|
71099
71290
|
}
|
|
71100
71291
|
console.log(`[SecureChannel] Joined shared 1:1 MLS group for group ${conversationGroupId.slice(0, 8)} via Welcome (epoch=${mgr.epoch})`);
|
|
71292
|
+
await this._flushMlsHold(conversationGroupId);
|
|
71101
71293
|
return;
|
|
71102
71294
|
}
|
|
71103
71295
|
if (conversationId) {
|
|
@@ -73068,21 +73260,30 @@ var init_gateway_send = __esm2({
|
|
|
73068
73260
|
});
|
|
73069
73261
|
function parseMentions(text) {
|
|
73070
73262
|
const mentions = [];
|
|
73071
|
-
const re2 =
|
|
73263
|
+
const re2 = new RegExp(MENTION_RE.source, MENTION_RE.flags);
|
|
73072
73264
|
let match;
|
|
73073
73265
|
while ((match = re2.exec(text)) !== null) {
|
|
73074
73266
|
mentions.push(match[1].toLowerCase());
|
|
73075
73267
|
}
|
|
73076
73268
|
return mentions;
|
|
73077
73269
|
}
|
|
73270
|
+
function resolveOwn(mention, names) {
|
|
73271
|
+
if (names.has(mention)) return mention;
|
|
73272
|
+
const parts = mention.split("-");
|
|
73273
|
+
for (let i2 = parts.length - 1; i2 > 0; i2--) {
|
|
73274
|
+
const candidate = parts.slice(0, i2).join("-");
|
|
73275
|
+
if (names.has(candidate)) return candidate;
|
|
73276
|
+
}
|
|
73277
|
+
return null;
|
|
73278
|
+
}
|
|
73078
73279
|
function owesRoomReply(plaintext, agentName, accountId, senderIsAgent, roomDisplayName, ownDisplayName, selfResolved = true) {
|
|
73079
73280
|
const mentions = parseMentions(plaintext);
|
|
73080
73281
|
if (mentions.length === 0) return false;
|
|
73081
|
-
|
|
73282
|
+
const ownNames = ownRoomNames(agentName, accountId, roomDisplayName, ownDisplayName);
|
|
73283
|
+
if (mentions.some((m2) => resolveOwn(m2, ownNames) !== null)) return true;
|
|
73284
|
+
if (mentions.some((m2) => resolveOwn(m2, BROADCAST_NAMES) !== null)) {
|
|
73082
73285
|
return senderIsAgent !== true;
|
|
73083
73286
|
}
|
|
73084
|
-
const ownNames = ownRoomNames(agentName, accountId, roomDisplayName, ownDisplayName);
|
|
73085
|
-
if (mentions.some((m2) => ownNames.has(m2))) return true;
|
|
73086
73287
|
if (!selfResolved) return true;
|
|
73087
73288
|
return false;
|
|
73088
73289
|
}
|
|
@@ -73100,9 +73301,13 @@ function ownRoomNames(agentName, accountId, roomDisplayName, ownDisplayName) {
|
|
|
73100
73301
|
add4(ownDisplayName);
|
|
73101
73302
|
return names;
|
|
73102
73303
|
}
|
|
73304
|
+
var MENTION_RE;
|
|
73305
|
+
var BROADCAST_NAMES;
|
|
73103
73306
|
var init_room_protocol = __esm2({
|
|
73104
73307
|
"src/room-protocol.ts"() {
|
|
73105
73308
|
"use strict";
|
|
73309
|
+
MENTION_RE = /@([\w-]+)/gi;
|
|
73310
|
+
BROADCAST_NAMES = /* @__PURE__ */ new Set(["all", "everyone"]);
|
|
73106
73311
|
}
|
|
73107
73312
|
});
|
|
73108
73313
|
var init_llm_response_parser = __esm2({
|
|
@@ -99198,7 +99403,7 @@ var init_index = __esm2({
|
|
|
99198
99403
|
await init_skill_telemetry();
|
|
99199
99404
|
await init_policy_enforcer();
|
|
99200
99405
|
init_room_protocol();
|
|
99201
|
-
VERSION = true ? "0.23.
|
|
99406
|
+
VERSION = true ? "0.23.31" : "0.0.0-dev";
|
|
99202
99407
|
}
|
|
99203
99408
|
});
|
|
99204
99409
|
await init_index();
|
|
@@ -100124,7 +100329,7 @@ async function main() {
|
|
|
100124
100329
|
const info = parseInfoFlags(process.argv.slice(2));
|
|
100125
100330
|
if (info.showVersion || info.showHelp) {
|
|
100126
100331
|
const version2 = buildClientVersion2(
|
|
100127
|
-
true ? "0.4.
|
|
100332
|
+
true ? "0.4.4" : void 0
|
|
100128
100333
|
);
|
|
100129
100334
|
if (info.showVersion) printLine(version2);
|
|
100130
100335
|
if (info.showHelp) {
|
|
@@ -100177,7 +100382,7 @@ async function main() {
|
|
|
100177
100382
|
agentName: cfg.agentName,
|
|
100178
100383
|
platform: "node",
|
|
100179
100384
|
clientVersion: buildClientVersion2(
|
|
100180
|
-
true ? "0.4.
|
|
100385
|
+
true ? "0.4.4" : void 0
|
|
100181
100386
|
)
|
|
100182
100387
|
});
|
|
100183
100388
|
channelRef = channel;
|
package/package.json
CHANGED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { type BridgeConfig } from "../config.js";
|
|
2
|
-
import type { ReapResult } from "../reap.js";
|
|
3
|
-
import { type ServiceBackend } from "./backend.js";
|
|
4
|
-
export interface InstallOnReadyDeps {
|
|
5
|
-
entrypoint: string;
|
|
6
|
-
env: NodeJS.ProcessEnv;
|
|
7
|
-
backend?: ServiceBackend;
|
|
8
|
-
hasCreds?: (dataDir: string) => boolean;
|
|
9
|
-
/** Contents of the installed launcher, or undefined when none is installed. */
|
|
10
|
-
readLauncher?: (path: string) => string | undefined;
|
|
11
|
-
fenceAuthExists?: (fenceHome: string) => boolean;
|
|
12
|
-
/** Resolves when no turn is in flight (GrokSession.idle). See rule 2. */
|
|
13
|
-
waitForIdle?: () => Promise<void>;
|
|
14
|
-
/** Bound on that wait. The terminal coming back is the product promise, so a
|
|
15
|
-
* wedged turn must never hold the customer's shell open. */
|
|
16
|
-
idleTimeoutMs?: number;
|
|
17
|
-
/** The ONE teardown (src/reap.ts). Must complete before launchctl runs. */
|
|
18
|
-
reap: () => Promise<ReapResult>;
|
|
19
|
-
exit: (code: number) => void;
|
|
20
|
-
log: (msg: string) => void;
|
|
21
|
-
}
|
|
22
|
-
interface ReadyChannel {
|
|
23
|
-
on(ev: "ready", cb: () => void): unknown;
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* One-paste install: enrol in the foreground, hand off to the supervisor, exit —
|
|
27
|
-
* so the customer's terminal comes back and the agent survives a reboot.
|
|
28
|
-
*
|
|
29
|
-
* Four rules this module exists to enforce.
|
|
30
|
-
*
|
|
31
|
-
* 1. REFUSE BEFORE REAPING. Everything that can say no does so before anything is
|
|
32
|
-
* torn down. Refusing afterwards leaves the customer with an approved device,
|
|
33
|
-
* a spent invite token, and no running process — strictly worse than never
|
|
34
|
-
* having guarded at all.
|
|
35
|
-
*
|
|
36
|
-
* 2. REAP COMPLETELY, THEN BOOTSTRAP. `LaunchdBackend.install` runs bootout →
|
|
37
|
-
* poll-until-gone → bootstrap → kickstart synchronously, so the service is
|
|
38
|
-
* live the instant install returns. A partial teardown means two ACP sessions
|
|
39
|
-
* and two WebSockets on one device. `reap()` reports failure rather than
|
|
40
|
-
* swallowing it, and a failed reap is a refusal.
|
|
41
|
-
*
|
|
42
|
-
* 3. COMPARE, DON'T DETECT. `status().loaded` means only that a plist with this
|
|
43
|
-
* label exists. The old `install` subcommand never guarded its entrypoint
|
|
44
|
-
* (subcommand.ts), so a customer can hold a LOADED plist baked against a
|
|
45
|
-
* pruned npx cache; restarting that repairs nothing and reports success.
|
|
46
|
-
* Restart only when a service is loaded AND its baked entrypoint is the one we
|
|
47
|
-
* would install. Compare the ENTRYPOINT, never the whole launcher script —
|
|
48
|
-
* that embeds the install-time PATH and is volatile across shells.
|
|
49
|
-
*
|
|
50
|
-
* 4. VERIFY BEFORE CLAIMING. `backend.install` returns void, and launchd's
|
|
51
|
-
* implementation runs `kickstart` regardless of every `bootstrap` exit code.
|
|
52
|
-
* This log line is the customer's only feedback, so it comes after a
|
|
53
|
-
* `status()` that returned loaded:true.
|
|
54
|
-
*/
|
|
55
|
-
export declare function installOnReady(channel: ReadyChannel, cfg: BridgeConfig, deps: InstallOnReadyDeps): void;
|
|
56
|
-
export {};
|
|
57
|
-
//# sourceMappingURL=install-on-ready.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"install-on-ready.d.ts","sourceRoot":"","sources":["../../src/service/install-on-ready.ts"],"names":[],"mappings":"AAEA,OAAO,EAA4C,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AAC3F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAG7C,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAElE,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IACvB,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC;IACxC,+EAA+E;IAC/E,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IACpD,eAAe,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC;IACjD,yEAAyE;IACzE,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC;iEAC6D;IAC7D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,2EAA2E;IAC3E,IAAI,EAAE,MAAM,OAAO,CAAC,UAAU,CAAC,CAAC;IAChC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7B,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC5B;AAMD,UAAU,YAAY;IACpB,EAAE,CAAC,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC;CAC1C;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,YAAY,EACrB,GAAG,EAAE,YAAY,EACjB,IAAI,EAAE,kBAAkB,GACvB,IAAI,CAgHN"}
|