openmates 0.27.0-alpha.23 → 0.27.0-alpha.25
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/{chunk-NQP5QUVR.js → chunk-D476Y5AI.js} +909 -477
- package/dist/{cli-C2G3DpGo.d.ts → cli-CKbfUQGp.d.ts} +25 -3
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +1 -1
- package/dist/index.d.ts +8 -2
- package/dist/index.js +1 -1
- package/dist/ruleDocuments-6VMP2CV5.js +91 -0
- package/fixtures/privacy-runtime/linux-arm64/libggml-base.so +0 -0
- package/fixtures/privacy-runtime/linux-arm64/libggml-base.so.0 +0 -0
- package/fixtures/privacy-runtime/linux-arm64/libggml-base.so.0.15.1 +0 -0
- package/fixtures/privacy-runtime/linux-arm64/libggml-cpu.so +0 -0
- package/fixtures/privacy-runtime/linux-arm64/libggml-cpu.so.0 +0 -0
- package/fixtures/privacy-runtime/linux-arm64/libggml-cpu.so.0.15.1 +0 -0
- package/fixtures/privacy-runtime/linux-arm64/libggml.so +0 -0
- package/fixtures/privacy-runtime/linux-arm64/libggml.so.0 +0 -0
- package/fixtures/privacy-runtime/linux-arm64/libggml.so.0.15.1 +0 -0
- package/fixtures/privacy-runtime/linux-arm64/manifest.json +9 -9
- package/package.json +4 -3
|
@@ -194,8 +194,8 @@ import { chmodSync, closeSync, fsyncSync, mkdirSync, openSync, readFileSync, ren
|
|
|
194
194
|
import { join } from "path";
|
|
195
195
|
var digest = (value) => createHash("sha256").update(value).digest("hex");
|
|
196
196
|
var shortenTaskText = (value, length) => {
|
|
197
|
-
const
|
|
198
|
-
return
|
|
197
|
+
const text7 = value.replace(/\s+/g, " ").trim();
|
|
198
|
+
return text7.length <= length ? text7 : `${text7.slice(0, length - 1)}\u2026`;
|
|
199
199
|
};
|
|
200
200
|
function atomicPrivateFile(path2, content) {
|
|
201
201
|
const temporary = `${path2}.${randomUUID()}.tmp`;
|
|
@@ -403,7 +403,7 @@ async function lockTaskDeliveryRecord(directory, id) {
|
|
|
403
403
|
}
|
|
404
404
|
|
|
405
405
|
// src/taskMutationDelivery.ts
|
|
406
|
-
var digest2 = (
|
|
406
|
+
var digest2 = (text7) => createHash3("sha256").update(text7).digest("hex");
|
|
407
407
|
var stable = (value) => JSON.stringify(value, (_key, item) => item && !Array.isArray(item) && typeof item === "object" ? Object.fromEntries(Object.entries(item).sort(([a], [b]) => a.localeCompare(b))) : item);
|
|
408
408
|
function reconcileMutation(mutation, current) {
|
|
409
409
|
if (mutation.kind === "delete") {
|
|
@@ -692,7 +692,7 @@ async function readCodexThread(threadId, socketPath) {
|
|
|
692
692
|
codexResumeArguments({ provider: "codex", id: threadId });
|
|
693
693
|
const socket = socketPath ?? await daemonSocket();
|
|
694
694
|
if (!isAbsolute(socket) || socket.includes(":")) throw new Error("Codex requires an absolute local socket path.");
|
|
695
|
-
return new Promise((
|
|
695
|
+
return new Promise((resolve18, reject) => {
|
|
696
696
|
const ws = new WebSocket(`ws+unix://${socket}:/`, {
|
|
697
697
|
perMessageDeflate: false,
|
|
698
698
|
handshakeTimeout: CONNECTION_TIMEOUT_MS,
|
|
@@ -706,7 +706,7 @@ async function readCodexThread(threadId, socketPath) {
|
|
|
706
706
|
if (ws.readyState === WebSocket.OPEN) ws.close();
|
|
707
707
|
else if (ws.readyState !== WebSocket.CLOSED) ws.terminate();
|
|
708
708
|
if (error) reject(error);
|
|
709
|
-
else
|
|
709
|
+
else resolve18(value);
|
|
710
710
|
};
|
|
711
711
|
const timer = setTimeout(() => finish(new Error("Codex connection timed out.")), CONNECTION_TIMEOUT_MS);
|
|
712
712
|
ws.on("error", () => finish(new Error("Could not connect to the local Codex daemon.")));
|
|
@@ -747,10 +747,10 @@ async function resumeCodexTask(context) {
|
|
|
747
747
|
const args = codexResumeArguments(context);
|
|
748
748
|
if (!process.stdin.isTTY || !process.stdout.isTTY) throw new Error("Task resume requires an interactive terminal; status and connect never launch work.");
|
|
749
749
|
await readCodexThread(context.id);
|
|
750
|
-
await new Promise((
|
|
750
|
+
await new Promise((resolve18, reject) => {
|
|
751
751
|
const child = spawn("codex", args, { stdio: "inherit" });
|
|
752
752
|
child.once("error", () => reject(new Error("Could not open the installed Codex CLI.")));
|
|
753
|
-
child.once("exit", (code) => code === 0 ?
|
|
753
|
+
child.once("exit", (code) => code === 0 ? resolve18() : reject(new Error(`Codex resume exited with status ${code ?? "interrupted"}.`)));
|
|
754
754
|
});
|
|
755
755
|
}
|
|
756
756
|
function taskOwnerConflict(owner) {
|
|
@@ -766,10 +766,10 @@ function assertCodexClaimCaller(threadId, currentThread = process.env.CODEX_THRE
|
|
|
766
766
|
}
|
|
767
767
|
|
|
768
768
|
// ../secret-scanner/src/identifierRanges.ts
|
|
769
|
-
function codingIdentifierRanges(
|
|
769
|
+
function codingIdentifierRanges(text7) {
|
|
770
770
|
const ranges = [];
|
|
771
771
|
const identifiers2 = /\b[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}\b|\b[\da-f]{40,64}\b|\[[A-Z][A-Z\d_]*\]/gi;
|
|
772
|
-
for (const match of Array.from(
|
|
772
|
+
for (const match of Array.from(text7.matchAll(identifiers2))) {
|
|
773
773
|
ranges.push({ start: match.index, end: match.index + match[0].length });
|
|
774
774
|
}
|
|
775
775
|
return ranges;
|
|
@@ -1247,16 +1247,16 @@ var PII_TYPE_TO_CATEGORY = {
|
|
|
1247
1247
|
USER_AT_HOSTNAME: "user_at_hostname",
|
|
1248
1248
|
MAC_ADDRESS: "mac_addresses"
|
|
1249
1249
|
};
|
|
1250
|
-
function detectPII(
|
|
1250
|
+
function detectPII(text7, excludedIdsOrOptions = /* @__PURE__ */ new Set()) {
|
|
1251
1251
|
const options = excludedIdsOrOptions instanceof Set ? { excludedIds: excludedIdsOrOptions } : excludedIdsOrOptions;
|
|
1252
1252
|
const excludedIds = options.excludedIds ?? /* @__PURE__ */ new Set();
|
|
1253
1253
|
const disabledCategories = options.disabledCategories ?? /* @__PURE__ */ new Set();
|
|
1254
1254
|
const personalEntries = options.personalDataEntries ?? [];
|
|
1255
|
-
if (!
|
|
1255
|
+
if (!text7 || text7.length < MIN_PII_TEXT_LENGTH && personalEntries.length === 0)
|
|
1256
1256
|
return [];
|
|
1257
1257
|
const matches2 = [];
|
|
1258
1258
|
const coveredRanges = [];
|
|
1259
|
-
const identifierRanges = codingIdentifierRanges(
|
|
1259
|
+
const identifierRanges = codingIdentifierRanges(text7);
|
|
1260
1260
|
const typeCounts = {};
|
|
1261
1261
|
const hasExclusions = excludedIds.size > 0;
|
|
1262
1262
|
const hasDisabledCategories = disabledCategories.size > 0;
|
|
@@ -1264,14 +1264,14 @@ function detectPII(text6, excludedIdsOrOptions = /* @__PURE__ */ new Set()) {
|
|
|
1264
1264
|
const urlExclusionZones = [];
|
|
1265
1265
|
URL_EXCLUSION_REGEX.lastIndex = 0;
|
|
1266
1266
|
let urlMatch;
|
|
1267
|
-
while ((urlMatch = URL_EXCLUSION_REGEX.exec(
|
|
1267
|
+
while ((urlMatch = URL_EXCLUSION_REGEX.exec(text7)) !== null) {
|
|
1268
1268
|
urlExclusionZones.push({
|
|
1269
1269
|
start: urlMatch.index,
|
|
1270
1270
|
end: urlMatch.index + urlMatch[0].length
|
|
1271
1271
|
});
|
|
1272
1272
|
}
|
|
1273
1273
|
const hasUrlExclusions = urlExclusionZones.length > 0;
|
|
1274
|
-
if (
|
|
1274
|
+
if (text7.length >= MIN_PII_TEXT_LENGTH) {
|
|
1275
1275
|
for (const pattern of PII_PATTERNS) {
|
|
1276
1276
|
if (hasDisabledCategories) {
|
|
1277
1277
|
const category = PII_TYPE_TO_CATEGORY[pattern.type];
|
|
@@ -1279,7 +1279,7 @@ function detectPII(text6, excludedIdsOrOptions = /* @__PURE__ */ new Set()) {
|
|
|
1279
1279
|
}
|
|
1280
1280
|
pattern.regex.lastIndex = 0;
|
|
1281
1281
|
let regexMatch;
|
|
1282
|
-
while ((regexMatch = pattern.regex.exec(
|
|
1282
|
+
while ((regexMatch = pattern.regex.exec(text7)) !== null) {
|
|
1283
1283
|
const matchText = regexMatch[0];
|
|
1284
1284
|
const startIndex = regexMatch.index;
|
|
1285
1285
|
const endIndex = startIndex + matchText.length;
|
|
@@ -1325,7 +1325,7 @@ function detectPII(text6, excludedIdsOrOptions = /* @__PURE__ */ new Set()) {
|
|
|
1325
1325
|
}
|
|
1326
1326
|
}
|
|
1327
1327
|
for (const searchText of textsToSearch) {
|
|
1328
|
-
const lowerText =
|
|
1328
|
+
const lowerText = text7.toLowerCase();
|
|
1329
1329
|
const lowerSearch = searchText.toLowerCase();
|
|
1330
1330
|
let searchFrom = 0;
|
|
1331
1331
|
while (searchFrom < lowerText.length) {
|
|
@@ -1337,7 +1337,7 @@ function detectPII(text6, excludedIdsOrOptions = /* @__PURE__ */ new Set()) {
|
|
|
1337
1337
|
(range) => startIndex >= range.start && startIndex < range.end || endIndex > range.start && endIndex <= range.end || startIndex <= range.start && endIndex >= range.end
|
|
1338
1338
|
);
|
|
1339
1339
|
if (!overlaps) {
|
|
1340
|
-
const matchText =
|
|
1340
|
+
const matchText = text7.substring(startIndex, endIndex);
|
|
1341
1341
|
const matchId = `pii-PERSONAL_DATA-${entry.id}-${startIndex}`;
|
|
1342
1342
|
if (!hasExclusions || !excludedIds.has(matchId)) {
|
|
1343
1343
|
const placeholder = entry.replaceWith.startsWith("[") ? entry.replaceWith : `[${entry.replaceWith}]`;
|
|
@@ -1438,8 +1438,8 @@ var ProjectFilePrivacy = class {
|
|
|
1438
1438
|
}
|
|
1439
1439
|
if (this.values.size + this.conflicts.length > 1e4) fail("pii_mapping_limit");
|
|
1440
1440
|
}
|
|
1441
|
-
restoreText(
|
|
1442
|
-
return
|
|
1441
|
+
restoreText(text7) {
|
|
1442
|
+
return text7.replace(TOKEN, (token) => {
|
|
1443
1443
|
if (this.ambiguous.has(token)) fail("pii_mapping_ambiguous");
|
|
1444
1444
|
const mapping = this.values.get(token);
|
|
1445
1445
|
const customToken = this.options.detection?.personalDataEntries?.some((entry) => (entry.replaceWith.startsWith("[") ? entry.replaceWith : `[${entry.replaceWith}]`) === token);
|
|
@@ -1477,28 +1477,28 @@ var ProjectFilePrivacy = class {
|
|
|
1477
1477
|
this.addMappings([{ placeholder, original, type }]);
|
|
1478
1478
|
return placeholder;
|
|
1479
1479
|
}
|
|
1480
|
-
redactText(
|
|
1480
|
+
redactText(text7, enhanced = []) {
|
|
1481
1481
|
const ranges = [];
|
|
1482
|
-
const tokens = Array.from(
|
|
1482
|
+
const tokens = Array.from(text7.matchAll(TOKEN)).map((match) => ({ start: match.index, end: match.index + match[0].length }));
|
|
1483
1483
|
for (const range of tokens) {
|
|
1484
|
-
const literal =
|
|
1484
|
+
const literal = text7.slice(range.start, range.end);
|
|
1485
1485
|
if (!(this.options.preserveMappedTokens && this.values.has(literal)) && (this.values.has(literal) || GENERATED_TOKEN.test(literal) || legacyToken(literal))) ranges.push(range);
|
|
1486
1486
|
}
|
|
1487
1487
|
const overlaps = (start, end) => [...tokens, ...ranges].some((r) => start < r.end && end > r.start);
|
|
1488
1488
|
for (const mapping of Array.from(this.values.values()).sort((a, b) => b.original.length - a.original.length)) {
|
|
1489
|
-
let start =
|
|
1489
|
+
let start = text7.indexOf(mapping.original);
|
|
1490
1490
|
while (start !== -1) {
|
|
1491
1491
|
const end = start + mapping.original.length;
|
|
1492
1492
|
if (!overlaps(start, end)) ranges.push({ start, end, type: mapping.type });
|
|
1493
|
-
start =
|
|
1493
|
+
start = text7.indexOf(mapping.original, end);
|
|
1494
1494
|
}
|
|
1495
1495
|
}
|
|
1496
1496
|
if (this.options.enabled !== false) {
|
|
1497
|
-
for (const match of detectPII(
|
|
1497
|
+
for (const match of detectPII(text7, this.options.detection)) {
|
|
1498
1498
|
if (!overlaps(match.startIndex, match.endIndex)) ranges.push({ start: match.startIndex, end: match.endIndex, type: match.type });
|
|
1499
1499
|
}
|
|
1500
1500
|
for (const range of enhanced) {
|
|
1501
|
-
if (!Number.isInteger(range.start) || !Number.isInteger(range.end) || range.start < 0 || range.end <= range.start || range.end >
|
|
1501
|
+
if (!Number.isInteger(range.start) || !Number.isInteger(range.end) || range.start < 0 || range.end <= range.start || range.end > text7.length) fail("pii_invalid_semantic_range");
|
|
1502
1502
|
let fragments = [{ ...range }];
|
|
1503
1503
|
for (const shield of [...tokens, ...ranges]) fragments = fragments.flatMap((part) => {
|
|
1504
1504
|
if (part.start >= shield.end || part.end <= shield.start) return [part];
|
|
@@ -1513,11 +1513,11 @@ var ProjectFilePrivacy = class {
|
|
|
1513
1513
|
let cursor = 0;
|
|
1514
1514
|
let result = "";
|
|
1515
1515
|
for (const range of ranges.sort((a, b) => a.start - b.start)) {
|
|
1516
|
-
result +=
|
|
1517
|
-
result +=
|
|
1516
|
+
result += text7.slice(cursor, range.start);
|
|
1517
|
+
result += text7.slice(range.start, range.end).split(/(\r?\n)/).map((part) => !part || /^(?:\r?\n)$/.test(part) ? part : this.token(part, range.type)).join("");
|
|
1518
1518
|
cursor = range.end;
|
|
1519
1519
|
}
|
|
1520
|
-
return result +
|
|
1520
|
+
return result + text7.slice(cursor);
|
|
1521
1521
|
}
|
|
1522
1522
|
async redactResult(value) {
|
|
1523
1523
|
const visit2 = async (item) => {
|
|
@@ -1556,26 +1556,26 @@ var LABELS = {
|
|
|
1556
1556
|
private_date: { type: "OTHER", category: "birthdays" },
|
|
1557
1557
|
private_url: { type: "OTHER", category: "private_urls" }
|
|
1558
1558
|
};
|
|
1559
|
-
function convertNativePrivacyRanges(
|
|
1559
|
+
function convertNativePrivacyRanges(text7, spans, disabled = /* @__PURE__ */ new Set()) {
|
|
1560
1560
|
const offsets = /* @__PURE__ */ new Map([[0, 0]]);
|
|
1561
1561
|
let bytes2 = 0;
|
|
1562
1562
|
let units = 0;
|
|
1563
|
-
for (const character of
|
|
1563
|
+
for (const character of text7) {
|
|
1564
1564
|
if (character.length === 1 && /[\uD800-\uDFFF]/.test(character)) throw privacyError("privacy_invalid_unicode");
|
|
1565
1565
|
bytes2 += Buffer.byteLength(character);
|
|
1566
1566
|
units += character.length;
|
|
1567
1567
|
offsets.set(bytes2, units);
|
|
1568
1568
|
}
|
|
1569
|
-
const protectedRanges = codingIdentifierRanges(
|
|
1569
|
+
const protectedRanges = codingIdentifierRanges(text7);
|
|
1570
1570
|
const result = [];
|
|
1571
1571
|
for (const span of spans) {
|
|
1572
1572
|
const label3 = LABELS[span.label];
|
|
1573
1573
|
const start = offsets.get(span.start), end = offsets.get(span.end);
|
|
1574
1574
|
if (!label3 || !Number.isInteger(span.start) || !Number.isInteger(span.end) || start === void 0 || end === void 0 || end <= start) throw privacyError("privacy_invalid_semantic_range");
|
|
1575
1575
|
if (disabled.has(label3.category) || span.label === "secret" && disabled.has("api_keys")) continue;
|
|
1576
|
-
const context =
|
|
1576
|
+
const context = text7.slice(Math.max(0, start - 60), Math.min(text7.length, end + 60));
|
|
1577
1577
|
const explicitSecret = /\b(?:password|secret|credential|api[_ -]?key|token)\b/i.test(context);
|
|
1578
|
-
if (protectedRanges.some((r) => start < r.end && end > r.start) && !(span.label === "secret" && explicitSecret && !
|
|
1578
|
+
if (protectedRanges.some((r) => start < r.end && end > r.start) && !(span.label === "secret" && explicitSecret && !text7.slice(start, end).startsWith("["))) continue;
|
|
1579
1579
|
if ((span.label === "private_date" || span.label === "account_number") && /\b(?:commit|sha|hash|build|release|branch|timestamp|version)\b/i.test(context) && !/\b(?:birth|birthday|born|dob|account|iban)\b/i.test(context)) continue;
|
|
1580
1580
|
result.push({ start, end, type: label3.type });
|
|
1581
1581
|
}
|
|
@@ -1591,30 +1591,30 @@ function privacyDetectionOptions(memories) {
|
|
|
1591
1591
|
})
|
|
1592
1592
|
} };
|
|
1593
1593
|
}
|
|
1594
|
-
async function scanEnhancedText(
|
|
1594
|
+
async function scanEnhancedText(text7, scope2, disabled = /* @__PURE__ */ new Set(), progress) {
|
|
1595
1595
|
const preferences = await readPrivacyPreferences();
|
|
1596
|
-
if (!
|
|
1596
|
+
if (!text7 || !enhancedScopeEnabled(preferences, scope2)) return [];
|
|
1597
1597
|
try {
|
|
1598
1598
|
await ensurePrivacyDaemon();
|
|
1599
1599
|
const ranges = [];
|
|
1600
|
-
for (let start = 0; start <
|
|
1601
|
-
let from = Math.max(0, start - 1024), end = Math.min(
|
|
1602
|
-
if (from > 0 && /[\uDC00-\uDFFF]/.test(
|
|
1603
|
-
if (end <
|
|
1604
|
-
progress?.(start,
|
|
1605
|
-
const window =
|
|
1600
|
+
for (let start = 0; start < text7.length; start += 8192) {
|
|
1601
|
+
let from = Math.max(0, start - 1024), end = Math.min(text7.length, start + 9216);
|
|
1602
|
+
if (from > 0 && /[\uDC00-\uDFFF]/.test(text7[from])) from--;
|
|
1603
|
+
if (end < text7.length && /[\uDC00-\uDFFF]/.test(text7[end])) end++;
|
|
1604
|
+
progress?.(start, text7.length);
|
|
1605
|
+
const window = text7.slice(from, end);
|
|
1606
1606
|
const result = await privacyRpc({ op: "scan", text: window, scope: privacyProfile(), idleSeconds: preferences.idleSeconds });
|
|
1607
1607
|
if (!Array.isArray(result.spans)) throw privacyError("privacy_worker_protocol_failed");
|
|
1608
1608
|
ranges.push(...convertNativePrivacyRanges(window, result.spans, disabled).map((r) => ({ ...r, start: r.start + from, end: r.end + from })));
|
|
1609
1609
|
}
|
|
1610
|
-
progress?.(
|
|
1610
|
+
progress?.(text7.length, text7.length);
|
|
1611
1611
|
return ranges;
|
|
1612
1612
|
} catch (error) {
|
|
1613
1613
|
await stopPrivacyDaemon();
|
|
1614
1614
|
throw error;
|
|
1615
1615
|
}
|
|
1616
1616
|
}
|
|
1617
|
-
async function prepareCliMessagePrivacy(
|
|
1617
|
+
async function prepareCliMessagePrivacy(text7, memories, existing = [], scope2 = { kind: "message" }, progress) {
|
|
1618
1618
|
const options = privacyDetectionOptions(memories);
|
|
1619
1619
|
let mappings = existing;
|
|
1620
1620
|
const privacy = new ProjectFilePrivacy({
|
|
@@ -1626,7 +1626,7 @@ async function prepareCliMessagePrivacy(text6, memories, existing = [], scope2 =
|
|
|
1626
1626
|
},
|
|
1627
1627
|
detectEnhanced: (value) => scanEnhancedText(value, scope2, options.detection.disabledCategories, progress)
|
|
1628
1628
|
});
|
|
1629
|
-
const message = await privacy.redactResult(
|
|
1629
|
+
const message = await privacy.redactResult(text7);
|
|
1630
1630
|
return { message, mappings: mappings.map((mapping) => ({ ...mapping, type: mapping.type ?? "OTHER" })) };
|
|
1631
1631
|
}
|
|
1632
1632
|
|
|
@@ -2246,7 +2246,7 @@ async function parseOpenCodeImportBuffer(payload, sourceName = "opencode-session
|
|
|
2246
2246
|
if (role !== "user" && role !== "assistant") continue;
|
|
2247
2247
|
const parts = Array.isArray(message.parts) ? message.parts.filter((part) => Boolean(part && typeof part === "object")) : [];
|
|
2248
2248
|
const textParts = parts.filter((part) => part.type === "text" && part.ignored !== true && typeof part.text === "string");
|
|
2249
|
-
const content = textParts.map((part) => String(part.text)).filter((
|
|
2249
|
+
const content = textParts.map((part) => String(part.text)).filter((text7) => text7.trim()).join("\n");
|
|
2250
2250
|
if (content.trim()) {
|
|
2251
2251
|
const time2 = messageInfo.time && typeof messageInfo.time === "object" ? messageInfo.time : {};
|
|
2252
2252
|
messages.push({
|
|
@@ -2994,12 +2994,12 @@ function createProjectFileJobExecutor(options) {
|
|
|
2994
2994
|
mutation = validateProjectFileMutation({ ...job.arguments, operation: job.operation, operation_id: job.operation_id });
|
|
2995
2995
|
if (context.privacy) mutation = context.privacy.restoreMutation(mutation);
|
|
2996
2996
|
if (!context.writeMode) throw Object.assign(new Error(), { code: "write_policy_required" });
|
|
2997
|
-
const
|
|
2998
|
-
proposalCommitment =
|
|
2999
|
-
if (context.writeMode === "always_ask" && approved.get(job.operation_id) !==
|
|
2997
|
+
const digest4 = await projectFileMutationDigest(context.projectKey, job.project_id, job.chat_id, mutation);
|
|
2998
|
+
proposalCommitment = digest4;
|
|
2999
|
+
if (context.writeMode === "always_ask" && approved.get(job.operation_id) !== digest4) {
|
|
3000
3000
|
const approvalRequest = { projectId: job.project_id, chatId: job.chat_id, mutation };
|
|
3001
3001
|
const proposal = context.privacy ? await context.privacy.redactResult(mutation) : mutation;
|
|
3002
|
-
await result("awaiting_approval", { proposal_commitment:
|
|
3002
|
+
await result("awaiting_approval", { proposal_commitment: digest4, proposal });
|
|
3003
3003
|
leaseReleased = true;
|
|
3004
3004
|
options.onWaitingForUser?.(approvalRequest);
|
|
3005
3005
|
if (!options.requestApproval) return;
|
|
@@ -3009,8 +3009,8 @@ function createProjectFileJobExecutor(options) {
|
|
|
3009
3009
|
await options.send("project_file_operation_reject", scope(job));
|
|
3010
3010
|
return;
|
|
3011
3011
|
}
|
|
3012
|
-
await options.approve(approvalRequest,
|
|
3013
|
-
approved.set(job.operation_id,
|
|
3012
|
+
await options.approve(approvalRequest, digest4);
|
|
3013
|
+
approved.set(job.operation_id, digest4);
|
|
3014
3014
|
processing.delete(job.operation_id);
|
|
3015
3015
|
await options.send("project_file_operation_claim", scope(job));
|
|
3016
3016
|
return;
|
|
@@ -3401,10 +3401,10 @@ async function projectFileContentHash(content) {
|
|
|
3401
3401
|
async function hostedProjectFileIdentity(projectKey, path2, kind) {
|
|
3402
3402
|
const normalized = normalizeHostedProjectPath(path2);
|
|
3403
3403
|
const key = await crypto.subtle.importKey("raw", new Uint8Array(projectKey).buffer, { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
|
|
3404
|
-
const
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
const hex = Array.from(
|
|
3404
|
+
const digest4 = new Uint8Array(await crypto.subtle.sign("HMAC", key, bytes(JSON.stringify(["openmates-hosted-file-v1", kind, normalized])))).slice(0, 16);
|
|
3405
|
+
digest4[6] = digest4[6] & 15 | 80;
|
|
3406
|
+
digest4[8] = digest4[8] & 63 | 128;
|
|
3407
|
+
const hex = Array.from(digest4, (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
3408
3408
|
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
3409
3409
|
}
|
|
3410
3410
|
function textContent(head) {
|
|
@@ -3623,8 +3623,8 @@ async function executeHostedProjectFileJob(adapter, job, mutation) {
|
|
|
3623
3623
|
if (!mutation) failure("invalid_file_mutation");
|
|
3624
3624
|
const creating = mutation.operation === "create_file";
|
|
3625
3625
|
const embedId = found[0]?.embedId ?? await hostedProjectFileIdentity(adapter.projectKey, path2, "embed");
|
|
3626
|
-
const
|
|
3627
|
-
const receipt = await adapter.receipt(embedId, job,
|
|
3626
|
+
const digest4 = await projectFileMutationDigest(adapter.projectKey, adapter.projectId, job.chat_id, mutation);
|
|
3627
|
+
const receipt = await adapter.receipt(embedId, job, digest4);
|
|
3628
3628
|
if (receipt?.status === "committed") return { path: path2, operation_id: job.operation_id, revision: receipt.current_revision, idempotent: true };
|
|
3629
3629
|
if (creating && found[0]) failure("file_exists");
|
|
3630
3630
|
if (!creating && !found[0]) failure("file_not_found");
|
|
@@ -3662,7 +3662,7 @@ async function executeHostedProjectFileJob(adapter, job, mutation) {
|
|
|
3662
3662
|
embed_id: embedId,
|
|
3663
3663
|
project_id: adapter.projectId,
|
|
3664
3664
|
chat_id: job.chat_id,
|
|
3665
|
-
proposal_digest:
|
|
3665
|
+
proposal_digest: digest4,
|
|
3666
3666
|
expected_revision: current?.revision ?? 0,
|
|
3667
3667
|
...adapter.teamId ? { team_id: adapter.teamId } : {},
|
|
3668
3668
|
head: { encrypted_content: await adapter.encrypt(await adapter.encodeContent(contentObject), embedKey), encrypted_text_preview: await adapter.encrypt(`${path2} (${content.split("\n").length} lines)`, embedKey), status: "finished", updated_at: now },
|
|
@@ -3913,8 +3913,8 @@ async function activateCliProjectFocus(client2, projectId, chatId, teamId, activ
|
|
|
3913
3913
|
const key = await client2.decryptProjectKey(detail.project, context);
|
|
3914
3914
|
if (!settings.encrypted_settings || settings.selection_required) throw new Error("Choose this Project's write policy in Project settings before starting work.");
|
|
3915
3915
|
if (isCurrent && !isCurrent()) return;
|
|
3916
|
-
const
|
|
3917
|
-
const focus =
|
|
3916
|
+
const text7 = await decryptWithAesGcmCombined(settings.encrypted_settings, key);
|
|
3917
|
+
const focus = text7 ? JSON.parse(text7).default_focus : void 0;
|
|
3918
3918
|
if (!focus?.focus_id || typeof focus.instructions !== "string") throw new Error("The Project's default focus is unavailable.");
|
|
3919
3919
|
if (isCurrent && !isCurrent()) return;
|
|
3920
3920
|
await client2.activateProjectFocus(projectId, {
|
|
@@ -3956,10 +3956,10 @@ function registerCliProjectFileExecutor(options) {
|
|
|
3956
3956
|
send: (event, payload) => options.ws.sendAsync(event, payload),
|
|
3957
3957
|
requestApproval: options.requestApproval,
|
|
3958
3958
|
requestReadApproval: options.requestReadApproval,
|
|
3959
|
-
approve: async (request,
|
|
3959
|
+
approve: async (request, digest4) => {
|
|
3960
3960
|
const focus = await options.client.getActiveProjectFocus(request.chatId);
|
|
3961
3961
|
if (focus?.project_id !== request.projectId) throw Object.assign(new Error(), { code: "project_focus_required" });
|
|
3962
|
-
await options.client.approveProjectWrite(request.projectId, { chat_id: request.chatId, operation_id: request.mutation.operation_id, proposal_digest:
|
|
3962
|
+
await options.client.approveProjectWrite(request.projectId, { chat_id: request.chatId, operation_id: request.mutation.operation_id, proposal_digest: digest4 }, { teamId: focus.team_id, personal: !focus.team_id });
|
|
3963
3963
|
},
|
|
3964
3964
|
resolve: async (job) => {
|
|
3965
3965
|
const focus = await options.client.getActiveProjectFocus(job.chat_id);
|
|
@@ -3979,7 +3979,7 @@ function registerCliProjectFileExecutor(options) {
|
|
|
3979
3979
|
key: options.chatKey,
|
|
3980
3980
|
mappings: [...history.messages.flatMap((message) => message.piiMappings ?? []), ...options.piiMappings ?? []],
|
|
3981
3981
|
...detection,
|
|
3982
|
-
detectEnhanced: (
|
|
3982
|
+
detectEnhanced: (text7) => scanEnhancedText(text7, { kind: "project", projectId: job.project_id }, detection.detection.disabledCategories),
|
|
3983
3983
|
read: async () => {
|
|
3984
3984
|
try {
|
|
3985
3985
|
return await readFile(path2, "utf8");
|
|
@@ -4062,7 +4062,7 @@ function registerCliProjectFileExecutor(options) {
|
|
|
4062
4062
|
return files;
|
|
4063
4063
|
},
|
|
4064
4064
|
readHead: (embedId) => options.client.readEncryptedProjectFile(job.project_id, embedId, projectKey, context),
|
|
4065
|
-
receipt: (embedId, receiptJob,
|
|
4065
|
+
receipt: (embedId, receiptJob, digest4) => options.client.getProjectFileRevisionReceipt(job.project_id, embedId, receiptJob.operation_id, receiptJob.chat_id, digest4, context),
|
|
4066
4066
|
commit: async (payload) => {
|
|
4067
4067
|
const requestId = randomUUID5();
|
|
4068
4068
|
const pending = options.ws.waitForMessage("commit_embed_revision_result", (value) => value.request_id === requestId, 3e4);
|
|
@@ -4174,11 +4174,11 @@ function matchEnabledRemoteCommandPreset(options) {
|
|
|
4174
4174
|
for (const preset of options.config.presets) {
|
|
4175
4175
|
if (options.presetId && preset.id !== options.presetId) continue;
|
|
4176
4176
|
if (!preset.commands.some((command) => stableJson(command) === stableJson(options.policy))) continue;
|
|
4177
|
-
const
|
|
4177
|
+
const digest4 = remoteCommandPresetDigest(options.config, preset.id);
|
|
4178
4178
|
const active = options.activeGrants.some(
|
|
4179
|
-
(grant) => grant.enabled === true && grant.project_id === options.projectId && grant.preset_id === preset.id && grant.definition_digest ===
|
|
4179
|
+
(grant) => grant.enabled === true && grant.project_id === options.projectId && grant.preset_id === preset.id && grant.definition_digest === digest4
|
|
4180
4180
|
);
|
|
4181
|
-
if (active) return { presetId: preset.id, definitionDigest:
|
|
4181
|
+
if (active) return { presetId: preset.id, definitionDigest: digest4 };
|
|
4182
4182
|
}
|
|
4183
4183
|
return null;
|
|
4184
4184
|
}
|
|
@@ -4432,13 +4432,13 @@ var RemoteCommandOutputAccumulator = class {
|
|
|
4432
4432
|
return { text: this.#text, coverage: "full", sequence_gap: false, upstream_truncated: false, omitted_chars: 0 };
|
|
4433
4433
|
}
|
|
4434
4434
|
const half = Math.max(0, Math.floor((MAX_COMPLETION_CHARS - OMISSION_MARKER.length) / 2));
|
|
4435
|
-
const
|
|
4435
|
+
const text7 = this.#text.length <= MAX_COMPLETION_CHARS ? this.#text : `${this.#text.slice(0, half)}${OMISSION_MARKER}${this.#text.slice(-half)}`;
|
|
4436
4436
|
return {
|
|
4437
|
-
text:
|
|
4437
|
+
text: text7,
|
|
4438
4438
|
coverage: "selected_excerpt",
|
|
4439
4439
|
sequence_gap: this.#sequenceGap,
|
|
4440
4440
|
upstream_truncated: true,
|
|
4441
|
-
omitted_chars: Math.max(0, this.#inputChars -
|
|
4441
|
+
omitted_chars: Math.max(0, this.#inputChars - text7.length + (text7.includes(OMISSION_MARKER) ? OMISSION_MARKER.length : 0))
|
|
4442
4442
|
};
|
|
4443
4443
|
}
|
|
4444
4444
|
};
|
|
@@ -4700,8 +4700,8 @@ async function remoteCommandPortableRequestDigest(projectKey, request) {
|
|
|
4700
4700
|
assertProjectKey(projectKey);
|
|
4701
4701
|
const identity2 = JSON.stringify(["openmates-remote-command-request-v1", canonicalPortableRemoteCommandRequest(request)]);
|
|
4702
4702
|
const key = await cryptoApi2.subtle.importKey("raw", new Uint8Array(projectKey).buffer, { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
|
|
4703
|
-
const
|
|
4704
|
-
return Buffer.from(
|
|
4703
|
+
const digest4 = await cryptoApi2.subtle.sign("HMAC", key, new TextEncoder().encode(identity2));
|
|
4704
|
+
return Buffer.from(digest4).toString("base64url");
|
|
4705
4705
|
}
|
|
4706
4706
|
function validateApproval(value) {
|
|
4707
4707
|
if (value.kind === "one_run") return;
|
|
@@ -4996,14 +4996,14 @@ var OpenMatesWsClient = class {
|
|
|
4996
4996
|
});
|
|
4997
4997
|
}
|
|
4998
4998
|
async open(timeoutMs = 1e4) {
|
|
4999
|
-
await new Promise((
|
|
4999
|
+
await new Promise((resolve18, reject) => {
|
|
5000
5000
|
const timeout = setTimeout(
|
|
5001
5001
|
() => reject(new Error("WebSocket open timeout")),
|
|
5002
5002
|
timeoutMs
|
|
5003
5003
|
);
|
|
5004
5004
|
this.socket.once("open", () => {
|
|
5005
5005
|
clearTimeout(timeout);
|
|
5006
|
-
|
|
5006
|
+
resolve18();
|
|
5007
5007
|
});
|
|
5008
5008
|
this.socket.once("error", (error) => {
|
|
5009
5009
|
clearTimeout(timeout);
|
|
@@ -5068,10 +5068,10 @@ var OpenMatesWsClient = class {
|
|
|
5068
5068
|
}
|
|
5069
5069
|
}
|
|
5070
5070
|
sendAsync(type, payload) {
|
|
5071
|
-
return new Promise((
|
|
5071
|
+
return new Promise((resolve18, reject) => {
|
|
5072
5072
|
this.socket.send(JSON.stringify({ type, payload }), (error) => {
|
|
5073
5073
|
if (error) reject(error);
|
|
5074
|
-
else
|
|
5074
|
+
else resolve18();
|
|
5075
5075
|
});
|
|
5076
5076
|
});
|
|
5077
5077
|
}
|
|
@@ -5139,9 +5139,9 @@ var OpenMatesWsClient = class {
|
|
|
5139
5139
|
return () => this.socket.off("message", onMessage);
|
|
5140
5140
|
}
|
|
5141
5141
|
waitForClose() {
|
|
5142
|
-
return new Promise((
|
|
5142
|
+
return new Promise((resolve18) => {
|
|
5143
5143
|
this.socket.once("close", (code, reason) => {
|
|
5144
|
-
|
|
5144
|
+
resolve18({ code, reason: reason.toString("utf-8") });
|
|
5145
5145
|
});
|
|
5146
5146
|
});
|
|
5147
5147
|
}
|
|
@@ -5236,7 +5236,7 @@ var OpenMatesWsClient = class {
|
|
|
5236
5236
|
if (this.recoveryOutputDiscoveryError) throw this.recoveryOutputDiscoveryError;
|
|
5237
5237
|
}
|
|
5238
5238
|
waitForMessage(expectedType, predicate, timeoutMs = 2e4) {
|
|
5239
|
-
return new Promise((
|
|
5239
|
+
return new Promise((resolve18, reject) => {
|
|
5240
5240
|
const seenTypes = /* @__PURE__ */ new Set();
|
|
5241
5241
|
let predicateMisses = 0;
|
|
5242
5242
|
const onMessage = (rawData) => {
|
|
@@ -5258,7 +5258,7 @@ var OpenMatesWsClient = class {
|
|
|
5258
5258
|
return;
|
|
5259
5259
|
}
|
|
5260
5260
|
cleanup();
|
|
5261
|
-
|
|
5261
|
+
resolve18(parsed);
|
|
5262
5262
|
} catch {
|
|
5263
5263
|
}
|
|
5264
5264
|
};
|
|
@@ -5296,7 +5296,7 @@ var OpenMatesWsClient = class {
|
|
|
5296
5296
|
* Used by ensureSynced to consume the full phased-sync event stream.
|
|
5297
5297
|
*/
|
|
5298
5298
|
collectMessages(terminatorType, timeoutMs = 9e4) {
|
|
5299
|
-
return new Promise((
|
|
5299
|
+
return new Promise((resolve18, reject) => {
|
|
5300
5300
|
const collected = [];
|
|
5301
5301
|
const onMessage = (rawData) => {
|
|
5302
5302
|
try {
|
|
@@ -5309,7 +5309,7 @@ var OpenMatesWsClient = class {
|
|
|
5309
5309
|
}
|
|
5310
5310
|
if (parsed.type === terminatorType) {
|
|
5311
5311
|
cleanup();
|
|
5312
|
-
|
|
5312
|
+
resolve18(collected);
|
|
5313
5313
|
return;
|
|
5314
5314
|
}
|
|
5315
5315
|
collected.push(parsed);
|
|
@@ -5322,7 +5322,7 @@ var OpenMatesWsClient = class {
|
|
|
5322
5322
|
};
|
|
5323
5323
|
const onClose = () => {
|
|
5324
5324
|
cleanup();
|
|
5325
|
-
|
|
5325
|
+
resolve18(collected);
|
|
5326
5326
|
};
|
|
5327
5327
|
const timeout = setTimeout(() => {
|
|
5328
5328
|
cleanup();
|
|
@@ -5360,7 +5360,7 @@ var OpenMatesWsClient = class {
|
|
|
5360
5360
|
const timeoutMs = options?.timeoutMs ?? 9e4;
|
|
5361
5361
|
const onStream = options?.onStream;
|
|
5362
5362
|
const asyncEmbedWaitMs = options?.asyncEmbedWaitMs ?? DEFAULT_ASYNC_EMBED_WAIT_MS;
|
|
5363
|
-
return new Promise((
|
|
5363
|
+
return new Promise((resolve18, reject) => {
|
|
5364
5364
|
let latestContent = "";
|
|
5365
5365
|
let messageId = null;
|
|
5366
5366
|
let taskId = null;
|
|
@@ -5454,8 +5454,8 @@ var OpenMatesWsClient = class {
|
|
|
5454
5454
|
if (!content || typeof content !== "object") return "";
|
|
5455
5455
|
try {
|
|
5456
5456
|
const root = content;
|
|
5457
|
-
const
|
|
5458
|
-
return typeof
|
|
5457
|
+
const text7 = root.content?.[0]?.content?.[0]?.text;
|
|
5458
|
+
return typeof text7 === "string" ? text7 : "";
|
|
5459
5459
|
} catch {
|
|
5460
5460
|
return "";
|
|
5461
5461
|
}
|
|
@@ -5469,7 +5469,7 @@ var OpenMatesWsClient = class {
|
|
|
5469
5469
|
if (waitingForUserPayload) {
|
|
5470
5470
|
if (pendingSubChatHandlers.size > 0) return;
|
|
5471
5471
|
cleanup();
|
|
5472
|
-
|
|
5472
|
+
resolve18({
|
|
5473
5473
|
status: "waiting_for_user",
|
|
5474
5474
|
messageId,
|
|
5475
5475
|
taskId,
|
|
@@ -5506,7 +5506,7 @@ var OpenMatesWsClient = class {
|
|
|
5506
5506
|
if (processingEmbedIds.size > 0 && !asyncEmbedTimer) {
|
|
5507
5507
|
asyncEmbedTimer = setTimeout(() => {
|
|
5508
5508
|
cleanup();
|
|
5509
|
-
|
|
5509
|
+
resolve18({
|
|
5510
5510
|
status: "completed",
|
|
5511
5511
|
messageId,
|
|
5512
5512
|
taskId,
|
|
@@ -5538,7 +5538,7 @@ var OpenMatesWsClient = class {
|
|
|
5538
5538
|
}
|
|
5539
5539
|
if (processingEmbedIds.size > 0) return;
|
|
5540
5540
|
cleanup();
|
|
5541
|
-
|
|
5541
|
+
resolve18({
|
|
5542
5542
|
status: "completed",
|
|
5543
5543
|
messageId,
|
|
5544
5544
|
taskId,
|
|
@@ -5955,7 +5955,7 @@ var OpenMatesWsClient = class {
|
|
|
5955
5955
|
const onClose = () => {
|
|
5956
5956
|
if (aiResponseDone && pendingProjectOperations.size === 0 && !awaitingUnidentifiedAsyncContinuation) {
|
|
5957
5957
|
cleanup();
|
|
5958
|
-
|
|
5958
|
+
resolve18({
|
|
5959
5959
|
status: "completed",
|
|
5960
5960
|
messageId,
|
|
5961
5961
|
taskId,
|
|
@@ -6010,29 +6010,55 @@ var OpenMatesWsClient = class {
|
|
|
6010
6010
|
}
|
|
6011
6011
|
};
|
|
6012
6012
|
|
|
6013
|
+
// ../ui/src/utils/loadedMemoryReceipt.ts
|
|
6014
|
+
var digest3 = /^[a-f0-9]{64}$/;
|
|
6015
|
+
var text3 = (value, max) => typeof value === "string" && !!value.trim() && value.length <= max;
|
|
6016
|
+
function parseMemoriesLoadedEvent(value) {
|
|
6017
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
6018
|
+
const event = value;
|
|
6019
|
+
if (event.type !== "memories_loaded" || typeof event.set_key !== "string" || !digest3.test(event.set_key) || !Array.isArray(event.memories) || !event.memories.length || event.memories.length > 24 || event.count !== event.memories.length) return null;
|
|
6020
|
+
const ids = /* @__PURE__ */ new Set();
|
|
6021
|
+
let size = 0;
|
|
6022
|
+
for (const entry of event.memories) {
|
|
6023
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry)) return null;
|
|
6024
|
+
const m = entry;
|
|
6025
|
+
if (!text3(m.id, 240) || ids.has(m.id) || !text3(m.title, 180) || !text3(m.body, 2e4) || typeof m.revision !== "string" || !digest3.test(m.revision)) return null;
|
|
6026
|
+
if (m.source === "app") {
|
|
6027
|
+
if (!text3(m.app_id, 64) || !/^[a-z][a-z0-9_]*$/.test(m.app_id) || !m.id.startsWith(`app:${m.app_id}:`) || m.project_id != null) return null;
|
|
6028
|
+
} else if (m.source === "project") {
|
|
6029
|
+
if (!text3(m.project_id, 240) || m.app_id != null) return null;
|
|
6030
|
+
} else return null;
|
|
6031
|
+
ids.add(m.id);
|
|
6032
|
+
size += m.body.length;
|
|
6033
|
+
if (size > 32e3) return null;
|
|
6034
|
+
}
|
|
6035
|
+
return event;
|
|
6036
|
+
}
|
|
6037
|
+
|
|
6013
6038
|
// src/chatContextEvents.ts
|
|
6014
6039
|
var DIRECTION_CORRECTION_NOTICE = "Chat is drifting too far away from the goals. Correction instruction was sent.";
|
|
6015
|
-
function
|
|
6040
|
+
function text4(value, limit) {
|
|
6016
6041
|
return typeof value === "string" && value.length > 0 && value.length <= limit;
|
|
6017
6042
|
}
|
|
6018
6043
|
function parseChatContextEvent(value, chatId) {
|
|
6019
6044
|
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
6020
6045
|
const event = value;
|
|
6021
|
-
if (!
|
|
6046
|
+
if (!text4(event.event_id, 128) || !Number.isSafeInteger(event.created_at) || Number(event.created_at) < 0 || chatId && event.chat_id !== void 0 && event.chat_id !== chatId) return null;
|
|
6047
|
+
if (event.type === "memories_loaded") return parseMemoriesLoadedEvent(event);
|
|
6022
6048
|
if (event.type === "rules_loaded") {
|
|
6023
|
-
if (!
|
|
6049
|
+
if (!text4(event.set_key, 128) || !Array.isArray(event.rules) || !event.rules.length || event.rules.length > 24 || event.count !== event.rules.length) return null;
|
|
6024
6050
|
const ids = /* @__PURE__ */ new Set();
|
|
6025
6051
|
let bodyChars = 0;
|
|
6026
6052
|
for (const rule of event.rules) {
|
|
6027
|
-
if (!rule || typeof rule !== "object" || !
|
|
6053
|
+
if (!rule || typeof rule !== "object" || !text4(rule.id, 128) || ids.has(rule.id) || !text4(rule.title, 200) || !["app", "personal", "project"].includes(rule.source) || !text4(rule.revision, 128) || !text4(rule.body, 32e3)) return null;
|
|
6028
6054
|
ids.add(rule.id);
|
|
6029
6055
|
bodyChars += rule.body.length;
|
|
6030
6056
|
}
|
|
6031
6057
|
if (bodyChars > 32e3) return null;
|
|
6032
6058
|
} else if (event.type === "chat_direction_correction") {
|
|
6033
|
-
if (event.notice !== DIRECTION_CORRECTION_NOTICE || !
|
|
6059
|
+
if (event.notice !== DIRECTION_CORRECTION_NOTICE || !text4(event.instruction, 8500) || !text4(event.delivery_id, 128)) return null;
|
|
6034
6060
|
} else if (event.type === "project_authoring_recommendation") {
|
|
6035
|
-
if (!
|
|
6061
|
+
if (!text4(event.recommendation_id, 128) || !text4(event.project_id, 128) || !["focus", "workflow"].includes(String(event.kind)) || !["create", "update"].includes(String(event.action)) || event.action === "update" && (!text4(event.target_id, 128) || !text4(event.expected_revision, 128)) || event.action === "create" && event.kind !== "focus") return null;
|
|
6036
6062
|
} else return null;
|
|
6037
6063
|
return event;
|
|
6038
6064
|
}
|
|
@@ -6044,12 +6070,12 @@ function parseChatContextContent(content) {
|
|
|
6044
6070
|
}
|
|
6045
6071
|
}
|
|
6046
6072
|
function chatContextSummary(event) {
|
|
6047
|
-
if (event.type === "rules_loaded") return `Loaded ${event.count}
|
|
6073
|
+
if (event.type === "memories_loaded" || event.type === "rules_loaded") return `Loaded ${event.count} memories`;
|
|
6048
6074
|
if (event.type === "chat_direction_correction") return DIRECTION_CORRECTION_NOTICE;
|
|
6049
6075
|
return `${event.action === "create" ? "Create" : "Update"} Project ${event.kind === "focus" ? "Focus" : "Workflow"}${event.title ? `: ${event.title}` : ""}`;
|
|
6050
6076
|
}
|
|
6051
6077
|
function chatContextDetails(event) {
|
|
6052
|
-
if (event.type === "rules_loaded") return event.rules.flatMap((rule) => [
|
|
6078
|
+
if (event.type === "memories_loaded" || event.type === "rules_loaded") return (event.type === "memories_loaded" ? event.memories : event.rules).flatMap((rule) => [
|
|
6053
6079
|
rule.title,
|
|
6054
6080
|
`${rule.source}${rule.project_id ? ` \xB7 Project ${rule.project_id}` : rule.app_id ? ` \xB7 ${rule.app_id}` : ""} \xB7 revision ${rule.revision}`,
|
|
6055
6081
|
"",
|
|
@@ -6072,7 +6098,7 @@ function registerChatContextEvents(options) {
|
|
|
6072
6098
|
const persist = (event) => {
|
|
6073
6099
|
if (seen.has(event.event_id)) return;
|
|
6074
6100
|
seen.add(event.event_id);
|
|
6075
|
-
if (event.type === "rules_loaded") {
|
|
6101
|
+
if (event.type === "memories_loaded" || event.type === "rules_loaded") {
|
|
6076
6102
|
if (event.set_key === previousRulesSetKey) return;
|
|
6077
6103
|
previousRulesSetKey = event.set_key;
|
|
6078
6104
|
}
|
|
@@ -6120,12 +6146,12 @@ function object(value) {
|
|
|
6120
6146
|
function keys(value, allowed) {
|
|
6121
6147
|
if (Object.keys(value).some((key) => !allowed.includes(key))) invalid();
|
|
6122
6148
|
}
|
|
6123
|
-
function
|
|
6149
|
+
function text5(value, limit) {
|
|
6124
6150
|
if (typeof value !== "string" || !value.trim() || value.length > limit) return invalid();
|
|
6125
6151
|
return value;
|
|
6126
6152
|
}
|
|
6127
6153
|
function identifier3(value, canonical) {
|
|
6128
|
-
const result =
|
|
6154
|
+
const result = text5(value, canonical ? 64 : 80);
|
|
6129
6155
|
if (!(canonical ? /^[a-z][a-z0-9_-]{0,63}$/ : /^[a-zA-Z0-9_-]{1,80}$/).test(result)) invalid();
|
|
6130
6156
|
return result;
|
|
6131
6157
|
}
|
|
@@ -6139,10 +6165,10 @@ function projectFocusDocumentFromMetadata(metadata, body) {
|
|
|
6139
6165
|
const hints = [header2.when_to_use, header2.preprocessor_hint, header2["preprocessor-hint"]].filter((value) => value !== void 0);
|
|
6140
6166
|
if (names.length !== 1 || hints.length !== 1) invalid();
|
|
6141
6167
|
const common = {
|
|
6142
|
-
name:
|
|
6143
|
-
description:
|
|
6144
|
-
when_to_use:
|
|
6145
|
-
instructions:
|
|
6168
|
+
name: text5(names[0], 200),
|
|
6169
|
+
description: text5(header2.description, 2e3),
|
|
6170
|
+
when_to_use: text5(hints[0], 2e3),
|
|
6171
|
+
instructions: text5(body.trim(), 64e3)
|
|
6146
6172
|
};
|
|
6147
6173
|
const phases = header2.phases === void 0 ? [] : header2.phases;
|
|
6148
6174
|
if (!Array.isArray(phases) || phases.length > 16) invalid();
|
|
@@ -6159,15 +6185,15 @@ function projectFocusDocumentFromMetadata(metadata, body) {
|
|
|
6159
6185
|
if (requirement.type !== void 0 && (typeof requirement.type !== "string" || !["semantic", "user_confirmation"].includes(requirement.type))) invalid();
|
|
6160
6186
|
return {
|
|
6161
6187
|
id: identifier3(requirement.id, true),
|
|
6162
|
-
text:
|
|
6188
|
+
text: text5(requirement.text, 4e3),
|
|
6163
6189
|
...requirement.type === void 0 ? {} : { type: requirement.type }
|
|
6164
6190
|
};
|
|
6165
6191
|
});
|
|
6166
6192
|
unique(gates.map((gate) => gate.id));
|
|
6167
6193
|
return {
|
|
6168
6194
|
id: identifier3(phase.id, true),
|
|
6169
|
-
title:
|
|
6170
|
-
instructions:
|
|
6195
|
+
title: text5(phase.title, 200),
|
|
6196
|
+
instructions: text5(phase.instructions, 16e3),
|
|
6171
6197
|
requirements: gates
|
|
6172
6198
|
};
|
|
6173
6199
|
});
|
|
@@ -6177,7 +6203,7 @@ function projectFocusDocumentFromMetadata(metadata, body) {
|
|
|
6177
6203
|
const legacy = phases.map((raw) => {
|
|
6178
6204
|
const phase = object(raw);
|
|
6179
6205
|
keys(phase, ["id", "name", "instructions"]);
|
|
6180
|
-
return { id: identifier3(phase.id, false), name:
|
|
6206
|
+
return { id: identifier3(phase.id, false), name: text5(phase.name, 120), instructions: text5(phase.instructions, 16e3) };
|
|
6181
6207
|
});
|
|
6182
6208
|
unique(legacy.map((phase) => phase.id));
|
|
6183
6209
|
return { ...common, phases: legacy };
|
|
@@ -6216,7 +6242,7 @@ async function discoverCliProjectCandidates(client2, options) {
|
|
|
6216
6242
|
}));
|
|
6217
6243
|
return entries.filter((entry) => entry !== null);
|
|
6218
6244
|
}
|
|
6219
|
-
async function loadActiveCliProjectContext(client2, chatId,
|
|
6245
|
+
async function loadActiveCliProjectContext(client2, chatId, text7) {
|
|
6220
6246
|
const active = await client2.getActiveProjectFocus(chatId);
|
|
6221
6247
|
if (!active) return {};
|
|
6222
6248
|
const options = { teamId: active.team_id, personal: !active.team_id };
|
|
@@ -6238,9 +6264,9 @@ async function loadActiveCliProjectContext(client2, chatId, text6) {
|
|
|
6238
6264
|
const metadataText = await decryptWithAesGcmCombined(item.encrypted_metadata, key);
|
|
6239
6265
|
const metadata = metadataText ? JSON.parse(metadataText) : {};
|
|
6240
6266
|
const path2 = typeof (metadata.path ?? metadata.display_path) === "string" ? String(metadata.path ?? metadata.display_path) : "";
|
|
6241
|
-
const match = /^\.openmates\/(rules|focuses|specs|facts)\/[^\0]+(?:\.md|\/SKILL\.md)$/.exec(path2);
|
|
6267
|
+
const match = /^\.openmates\/(memories|rules|focuses|specs|facts)\/[^\0]+(?:\.md|\/SKILL\.md)$/.exec(path2);
|
|
6242
6268
|
if (!match || path2.split("/").some((part) => part === ".." || part === "." || !part)) continue;
|
|
6243
|
-
const kind = { rules: "rule", focuses: "focus", specs: "spec", facts: "
|
|
6269
|
+
const kind = { memories: "memory", rules: "rule", focuses: "focus", specs: "spec", facts: "memory" }[match[1]];
|
|
6244
6270
|
const title = metadata.focus_title ?? metadata.title ?? metadata.name;
|
|
6245
6271
|
const description = metadata.focus_description ?? metadata.summary ?? metadata.description;
|
|
6246
6272
|
const currentRevision = revision(item);
|
|
@@ -6272,9 +6298,9 @@ async function loadActiveCliProjectContext(client2, chatId, text6) {
|
|
|
6272
6298
|
if (title && description) candidates.push({ kind: "folder", id: folder.folder_id, title: title.slice(0, 200), description: description.slice(0, 640), when_to_use: "", revision: revision(folder) });
|
|
6273
6299
|
}
|
|
6274
6300
|
let selected = [];
|
|
6275
|
-
if (
|
|
6301
|
+
if (text7?.trim() && candidates.length) selected = await client2.selectProjectContext(
|
|
6276
6302
|
active.project_id,
|
|
6277
|
-
{ chat_id: chatId, text:
|
|
6303
|
+
{ chat_id: chatId, text: text7.slice(0, 8e3), candidates: candidates.slice(0, 24) },
|
|
6278
6304
|
options
|
|
6279
6305
|
);
|
|
6280
6306
|
const specialistId = active.specialist_focus_id?.startsWith(`project-focus:${active.project_id}:`) ? active.specialist_focus_id.split(":")[2] : active.specialist_focus_id;
|
|
@@ -6302,7 +6328,7 @@ async function loadActiveCliProjectContext(client2, chatId, text6) {
|
|
|
6302
6328
|
if (typeof document !== "string" || document.length > (candidate.kind === "focus" ? 6e4 : 24e3) || totalChars + document.length > 64e3) continue;
|
|
6303
6329
|
totalChars += document.length;
|
|
6304
6330
|
if (candidate.kind === "focus") result.project_focus_documents.push({ item_id: candidate.id, document, revision: candidate.revision });
|
|
6305
|
-
else if (candidate.kind === "rule") result.custom_rule_documents.push({ id: candidate.id, source: "project", project_id: active.project_id, document });
|
|
6331
|
+
else if (candidate.kind === "rule") result.custom_rule_documents.push({ id: candidate.id, source: "project", project_id: active.project_id, document, item_revision: candidate.revision });
|
|
6306
6332
|
else result.project_context_documents.push({ item_id: candidate.id, kind: candidate.kind, title: candidate.title, description: candidate.description, document, revision: candidate.revision });
|
|
6307
6333
|
}
|
|
6308
6334
|
const [fresh, latest] = await Promise.all([client2.getActiveProjectFocus(chatId), client2.getProject(active.project_id, options)]);
|
|
@@ -6419,25 +6445,20 @@ async function collectRelatedCliTaskContext(client2, chatId, options, records, n
|
|
|
6419
6445
|
}
|
|
6420
6446
|
return candidates;
|
|
6421
6447
|
}
|
|
6422
|
-
async function prepareCliJevContext(client2, chatId, options, supplied = {},
|
|
6448
|
+
async function prepareCliJevContext(client2, chatId, options, supplied = {}, text7) {
|
|
6423
6449
|
let candidates = [];
|
|
6424
6450
|
let active = {};
|
|
6425
6451
|
let tasks = [];
|
|
6426
6452
|
let ownedTaskRecords = [];
|
|
6427
|
-
let personalRules = [];
|
|
6428
6453
|
await Promise.all([
|
|
6429
6454
|
discoverCliProjectCandidates(client2, options).then((value) => {
|
|
6430
6455
|
candidates = value;
|
|
6431
6456
|
}).catch(() => {
|
|
6432
6457
|
}),
|
|
6433
|
-
loadActiveCliProjectContext(client2, chatId,
|
|
6458
|
+
loadActiveCliProjectContext(client2, chatId, text7).then((value) => {
|
|
6434
6459
|
active = value;
|
|
6435
6460
|
}).catch(() => {
|
|
6436
6461
|
}),
|
|
6437
|
-
client2.getCustomRuleDocuments().then((value) => {
|
|
6438
|
-
personalRules = value;
|
|
6439
|
-
}).catch(() => {
|
|
6440
|
-
}),
|
|
6441
6462
|
(async () => {
|
|
6442
6463
|
const records = await client2.listUserTasks({ ...options, limit: 500 });
|
|
6443
6464
|
ownedTaskRecords = records;
|
|
@@ -6457,9 +6478,9 @@ async function prepareCliJevContext(client2, chatId, options, supplied = {}, tex
|
|
|
6457
6478
|
const customDocuments = [];
|
|
6458
6479
|
let documentChars = 0;
|
|
6459
6480
|
const documentIds = /* @__PURE__ */ new Set();
|
|
6460
|
-
for (const rule of [...
|
|
6481
|
+
for (const rule of [...loaded.custom_rule_documents ?? [], ...supplied.custom_memory_documents ?? supplied.custom_rule_documents ?? []]) {
|
|
6461
6482
|
const identity2 = `${rule.source}:${rule.project_id ?? ""}:${rule.id}`;
|
|
6462
|
-
if (rule.source
|
|
6483
|
+
if (rule.source !== "project" || rule.project_id !== current?.project_id || typeof rule.document !== "string" || rule.document.length > 24e3 || documentChars + rule.document.length > 64e3 || documentIds.has(identity2) || customDocuments.length >= 24) continue;
|
|
6463
6484
|
documentChars += rule.document.length;
|
|
6464
6485
|
documentIds.add(identity2);
|
|
6465
6486
|
customDocuments.push(rule);
|
|
@@ -6468,7 +6489,7 @@ async function prepareCliJevContext(client2, chatId, options, supplied = {}, tex
|
|
|
6468
6489
|
accepted_plan_context: acceptedPlan,
|
|
6469
6490
|
project_focus_candidates: (supplied.project_focus_candidates ?? candidates).slice(0, 40),
|
|
6470
6491
|
related_task_candidates: (supplied.related_task_candidates ?? tasks).slice(0, 24),
|
|
6471
|
-
|
|
6492
|
+
custom_memory_documents: customDocuments,
|
|
6472
6493
|
project_focus_catalog: current ? (supplied.project_focus_catalog ?? loaded.project_focus_catalog ?? []).slice(0, 20) : [],
|
|
6473
6494
|
project_focus_documents: current ? (supplied.project_focus_documents ?? loaded.project_focus_documents ?? []).slice(0, 20) : [],
|
|
6474
6495
|
project_context_documents: current ? (supplied.project_context_documents ?? loaded.project_context_documents ?? []).slice(0, 20) : []
|
|
@@ -6493,8 +6514,8 @@ function registerProjectFocusCountdown(options) {
|
|
|
6493
6514
|
const projectId = focusId.slice("project-".length);
|
|
6494
6515
|
let finish = () => {
|
|
6495
6516
|
};
|
|
6496
|
-
const done = new Promise((
|
|
6497
|
-
finish =
|
|
6517
|
+
const done = new Promise((resolve18) => {
|
|
6518
|
+
finish = resolve18;
|
|
6498
6519
|
});
|
|
6499
6520
|
const entry = { requestId, timer: null, cancelled: false, done, finish };
|
|
6500
6521
|
current = entry;
|
|
@@ -6635,8 +6656,8 @@ async function startCliProjectAuthoring(client2, recommendation, history) {
|
|
|
6635
6656
|
const key = await client2.decryptProjectKey(detail.project, options);
|
|
6636
6657
|
for (const item of detail.items.filter((item2) => item2.item_type === "workflow" && !item2.deleted_target_state)) {
|
|
6637
6658
|
if (await decryptWithAesGcmCombined(item.target_id_encrypted, key) !== recommendation.target_id) continue;
|
|
6638
|
-
const
|
|
6639
|
-
const metadata =
|
|
6659
|
+
const text7 = item.encrypted_metadata ? await decryptWithAesGcmCombined(item.encrypted_metadata, key) : null;
|
|
6660
|
+
const metadata = text7 ? JSON.parse(text7) : {};
|
|
6640
6661
|
if (metadata.remote_workflow_file && typeof metadata.remote_workflow_file === "object") remoteBinding = metadata.remote_workflow_file;
|
|
6641
6662
|
break;
|
|
6642
6663
|
}
|
|
@@ -7310,8 +7331,8 @@ function parseDelimitedLine(line, delimiter) {
|
|
|
7310
7331
|
cells2.push(current);
|
|
7311
7332
|
return cells2;
|
|
7312
7333
|
}
|
|
7313
|
-
function delimitedTextToMarkdownTable(
|
|
7314
|
-
const rows2 =
|
|
7334
|
+
function delimitedTextToMarkdownTable(text7, delimiter) {
|
|
7335
|
+
const rows2 = text7.split(/\r?\n/).map((line) => line.trimEnd()).filter((line) => line.length > 0).map((line) => parseDelimitedLine(line, delimiter));
|
|
7315
7336
|
if (rows2.length === 0) return "";
|
|
7316
7337
|
const maxCols = Math.max(...rows2.map((row) => row.length));
|
|
7317
7338
|
const normalized = rows2.map((row) => {
|
|
@@ -7358,7 +7379,7 @@ async function docxBufferToHtml(buffer) {
|
|
|
7358
7379
|
const zip = await JSZip2.loadAsync(buffer);
|
|
7359
7380
|
const documentXml = await zip.file("word/document.xml")?.async("string");
|
|
7360
7381
|
if (!documentXml) return "";
|
|
7361
|
-
const paragraphs = getXmlBlocks(documentXml, "p").map(getTextFromDocxParagraph).map((
|
|
7382
|
+
const paragraphs = getXmlBlocks(documentXml, "p").map(getTextFromDocxParagraph).map((text7) => text7.trim()).filter(Boolean);
|
|
7362
7383
|
return paragraphs.map((paragraph) => `<p>${escapeHtml(paragraph)}</p>`).join("\n");
|
|
7363
7384
|
}
|
|
7364
7385
|
function columnLettersToIndex(letters) {
|
|
@@ -8197,8 +8218,8 @@ function splitLongParagraph(paragraph) {
|
|
|
8197
8218
|
if (remainder) chunks.push(remainder);
|
|
8198
8219
|
return chunks;
|
|
8199
8220
|
}
|
|
8200
|
-
function fallback(
|
|
8201
|
-
if (!language.toLowerCase().startsWith("de")) return
|
|
8221
|
+
function fallback(text7, language) {
|
|
8222
|
+
if (!language.toLowerCase().startsWith("de")) return text7;
|
|
8202
8223
|
const german = {
|
|
8203
8224
|
"Search results are available.": "Suchergebnisse sind verf\xFCgbar.",
|
|
8204
8225
|
"I used the News Search skill.": "Ich habe die News-Suche verwendet.",
|
|
@@ -8207,7 +8228,7 @@ function fallback(text6, language) {
|
|
|
8207
8228
|
"A code example is available.": "Ein Codebeispiel ist verf\xFCgbar.",
|
|
8208
8229
|
"A table is available.": "Eine Tabelle ist verf\xFCgbar."
|
|
8209
8230
|
};
|
|
8210
|
-
return german[
|
|
8231
|
+
return german[text7] ?? text7;
|
|
8211
8232
|
}
|
|
8212
8233
|
function projectFence(markdown, language) {
|
|
8213
8234
|
const body = markdown.replace(/^```[^\n]*\n|\n?```$/g, "").trim();
|
|
@@ -8289,8 +8310,8 @@ function rejectProtonCredentialFlags(argsOrFlags) {
|
|
|
8289
8310
|
throw new Error(`${rejected.split("=")[0]} is not allowed. Bridge credentials must be read privately from Proton Bridge or a hidden prompt.`);
|
|
8290
8311
|
}
|
|
8291
8312
|
}
|
|
8292
|
-
function redactProtonBridgeSecrets(
|
|
8293
|
-
return
|
|
8313
|
+
function redactProtonBridgeSecrets(text7) {
|
|
8314
|
+
return text7.replace(CREDENTIAL_VALUE_RE, "$1<redacted>");
|
|
8294
8315
|
}
|
|
8295
8316
|
function containsCredentialLikeField(value) {
|
|
8296
8317
|
return containsCredentialLikeKey(value);
|
|
@@ -8420,7 +8441,7 @@ function validateProtonBridgeCredentials(credentials) {
|
|
|
8420
8441
|
}
|
|
8421
8442
|
async function validateProtonBridgeImap(credentials, timeoutMs = DEFAULT_IMAP_TIMEOUT_MS) {
|
|
8422
8443
|
validateProtonBridgeCredentials(credentials);
|
|
8423
|
-
await new Promise((
|
|
8444
|
+
await new Promise((resolve18, reject) => {
|
|
8424
8445
|
const socket = connectTcp({ host: credentials.imapHost, port: credentials.imapPort });
|
|
8425
8446
|
const timer = setTimeout(() => {
|
|
8426
8447
|
socket.destroy();
|
|
@@ -8429,7 +8450,7 @@ async function validateProtonBridgeImap(credentials, timeoutMs = DEFAULT_IMAP_TI
|
|
|
8429
8450
|
socket.once("connect", () => {
|
|
8430
8451
|
clearTimeout(timer);
|
|
8431
8452
|
socket.end();
|
|
8432
|
-
|
|
8453
|
+
resolve18();
|
|
8433
8454
|
});
|
|
8434
8455
|
socket.once("error", (error) => {
|
|
8435
8456
|
clearTimeout(timer);
|
|
@@ -8606,8 +8627,8 @@ async function localConnectorRequestLoop(client2, params) {
|
|
|
8606
8627
|
const ws = await client2.openLocalConnectorWebSocket();
|
|
8607
8628
|
const sendQueue = new ProtonDelayedSendQueue();
|
|
8608
8629
|
let resolveOnce = null;
|
|
8609
|
-
const onceHandled = new Promise((
|
|
8610
|
-
resolveOnce =
|
|
8630
|
+
const onceHandled = new Promise((resolve18) => {
|
|
8631
|
+
resolveOnce = resolve18;
|
|
8611
8632
|
});
|
|
8612
8633
|
const removeListener = ws.onLocalConnectorRequest((request) => {
|
|
8613
8634
|
void handleLocalConnectorRequest(client2, request, params, sendQueue).finally(() => {
|
|
@@ -8675,8 +8696,8 @@ async function handleLocalConnectorRequest(client2, request, params, sendQueue)
|
|
|
8675
8696
|
}
|
|
8676
8697
|
async function waitForAbort(signal) {
|
|
8677
8698
|
if (signal.aborted) return;
|
|
8678
|
-
await new Promise((
|
|
8679
|
-
signal.addEventListener("abort", () =>
|
|
8699
|
+
await new Promise((resolve18) => {
|
|
8700
|
+
signal.addEventListener("abort", () => resolve18(), { once: true });
|
|
8680
8701
|
});
|
|
8681
8702
|
}
|
|
8682
8703
|
async function searchProtonBridgeImap(credentials, arguments_) {
|
|
@@ -8687,7 +8708,7 @@ async function searchProtonBridgeImap(credentials, arguments_) {
|
|
|
8687
8708
|
const limit = clampLimit(arguments_.limit);
|
|
8688
8709
|
const imap = await openTextSocket(credentials.imapHost, credentials.imapPort, IMAP_COMMAND_TIMEOUT_MS);
|
|
8689
8710
|
try {
|
|
8690
|
-
await imap.readUntil((
|
|
8711
|
+
await imap.readUntil((text7) => /^\* OK/im.test(text7));
|
|
8691
8712
|
await imap.command(`LOGIN ${quoteImap(credentials.imapUsername)} ${quoteImap(credentials.imapPassword)}`);
|
|
8692
8713
|
await imap.command(`SELECT ${quoteImap(mailbox)}`);
|
|
8693
8714
|
const searchResponse = await imap.command(buildImapSearchCommand({ query, startDate, endDate }));
|
|
@@ -8735,22 +8756,22 @@ async function sendProtonBridgeSmtp(credentials, payload) {
|
|
|
8735
8756
|
const messageId = `<om-${randomUUID7()}@local.openmates>`;
|
|
8736
8757
|
const smtp = await openTextSocket(credentials.smtpHost, credentials.smtpPort, SMTP_COMMAND_TIMEOUT_MS);
|
|
8737
8758
|
try {
|
|
8738
|
-
await smtp.readUntil((
|
|
8739
|
-
await smtp.rawCommand("EHLO openmates.local", (
|
|
8759
|
+
await smtp.readUntil((text7) => /^220[ -]/m.test(text7));
|
|
8760
|
+
await smtp.rawCommand("EHLO openmates.local", (text7) => /^250\s/m.test(text7), /^250[ -]/m);
|
|
8740
8761
|
const auth = Buffer.from(`\0${credentials.smtpUsername || credentials.imapUsername}\0${credentials.smtpPassword || credentials.imapPassword}`).toString("base64");
|
|
8741
8762
|
try {
|
|
8742
|
-
await smtp.rawCommand(`AUTH PLAIN ${auth}`, (
|
|
8763
|
+
await smtp.rawCommand(`AUTH PLAIN ${auth}`, (text7) => /^235[ -]/m.test(text7), /^235[ -]/m);
|
|
8743
8764
|
} catch {
|
|
8744
8765
|
throw new Error("Local SMTP authentication failed.");
|
|
8745
8766
|
}
|
|
8746
|
-
await smtp.rawCommand(`MAIL FROM:<${from}>`, (
|
|
8767
|
+
await smtp.rawCommand(`MAIL FROM:<${from}>`, (text7) => /^250[ -]/m.test(text7), /^250[ -]/m);
|
|
8747
8768
|
for (const recipient of to) {
|
|
8748
|
-
await smtp.rawCommand(`RCPT TO:<${recipient}>`, (
|
|
8769
|
+
await smtp.rawCommand(`RCPT TO:<${recipient}>`, (text7) => /^250[ -]/m.test(text7), /^250[ -]/m);
|
|
8749
8770
|
}
|
|
8750
|
-
await smtp.rawCommand("DATA", (
|
|
8771
|
+
await smtp.rawCommand("DATA", (text7) => /^354[ -]/m.test(text7), /^354[ -]/m);
|
|
8751
8772
|
await smtp.rawCommand(`${buildSmtpMessage({ from, to, subject, bodyText, messageId })}\r
|
|
8752
|
-
.`, (
|
|
8753
|
-
await smtp.rawCommand("QUIT", (
|
|
8773
|
+
.`, (text7) => /^250[ -]/m.test(text7), /^250[ -]/m);
|
|
8774
|
+
await smtp.rawCommand("QUIT", (text7) => /^221[ -]/m.test(text7), /^221[ -]/m).catch(() => void 0);
|
|
8754
8775
|
return { provider: PROTON_BRIDGE_PROVIDER_ID, message_id: messageId, delivered: true };
|
|
8755
8776
|
} finally {
|
|
8756
8777
|
smtp.close();
|
|
@@ -8838,14 +8859,14 @@ async function openTextSocket(host, port, timeoutMs) {
|
|
|
8838
8859
|
socket.on("data", (chunk) => {
|
|
8839
8860
|
buffer += String(chunk);
|
|
8840
8861
|
});
|
|
8841
|
-
await new Promise((
|
|
8862
|
+
await new Promise((resolve18, reject) => {
|
|
8842
8863
|
const timer = setTimeout(() => {
|
|
8843
8864
|
socket.destroy();
|
|
8844
8865
|
reject(new Error(`Timed out connecting to ${host}:${port}.`));
|
|
8845
8866
|
}, timeoutMs);
|
|
8846
8867
|
socket.once("connect", () => {
|
|
8847
8868
|
clearTimeout(timer);
|
|
8848
|
-
|
|
8869
|
+
resolve18();
|
|
8849
8870
|
});
|
|
8850
8871
|
socket.once("error", (error) => {
|
|
8851
8872
|
clearTimeout(timer);
|
|
@@ -8862,7 +8883,7 @@ async function openTextSocket(host, port, timeoutMs) {
|
|
|
8862
8883
|
buffer = "";
|
|
8863
8884
|
socket.write(`${tag} ${command}\r
|
|
8864
8885
|
`);
|
|
8865
|
-
const response = await waitForSocketText(socket, () => buffer, (
|
|
8886
|
+
const response = await waitForSocketText(socket, () => buffer, (text7) => marker.test(text7), timeoutMs);
|
|
8866
8887
|
if (expected && !expected.test(response)) {
|
|
8867
8888
|
throw new Error(`Local mail command failed: ${redactProtonBridgeSecrets(response.split(/\r?\n/).slice(-2).join(" "))}`);
|
|
8868
8889
|
}
|
|
@@ -8885,11 +8906,11 @@ async function openTextSocket(host, port, timeoutMs) {
|
|
|
8885
8906
|
};
|
|
8886
8907
|
}
|
|
8887
8908
|
async function waitForSocketText(socket, getBuffer, done, timeoutMs) {
|
|
8888
|
-
return await new Promise((
|
|
8909
|
+
return await new Promise((resolve18, reject) => {
|
|
8889
8910
|
const timer = setTimeout(() => cleanup(() => reject(new Error("Timed out waiting for local mail server response."))), timeoutMs);
|
|
8890
8911
|
const check = () => {
|
|
8891
|
-
const
|
|
8892
|
-
if (done(
|
|
8912
|
+
const text7 = getBuffer();
|
|
8913
|
+
if (done(text7)) cleanup(() => resolve18(text7));
|
|
8893
8914
|
};
|
|
8894
8915
|
const onData = () => check();
|
|
8895
8916
|
const onError = (error) => cleanup(() => reject(error));
|
|
@@ -8914,7 +8935,7 @@ function startProtonBridgeProcess(command, args) {
|
|
|
8914
8935
|
if (child.exitCode !== null || child.killed) return;
|
|
8915
8936
|
child.kill("SIGTERM");
|
|
8916
8937
|
await Promise.race([
|
|
8917
|
-
new Promise((
|
|
8938
|
+
new Promise((resolve18) => child.once("exit", () => resolve18())),
|
|
8918
8939
|
sleep(2e3).then(() => {
|
|
8919
8940
|
if (child.exitCode === null && !child.killed) child.kill("SIGKILL");
|
|
8920
8941
|
})
|
|
@@ -9013,7 +9034,7 @@ async function captureOrPromptBridgeCredentials(command, args) {
|
|
|
9013
9034
|
}
|
|
9014
9035
|
}
|
|
9015
9036
|
async function captureProtonBridgeInfo(command, args) {
|
|
9016
|
-
return await new Promise((
|
|
9037
|
+
return await new Promise((resolve18, reject) => {
|
|
9017
9038
|
const child = spawn2(command, args, { stdio: "pipe" });
|
|
9018
9039
|
let output = "";
|
|
9019
9040
|
let errorOutput = "";
|
|
@@ -9033,7 +9054,7 @@ async function captureProtonBridgeInfo(command, args) {
|
|
|
9033
9054
|
});
|
|
9034
9055
|
child.once("exit", () => {
|
|
9035
9056
|
clearTimeout(timer);
|
|
9036
|
-
if (output.trim())
|
|
9057
|
+
if (output.trim()) resolve18(output);
|
|
9037
9058
|
else reject(new Error(redactProtonBridgeSecrets(errorOutput || "Proton Bridge info produced no output.")));
|
|
9038
9059
|
});
|
|
9039
9060
|
child.stdin.write("info\nquit\n");
|
|
@@ -9063,11 +9084,11 @@ async function promptHidden(prompt) {
|
|
|
9063
9084
|
const wasRaw = stdin.isRaw === true;
|
|
9064
9085
|
stdin.setRawMode(true);
|
|
9065
9086
|
stdin.resume();
|
|
9066
|
-
return await new Promise((
|
|
9087
|
+
return await new Promise((resolve18, reject) => {
|
|
9067
9088
|
let value = "";
|
|
9068
9089
|
const onData = (chunk) => {
|
|
9069
|
-
const
|
|
9070
|
-
for (const char of
|
|
9090
|
+
const text7 = chunk.toString("utf8");
|
|
9091
|
+
for (const char of text7) {
|
|
9071
9092
|
if (char === "") {
|
|
9072
9093
|
cleanup();
|
|
9073
9094
|
reject(new Error("Bridge credential prompt cancelled."));
|
|
@@ -9076,7 +9097,7 @@ async function promptHidden(prompt) {
|
|
|
9076
9097
|
if (char === "\r" || char === "\n") {
|
|
9077
9098
|
cleanup();
|
|
9078
9099
|
stderr.write("\n");
|
|
9079
|
-
|
|
9100
|
+
resolve18(value);
|
|
9080
9101
|
return;
|
|
9081
9102
|
}
|
|
9082
9103
|
if (char === "\x7F" || char === "\b") {
|
|
@@ -9646,8 +9667,8 @@ function parseUserFlows(value) {
|
|
|
9646
9667
|
}
|
|
9647
9668
|
function deriveShortId(record8) {
|
|
9648
9669
|
const source = record8.plan_id || `${record8.created_at ?? ""}-${record8.updated_at ?? ""}`;
|
|
9649
|
-
const
|
|
9650
|
-
return `${DEFAULT_PLAN_PREFIX}-${
|
|
9670
|
+
const digest4 = createHash12("sha256").update(source).digest("hex").slice(0, 6).toUpperCase();
|
|
9671
|
+
return `${DEFAULT_PLAN_PREFIX}-${digest4}`;
|
|
9651
9672
|
}
|
|
9652
9673
|
function nowSeconds() {
|
|
9653
9674
|
return Math.floor(Date.now() / 1e3);
|
|
@@ -9781,8 +9802,8 @@ async function hashPairSecret(secret) {
|
|
|
9781
9802
|
const bytes2 = decodeBase64url(secret, 32);
|
|
9782
9803
|
if (bytes2.length !== 32) throw new Error("Invalid pairing secret");
|
|
9783
9804
|
try {
|
|
9784
|
-
const
|
|
9785
|
-
return [...
|
|
9805
|
+
const digest4 = new Uint8Array(await crypto.subtle.digest("SHA-256", ownedBuffer(bytes2)));
|
|
9806
|
+
return [...digest4].map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
9786
9807
|
} finally {
|
|
9787
9808
|
bytes2.fill(0);
|
|
9788
9809
|
}
|
|
@@ -10360,6 +10381,13 @@ async function buildSubChatEncryptedMetadataPayloads(params) {
|
|
|
10360
10381
|
return payloads;
|
|
10361
10382
|
}
|
|
10362
10383
|
var MEMORY_TYPE_REGISTRY = {
|
|
10384
|
+
"openmates/memories": {
|
|
10385
|
+
appId: "openmates",
|
|
10386
|
+
itemType: "memories",
|
|
10387
|
+
entryType: "list",
|
|
10388
|
+
required: ["title", "document"],
|
|
10389
|
+
properties: { title: { type: "string" }, document: { type: "string" } }
|
|
10390
|
+
},
|
|
10363
10391
|
"books/favorite_books": {
|
|
10364
10392
|
appId: "books",
|
|
10365
10393
|
itemType: "favorite_books",
|
|
@@ -10769,8 +10797,8 @@ var MATE_NAMES = {
|
|
|
10769
10797
|
general_knowledge: "George",
|
|
10770
10798
|
onboarding_support: "Suki"
|
|
10771
10799
|
};
|
|
10772
|
-
function stripLegacySuggestionPrefix(
|
|
10773
|
-
return
|
|
10800
|
+
function stripLegacySuggestionPrefix(text7) {
|
|
10801
|
+
return text7.replace(/^\s*\[[^\]]+\]\s*/, "").trim();
|
|
10774
10802
|
}
|
|
10775
10803
|
var CLOUD_API_URL = "https://api.openmates.org";
|
|
10776
10804
|
var DEFAULT_API_URL = process.env.OPENMATES_API_URL ?? CLOUD_API_URL;
|
|
@@ -13496,7 +13524,7 @@ var OpenMatesClient = class _OpenMatesClient {
|
|
|
13496
13524
|
}
|
|
13497
13525
|
async requestAssistantSpeechMessage(ws, chatId, messageId, segments2) {
|
|
13498
13526
|
const timeoutMs = 10 * 60 * 1e3;
|
|
13499
|
-
return await new Promise((
|
|
13527
|
+
return await new Promise((resolve18, reject) => {
|
|
13500
13528
|
const expected = /* @__PURE__ */ new Set();
|
|
13501
13529
|
const queued = /* @__PURE__ */ new Set();
|
|
13502
13530
|
const terminal = /* @__PURE__ */ new Map();
|
|
@@ -13505,7 +13533,7 @@ var OpenMatesClient = class _OpenMatesClient {
|
|
|
13505
13533
|
if (!accepted || expected.size === 0 || terminal.size !== expected.size) return;
|
|
13506
13534
|
cleanup();
|
|
13507
13535
|
const statuses = [...terminal.values()];
|
|
13508
|
-
|
|
13536
|
+
resolve18({
|
|
13509
13537
|
generated: statuses.filter((status) => status.status === "ready" && queued.has(String(status.segment_id))).length,
|
|
13510
13538
|
reused: statuses.filter((status) => status.status === "ready" && !queued.has(String(status.segment_id))).length,
|
|
13511
13539
|
failed: statuses.filter((status) => status.status === "error").length,
|
|
@@ -15007,8 +15035,8 @@ var OpenMatesClient = class _OpenMatesClient {
|
|
|
15007
15035
|
}
|
|
15008
15036
|
let dispatchHandlersReady = () => {
|
|
15009
15037
|
};
|
|
15010
|
-
const handlersReady = new Promise((
|
|
15011
|
-
dispatchHandlersReady =
|
|
15038
|
+
const handlersReady = new Promise((resolve18) => {
|
|
15039
|
+
dispatchHandlersReady = resolve18;
|
|
15012
15040
|
});
|
|
15013
15041
|
let precollectedResponse = params.precollectResponse && params.incognito && shouldWaitForAi ? ws.collectAiResponse(messageId, chatId, { onStream: params.onStream, timeoutMs: params.responseTimeoutMs }) : null;
|
|
15014
15042
|
if (!params.incognito && chatKeyBytes && encryptedChatKey) {
|
|
@@ -15597,7 +15625,7 @@ var OpenMatesClient = class _OpenMatesClient {
|
|
|
15597
15625
|
);
|
|
15598
15626
|
const remainingMs = claimRetryDeadline - Date.now();
|
|
15599
15627
|
if (remainingMs <= claimRetryDelayMs) throw error;
|
|
15600
|
-
await new Promise((
|
|
15628
|
+
await new Promise((resolve18) => setTimeout(resolve18, claimRetryDelayMs));
|
|
15601
15629
|
claimRetryDelayMs = Math.min(claimRetryDelayMs * 2, 2e3);
|
|
15602
15630
|
} finally {
|
|
15603
15631
|
stopWatchingErrors();
|
|
@@ -16452,13 +16480,13 @@ var OpenMatesClient = class _OpenMatesClient {
|
|
|
16452
16480
|
);
|
|
16453
16481
|
} catch (error) {
|
|
16454
16482
|
lastTransientError = error instanceof Error ? error.message : String(error);
|
|
16455
|
-
await new Promise((
|
|
16483
|
+
await new Promise((resolve18) => setTimeout(resolve18, SKILL_TASK_POLL_INTERVAL_MS));
|
|
16456
16484
|
continue;
|
|
16457
16485
|
}
|
|
16458
16486
|
if (!response.ok) {
|
|
16459
16487
|
if (response.status >= SKILL_TASK_POLL_TRANSIENT_ERROR_STATUS) {
|
|
16460
16488
|
lastTransientError = `HTTP ${response.status}`;
|
|
16461
|
-
await new Promise((
|
|
16489
|
+
await new Promise((resolve18) => setTimeout(resolve18, SKILL_TASK_POLL_INTERVAL_MS));
|
|
16462
16490
|
continue;
|
|
16463
16491
|
}
|
|
16464
16492
|
throw new Error(`Task ${taskId} polling failed with HTTP ${response.status}. Generation was not retried; retain this task ID for recovery.`);
|
|
@@ -16470,7 +16498,7 @@ var OpenMatesClient = class _OpenMatesClient {
|
|
|
16470
16498
|
if (response.data.status === "failed") {
|
|
16471
16499
|
throw new Error(response.data.error ?? "Task failed");
|
|
16472
16500
|
}
|
|
16473
|
-
await new Promise((
|
|
16501
|
+
await new Promise((resolve18) => setTimeout(resolve18, SKILL_TASK_POLL_INTERVAL_MS));
|
|
16474
16502
|
}
|
|
16475
16503
|
if (lastTransientError) {
|
|
16476
16504
|
throw new Error(
|
|
@@ -17297,11 +17325,11 @@ var OpenMatesClient = class _OpenMatesClient {
|
|
|
17297
17325
|
}
|
|
17298
17326
|
return response.data.events ?? [];
|
|
17299
17327
|
}
|
|
17300
|
-
async followUpWorkflowInput(sessionId,
|
|
17328
|
+
async followUpWorkflowInput(sessionId, text7) {
|
|
17301
17329
|
this.requireSession();
|
|
17302
17330
|
const response = await this.http.post(
|
|
17303
17331
|
`/v1/workflows/input/${encodeURIComponent(sessionId)}/follow-up`,
|
|
17304
|
-
{ text:
|
|
17332
|
+
{ text: text7 },
|
|
17305
17333
|
this.getCliRequestHeaders()
|
|
17306
17334
|
);
|
|
17307
17335
|
if (!response.ok || !response.data.session) {
|
|
@@ -17456,11 +17484,13 @@ var OpenMatesClient = class _OpenMatesClient {
|
|
|
17456
17484
|
async getCustomRuleDocuments() {
|
|
17457
17485
|
const user = await this.whoAmI();
|
|
17458
17486
|
const settings = await this.decryptSettingsRecord(user.encrypted_settings);
|
|
17459
|
-
|
|
17487
|
+
const legacy = Array.isArray(settings.rule_documents) ? settings.rule_documents : [];
|
|
17488
|
+
const canonical = Array.isArray(settings.memory_documents) ? settings.memory_documents : [];
|
|
17489
|
+
const byId = new Map([...legacy, ...canonical].filter((value) => value && typeof value.id === "string").map((value) => [value.id, value]));
|
|
17460
17490
|
let chars = 0;
|
|
17461
17491
|
const documents = [];
|
|
17462
|
-
for (const value of
|
|
17463
|
-
if (!value || typeof value !== "object" || value.source !== void 0 && value.source !== "personal" || typeof value.id !== "string" || !value.id || value.id.length >
|
|
17492
|
+
for (const value of [...byId.values()].slice(0, 24)) {
|
|
17493
|
+
if (!value || typeof value !== "object" || value.source !== void 0 && value.source !== "personal" || typeof value.id !== "string" || !value.id || value.id.length > 240 || typeof value.document !== "string" || value.document.length > 24e3) continue;
|
|
17464
17494
|
if (chars + value.document.length > 64e3) continue;
|
|
17465
17495
|
chars += value.document.length;
|
|
17466
17496
|
documents.push({ id: value.id, source: "personal", document: value.document });
|
|
@@ -18592,7 +18622,7 @@ var OpenMatesClient = class _OpenMatesClient {
|
|
|
18592
18622
|
`Rate limited by settings API; retrying in ${Math.ceil(SETTINGS_GET_RATE_LIMIT_RETRY_MS / 1e3)}s...
|
|
18593
18623
|
`
|
|
18594
18624
|
);
|
|
18595
|
-
await new Promise((
|
|
18625
|
+
await new Promise((resolve18) => setTimeout(resolve18, SETTINGS_GET_RATE_LIMIT_RETRY_MS));
|
|
18596
18626
|
response = await this.http.get(normalizedPath, headers);
|
|
18597
18627
|
}
|
|
18598
18628
|
if (!response.ok) {
|
|
@@ -19283,6 +19313,26 @@ var OpenMatesClient = class _OpenMatesClient {
|
|
|
19283
19313
|
data: parsed
|
|
19284
19314
|
});
|
|
19285
19315
|
}
|
|
19316
|
+
if (!teamId) {
|
|
19317
|
+
let accountDocuments = [];
|
|
19318
|
+
try {
|
|
19319
|
+
accountDocuments = await this.getCustomRuleDocuments();
|
|
19320
|
+
} catch {
|
|
19321
|
+
}
|
|
19322
|
+
for (const memory of accountDocuments) {
|
|
19323
|
+
const title = /^title:\s*(.+)$/m.exec(memory.document)?.[1]?.replace(/^['"]|['"]$/g, "") ?? "Memory";
|
|
19324
|
+
results.push({
|
|
19325
|
+
id: `account-memory-${memory.id.replace(/^personal:/, "")}`,
|
|
19326
|
+
app_id: "openmates",
|
|
19327
|
+
item_type: "memories",
|
|
19328
|
+
item_key_hash: "",
|
|
19329
|
+
data: { title, document: memory.document },
|
|
19330
|
+
created_at: 0,
|
|
19331
|
+
updated_at: 0,
|
|
19332
|
+
item_version: 1
|
|
19333
|
+
});
|
|
19334
|
+
}
|
|
19335
|
+
}
|
|
19286
19336
|
return results;
|
|
19287
19337
|
}
|
|
19288
19338
|
/**
|
|
@@ -19310,6 +19360,13 @@ var OpenMatesClient = class _OpenMatesClient {
|
|
|
19310
19360
|
* @param currentVersion - The entry's current item_version from listMemories()
|
|
19311
19361
|
*/
|
|
19312
19362
|
async updateMemory(params) {
|
|
19363
|
+
if (params.entryId.startsWith("account-memory-")) {
|
|
19364
|
+
if (params.appId !== "openmates" || params.itemType !== "memories" || this.resolveTeamContext(params)) {
|
|
19365
|
+
throw new Error("Account Memories belong to the personal OpenMates category.");
|
|
19366
|
+
}
|
|
19367
|
+
await this.mutateAccountMemory(params.entryId, params.itemValue);
|
|
19368
|
+
return { success: true, id: params.entryId };
|
|
19369
|
+
}
|
|
19313
19370
|
return this.upsertMemory({
|
|
19314
19371
|
appId: params.appId,
|
|
19315
19372
|
itemType: params.itemType,
|
|
@@ -19325,6 +19382,11 @@ var OpenMatesClient = class _OpenMatesClient {
|
|
|
19325
19382
|
* WebSocket. The server deletes from Directus and broadcasts to all devices.
|
|
19326
19383
|
*/
|
|
19327
19384
|
async deleteMemory(entryId, options = {}) {
|
|
19385
|
+
if (entryId.startsWith("account-memory-")) {
|
|
19386
|
+
if (this.resolveTeamContext(options)) throw new Error("Account Memories belong to the personal OpenMates category.");
|
|
19387
|
+
await this.mutateAccountMemory(entryId);
|
|
19388
|
+
return { success: true };
|
|
19389
|
+
}
|
|
19328
19390
|
const { ws } = await this.openWsClient();
|
|
19329
19391
|
try {
|
|
19330
19392
|
const teamId = this.resolveTeamContext(options);
|
|
@@ -19345,6 +19407,34 @@ var OpenMatesClient = class _OpenMatesClient {
|
|
|
19345
19407
|
// -------------------------------------------------------------------------
|
|
19346
19408
|
// Private helpers
|
|
19347
19409
|
// -------------------------------------------------------------------------
|
|
19410
|
+
/** Edit legacy account guides in their encrypted owner store, never as public app data. */
|
|
19411
|
+
async mutateAccountMemory(entryId, value) {
|
|
19412
|
+
const sessionId = this.requireSession().sessionId;
|
|
19413
|
+
const user = await this.whoAmI();
|
|
19414
|
+
const settings = await this.decryptSettingsRecord(user.encrypted_settings);
|
|
19415
|
+
const legacy = Array.isArray(settings.rule_documents) ? settings.rule_documents : [];
|
|
19416
|
+
const canonical = Array.isArray(settings.memory_documents) ? settings.memory_documents : [];
|
|
19417
|
+
const documents = new Map([...legacy, ...canonical].filter((document) => document && typeof document.id === "string").map((document) => [document.id, document]));
|
|
19418
|
+
const original = [...documents.values()].find((document) => `account-memory-${document.id.replace(/^personal:/, "")}` === entryId);
|
|
19419
|
+
if (!original || typeof original.document !== "string") throw new Error("Account Memory is unavailable.");
|
|
19420
|
+
if (value) {
|
|
19421
|
+
if (typeof value.title !== "string" || typeof value.document !== "string") throw new Error("Memory title and document are required.");
|
|
19422
|
+
const { parseRuleDocument, serializeRuleDocument } = await import("./ruleDocuments-6VMP2CV5.js");
|
|
19423
|
+
const document = serializeRuleDocument({ ...parseRuleDocument(value.document), title: value.title });
|
|
19424
|
+
documents.set(original.id, { id: original.id, document });
|
|
19425
|
+
settings.memory_documents = [...documents.values()].map(({ id, document: document2 }) => ({ id, document: document2 }));
|
|
19426
|
+
} else {
|
|
19427
|
+
for (const name of ["rule_documents", "memory_documents"]) {
|
|
19428
|
+
if (Array.isArray(settings[name])) settings[name] = settings[name].filter((document) => document.id !== original.id);
|
|
19429
|
+
}
|
|
19430
|
+
}
|
|
19431
|
+
const ciphertext = await encryptWithAesGcmCombined(JSON.stringify(settings), this.getMasterKeyBytes());
|
|
19432
|
+
const current = await this.whoAmI();
|
|
19433
|
+
if (this.requireSession().sessionId !== sessionId || current.encrypted_settings !== user.encrypted_settings || (current.id ?? current.user_id) !== (user.id ?? user.user_id)) {
|
|
19434
|
+
throw new Error("Account settings changed. Reload before editing the Memory.");
|
|
19435
|
+
}
|
|
19436
|
+
await this.settingsPost("/v1/settings/encrypted-account", { encrypted_settings: ciphertext });
|
|
19437
|
+
}
|
|
19348
19438
|
/**
|
|
19349
19439
|
* Validate memory item_value against the registered schema and
|
|
19350
19440
|
* encrypt + send over WebSocket.
|
|
@@ -20831,7 +20921,7 @@ function filenameFromContentDisposition(header2) {
|
|
|
20831
20921
|
return plain?.trim() ?? null;
|
|
20832
20922
|
}
|
|
20833
20923
|
function sleep2(ms) {
|
|
20834
|
-
return new Promise((
|
|
20924
|
+
return new Promise((resolve18) => setTimeout(resolve18, ms));
|
|
20835
20925
|
}
|
|
20836
20926
|
function printLogo() {
|
|
20837
20927
|
const W = "\x1B[1;37m";
|
|
@@ -27925,13 +28015,13 @@ var OpenMates = class {
|
|
|
27925
28015
|
});
|
|
27926
28016
|
} catch (error) {
|
|
27927
28017
|
lastTransientError = error instanceof Error ? error.message : String(error);
|
|
27928
|
-
await new Promise((
|
|
28018
|
+
await new Promise((resolve18) => setTimeout(resolve18, CODE_RUN_POLL_INTERVAL_MS));
|
|
27929
28019
|
continue;
|
|
27930
28020
|
}
|
|
27931
28021
|
if (!response.ok) {
|
|
27932
28022
|
if (response.status >= SKILL_TASK_POLL_TRANSIENT_ERROR_STATUS2) {
|
|
27933
28023
|
lastTransientError = `HTTP ${response.status}`;
|
|
27934
|
-
await new Promise((
|
|
28024
|
+
await new Promise((resolve18) => setTimeout(resolve18, CODE_RUN_POLL_INTERVAL_MS));
|
|
27935
28025
|
continue;
|
|
27936
28026
|
}
|
|
27937
28027
|
throw new OpenMatesApiError(response.status, await this.safeJson(response));
|
|
@@ -27940,7 +28030,7 @@ var OpenMates = class {
|
|
|
27940
28030
|
const status = await this.parseResponse(response);
|
|
27941
28031
|
const value = typeof status.status === "string" ? status.status : "";
|
|
27942
28032
|
if (CODE_RUN_TERMINAL_STATUSES.has(value)) return status;
|
|
27943
|
-
await new Promise((
|
|
28033
|
+
await new Promise((resolve18) => setTimeout(resolve18, CODE_RUN_POLL_INTERVAL_MS));
|
|
27944
28034
|
}
|
|
27945
28035
|
if (lastTransientError) {
|
|
27946
28036
|
throw new Error(`Code Run did not complete within ${CODE_RUN_POLL_TIMEOUT_MS / 1e3}s; last polling error: ${lastTransientError}`);
|
|
@@ -27965,13 +28055,13 @@ var OpenMates = class {
|
|
|
27965
28055
|
});
|
|
27966
28056
|
} catch (error) {
|
|
27967
28057
|
lastTransientError = error instanceof Error ? error.message : String(error);
|
|
27968
|
-
await new Promise((
|
|
28058
|
+
await new Promise((resolve18) => setTimeout(resolve18, SKILL_TASK_POLL_INTERVAL_MS2));
|
|
27969
28059
|
continue;
|
|
27970
28060
|
}
|
|
27971
28061
|
if (!response.ok) {
|
|
27972
28062
|
if (response.status >= SKILL_TASK_POLL_TRANSIENT_ERROR_STATUS2) {
|
|
27973
28063
|
lastTransientError = `HTTP ${response.status}`;
|
|
27974
|
-
await new Promise((
|
|
28064
|
+
await new Promise((resolve18) => setTimeout(resolve18, SKILL_TASK_POLL_INTERVAL_MS2));
|
|
27975
28065
|
continue;
|
|
27976
28066
|
}
|
|
27977
28067
|
throw new OpenMatesApiError(response.status, await this.safeJson(response));
|
|
@@ -27980,7 +28070,7 @@ var OpenMates = class {
|
|
|
27980
28070
|
const task = await this.parseResponse(response);
|
|
27981
28071
|
if (task.status === "completed") return task;
|
|
27982
28072
|
if (task.status === "failed") throw new Error(task.error ?? "Task failed");
|
|
27983
|
-
await new Promise((
|
|
28073
|
+
await new Promise((resolve18) => setTimeout(resolve18, SKILL_TASK_POLL_INTERVAL_MS2));
|
|
27984
28074
|
}
|
|
27985
28075
|
if (lastTransientError) {
|
|
27986
28076
|
throw new Error(`Task ${taskId} did not complete within ${SKILL_TASK_POLL_TIMEOUT_MS2 / 1e3}s; last polling error: ${lastTransientError}`);
|
|
@@ -29057,7 +29147,7 @@ var OpenMatesChats = class {
|
|
|
29057
29147
|
}
|
|
29058
29148
|
const remainingMs = deadline - Date.now();
|
|
29059
29149
|
if (remainingMs <= 0) break;
|
|
29060
|
-
await new Promise((
|
|
29150
|
+
await new Promise((resolve18) => setTimeout(resolve18, Math.min(pollIntervalMs, remainingMs)));
|
|
29061
29151
|
}
|
|
29062
29152
|
throw new OpenMatesConfigError("Timed out waiting for saved chat recovery");
|
|
29063
29153
|
}
|
|
@@ -29770,6 +29860,19 @@ var OpenMatesMemories = class {
|
|
|
29770
29860
|
constructor(client2) {
|
|
29771
29861
|
this.client = client2;
|
|
29772
29862
|
}
|
|
29863
|
+
/** Reviewed, read-only app guidance; independent of private encrypted entries. */
|
|
29864
|
+
async published(options = {}) {
|
|
29865
|
+
if (options.appId) {
|
|
29866
|
+
const app = await this.client.getPublic(
|
|
29867
|
+
`/v1/apps/${encodeURIComponent(options.appId)}/metadata?include_unavailable=true`
|
|
29868
|
+
);
|
|
29869
|
+
return { memories: app.memories ?? [] };
|
|
29870
|
+
}
|
|
29871
|
+
const metadata = await this.client.getPublic(
|
|
29872
|
+
"/v1/apps/metadata?include_unavailable=true"
|
|
29873
|
+
);
|
|
29874
|
+
return { memories: Object.values(metadata.apps).flatMap((app) => app.memories ?? []) };
|
|
29875
|
+
}
|
|
29773
29876
|
async list(options = {}) {
|
|
29774
29877
|
const data = await this.client.get(withQuery("/v1/sdk/memories", options.query));
|
|
29775
29878
|
const memories = await Promise.all((data.memories ?? []).map(async (memory) => {
|
|
@@ -30345,7 +30448,7 @@ function isTaskVersionConflict(error) {
|
|
|
30345
30448
|
return error instanceof OpenMatesApiError && error.status === 409 && String(JSON.stringify(error.data)).includes("TASK_VERSION_CONFLICT");
|
|
30346
30449
|
}
|
|
30347
30450
|
function delay(ms) {
|
|
30348
|
-
return new Promise((
|
|
30451
|
+
return new Promise((resolve18) => setTimeout(resolve18, ms));
|
|
30349
30452
|
}
|
|
30350
30453
|
var OpenMatesPlans = class {
|
|
30351
30454
|
client;
|
|
@@ -30929,8 +31032,8 @@ var OpenMatesWorkflows = class {
|
|
|
30929
31032
|
const response = await this.client.get(`/v1/workflows/input/${encodeURIComponent(sessionId)}/events?after_event_id=${encodeURIComponent(String(afterEventId))}`);
|
|
30930
31033
|
return response.events ?? [];
|
|
30931
31034
|
}
|
|
30932
|
-
async followUpInput(sessionId,
|
|
30933
|
-
const response = await this.client.request(`/v1/workflows/input/${encodeURIComponent(sessionId)}/follow-up`, { text:
|
|
31035
|
+
async followUpInput(sessionId, text7) {
|
|
31036
|
+
const response = await this.client.request(`/v1/workflows/input/${encodeURIComponent(sessionId)}/follow-up`, { text: text7 });
|
|
30934
31037
|
if (!response.session) throw new OpenMatesApiError(500, { detail: "Workflow input response missing session" });
|
|
30935
31038
|
return response.session;
|
|
30936
31039
|
}
|
|
@@ -31304,7 +31407,7 @@ var OpenMatesEmbedPreview = class {
|
|
|
31304
31407
|
if (["running", "failed", "timeout", "cancelled", "stopped"].includes(status.status)) {
|
|
31305
31408
|
return status;
|
|
31306
31409
|
}
|
|
31307
|
-
await new Promise((
|
|
31410
|
+
await new Promise((resolve18) => setTimeout(resolve18, 1e3));
|
|
31308
31411
|
}
|
|
31309
31412
|
throw new OpenMatesApiError(408, { detail: "Application preview did not reach running state before timeout" });
|
|
31310
31413
|
}
|
|
@@ -32200,27 +32303,27 @@ var SecretRegistry = class {
|
|
|
32200
32303
|
textsToAdd.push(entry.textToHide);
|
|
32201
32304
|
}
|
|
32202
32305
|
if (entry.additionalTexts) {
|
|
32203
|
-
for (const
|
|
32204
|
-
if (
|
|
32205
|
-
textsToAdd.push(
|
|
32306
|
+
for (const text7 of entry.additionalTexts) {
|
|
32307
|
+
if (text7 && text7.trim().length > 0) {
|
|
32308
|
+
textsToAdd.push(text7);
|
|
32206
32309
|
}
|
|
32207
32310
|
}
|
|
32208
32311
|
}
|
|
32209
|
-
for (const
|
|
32312
|
+
for (const text7 of textsToAdd) {
|
|
32210
32313
|
const placeholder = entry.replaceWith.startsWith("[") ? entry.replaceWith : `[${entry.replaceWith}]`;
|
|
32211
32314
|
const regEntry = {
|
|
32212
|
-
value:
|
|
32315
|
+
value: text7,
|
|
32213
32316
|
token: placeholder,
|
|
32214
32317
|
source: "settings",
|
|
32215
32318
|
name: entry.id,
|
|
32216
32319
|
type: "PERSONAL_DATA",
|
|
32217
|
-
length:
|
|
32320
|
+
length: text7.length
|
|
32218
32321
|
};
|
|
32219
|
-
this.entries.set(
|
|
32220
|
-
this.usedPlaceholders.set(placeholder,
|
|
32221
|
-
const lower =
|
|
32222
|
-
if (lower !==
|
|
32223
|
-
this.variantToOriginal.set(lower,
|
|
32322
|
+
this.entries.set(text7, regEntry);
|
|
32323
|
+
this.usedPlaceholders.set(placeholder, text7);
|
|
32324
|
+
const lower = text7.toLowerCase();
|
|
32325
|
+
if (lower !== text7) {
|
|
32326
|
+
this.variantToOriginal.set(lower, text7);
|
|
32224
32327
|
}
|
|
32225
32328
|
}
|
|
32226
32329
|
this.automaton = null;
|
|
@@ -32274,12 +32377,12 @@ var SecretRegistry = class {
|
|
|
32274
32377
|
* @param text Text to scan
|
|
32275
32378
|
* @returns Array of secret mappings for all matches found
|
|
32276
32379
|
*/
|
|
32277
|
-
findAll(
|
|
32380
|
+
findAll(text7) {
|
|
32278
32381
|
if (this.entries.size === 0) return [];
|
|
32279
32382
|
if (!this.automaton) {
|
|
32280
32383
|
this.buildAutomaton();
|
|
32281
32384
|
}
|
|
32282
|
-
const results = this.automaton.search(
|
|
32385
|
+
const results = this.automaton.search(text7);
|
|
32283
32386
|
const mappings = [];
|
|
32284
32387
|
const coveredRanges = [];
|
|
32285
32388
|
const sortedResults = [];
|
|
@@ -32484,17 +32587,17 @@ var SecretScanner = class {
|
|
|
32484
32587
|
* @param text Text to scan and redact
|
|
32485
32588
|
* @returns Object with redacted text and mappings for restoration
|
|
32486
32589
|
*/
|
|
32487
|
-
redact(
|
|
32488
|
-
if (!
|
|
32590
|
+
redact(text7) {
|
|
32591
|
+
if (!text7) return { redacted: text7, mappings: [] };
|
|
32489
32592
|
const allMappings = [];
|
|
32490
32593
|
const coveredRanges = [];
|
|
32491
|
-
const urlExclusionZones = getUrlExclusionZones(
|
|
32492
|
-
const identifierRanges = codingIdentifierRanges(
|
|
32594
|
+
const urlExclusionZones = getUrlExclusionZones(text7);
|
|
32595
|
+
const identifierRanges = codingIdentifierRanges(text7);
|
|
32493
32596
|
if (this.options.enableRegistryDetection && this.registry.size > 0) {
|
|
32494
|
-
const registryMappings = this.registry.findAll(
|
|
32597
|
+
const registryMappings = this.registry.findAll(text7);
|
|
32495
32598
|
for (const mapping of registryMappings) {
|
|
32496
32599
|
let searchFrom = 0;
|
|
32497
|
-
const searchText =
|
|
32600
|
+
const searchText = text7.toLowerCase();
|
|
32498
32601
|
const matchLower = mapping.original.toLowerCase();
|
|
32499
32602
|
while (searchFrom < searchText.length) {
|
|
32500
32603
|
const idx = searchText.indexOf(matchLower, searchFrom);
|
|
@@ -32510,7 +32613,7 @@ var SecretScanner = class {
|
|
|
32510
32613
|
for (const pattern of [...SECRET_PATTERNS, ...GENERAL_PII_PATTERNS]) {
|
|
32511
32614
|
pattern.regex.lastIndex = 0;
|
|
32512
32615
|
let match;
|
|
32513
|
-
while ((match = pattern.regex.exec(
|
|
32616
|
+
while ((match = pattern.regex.exec(text7)) !== null) {
|
|
32514
32617
|
const matchText = match[0];
|
|
32515
32618
|
const startIndex = match.index;
|
|
32516
32619
|
const endIndex = startIndex + matchText.length;
|
|
@@ -32541,7 +32644,7 @@ var SecretScanner = class {
|
|
|
32541
32644
|
}
|
|
32542
32645
|
}
|
|
32543
32646
|
}
|
|
32544
|
-
let redacted =
|
|
32647
|
+
let redacted = text7;
|
|
32545
32648
|
const sortedMappings = [...allMappings].sort(
|
|
32546
32649
|
(a, b) => b.original.length - a.original.length
|
|
32547
32650
|
);
|
|
@@ -32570,9 +32673,9 @@ var SecretScanner = class {
|
|
|
32570
32673
|
* @param mappings Mappings from a previous redact() call
|
|
32571
32674
|
* @returns Text with placeholders replaced by original values
|
|
32572
32675
|
*/
|
|
32573
|
-
restore(
|
|
32574
|
-
if (!
|
|
32575
|
-
let result =
|
|
32676
|
+
restore(text7, mappings) {
|
|
32677
|
+
if (!text7 || !mappings || mappings.length === 0) return text7;
|
|
32678
|
+
let result = text7;
|
|
32576
32679
|
for (const mapping of mappings) {
|
|
32577
32680
|
result = result.split(mapping.placeholder).join(mapping.original);
|
|
32578
32681
|
}
|
|
@@ -32591,11 +32694,11 @@ var SecretScanner = class {
|
|
|
32591
32694
|
function escapeRegExp2(string3) {
|
|
32592
32695
|
return string3.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
32593
32696
|
}
|
|
32594
|
-
function getUrlExclusionZones(
|
|
32697
|
+
function getUrlExclusionZones(text7) {
|
|
32595
32698
|
const urlExclusionRegex = /https?:\/\/[^\s]+/g;
|
|
32596
32699
|
const zones = [];
|
|
32597
32700
|
let match;
|
|
32598
|
-
while ((match = urlExclusionRegex.exec(
|
|
32701
|
+
while ((match = urlExclusionRegex.exec(text7)) !== null) {
|
|
32599
32702
|
zones.push({ start: match.index, end: match.index + match[0].length });
|
|
32600
32703
|
}
|
|
32601
32704
|
return zones;
|
|
@@ -32672,18 +32775,18 @@ var OutputRedactor = class {
|
|
|
32672
32775
|
* @param text Text to scan
|
|
32673
32776
|
* @returns Redacted text with placeholders
|
|
32674
32777
|
*/
|
|
32675
|
-
redact(
|
|
32676
|
-
return this.redactWithMappings(
|
|
32778
|
+
redact(text7) {
|
|
32779
|
+
return this.redactWithMappings(text7).redacted;
|
|
32677
32780
|
}
|
|
32678
32781
|
/**
|
|
32679
32782
|
* Redact and return both redacted text and mappings.
|
|
32680
32783
|
* Used when we need to store mappings alongside message data.
|
|
32681
32784
|
*/
|
|
32682
|
-
redactWithMappings(
|
|
32683
|
-
if (!
|
|
32684
|
-
return { redacted:
|
|
32785
|
+
redactWithMappings(text7) {
|
|
32786
|
+
if (!text7 || !this.initialized || !this.privacyEnabled) {
|
|
32787
|
+
return { redacted: text7, mappings: [] };
|
|
32685
32788
|
}
|
|
32686
|
-
const result = this.scanner.redact(
|
|
32789
|
+
const result = this.scanner.redact(text7);
|
|
32687
32790
|
const excluded = result.mappings.filter((m) => this.disabledCategories.has(PII_TYPE_TO_CATEGORY[m.type] ?? ""));
|
|
32688
32791
|
if (excluded.length) {
|
|
32689
32792
|
result.redacted = this.scanner.restore(result.redacted, excluded);
|
|
@@ -32698,9 +32801,9 @@ var OutputRedactor = class {
|
|
|
32698
32801
|
* Restore placeholders back to original values.
|
|
32699
32802
|
* Only uses mappings from this session (never from external sources).
|
|
32700
32803
|
*/
|
|
32701
|
-
restore(
|
|
32702
|
-
if (!
|
|
32703
|
-
return this.scanner.restore(
|
|
32804
|
+
restore(text7) {
|
|
32805
|
+
if (!text7 || this.sessionMappings.size === 0) return text7;
|
|
32806
|
+
return this.scanner.restore(text7, Array.from(this.sessionMappings.values()));
|
|
32704
32807
|
}
|
|
32705
32808
|
/** Mappings accumulated while preparing attachments and this message. */
|
|
32706
32809
|
getMappings() {
|
|
@@ -32759,8 +32862,8 @@ function createWebsiteEmbed(url) {
|
|
|
32759
32862
|
status: "finished"
|
|
32760
32863
|
};
|
|
32761
32864
|
}
|
|
32762
|
-
function replaceUrlsInText(
|
|
32763
|
-
return
|
|
32865
|
+
function replaceUrlsInText(text7, embeds) {
|
|
32866
|
+
return text7.replace(URL_PATTERN, (rawUrl) => {
|
|
32764
32867
|
const { url, suffix } = trimTrailingUrlPunctuation(rawUrl);
|
|
32765
32868
|
if (!url) return rawUrl;
|
|
32766
32869
|
try {
|
|
@@ -33350,8 +33453,8 @@ async function renderRemotionShareLink(embedId, client2, ln) {
|
|
|
33350
33453
|
}
|
|
33351
33454
|
}
|
|
33352
33455
|
function generateQr(value) {
|
|
33353
|
-
return new Promise((
|
|
33354
|
-
qrcode2.generate(value, { small: true }, (qr) =>
|
|
33456
|
+
return new Promise((resolve18) => {
|
|
33457
|
+
qrcode2.generate(value, { small: true }, (qr) => resolve18(qr));
|
|
33355
33458
|
});
|
|
33356
33459
|
}
|
|
33357
33460
|
function remotionMeta(c) {
|
|
@@ -33760,12 +33863,12 @@ function renderAudioTranscribePreview(c, ln) {
|
|
|
33760
33863
|
const language = str(c.language) ?? "";
|
|
33761
33864
|
if (duration) ln(`\x1B[2mDuration: ${duration}\x1B[0m`);
|
|
33762
33865
|
if (language) ln(`\x1B[2mLanguage: ${language}\x1B[0m`);
|
|
33763
|
-
const
|
|
33764
|
-
if (
|
|
33866
|
+
const text7 = str(c.text) ?? str(c.transcript) ?? "";
|
|
33867
|
+
if (text7) ln(trunc(text7, 60));
|
|
33765
33868
|
}
|
|
33766
33869
|
function renderAudioTranscribeFullscreen(c) {
|
|
33767
|
-
const
|
|
33768
|
-
if (
|
|
33870
|
+
const text7 = str(c.text) ?? str(c.transcript) ?? "";
|
|
33871
|
+
if (text7) console.log(text7);
|
|
33769
33872
|
else console.log("No transcript available.");
|
|
33770
33873
|
}
|
|
33771
33874
|
function renderByDirectType(embed, c, ln) {
|
|
@@ -33998,8 +34101,8 @@ function renderDirectTypeFullscreen(embed, c) {
|
|
|
33998
34101
|
|
|
33999
34102
|
`);
|
|
34000
34103
|
if (html) {
|
|
34001
|
-
const
|
|
34002
|
-
console.log(
|
|
34104
|
+
const text7 = html.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
|
|
34105
|
+
console.log(text7);
|
|
34003
34106
|
}
|
|
34004
34107
|
break;
|
|
34005
34108
|
}
|
|
@@ -34010,8 +34113,8 @@ function renderDirectTypeFullscreen(embed, c) {
|
|
|
34010
34113
|
|
|
34011
34114
|
`);
|
|
34012
34115
|
if (html) {
|
|
34013
|
-
const
|
|
34014
|
-
console.log(
|
|
34116
|
+
const text7 = html.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
|
|
34117
|
+
console.log(text7);
|
|
34015
34118
|
}
|
|
34016
34119
|
break;
|
|
34017
34120
|
}
|
|
@@ -34248,7 +34351,7 @@ import { appendFileSync, chmodSync as chmodSync7, closeSync as closeSync4, copyF
|
|
|
34248
34351
|
import { createInterface as createInterface4 } from "readline";
|
|
34249
34352
|
import { createInterface as createPromptInterface } from "readline/promises";
|
|
34250
34353
|
import { homedir as homedir4, tmpdir as tmpdir2 } from "os";
|
|
34251
|
-
import { dirname as dirname9, join as join15, resolve as
|
|
34354
|
+
import { dirname as dirname9, join as join15, resolve as resolve7 } from "path";
|
|
34252
34355
|
|
|
34253
34356
|
// src/branding.ts
|
|
34254
34357
|
var OPENMATES_WORDMARK = "OPENMATES";
|
|
@@ -35074,8 +35177,42 @@ import { execFileSync as execFileSync3 } from "child_process";
|
|
|
35074
35177
|
import { createHash as createHash16 } from "crypto";
|
|
35075
35178
|
import { accessSync, constants as constants2, existsSync as existsSync9, mkdirSync as mkdirSync9, mkdtempSync, readFileSync as readFileSync10, renameSync as renameSync4, rmSync as rmSync5, writeFileSync as writeFileSync5 } from "fs";
|
|
35076
35179
|
import { tmpdir } from "os";
|
|
35077
|
-
import { dirname as dirname7, join as join12 } from "path";
|
|
35078
|
-
var hash2 = (
|
|
35180
|
+
import { dirname as dirname7, join as join12, isAbsolute as isAbsolute3, resolve as resolve6 } from "path";
|
|
35181
|
+
var hash2 = (text7) => createHash16("sha256").update(text7).digest("hex");
|
|
35182
|
+
function caddyConfigFromArgs(args, cwd) {
|
|
35183
|
+
const index = args.indexOf("--config");
|
|
35184
|
+
const value = index >= 0 ? args[index + 1] : args.find((arg) => arg.startsWith("--config="))?.slice(9);
|
|
35185
|
+
if (!value || value.startsWith("--")) return void 0;
|
|
35186
|
+
if (!isAbsolute3(value) && !cwd) throw new Error("caddy_relative_config_requires_explicit_path");
|
|
35187
|
+
return resolve6(cwd ?? "/", value);
|
|
35188
|
+
}
|
|
35189
|
+
function detectCaddyConfigPath(explicit) {
|
|
35190
|
+
if (explicit) return resolve6(explicit);
|
|
35191
|
+
let pid;
|
|
35192
|
+
try {
|
|
35193
|
+
pid = execFileSync3("systemctl", ["show", "caddy", "--property=MainPID", "--value"], {
|
|
35194
|
+
encoding: "utf8",
|
|
35195
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
35196
|
+
timeout: 5e3
|
|
35197
|
+
}).trim();
|
|
35198
|
+
} catch {
|
|
35199
|
+
}
|
|
35200
|
+
if (pid && /^[1-9]\d*$/.test(pid)) {
|
|
35201
|
+
try {
|
|
35202
|
+
const args = readFileSync10(`/proc/${pid}/cmdline`, "utf8").split("\0").filter(Boolean);
|
|
35203
|
+
const config = caddyConfigFromArgs(args);
|
|
35204
|
+
if (config) return config;
|
|
35205
|
+
} catch {
|
|
35206
|
+
throw new Error("caddy_running_config_requires_explicit_path");
|
|
35207
|
+
}
|
|
35208
|
+
throw new Error("caddy_running_config_requires_explicit_path");
|
|
35209
|
+
}
|
|
35210
|
+
return existsSync9("/etc/caddy/Caddyfile") ? "/etc/caddy/Caddyfile" : void 0;
|
|
35211
|
+
}
|
|
35212
|
+
function caddyUpdateRetryCommand(input) {
|
|
35213
|
+
const quote = (value) => `'${value.replaceAll("'", "'\\''")}'`;
|
|
35214
|
+
return `sudo -v && openmates server caddy update --path ${quote(input.installPath)} --role ${quote(input.role)} --caddy-config ${quote(input.configPath)}` + (input.profile === "official-upload" ? " --caddy-profile official-upload" : "");
|
|
35215
|
+
}
|
|
35079
35216
|
function resolveCaddyProfile(role, explicit, previous) {
|
|
35080
35217
|
if (explicit === void 0) return previous ?? "self-host";
|
|
35081
35218
|
if (role !== "upload" || explicit !== "official-upload") throw new Error("caddy_profile_unsupported");
|
|
@@ -35286,7 +35423,17 @@ var HOST_TRANSACTION = String.raw`
|
|
|
35286
35423
|
const fs = require('node:fs'), cp = require('node:child_process'), crypto = require('node:crypto'), path = require('node:path');
|
|
35287
35424
|
const input = JSON.parse(fs.readFileSync(0, 'utf8'));
|
|
35288
35425
|
const digest = text => crypto.createHash('sha256').update(text).digest('hex');
|
|
35289
|
-
function run(command, args) {
|
|
35426
|
+
function run(command, args) {
|
|
35427
|
+
const options = {stdio: ['ignore','pipe','pipe'], timeout: 20000};
|
|
35428
|
+
try { cp.execFileSync(command, args, options); }
|
|
35429
|
+
catch (error) {
|
|
35430
|
+
// A user-owned Caddyfile can still belong to a root-managed service.
|
|
35431
|
+
// Honor a cached sudo session for reload without elevating file access.
|
|
35432
|
+
if (command !== 'systemctl') throw error;
|
|
35433
|
+
try { cp.execFileSync('sudo', ['-n', command, ...args], options); }
|
|
35434
|
+
catch { throw error; }
|
|
35435
|
+
}
|
|
35436
|
+
}
|
|
35290
35437
|
function replace(content, metadata) {
|
|
35291
35438
|
const temp = input.configPath + '.openmates-' + crypto.randomUUID();
|
|
35292
35439
|
let fd;
|
|
@@ -35346,7 +35493,7 @@ try {
|
|
|
35346
35493
|
function caddyHostOperation(input) {
|
|
35347
35494
|
let privileged = false;
|
|
35348
35495
|
try {
|
|
35349
|
-
accessSync(dirname7(input.configPath), constants2.W_OK);
|
|
35496
|
+
accessSync(input.action === "read" ? input.configPath : dirname7(input.configPath), input.action === "read" ? constants2.R_OK : constants2.W_OK);
|
|
35350
35497
|
} catch {
|
|
35351
35498
|
privileged = true;
|
|
35352
35499
|
}
|
|
@@ -35390,6 +35537,12 @@ async function verifyCaddyCoreRoutes(apiUrl, origin) {
|
|
|
35390
35537
|
redirect: "error",
|
|
35391
35538
|
signal: AbortSignal.timeout(5e3)
|
|
35392
35539
|
});
|
|
35540
|
+
const embedPreflight = await request("/v1/embeds/chats/00000000-0000-4000-8000-000000000000/references/availability", { method: "OPTIONS", headers: {
|
|
35541
|
+
Origin: origin,
|
|
35542
|
+
"Access-Control-Request-Method": "POST",
|
|
35543
|
+
"Access-Control-Request-Headers": "content-type"
|
|
35544
|
+
} });
|
|
35545
|
+
if (!embedPreflight.ok || embedPreflight.headers.get("access-control-allow-origin") !== origin || embedPreflight.headers.get("access-control-allow-credentials") !== "true") throw new Error("caddy_embed_reference_cors_failed");
|
|
35393
35546
|
const availability = await request("/v1/features/availability");
|
|
35394
35547
|
if (!availability.ok) throw new Error("caddy_availability_route_failed");
|
|
35395
35548
|
const features = await availability.json();
|
|
@@ -35682,7 +35835,7 @@ function isBrevoAcceptedResponse(pathName, method, status, responseBody) {
|
|
|
35682
35835
|
}
|
|
35683
35836
|
async function requestBrevo(pathName, method, apiKey, payload) {
|
|
35684
35837
|
const body = payload ? JSON.stringify(payload) : void 0;
|
|
35685
|
-
await new Promise((
|
|
35838
|
+
await new Promise((resolve18, reject) => {
|
|
35686
35839
|
const request = httpsRequest(buildBrevoRequestOptions(pathName, method, apiKey, body), (response) => {
|
|
35687
35840
|
let responseBytes = 0;
|
|
35688
35841
|
const chunks = [];
|
|
@@ -35694,8 +35847,8 @@ async function requestBrevo(pathName, method, apiKey, payload) {
|
|
|
35694
35847
|
response.on("end", () => {
|
|
35695
35848
|
const status = response.statusCode ?? 0;
|
|
35696
35849
|
const responseBody = Buffer.concat(chunks).toString("utf8");
|
|
35697
|
-
if (isBrevoAcceptedResponse(pathName, method, status, responseBody))
|
|
35698
|
-
else if (isBrevoIdempotencyDuplicate(status, responseBody, payload))
|
|
35850
|
+
if (isBrevoAcceptedResponse(pathName, method, status, responseBody)) resolve18();
|
|
35851
|
+
else if (isBrevoIdempotencyDuplicate(status, responseBody, payload)) resolve18();
|
|
35699
35852
|
else reject(new Error(`brevo_delivery_failed:${status}`));
|
|
35700
35853
|
});
|
|
35701
35854
|
});
|
|
@@ -35863,7 +36016,7 @@ async function sendGenericWebhook(target, secret, payload, allowLocalDevelopment
|
|
|
35863
36016
|
const eventId = randomUUID12();
|
|
35864
36017
|
const signed = signRuntimeWebhookPayload(payload, secret, timestamp, eventId);
|
|
35865
36018
|
const selected = addresses[0];
|
|
35866
|
-
await new Promise((
|
|
36019
|
+
await new Promise((resolve18, reject) => {
|
|
35867
36020
|
const requestFunction = url.protocol === "https:" ? httpsRequest : httpRequest;
|
|
35868
36021
|
const request = requestFunction({
|
|
35869
36022
|
protocol: url.protocol,
|
|
@@ -35883,7 +36036,7 @@ async function sendGenericWebhook(target, secret, payload, allowLocalDevelopment
|
|
|
35883
36036
|
});
|
|
35884
36037
|
response.on("end", () => {
|
|
35885
36038
|
const status = response.statusCode ?? 0;
|
|
35886
|
-
if (status >= 200 && status < 300)
|
|
36039
|
+
if (status >= 200 && status < 300) resolve18();
|
|
35887
36040
|
else reject(new Error(`webhook_delivery_failed:${status}`));
|
|
35888
36041
|
});
|
|
35889
36042
|
});
|
|
@@ -35964,7 +36117,7 @@ async function deliverWithRetries(channel, send) {
|
|
|
35964
36117
|
await send();
|
|
35965
36118
|
return { channel, status: "delivered", attempts: attempt };
|
|
35966
36119
|
} catch {
|
|
35967
|
-
if (attempt < 3) await new Promise((
|
|
36120
|
+
if (attempt < 3) await new Promise((resolve18) => setTimeout(resolve18, 250 * 2 ** (attempt - 1)));
|
|
35968
36121
|
}
|
|
35969
36122
|
}
|
|
35970
36123
|
return { channel, status: "exhausted", attempts: 3, sanitizedReason: "delivery_failed" };
|
|
@@ -35977,7 +36130,7 @@ async function deliverUpdateCompletionEmail(config, payload, send = sendUpdateCo
|
|
|
35977
36130
|
await send(config, payload);
|
|
35978
36131
|
return { status: "accepted", attempts };
|
|
35979
36132
|
} catch {
|
|
35980
|
-
if (attempts < 3) await new Promise((
|
|
36133
|
+
if (attempts < 3) await new Promise((resolve18) => setTimeout(resolve18, 250 * 2 ** (attempts - 1)));
|
|
35981
36134
|
}
|
|
35982
36135
|
}
|
|
35983
36136
|
return { status: "failed", attempts: Math.max(previousAttempts, 3), sanitizedReason: "delivery_failed" };
|
|
@@ -36608,9 +36761,9 @@ function exec(cmd, cwd) {
|
|
|
36608
36761
|
return execSync(cmd, { cwd, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
36609
36762
|
}
|
|
36610
36763
|
function runInteractive(cmd, args, cwd) {
|
|
36611
|
-
return new Promise((
|
|
36764
|
+
return new Promise((resolve18, reject) => {
|
|
36612
36765
|
const child = nodeSpawn(cmd, args, { cwd, stdio: "inherit", shell: false });
|
|
36613
|
-
child.on("close", (code) =>
|
|
36766
|
+
child.on("close", (code) => resolve18(code ?? 1));
|
|
36614
36767
|
child.on("error", reject);
|
|
36615
36768
|
});
|
|
36616
36769
|
}
|
|
@@ -36703,7 +36856,7 @@ function getInstallDeploymentMode(installPath, config) {
|
|
|
36703
36856
|
function getOpenMatesCloudOverlayPath(flags, config) {
|
|
36704
36857
|
const explicit = flags["openmatescloud-path"] ?? flags["openmates-cloud-path"];
|
|
36705
36858
|
if (explicit === true) throw new Error("Provide an OpenMatesCloud path: --openmatescloud-path <dir>.");
|
|
36706
|
-
if (typeof explicit === "string") return
|
|
36859
|
+
if (typeof explicit === "string") return resolve7(explicit);
|
|
36707
36860
|
return config?.openMatesCloudOverlayPath;
|
|
36708
36861
|
}
|
|
36709
36862
|
function hasServiceFilter(flags) {
|
|
@@ -37095,7 +37248,7 @@ function fileHash(path2) {
|
|
|
37095
37248
|
async function loadSelfHostComposeTemplate(templateRef, role, imageTag, packageVersion = getPackageVersion()) {
|
|
37096
37249
|
const templateDir = process.env.OPENMATES_SELFHOST_TEMPLATE_DIR;
|
|
37097
37250
|
if (templateDir) {
|
|
37098
|
-
return readFileSync12(join15(
|
|
37251
|
+
return readFileSync12(join15(resolve7(templateDir), ROLE_TEMPLATE_FILES[role]), "utf-8");
|
|
37099
37252
|
}
|
|
37100
37253
|
const packaged = packagedTemplatePath(role);
|
|
37101
37254
|
const source = resolveTemplateSource({
|
|
@@ -37236,10 +37389,10 @@ function warnIfMissingLlmCredentials(installPath) {
|
|
|
37236
37389
|
}
|
|
37237
37390
|
async function confirmDestructive(phrase) {
|
|
37238
37391
|
const rl = createInterface4({ input: process.stdin, output: process.stderr });
|
|
37239
|
-
return new Promise((
|
|
37392
|
+
return new Promise((resolve18) => {
|
|
37240
37393
|
rl.question(`Type "${phrase}" to confirm: `, (answer) => {
|
|
37241
37394
|
rl.close();
|
|
37242
|
-
|
|
37395
|
+
resolve18(answer.trim() === phrase);
|
|
37243
37396
|
});
|
|
37244
37397
|
});
|
|
37245
37398
|
}
|
|
@@ -37628,7 +37781,7 @@ function writeDeploymentModeEnv(installPath, deploymentMode, overlayPath) {
|
|
|
37628
37781
|
writeEnvContent(installPath, content);
|
|
37629
37782
|
return { overlayPath: null };
|
|
37630
37783
|
}
|
|
37631
|
-
const resolvedOverlayPath =
|
|
37784
|
+
const resolvedOverlayPath = resolve7(overlayPath ?? defaultOpenMatesCloudOverlayPath(installPath));
|
|
37632
37785
|
const overlayComposeFile = defaultOpenMatesCloudComposeFile(resolvedOverlayPath);
|
|
37633
37786
|
if (!existsSync11(resolvedOverlayPath) || !existsSync11(overlayComposeFile)) {
|
|
37634
37787
|
throw new Error(
|
|
@@ -37739,7 +37892,7 @@ function printServerCommandStart(subcommand, rest, flags) {
|
|
|
37739
37892
|
console.log(renderOpenMatesAsciiLogo());
|
|
37740
37893
|
console.log("");
|
|
37741
37894
|
console.log(`Running OpenMates ${command}...`);
|
|
37742
|
-
if (typeof flags.path === "string") console.log(`Path: ${
|
|
37895
|
+
if (typeof flags.path === "string") console.log(`Path: ${resolve7(flags.path)}`);
|
|
37743
37896
|
if (typeof flags.role === "string") console.log(`Role: ${flags.role}`);
|
|
37744
37897
|
console.log("");
|
|
37745
37898
|
}
|
|
@@ -37881,7 +38034,7 @@ function createServerBackup(installPath, role, options = {}) {
|
|
|
37881
38034
|
const plan = planBackup({ role, includeObservability: options.includeObservability });
|
|
37882
38035
|
const backupDir = roleBackupDir(installPath, role);
|
|
37883
38036
|
mkdirSync12(backupDir, { recursive: true, mode: 448 });
|
|
37884
|
-
const archivePath = options.output ?
|
|
38037
|
+
const archivePath = options.output ? resolve7(options.output) : join15(backupDir, options.preUpdate ? `latest-pre-update-${role}.tar.gz` : `openmates-${role}-${nowStamp()}.tar.gz`);
|
|
37885
38038
|
mkdirSync12(dirname9(archivePath), { recursive: true, mode: 448 });
|
|
37886
38039
|
const tempDir = mkdtempSync2(join15(backupDir, ".tmp-"));
|
|
37887
38040
|
const env = readEnvMap(installPath);
|
|
@@ -37936,7 +38089,7 @@ function validateExtractedServerBackup(tempDir, role) {
|
|
|
37936
38089
|
}
|
|
37937
38090
|
}
|
|
37938
38091
|
function withValidatedServerBackup(installPath, role, file, useBackup, tempRoot = roleBackupDir(installPath, role)) {
|
|
37939
|
-
const archivePath =
|
|
38092
|
+
const archivePath = resolve7(file);
|
|
37940
38093
|
if (!existsSync11(archivePath)) throw new Error(`Backup file not found: ${archivePath}`);
|
|
37941
38094
|
mkdirSync12(tempRoot, { recursive: true, mode: 448 });
|
|
37942
38095
|
const tempDir = mkdtempSync2(join15(tempRoot, ".restore-"));
|
|
@@ -38291,12 +38444,12 @@ async function serverRegister(flags) {
|
|
|
38291
38444
|
if (!existsSync11(envPath)) {
|
|
38292
38445
|
throw new Error(`Runtime env file not found: ${envPath}`);
|
|
38293
38446
|
}
|
|
38294
|
-
const gitRoot =
|
|
38447
|
+
const gitRoot = resolve7(exec("git rev-parse --show-toplevel", installPath));
|
|
38295
38448
|
if (gitRoot !== installPath) {
|
|
38296
38449
|
throw new Error(`--path must point to the OpenMates Git checkout root (${gitRoot}).`);
|
|
38297
38450
|
}
|
|
38298
38451
|
const existing = loadServerConfig();
|
|
38299
|
-
if (existing?.installPath &&
|
|
38452
|
+
if (existing?.installPath && resolve7(existing.installPath) !== installPath && flags.yes !== true) {
|
|
38300
38453
|
throw new Error(
|
|
38301
38454
|
`Another server is registered at ${existing.installPath}. Rerun with --yes to replace the local CLI registration; no server data will be changed.`
|
|
38302
38455
|
);
|
|
@@ -38346,8 +38499,8 @@ async function serverRegister(flags) {
|
|
|
38346
38499
|
}
|
|
38347
38500
|
}
|
|
38348
38501
|
async function serverInstall(flags) {
|
|
38349
|
-
const installPath = typeof flags.path === "string" ?
|
|
38350
|
-
const sourcePath = typeof flags["source-path"] === "string" ?
|
|
38502
|
+
const installPath = typeof flags.path === "string" ? resolve7(flags.path) : DEFAULT_INSTALL_PATH;
|
|
38503
|
+
const sourcePath = typeof flags["source-path"] === "string" ? resolve7(flags["source-path"]) : null;
|
|
38351
38504
|
const fromSource = flags["from-source"] === true || sourcePath !== null;
|
|
38352
38505
|
const role = getServerRole(flags, null);
|
|
38353
38506
|
const profile = getCoreProfile(flags, null);
|
|
@@ -38372,7 +38525,7 @@ async function serverInstall(flags) {
|
|
|
38372
38525
|
mkdirSync12(installPath, { recursive: true });
|
|
38373
38526
|
ensureRuntimeMetricsDirectory(installPath);
|
|
38374
38527
|
if (typeof flags["env-path"] === "string") {
|
|
38375
|
-
const envSource =
|
|
38528
|
+
const envSource = resolve7(flags["env-path"]);
|
|
38376
38529
|
if (!existsSync11(envSource)) {
|
|
38377
38530
|
throw new Error(`Env file not found: ${envSource}`);
|
|
38378
38531
|
}
|
|
@@ -38450,7 +38603,7 @@ CLI default API: ${cliUrls2.apiUrl}`);
|
|
|
38450
38603
|
}
|
|
38451
38604
|
ensureRuntimeMetricsDirectory(installPath);
|
|
38452
38605
|
if (typeof flags["env-path"] === "string") {
|
|
38453
|
-
const envSource =
|
|
38606
|
+
const envSource = resolve7(flags["env-path"]);
|
|
38454
38607
|
if (!existsSync11(envSource)) {
|
|
38455
38608
|
throw new Error(`Env file not found: ${envSource}`);
|
|
38456
38609
|
}
|
|
@@ -38727,7 +38880,7 @@ async function persistRuntimeResult(installPath, role, output) {
|
|
|
38727
38880
|
return deliveries.flat();
|
|
38728
38881
|
}
|
|
38729
38882
|
async function installRuntimeMonitoringServices(installPath, role) {
|
|
38730
|
-
const executablePath =
|
|
38883
|
+
const executablePath = resolve7(process.argv[1] ?? "/usr/local/bin/openmates");
|
|
38731
38884
|
const plan = planRuntimeMonitoringServices({ role, installPath, executablePath });
|
|
38732
38885
|
const notificationConfig = runtimeNotificationConfig(installPath);
|
|
38733
38886
|
const emailServiceAvailable = notificationConfig.email ? await probeRuntimeEmailService(notificationConfig.email) : false;
|
|
@@ -38814,7 +38967,9 @@ async function autoInstallRuntimeMonitoringServices(installPath, role) {
|
|
|
38814
38967
|
}
|
|
38815
38968
|
function caddyUpdatePlan(installPath, role, config, flags) {
|
|
38816
38969
|
if (flags["caddy-config"] === true) throw new Error("Provide --caddy-config <file>.");
|
|
38817
|
-
const
|
|
38970
|
+
const explicit = typeof flags["caddy-config"] === "string" ? flags["caddy-config"] : void 0;
|
|
38971
|
+
const configPath = detectCaddyConfigPath(explicit) ?? "/etc/caddy/Caddyfile";
|
|
38972
|
+
if (explicit && !existsSync11(configPath)) throw new Error("caddy_explicit_config_missing");
|
|
38818
38973
|
const required2 = role === "core" && getInstallDeploymentMode(installPath, config) === "official_cloud";
|
|
38819
38974
|
if (!existsSync11(configPath) && required2) throw new Error("Managed cloud Caddyfile is missing; update cannot proceed.");
|
|
38820
38975
|
const prior = role === "upload" ? readCaddyUpdateState(join15(installPath, ".openmates", "caddy", `${role}.json`), configPath, null) : void 0;
|
|
@@ -38896,7 +39051,69 @@ async function runCaddyUpdateStep(input) {
|
|
|
38896
39051
|
} catch (error) {
|
|
38897
39052
|
const reason = error instanceof Error && /^caddy_[a-z_:-]+$/.test(error.message) ? error.message : "caddy_update_failed";
|
|
38898
39053
|
writeServerUpdateStatus(input.installPath, input.role, { status: "degraded", step: "caddy-update", caddy: { status: "failed", sanitizedReason: reason } });
|
|
38899
|
-
|
|
39054
|
+
const command = caddyRetryForInstall(input.installPath, input.role, input.flags, reason);
|
|
39055
|
+
throw new Error(`Caddy update failed (${reason}); update is degraded. Updated containers remain running.
|
|
39056
|
+
After resolving the reported problem, run:
|
|
39057
|
+
${command}`);
|
|
39058
|
+
}
|
|
39059
|
+
}
|
|
39060
|
+
function caddyRetryForInstall(installPath, role, flags, reason) {
|
|
39061
|
+
const explicit = typeof flags["caddy-config"] === "string" ? flags["caddy-config"] : void 0;
|
|
39062
|
+
let configPath = explicit ?? "/path/to/active/Caddyfile";
|
|
39063
|
+
try {
|
|
39064
|
+
configPath = detectCaddyConfigPath(explicit) ?? "/etc/caddy/Caddyfile";
|
|
39065
|
+
} catch {
|
|
39066
|
+
}
|
|
39067
|
+
return caddyUpdateRetryCommand({
|
|
39068
|
+
installPath,
|
|
39069
|
+
role,
|
|
39070
|
+
configPath,
|
|
39071
|
+
profile: flags["caddy-profile"] === "official-upload" || reason === "caddy_profile_required_official_upload" ? "official-upload" : void 0
|
|
39072
|
+
});
|
|
39073
|
+
}
|
|
39074
|
+
async function updateCaddyOnly(installPath, role, config, flags) {
|
|
39075
|
+
const release2 = acquireServerUpdateLock(installPath);
|
|
39076
|
+
let result;
|
|
39077
|
+
try {
|
|
39078
|
+
await withEngineeringRuntimeOperation(installPath, "caddy-update", ["caddy"], async () => {
|
|
39079
|
+
result = await updateServerCaddy({ installPath, role, config, flags, mode: getInstallMode(installPath, config), withOverrides: flags["with-overrides"] === true || config?.composeProfile === "full" });
|
|
39080
|
+
});
|
|
39081
|
+
return result;
|
|
39082
|
+
} finally {
|
|
39083
|
+
release2();
|
|
39084
|
+
}
|
|
39085
|
+
}
|
|
39086
|
+
async function updateCaddyAfterCliUpgrade(flags) {
|
|
39087
|
+
let installPath;
|
|
39088
|
+
try {
|
|
39089
|
+
installPath = resolveServerPath(flags);
|
|
39090
|
+
} catch (error) {
|
|
39091
|
+
if (flags.path !== void 0) throw error;
|
|
39092
|
+
return void 0;
|
|
39093
|
+
}
|
|
39094
|
+
const config = loadConfigForInstallPath(installPath);
|
|
39095
|
+
const role = getServerRole(flags, config);
|
|
39096
|
+
let configPath;
|
|
39097
|
+
try {
|
|
39098
|
+
configPath = detectCaddyConfigPath(typeof flags["caddy-config"] === "string" ? flags["caddy-config"] : void 0);
|
|
39099
|
+
} catch {
|
|
39100
|
+
return { status: "pending", reason: "caddy_running_config_requires_explicit_path", retryCommand: caddyUpdateRetryCommand({ installPath, role, configPath: "/path/to/active/Caddyfile" }) };
|
|
39101
|
+
}
|
|
39102
|
+
if (!configPath) return void 0;
|
|
39103
|
+
const retryCommand = caddyUpdateRetryCommand({
|
|
39104
|
+
installPath,
|
|
39105
|
+
role,
|
|
39106
|
+
configPath,
|
|
39107
|
+
profile: flags["caddy-profile"] === "official-upload" ? "official-upload" : void 0
|
|
39108
|
+
});
|
|
39109
|
+
if (flags["dry-run"] === true || !config && typeof flags.path !== "string") {
|
|
39110
|
+
return { status: flags["dry-run"] === true ? "planned" : "pending", retryCommand };
|
|
39111
|
+
}
|
|
39112
|
+
try {
|
|
39113
|
+
return await updateCaddyOnly(installPath, role, config, { ...flags, "caddy-config": configPath });
|
|
39114
|
+
} catch (error) {
|
|
39115
|
+
const reason = error instanceof Error && /^caddy_[a-z_:-]+$/.test(error.message) ? error.message : "caddy_update_failed";
|
|
39116
|
+
return { status: "pending", retryCommand: reason === "caddy_profile_required_official_upload" ? caddyUpdateRetryCommand({ installPath, role, configPath, profile: "official-upload" }) : retryCommand, reason };
|
|
38900
39117
|
}
|
|
38901
39118
|
}
|
|
38902
39119
|
async function serverUpdate(client2, rest, flags) {
|
|
@@ -39515,7 +39732,7 @@ async function serverMonitoring(rest, flags) {
|
|
|
39515
39732
|
const config = loadConfigForInstallPath(installPath);
|
|
39516
39733
|
const role = getServerRole(flags, config);
|
|
39517
39734
|
if (rest[0] === "install-service") {
|
|
39518
|
-
const plan = planRuntimeMonitoringServices({ role, installPath, executablePath:
|
|
39735
|
+
const plan = planRuntimeMonitoringServices({ role, installPath, executablePath: resolve7(process.argv[1] ?? "/usr/local/bin/openmates") });
|
|
39519
39736
|
const files = [
|
|
39520
39737
|
[plan.serviceName, plan.unit],
|
|
39521
39738
|
[plan.timerName, plan.timer],
|
|
@@ -40212,9 +40429,35 @@ async function serverPreflight(flags) {
|
|
|
40212
40429
|
console.log(` Caddy steps: ${caddyPlan.steps.join(" -> ")}`);
|
|
40213
40430
|
}
|
|
40214
40431
|
async function serverCaddy(rest, flags) {
|
|
40432
|
+
if (rest[0] === "update") {
|
|
40433
|
+
if (flags["caddy-config"] === true) throw new Error("Provide --caddy-config <file>.");
|
|
40434
|
+
const installPath = resolveServerPath(flags);
|
|
40435
|
+
const config2 = loadConfigForInstallPath(installPath);
|
|
40436
|
+
const role2 = getServerRole(flags, config2);
|
|
40437
|
+
try {
|
|
40438
|
+
const plan2 = caddyUpdatePlan(installPath, role2, config2, flags);
|
|
40439
|
+
const retryCommand = caddyUpdateRetryCommand({ installPath, role: role2, configPath: plan2.configPath, profile: plan2.profile });
|
|
40440
|
+
if (flags["dry-run"] === true) {
|
|
40441
|
+
if (flags.json === true) printJson({ command: "caddy update", ...plan2, role: role2, path: installPath, mode: getInstallMode(installPath, config2), retryCommand });
|
|
40442
|
+
else console.log(`Caddy release update: ${plan2.status}
|
|
40443
|
+
Run: ${retryCommand}`);
|
|
40444
|
+
return;
|
|
40445
|
+
}
|
|
40446
|
+
const result = plan2.status === "not_installed" ? { status: "not_installed" } : await updateCaddyOnly(installPath, role2, config2, { ...flags, "caddy-config": plan2.configPath });
|
|
40447
|
+
if (flags.json === true) printJson({ command: "caddy update", role: role2, ...result });
|
|
40448
|
+
else console.log(`Caddy: ${result.status}`);
|
|
40449
|
+
} catch (error) {
|
|
40450
|
+
const reason = error instanceof Error && /^caddy_[a-z_:-]+$/.test(error.message) ? error.message : "caddy_update_failed";
|
|
40451
|
+
const retryCommand = caddyRetryForInstall(installPath, role2, flags, reason);
|
|
40452
|
+
throw new Error(`Caddy update failed (${reason}).
|
|
40453
|
+
After resolving the reported problem, run:
|
|
40454
|
+
${retryCommand}`);
|
|
40455
|
+
}
|
|
40456
|
+
return;
|
|
40457
|
+
}
|
|
40215
40458
|
const action = rest[0] ?? "status";
|
|
40216
40459
|
if (!["check", "status", "diff", "apply"].includes(action)) {
|
|
40217
|
-
throw new Error("Usage: openmates server caddy check|status|diff|apply [--role core|upload|preview]");
|
|
40460
|
+
throw new Error("Usage: openmates server caddy check|status|diff|apply|update [--role core|upload|preview]");
|
|
40218
40461
|
}
|
|
40219
40462
|
const config = loadServerConfig();
|
|
40220
40463
|
const role = getServerRole(flags, config);
|
|
@@ -40503,6 +40746,8 @@ Command Options:
|
|
|
40503
40746
|
|
|
40504
40747
|
caddy:
|
|
40505
40748
|
openmates server caddy check|status|diff|apply [--role core|upload|preview] [--config /etc/caddy/Caddyfile]
|
|
40749
|
+
openmates server caddy update [--path <installation>] [--role core|upload|preview] [--caddy-config <file>] [--dry-run]
|
|
40750
|
+
Merge the installed server release's configuration, preserve host edits, validate and reload.
|
|
40506
40751
|
|
|
40507
40752
|
reset:
|
|
40508
40753
|
--delete-user-data-only Only delete database and cache (preserve config)
|
|
@@ -40605,7 +40850,7 @@ async function handleServer(client2, subcommand, rest, flags) {
|
|
|
40605
40850
|
|
|
40606
40851
|
// src/codeRunInput.ts
|
|
40607
40852
|
import { readdir, readFile as readFile2, stat as stat2 } from "fs/promises";
|
|
40608
|
-
import { basename as basename3, relative as relative2, resolve as
|
|
40853
|
+
import { basename as basename3, relative as relative2, resolve as resolve8 } from "path";
|
|
40609
40854
|
var CODE_RUN_MAX_FILES = 50;
|
|
40610
40855
|
var CODE_RUN_MAX_FILE_BYTES = 1e6;
|
|
40611
40856
|
var CODE_RUN_MAX_TOTAL_BYTES = 1e7;
|
|
@@ -40649,7 +40894,7 @@ async function buildCodeRunRequestsFromFlags(flags) {
|
|
|
40649
40894
|
}, buffer.byteLength);
|
|
40650
40895
|
}
|
|
40651
40896
|
for (const filePath of toList(flags.file)) {
|
|
40652
|
-
const absolute =
|
|
40897
|
+
const absolute = resolve8(filePath);
|
|
40653
40898
|
const buffer = await readFile2(absolute);
|
|
40654
40899
|
const sandboxPath = normalizeCodeRunPath(basename3(filePath));
|
|
40655
40900
|
addFile({
|
|
@@ -40661,7 +40906,7 @@ async function buildCodeRunRequestsFromFlags(flags) {
|
|
|
40661
40906
|
}, buffer.byteLength);
|
|
40662
40907
|
}
|
|
40663
40908
|
for (const dirPath of toList(flags.dir)) {
|
|
40664
|
-
const root =
|
|
40909
|
+
const root = resolve8(dirPath);
|
|
40665
40910
|
const dirFiles = await collectDirectoryFiles(root, flags.include, flags.exclude);
|
|
40666
40911
|
for (const absolute of dirFiles) {
|
|
40667
40912
|
const sandboxPath = normalizeCodeRunPath(relative2(root, absolute).replace(/\\/g, "/"));
|
|
@@ -40678,10 +40923,10 @@ async function buildCodeRunRequestsFromFlags(flags) {
|
|
|
40678
40923
|
for (const url of toList(flags.url)) {
|
|
40679
40924
|
const response = await fetch(url);
|
|
40680
40925
|
if (!response.ok) throw new Error(`Failed to download Code Run URL ${redactUrl(url)} (HTTP ${response.status})`);
|
|
40681
|
-
const
|
|
40926
|
+
const text7 = await response.text();
|
|
40682
40927
|
const urlPath = new URL(url).pathname;
|
|
40683
40928
|
const sandboxPath = normalizeCodeRunPath(entry || basename3(urlPath) || "main.txt");
|
|
40684
|
-
const buffer = Buffer.from(
|
|
40929
|
+
const buffer = Buffer.from(text7, "utf8");
|
|
40685
40930
|
addFile({
|
|
40686
40931
|
path: sandboxPath,
|
|
40687
40932
|
content_base64: buffer.toString("base64"),
|
|
@@ -40691,9 +40936,9 @@ async function buildCodeRunRequestsFromFlags(flags) {
|
|
|
40691
40936
|
}, buffer.byteLength);
|
|
40692
40937
|
}
|
|
40693
40938
|
if (flags.repo) {
|
|
40694
|
-
await addGithubRepoFiles(flags.repo, toList(flags.include), async (path2,
|
|
40939
|
+
await addGithubRepoFiles(flags.repo, toList(flags.include), async (path2, text7) => {
|
|
40695
40940
|
const sandboxPath = normalizeCodeRunPath(path2);
|
|
40696
|
-
const buffer = Buffer.from(
|
|
40941
|
+
const buffer = Buffer.from(text7, "utf8");
|
|
40697
40942
|
addFile({
|
|
40698
40943
|
path: sandboxPath,
|
|
40699
40944
|
content_base64: buffer.toString("base64"),
|
|
@@ -40758,7 +41003,7 @@ async function collectDirectoryFiles(root, include, exclude) {
|
|
|
40758
41003
|
const files = [];
|
|
40759
41004
|
async function walk(directory) {
|
|
40760
41005
|
for (const entry of await readdir(directory, { withFileTypes: true })) {
|
|
40761
|
-
const absolute =
|
|
41006
|
+
const absolute = resolve8(directory, entry.name);
|
|
40762
41007
|
const rel = relative2(root, absolute).replace(/\\/g, "/");
|
|
40763
41008
|
if (matchesAny(rel, excludes) || matchesAny(entry.name, excludes)) continue;
|
|
40764
41009
|
if (entry.isDirectory()) {
|
|
@@ -59413,6 +59658,14 @@ Only output the final Markdown table. Do NOT include explanations, notes, or any
|
|
|
59413
59658
|
}
|
|
59414
59659
|
}
|
|
59415
59660
|
},
|
|
59661
|
+
openmates: {
|
|
59662
|
+
memories: {
|
|
59663
|
+
text: "Memories",
|
|
59664
|
+
description: {
|
|
59665
|
+
text: "Your facts, preferences and reusable guidance. Shared with a mate only after permission or an explicit mention."
|
|
59666
|
+
}
|
|
59667
|
+
}
|
|
59668
|
+
},
|
|
59416
59669
|
plants: {
|
|
59417
59670
|
my_plants: {
|
|
59418
59671
|
text: "My Plants",
|
|
@@ -73458,6 +73711,152 @@ As of mid-2026, the severe supply shocks from the 2024\u20132025 avian flu have
|
|
|
73458
73711
|
text: "Sophia"
|
|
73459
73712
|
}
|
|
73460
73713
|
},
|
|
73714
|
+
memories: {
|
|
73715
|
+
manage: {
|
|
73716
|
+
text: "Memories"
|
|
73717
|
+
},
|
|
73718
|
+
guide_description: {
|
|
73719
|
+
text: "Save facts, preferences or reusable guidance as a Memory. Focus modes guide your current work; Specifications define required outcomes."
|
|
73720
|
+
},
|
|
73721
|
+
scope: {
|
|
73722
|
+
text: "Memory source"
|
|
73723
|
+
},
|
|
73724
|
+
source_app: {
|
|
73725
|
+
text: "App-provided"
|
|
73726
|
+
},
|
|
73727
|
+
sources_help: {
|
|
73728
|
+
text: "Public memories are provided by apps and load automatically when relevant. Private memories are encrypted. Personal memories are shared with your approval or an explicit mention; Project memories load with active Project access."
|
|
73729
|
+
},
|
|
73730
|
+
visibility_public: {
|
|
73731
|
+
text: "Public"
|
|
73732
|
+
},
|
|
73733
|
+
visibility_private: {
|
|
73734
|
+
text: "Private"
|
|
73735
|
+
},
|
|
73736
|
+
source_personal: {
|
|
73737
|
+
text: "Personal"
|
|
73738
|
+
},
|
|
73739
|
+
source_project: {
|
|
73740
|
+
text: "Project"
|
|
73741
|
+
},
|
|
73742
|
+
loaded: {
|
|
73743
|
+
text: "Loaded {count} memories."
|
|
73744
|
+
},
|
|
73745
|
+
revision: {
|
|
73746
|
+
text: "Revision"
|
|
73747
|
+
},
|
|
73748
|
+
project_storage: {
|
|
73749
|
+
text: "Project Memories are encrypted Markdown files and load when relevant while this chat has active Project access."
|
|
73750
|
+
},
|
|
73751
|
+
activation_required: {
|
|
73752
|
+
text: "Activate this Project in a chat before creating or editing its Memories."
|
|
73753
|
+
},
|
|
73754
|
+
title: {
|
|
73755
|
+
text: "Title"
|
|
73756
|
+
},
|
|
73757
|
+
description: {
|
|
73758
|
+
text: "Description"
|
|
73759
|
+
},
|
|
73760
|
+
when_to_use: {
|
|
73761
|
+
text: "When to use"
|
|
73762
|
+
},
|
|
73763
|
+
practices: {
|
|
73764
|
+
text: "Memory (Markdown)"
|
|
73765
|
+
},
|
|
73766
|
+
empty: {
|
|
73767
|
+
text: "No Memories saved here yet."
|
|
73768
|
+
},
|
|
73769
|
+
new: {
|
|
73770
|
+
text: "New Memory"
|
|
73771
|
+
},
|
|
73772
|
+
saved: {
|
|
73773
|
+
text: "Memory saved."
|
|
73774
|
+
},
|
|
73775
|
+
invalid_document: {
|
|
73776
|
+
text: "Add a title, description, applicability and practices within the field limits."
|
|
73777
|
+
},
|
|
73778
|
+
save_failed: {
|
|
73779
|
+
text: "Could not load or save the Memories. Please try again."
|
|
73780
|
+
},
|
|
73781
|
+
authoring_suggestions: {
|
|
73782
|
+
text: "Suggested Project improvements"
|
|
73783
|
+
},
|
|
73784
|
+
create_focus: {
|
|
73785
|
+
text: "Create Focus"
|
|
73786
|
+
},
|
|
73787
|
+
update_focus: {
|
|
73788
|
+
text: "Update Focus"
|
|
73789
|
+
},
|
|
73790
|
+
create_workflow: {
|
|
73791
|
+
text: "Create Workflow"
|
|
73792
|
+
},
|
|
73793
|
+
update_workflow: {
|
|
73794
|
+
text: "Update Workflow"
|
|
73795
|
+
},
|
|
73796
|
+
authoring_started: {
|
|
73797
|
+
text: "Started"
|
|
73798
|
+
},
|
|
73799
|
+
authoring_failed: {
|
|
73800
|
+
text: "Could not start this update. Please try again."
|
|
73801
|
+
},
|
|
73802
|
+
expanded: {
|
|
73803
|
+
text: "Expanded"
|
|
73804
|
+
},
|
|
73805
|
+
collapsed: {
|
|
73806
|
+
text: "Collapsed"
|
|
73807
|
+
},
|
|
73808
|
+
authoring_save_failed: {
|
|
73809
|
+
text: "Could not save this draft. Please try again."
|
|
73810
|
+
},
|
|
73811
|
+
review_draft: {
|
|
73812
|
+
text: "Review draft"
|
|
73813
|
+
},
|
|
73814
|
+
save_draft: {
|
|
73815
|
+
text: "Save draft"
|
|
73816
|
+
},
|
|
73817
|
+
job_running: {
|
|
73818
|
+
text: "Working on this improvement\u2026"
|
|
73819
|
+
},
|
|
73820
|
+
job_queued: {
|
|
73821
|
+
text: "Waiting to start."
|
|
73822
|
+
},
|
|
73823
|
+
job_needs_input: {
|
|
73824
|
+
text: "More information is needed."
|
|
73825
|
+
},
|
|
73826
|
+
job_needs_save: {
|
|
73827
|
+
text: "Draft ready for review and saving."
|
|
73828
|
+
},
|
|
73829
|
+
job_needs_binding_save: {
|
|
73830
|
+
text: "Save the remaining Project file connection."
|
|
73831
|
+
},
|
|
73832
|
+
job_pending_file: {
|
|
73833
|
+
text: "Waiting for the connected file."
|
|
73834
|
+
},
|
|
73835
|
+
job_partial: {
|
|
73836
|
+
text: "Some changes completed. The remaining changes need attention."
|
|
73837
|
+
},
|
|
73838
|
+
job_conflict: {
|
|
73839
|
+
text: "The source changed. Review the conflict before continuing."
|
|
73840
|
+
},
|
|
73841
|
+
job_ready: {
|
|
73842
|
+
text: "Project improvement saved."
|
|
73843
|
+
},
|
|
73844
|
+
job_failed: {
|
|
73845
|
+
text: "This improvement could not be completed."
|
|
73846
|
+
},
|
|
73847
|
+
job_saved: {
|
|
73848
|
+
text: "Saved."
|
|
73849
|
+
},
|
|
73850
|
+
job_cancelled: {
|
|
73851
|
+
text: "Cancelled."
|
|
73852
|
+
},
|
|
73853
|
+
job_waiting: {
|
|
73854
|
+
text: "Waiting for a job update."
|
|
73855
|
+
},
|
|
73856
|
+
app_loading: {
|
|
73857
|
+
text: "Public \xB7 Provided by the app \xB7 Read-only \xB7 Loads automatically when relevant"
|
|
73858
|
+
}
|
|
73859
|
+
},
|
|
73461
73860
|
metadata: {
|
|
73462
73861
|
default: {
|
|
73463
73862
|
title: {
|
|
@@ -84150,7 +84549,7 @@ function buildAssistantFeedbackDecision(rating) {
|
|
|
84150
84549
|
import { createHash as createHash18, randomUUID as randomUUID15 } from "crypto";
|
|
84151
84550
|
import { existsSync as existsSync12, mkdtempSync as mkdtempSync3, readFileSync as readFileSync13, readdirSync as readdirSync6, writeFileSync as writeFileSync8 } from "fs";
|
|
84152
84551
|
import { tmpdir as tmpdir3 } from "os";
|
|
84153
|
-
import { dirname as dirname10, join as join16, resolve as
|
|
84552
|
+
import { dirname as dirname10, join as join16, resolve as resolve9 } from "path";
|
|
84154
84553
|
import { fileURLToPath } from "url";
|
|
84155
84554
|
var DEFAULT_JUDGE_MODEL = "google/gemini-3-flash-preview";
|
|
84156
84555
|
var DEFAULT_PROMPT_BUDGET_MODEL = "google/gemini-3.5-flash";
|
|
@@ -84564,7 +84963,7 @@ async function handleBenchmark(client2, subcommand, rest, flags) {
|
|
|
84564
84963
|
const dryRun = flags["dry-run"] === true;
|
|
84565
84964
|
const output = typeof flags.output === "string" ? flags.output : void 0;
|
|
84566
84965
|
const runId = typeof flags["run-id"] === "string" ? flags["run-id"] : randomUUID15();
|
|
84567
|
-
const imagePath = typeof flags.image === "string" ?
|
|
84966
|
+
const imagePath = typeof flags.image === "string" ? resolve9(flags.image) : defaultImageFixturePath();
|
|
84568
84967
|
if (!dryRun && flags["confirm-spend-credits"] !== true) {
|
|
84569
84968
|
throw new Error(
|
|
84570
84969
|
"Benchmark runs spend real credits from the logged-in account. Rerun with --confirm-spend-credits, or use --dry-run to preview the plan."
|
|
@@ -85284,13 +85683,13 @@ function parseJudgment(answer) {
|
|
|
85284
85683
|
return { score: null, reason: null };
|
|
85285
85684
|
}
|
|
85286
85685
|
}
|
|
85287
|
-
function extractJsonObject(
|
|
85288
|
-
const fenced =
|
|
85686
|
+
function extractJsonObject(text7) {
|
|
85687
|
+
const fenced = text7.match(/```(?:json)?\s*([\s\S]*?)\s*```/i);
|
|
85289
85688
|
if (fenced) return fenced[1];
|
|
85290
|
-
const start =
|
|
85291
|
-
const end =
|
|
85689
|
+
const start = text7.indexOf("{");
|
|
85690
|
+
const end = text7.lastIndexOf("}");
|
|
85292
85691
|
if (start === -1 || end === -1 || end <= start) return null;
|
|
85293
|
-
return
|
|
85692
|
+
return text7.slice(start, end + 1);
|
|
85294
85693
|
}
|
|
85295
85694
|
function loadPricingForModels(models) {
|
|
85296
85695
|
const availablePricing = loadProviderPricing();
|
|
@@ -85319,21 +85718,21 @@ function loadProviderPricing() {
|
|
|
85319
85718
|
for (const fileName of readdirSync6(providersDir)) {
|
|
85320
85719
|
if (!fileName.endsWith(".yml")) continue;
|
|
85321
85720
|
const filePath = join16(providersDir, fileName);
|
|
85322
|
-
const
|
|
85323
|
-
const provider = parseProviderId(
|
|
85324
|
-
for (const modelPricing of parseModelPricing(
|
|
85721
|
+
const text7 = readFileSync13(filePath, "utf-8");
|
|
85722
|
+
const provider = parseProviderId(text7) ?? fileName.replace(/\.yml$/, "");
|
|
85723
|
+
for (const modelPricing of parseModelPricing(text7, provider)) {
|
|
85325
85724
|
pricing.set(`${modelPricing.provider}/${modelPricing.modelId}`, modelPricing);
|
|
85326
85725
|
pricing.set(modelPricing.modelId, modelPricing);
|
|
85327
85726
|
}
|
|
85328
85727
|
}
|
|
85329
85728
|
return pricing;
|
|
85330
85729
|
}
|
|
85331
|
-
function parseProviderId(
|
|
85332
|
-
const match =
|
|
85730
|
+
function parseProviderId(text7) {
|
|
85731
|
+
const match = text7.match(/^provider_id:\s*["']?([^"'\n]+)["']?/m);
|
|
85333
85732
|
return match?.[1]?.trim() ?? null;
|
|
85334
85733
|
}
|
|
85335
|
-
function parseModelPricing(
|
|
85336
|
-
const lines =
|
|
85734
|
+
function parseModelPricing(text7, provider) {
|
|
85735
|
+
const lines = text7.split("\n");
|
|
85337
85736
|
const results = [];
|
|
85338
85737
|
let modelId = null;
|
|
85339
85738
|
let inModel = false;
|
|
@@ -85376,7 +85775,7 @@ function findProvidersDir() {
|
|
|
85376
85775
|
const candidate = join16(current, "backend", "providers");
|
|
85377
85776
|
if (existsSync12(candidate)) return candidate;
|
|
85378
85777
|
const parentCandidate = join16(current, "..", "..", "backend", "providers");
|
|
85379
|
-
if (existsSync12(parentCandidate)) return
|
|
85778
|
+
if (existsSync12(parentCandidate)) return resolve9(parentCandidate);
|
|
85380
85779
|
const next = dirname10(current);
|
|
85381
85780
|
if (next === current) break;
|
|
85382
85781
|
current = next;
|
|
@@ -85895,10 +86294,10 @@ var TuiTerminal = class {
|
|
|
85895
86294
|
const tail = rows2.length < this.height ? `\x1B[${rows2.length + 1};1H\x1B[J` : "";
|
|
85896
86295
|
this.output.write(`\x1B[?2026h${body}${tail}\x1B[?2026l`);
|
|
85897
86296
|
}
|
|
85898
|
-
receiveInput(
|
|
86297
|
+
receiveInput(text7) {
|
|
85899
86298
|
if (this.inputTimer) clearTimeout(this.inputTimer);
|
|
85900
86299
|
this.inputTimer = null;
|
|
85901
|
-
this.pendingInput +=
|
|
86300
|
+
this.pendingInput += text7;
|
|
85902
86301
|
const marker = this.paste ? "\x1B[201~" : "\x1B[200~";
|
|
85903
86302
|
const found = this.pendingInput.indexOf(marker);
|
|
85904
86303
|
if (found >= 0) {
|
|
@@ -85926,10 +86325,10 @@ var TuiTerminal = class {
|
|
|
85926
86325
|
}, 30);
|
|
85927
86326
|
}
|
|
85928
86327
|
/** Consume SGR mouse reports without letting clicks become composer text. */
|
|
85929
|
-
dispatchInput(
|
|
86328
|
+
dispatchInput(text7) {
|
|
85930
86329
|
if (this.mouseTimer) clearTimeout(this.mouseTimer);
|
|
85931
86330
|
this.mouseTimer = null;
|
|
85932
|
-
const input = this.pendingMouse +
|
|
86331
|
+
const input = this.pendingMouse + text7;
|
|
85933
86332
|
this.pendingMouse = "";
|
|
85934
86333
|
let offset = 0;
|
|
85935
86334
|
while (offset < input.length) {
|
|
@@ -86328,25 +86727,25 @@ function wrapCells(value, width) {
|
|
|
86328
86727
|
width = Math.max(1, width);
|
|
86329
86728
|
const result = [];
|
|
86330
86729
|
for (const line of terminalText(value).split("\n")) {
|
|
86331
|
-
let
|
|
86730
|
+
let text7 = "", used = 0;
|
|
86332
86731
|
for (const { segment } of segments.segment(line)) {
|
|
86333
86732
|
const size = graphemeWidth(segment);
|
|
86334
86733
|
if (size > width) {
|
|
86335
|
-
if (
|
|
86734
|
+
if (text7) result.push(text7);
|
|
86336
86735
|
result.push("?");
|
|
86337
|
-
|
|
86736
|
+
text7 = "";
|
|
86338
86737
|
used = 0;
|
|
86339
86738
|
continue;
|
|
86340
86739
|
}
|
|
86341
86740
|
if (used + size > width) {
|
|
86342
|
-
result.push(
|
|
86343
|
-
|
|
86741
|
+
result.push(text7);
|
|
86742
|
+
text7 = "";
|
|
86344
86743
|
used = 0;
|
|
86345
86744
|
}
|
|
86346
|
-
|
|
86745
|
+
text7 += segment;
|
|
86347
86746
|
used += size;
|
|
86348
86747
|
}
|
|
86349
|
-
result.push(
|
|
86748
|
+
result.push(text7);
|
|
86350
86749
|
}
|
|
86351
86750
|
return result;
|
|
86352
86751
|
}
|
|
@@ -87000,8 +87399,8 @@ var NODE_FIELDS = {
|
|
|
87000
87399
|
custom_code: ["code"]
|
|
87001
87400
|
};
|
|
87002
87401
|
function compact(value, max = 80) {
|
|
87003
|
-
const
|
|
87004
|
-
const oneLine3 =
|
|
87402
|
+
const text7 = typeof value === "string" ? value : Array.isArray(value) ? value.map((item) => compact(item, max)).join(", ") : value && typeof value === "object" ? Object.entries(value).map(([key, item]) => `${key.replaceAll("_", " ")}: ${compact(item, max)}`).join(" \xB7 ") : String(value);
|
|
87403
|
+
const oneLine3 = text7.replace(/\s+/g, " ");
|
|
87005
87404
|
return truncateCells(oneLine3, max);
|
|
87006
87405
|
}
|
|
87007
87406
|
function label2(node) {
|
|
@@ -87764,7 +88163,7 @@ function renderWorkspaceFrame(state, rawWidth, rawHeight, body, options = {}) {
|
|
|
87764
88163
|
const title = state.activeChat?.title && state.workspace === "chats" ? ` \xB7 ${state.activeChat.title}` : "";
|
|
87765
88164
|
const nav = contentWidth >= 90 ? `OpenMates ${labels}${title}` : `OpenMates [${titleCase(state.workspace)}] ${state.sidebarOpen ? "Sidebar open" : "Ctrl+B sidebar"}${title}`;
|
|
87766
88165
|
const inputWidth = Math.max(1, contentWidth - 6);
|
|
87767
|
-
const inputLines = state.input.split("\n").flatMap((
|
|
88166
|
+
const inputLines = state.input.split("\n").flatMap((text7) => wrapCells(text7, inputWidth));
|
|
87768
88167
|
const showComposer = state.workspace !== "apps" || state.focus === "composer" || Boolean(state.input);
|
|
87769
88168
|
const composerRows = showComposer ? Math.min(3, Math.max(1, inputLines.length)) : 0;
|
|
87770
88169
|
const bodyHeight = Math.max(1, height - 2 - (showComposer ? composerRows + 3 : 1));
|
|
@@ -87819,8 +88218,8 @@ function renderWorkspaceFrame(state, rawWidth, rawHeight, body, options = {}) {
|
|
|
87819
88218
|
let remaining = span;
|
|
87820
88219
|
rendered = "";
|
|
87821
88220
|
for (const part of style.spans) {
|
|
87822
|
-
const
|
|
87823
|
-
rendered += part.background ? backgroundLine(
|
|
88221
|
+
const text7 = truncateCells(terminalText(part.text).replace(/\n/g, " "), remaining), size = cells(text7);
|
|
88222
|
+
rendered += part.background ? backgroundLine(text7, size, part.background, mode, part.bold) : text7;
|
|
87824
88223
|
remaining -= size;
|
|
87825
88224
|
if (!remaining) break;
|
|
87826
88225
|
}
|
|
@@ -87837,12 +88236,12 @@ function renderWorkspaceFrame(state, rawWidth, rawHeight, body, options = {}) {
|
|
|
87837
88236
|
const hintColor = state.focus === "composer" ? "#a0a0a0" : "#ff553b";
|
|
87838
88237
|
const composer = [];
|
|
87839
88238
|
if (showComposer) {
|
|
87840
|
-
const inputRows = inputLines.slice(-composerRows).map((
|
|
87841
|
-
if (contentWidth < 6) composer.push(...inputRows.map((
|
|
88239
|
+
const inputRows = inputLines.slice(-composerRows).map((text7, i) => `${i ? " " : "> "}${text7 || (!state.input ? placeholder : "")}`);
|
|
88240
|
+
if (contentWidth < 6) composer.push(...inputRows.map((text7) => place(padCells(text7, contentWidth))), place(foreground(padCells(hint, contentWidth), hintColor, mode)), place(" ".repeat(contentWidth)), place(" ".repeat(contentWidth)));
|
|
87842
88241
|
else {
|
|
87843
88242
|
const edge = (left, right) => place(foreground(left + line.repeat(contentWidth - 2) + right, "#6b6b6b", mode));
|
|
87844
|
-
const inputRow = (
|
|
87845
|
-
composer.push(edge(ascii ? "+" : "\u256D", ascii ? "+" : "\u256E"), ...inputRows.map((
|
|
88243
|
+
const inputRow = (text7, color) => place(foreground(vertical, "#6b6b6b", mode) + " " + foreground(padCells(text7, contentWidth - 4), color ?? "#e6e6e6", mode) + " " + foreground(vertical, "#6b6b6b", mode));
|
|
88244
|
+
composer.push(edge(ascii ? "+" : "\u256D", ascii ? "+" : "\u256E"), ...inputRows.map((text7) => inputRow(text7)), inputRow(hint, hintColor), edge(ascii ? "+" : "\u2570", ascii ? "+" : "\u256F"));
|
|
87846
88245
|
}
|
|
87847
88246
|
}
|
|
87848
88247
|
const frame = [
|
|
@@ -87894,8 +88293,8 @@ function renderCardCarousel(cards, width, selectedIndex, focused) {
|
|
|
87894
88293
|
return { text: spans.map((span) => span.text).join(""), spans };
|
|
87895
88294
|
});
|
|
87896
88295
|
}
|
|
87897
|
-
function centeredCarouselText(
|
|
87898
|
-
const value = truncateCells(
|
|
88296
|
+
function centeredCarouselText(text7, width) {
|
|
88297
|
+
const value = truncateCells(text7, width);
|
|
87899
88298
|
return " ".repeat(Math.max(0, Math.floor((width - cells(value)) / 2))) + value;
|
|
87900
88299
|
}
|
|
87901
88300
|
|
|
@@ -88175,7 +88574,7 @@ function homeHeader(state, width, height) {
|
|
|
88175
88574
|
const title = inspiration?.feature?.title || inspiration?.title || "Daily inspiration";
|
|
88176
88575
|
const banner = [centered2(`DAILY INSPIRATION ${state.focus === "inspiration" ? "\u2039 Enter open \u203A" : "\u2039 Ctrl+O explore \u203A"}`, width), "", ...parts.map((line) => centered2(line, width)), centered2(title, width)];
|
|
88177
88576
|
while (banner.length < rows2) banner.push("");
|
|
88178
|
-
banner.forEach((
|
|
88577
|
+
banner.forEach((text7) => result.push({ text: text7, background: gradient.start }));
|
|
88179
88578
|
result.push("", { text: centered2(state.workspace === "apps" ? prompts.apps : state.username ? `Hey ${state.username}!` : "Hey there!", width), bold: true });
|
|
88180
88579
|
if (state.workspace !== "chats" || !homeChatItems(state).length) result.push({ text: centered2(state.workspace === "apps" ? "Use your apps directly and return to saved results." : prompts[state.workspace], width), color: "#cfcfcf" });
|
|
88181
88580
|
result.push("");
|
|
@@ -88397,7 +88796,15 @@ function parseApp(value, idHint = "") {
|
|
|
88397
88796
|
}];
|
|
88398
88797
|
}),
|
|
88399
88798
|
focusModes: rows(value.focus_modes).map((entry) => ({ id: string2(entry.id), name: string2(entry.name), description: string2(entry.description) })),
|
|
88400
|
-
settingsMemories:
|
|
88799
|
+
settingsMemories: [
|
|
88800
|
+
...rows(value.settings_and_memories).map((entry) => ({ id: string2(entry.id), name: string2(entry.name), description: string2(entry.description) })),
|
|
88801
|
+
...rows(value.memories).map((entry) => ({
|
|
88802
|
+
id: string2(entry.id),
|
|
88803
|
+
name: string2(entry.title),
|
|
88804
|
+
description: `App-provided \xB7 Read-only \xB7 Loads automatically when relevant. ${string2(entry.description)}`,
|
|
88805
|
+
body: string2(entry.body)
|
|
88806
|
+
}))
|
|
88807
|
+
]
|
|
88401
88808
|
};
|
|
88402
88809
|
}
|
|
88403
88810
|
async function loadTuiApps(client2) {
|
|
@@ -88482,7 +88889,7 @@ function renderTuiAppIdentity(app, width) {
|
|
|
88482
88889
|
}
|
|
88483
88890
|
function renderTuiAppTabs(tab, width) {
|
|
88484
88891
|
const tabs = ["skills", "focus_modes", "settings_memories", "embeds", "workflows"];
|
|
88485
|
-
const labels = { skills: "Skills", focus_modes: "Focus modes", settings_memories: "
|
|
88892
|
+
const labels = { skills: "Skills", focus_modes: "Focus modes", settings_memories: "Memories", embeds: "Embeds", workflows: "Workflows" };
|
|
88486
88893
|
return outlinedTabs(tabs, labels, tab, width);
|
|
88487
88894
|
}
|
|
88488
88895
|
function renderTuiApp(app, options) {
|
|
@@ -88504,9 +88911,10 @@ function renderTuiApp(app, options) {
|
|
|
88504
88911
|
if (!items.length) lines.push("Nothing in this section.");
|
|
88505
88912
|
for (const item of items) {
|
|
88506
88913
|
lines.push(truncateCells(`${item.id === options.selectedId ? ">" : " "} ${item.name}`, width));
|
|
88507
|
-
if (item.description) lines.push(
|
|
88914
|
+
if (item.description) lines.push(...textLines(` ${oneLine2(item.description)}`, width));
|
|
88915
|
+
if ("body" in item && item.body && item.id === options.selectedId) lines.push(...textLines(item.body, width));
|
|
88508
88916
|
}
|
|
88509
|
-
lines.push("", "Manage
|
|
88917
|
+
lines.push("", "Manage private Memories in the web app.");
|
|
88510
88918
|
} else if (options.tab === "embeds") lines.push("Saved results load from the encrypted Apps history. Use Enter to inspect a result.");
|
|
88511
88919
|
else lines.push("Saved workflows for this app load from Workflows. Open a workflow there to inspect it.");
|
|
88512
88920
|
return lines;
|
|
@@ -88864,8 +89272,8 @@ function readableFields(value, width) {
|
|
|
88864
89272
|
lines.push(`${indent}${label3}`);
|
|
88865
89273
|
for (const [key, entry] of Object.entries(item)) visit2(readableLabel(key), entry, `${indent} `);
|
|
88866
89274
|
} else {
|
|
88867
|
-
const
|
|
88868
|
-
const [first = "", ...rest] =
|
|
89275
|
+
const text7 = item === null ? "None" : typeof item === "boolean" ? item ? "Yes" : "No" : String(item);
|
|
89276
|
+
const [first = "", ...rest] = text7.split("\n");
|
|
88869
89277
|
lines.push(`${indent}${label3} ${first}`);
|
|
88870
89278
|
lines.push(...rest.map((line) => `${indent} ${line}`));
|
|
88871
89279
|
}
|
|
@@ -89065,7 +89473,7 @@ function renderTuiFrame(state, width, height, options = {}) {
|
|
|
89065
89473
|
return renderWorkspaceFrame(state, width, height, renderBody(state, bodyWidth, height), { ...options, stickyRows, headerRows: state.screen === "chat" || state.screen === "example" ? renderChatHeader(state, bodyWidth).length : void 0 });
|
|
89066
89474
|
}
|
|
89067
89475
|
function coloredHero(lines, rows2, gradient = PRIMARY_GRADIENT) {
|
|
89068
|
-
return lines.map((
|
|
89476
|
+
return lines.map((text7, index) => index < rows2 ? { text: text7, background: gradient.start } : text7);
|
|
89069
89477
|
}
|
|
89070
89478
|
var blueHero = (lines, rows2) => coloredHero(lines, rows2);
|
|
89071
89479
|
function homeCards(lines, width, gradients) {
|
|
@@ -89077,7 +89485,7 @@ function homeCards(lines, width, gradients) {
|
|
|
89077
89485
|
}
|
|
89078
89486
|
return groups.filter((group) => group.length).flatMap((group, index) => {
|
|
89079
89487
|
const cardWidth = Math.min(width, Math.max(...group.map(cells))), inset = Math.max(0, Math.floor((width - cardWidth) / 2));
|
|
89080
|
-
return [...group.map((
|
|
89488
|
+
return [...group.map((text7) => ({ text: text7, background: (gradients[index] ?? PRIMARY_GRADIENT).start, inset })), ""];
|
|
89081
89489
|
});
|
|
89082
89490
|
}
|
|
89083
89491
|
function renderBody(state, width, height) {
|
|
@@ -89412,9 +89820,9 @@ import { randomUUID as randomUUID19 } from "crypto";
|
|
|
89412
89820
|
var AuthoringSaveApprovalRequired = class extends Error {
|
|
89413
89821
|
digest;
|
|
89414
89822
|
mutation;
|
|
89415
|
-
constructor(
|
|
89823
|
+
constructor(digest4, mutation) {
|
|
89416
89824
|
super("Review the generated file, then choose Save to approve this exact write.");
|
|
89417
|
-
this.digest =
|
|
89825
|
+
this.digest = digest4;
|
|
89418
89826
|
this.mutation = mutation;
|
|
89419
89827
|
}
|
|
89420
89828
|
};
|
|
@@ -89431,9 +89839,9 @@ function required(value) {
|
|
|
89431
89839
|
return value;
|
|
89432
89840
|
}
|
|
89433
89841
|
function authoringReplacementPatch(path2, original, content) {
|
|
89434
|
-
const lines = (
|
|
89435
|
-
if (!
|
|
89436
|
-
const parts =
|
|
89842
|
+
const lines = (text7, prefix) => {
|
|
89843
|
+
if (!text7) return { count: 0, rows: [] };
|
|
89844
|
+
const parts = text7.split("\n");
|
|
89437
89845
|
const newline = parts.at(-1) === "";
|
|
89438
89846
|
if (newline) parts.pop();
|
|
89439
89847
|
const rows2 = parts.map((line) => prefix + line);
|
|
@@ -89511,18 +89919,18 @@ async function persistCliProjectAuthoringJob(client2, job, approvedDigest) {
|
|
|
89511
89919
|
expected_base: await projectFileContentHash(original),
|
|
89512
89920
|
patch: authoringReplacementPatch(path2, original, markdown)
|
|
89513
89921
|
} : { operation: "create_file", operation_id: operationId, path: path2, expected_base: null, content: markdown };
|
|
89514
|
-
const
|
|
89922
|
+
const digest4 = await projectFileMutationDigest(projectKey, projectId, chatId, mutation);
|
|
89515
89923
|
let receipt;
|
|
89516
89924
|
try {
|
|
89517
|
-
receipt = await client2.getProjectFileRevisionReceipt(projectId, embedId, operationId, chatId,
|
|
89925
|
+
receipt = await client2.getProjectFileRevisionReceipt(projectId, embedId, operationId, chatId, digest4, options);
|
|
89518
89926
|
} catch (error) {
|
|
89519
89927
|
if (settings.write_mode !== "always_ask" || !error || typeof error !== "object" || !("code" in error) || error.code !== "PROJECT_WRITE_APPROVAL_REQUIRED" || !("status" in error) || error.status !== 409) throw error;
|
|
89520
89928
|
receipt = null;
|
|
89521
89929
|
}
|
|
89522
89930
|
if (receipt?.status !== "committed" && settings.write_mode === "always_ask") {
|
|
89523
|
-
if (approvedDigest !==
|
|
89931
|
+
if (approvedDigest !== digest4) throw new AuthoringSaveApprovalRequired(digest4, mutation);
|
|
89524
89932
|
await fresh();
|
|
89525
|
-
await client2.approveProjectWrite(projectId, { chat_id: chatId, operation_id: operationId, proposal_digest:
|
|
89933
|
+
await client2.approveProjectWrite(projectId, { chat_id: chatId, operation_id: operationId, proposal_digest: digest4 }, options);
|
|
89526
89934
|
}
|
|
89527
89935
|
const focusMetadata = {
|
|
89528
89936
|
...metadata,
|
|
@@ -89538,8 +89946,8 @@ async function persistCliProjectAuthoringJob(client2, job, approvedDigest) {
|
|
|
89538
89946
|
for (const row of detail.items) {
|
|
89539
89947
|
if (!["embed", "upload"].includes(row.item_type) || row.deleted_target_state) continue;
|
|
89540
89948
|
const target = await decryptWithAesGcmCombined(row.target_id_encrypted, projectKey);
|
|
89541
|
-
const
|
|
89542
|
-
const meta =
|
|
89949
|
+
const text7 = row.encrypted_metadata ? await decryptWithAesGcmCombined(row.encrypted_metadata, projectKey) : null;
|
|
89950
|
+
const meta = text7 ? record6(JSON.parse(text7)) : {};
|
|
89543
89951
|
const filePath = meta.path ?? meta.file_path ?? meta.filename ?? meta.display_path;
|
|
89544
89952
|
if (target && typeof filePath === "string") files.push({ embedId: target, path: filePath });
|
|
89545
89953
|
}
|
|
@@ -89768,8 +90176,8 @@ function watchTuiAuthoring(context, event, jobId) {
|
|
|
89768
90176
|
control.watching = true;
|
|
89769
90177
|
void (async () => {
|
|
89770
90178
|
for (let attempt = 0; attempt < 40 && context.state.chatContextAuthoringControls[event.event_id] === control; attempt++) {
|
|
89771
|
-
await new Promise((
|
|
89772
|
-
const timer = setTimeout(
|
|
90179
|
+
await new Promise((resolve18) => {
|
|
90180
|
+
const timer = setTimeout(resolve18, 3e3);
|
|
89773
90181
|
timer.unref();
|
|
89774
90182
|
});
|
|
89775
90183
|
if (context.state.chatContextAuthoringControls[event.event_id] !== control) return;
|
|
@@ -89822,16 +90230,16 @@ async function openTuiAuthoringExecutor(context, event) {
|
|
|
89822
90230
|
ws,
|
|
89823
90231
|
chatId: event.chat_id,
|
|
89824
90232
|
chatKey: key,
|
|
89825
|
-
requestApproval: (request) => new Promise((
|
|
90233
|
+
requestApproval: (request) => new Promise((resolve18) => {
|
|
89826
90234
|
if (approval) {
|
|
89827
|
-
|
|
90235
|
+
resolve18(false);
|
|
89828
90236
|
return;
|
|
89829
90237
|
}
|
|
89830
|
-
approval =
|
|
90238
|
+
approval = resolve18;
|
|
89831
90239
|
control.approve = () => {
|
|
89832
90240
|
approval = void 0;
|
|
89833
90241
|
control.approve = void 0;
|
|
89834
|
-
|
|
90242
|
+
resolve18(true);
|
|
89835
90243
|
};
|
|
89836
90244
|
const entry = context.state.chatContextAuthoringJobs[event.event_id];
|
|
89837
90245
|
if (entry) entry.status = "needs_write_approval";
|
|
@@ -90220,8 +90628,8 @@ async function handleWorkspaceCommand(context, command) {
|
|
|
90220
90628
|
if (request !== state.routeVersion) return true;
|
|
90221
90629
|
state.detailTitle = embed.textPreview || (embed.appId ? `${embed.appId}${embed.skillId ? `/${embed.skillId}` : ""}` : embed.type?.replaceAll("_", " ")) || "Embed";
|
|
90222
90630
|
const body = embed.content;
|
|
90223
|
-
const
|
|
90224
|
-
state.detailLines = typeof
|
|
90631
|
+
const text7 = ["code", "markdown", "content", "text", "transcript"].map((key) => body?.[key]).find((value) => typeof value === "string");
|
|
90632
|
+
state.detailLines = typeof text7 === "string" ? text7.split("\n") : formatEmbedPreviewLines(embed, 100);
|
|
90225
90633
|
}
|
|
90226
90634
|
render();
|
|
90227
90635
|
return true;
|
|
@@ -90720,10 +91128,10 @@ async function handleWorkspaceKey(context, chunk, key) {
|
|
|
90720
91128
|
state.filter = "";
|
|
90721
91129
|
}
|
|
90722
91130
|
} else if (file) {
|
|
90723
|
-
const
|
|
91131
|
+
const text7 = await readTuiProjectFile(context.client, project, file);
|
|
90724
91132
|
if (request === state.routeVersion && state.activeProject?.id === project.id) {
|
|
90725
91133
|
state.detailTitle = file.name;
|
|
90726
|
-
state.detailLines =
|
|
91134
|
+
state.detailLines = text7.split("\n");
|
|
90727
91135
|
state.screen = "embed";
|
|
90728
91136
|
state.scrollOffset = 0;
|
|
90729
91137
|
}
|
|
@@ -90808,9 +91216,9 @@ async function handleWorkspaceKey(context, chunk, key) {
|
|
|
90808
91216
|
return true;
|
|
90809
91217
|
}
|
|
90810
91218
|
if (key.name === "return" && state.screen === "chats" && state.input.trim()) {
|
|
90811
|
-
const
|
|
91219
|
+
const text7 = state.input.trim();
|
|
90812
91220
|
newChat(state);
|
|
90813
|
-
await context.send(
|
|
91221
|
+
await context.send(text7);
|
|
90814
91222
|
return true;
|
|
90815
91223
|
}
|
|
90816
91224
|
const cursor = state.inputCursor ?? state.input.length;
|
|
@@ -90852,9 +91260,9 @@ async function handleWorkspaceKey(context, chunk, key) {
|
|
|
90852
91260
|
return true;
|
|
90853
91261
|
}
|
|
90854
91262
|
if (key.name === "paste" || !key.ctrl && !key.meta && chunk && chunk >= " ") {
|
|
90855
|
-
const
|
|
90856
|
-
state.input = state.input.slice(0, cursor) +
|
|
90857
|
-
state.inputCursor = cursor +
|
|
91263
|
+
const text7 = terminalText(chunk);
|
|
91264
|
+
state.input = state.input.slice(0, cursor) + text7 + state.input.slice(cursor);
|
|
91265
|
+
state.inputCursor = cursor + text7.length;
|
|
90858
91266
|
rememberDraft(state);
|
|
90859
91267
|
render();
|
|
90860
91268
|
return true;
|
|
@@ -91055,8 +91463,8 @@ async function runTui(client2, terminal = new TuiTerminal()) {
|
|
|
91055
91463
|
}).catch(() => {
|
|
91056
91464
|
});
|
|
91057
91465
|
}
|
|
91058
|
-
return new Promise((
|
|
91059
|
-
resolveResult =
|
|
91466
|
+
return new Promise((resolve18) => {
|
|
91467
|
+
resolveResult = resolve18;
|
|
91060
91468
|
});
|
|
91061
91469
|
}
|
|
91062
91470
|
async function handleKey(params) {
|
|
@@ -91235,13 +91643,13 @@ async function handleEnter(params) {
|
|
|
91235
91643
|
render();
|
|
91236
91644
|
return;
|
|
91237
91645
|
}
|
|
91238
|
-
const
|
|
91239
|
-
if (!
|
|
91240
|
-
if (
|
|
91241
|
-
await handleCommand({ command:
|
|
91646
|
+
const text7 = state.input.trim();
|
|
91647
|
+
if (!text7) return;
|
|
91648
|
+
if (text7.startsWith("/")) {
|
|
91649
|
+
await handleCommand({ command: text7, state, client: client2, terminal, render, finish });
|
|
91242
91650
|
return;
|
|
91243
91651
|
}
|
|
91244
|
-
await sendTuiMessage({ message:
|
|
91652
|
+
await sendTuiMessage({ message: text7, state, client: client2, render });
|
|
91245
91653
|
}
|
|
91246
91654
|
async function handleCommand(params) {
|
|
91247
91655
|
const { command, state, client: client2, terminal, render, finish } = params;
|
|
@@ -91894,17 +92302,17 @@ function clamp(value, min, max) {
|
|
|
91894
92302
|
import { createHash as createHash21 } from "crypto";
|
|
91895
92303
|
import { spawn as spawn3 } from "child_process";
|
|
91896
92304
|
import { existsSync as existsSync13, readFileSync as readFileSync14, readdirSync as readdirSync7 } from "fs";
|
|
91897
|
-
import { isAbsolute as
|
|
92305
|
+
import { isAbsolute as isAbsolute4, join as join17, resolve as resolve10 } from "path";
|
|
91898
92306
|
import lockfile4 from "proper-lockfile";
|
|
91899
92307
|
function startCodexTaskBridges(roots, snapshots, stateRoot, notice) {
|
|
91900
92308
|
const configPath = join17(stateRoot, "codex-adapter.json");
|
|
91901
92309
|
const children = [];
|
|
91902
92310
|
if (existsSync13(configPath)) {
|
|
91903
92311
|
const config = JSON.parse(readFileSync14(configPath, "utf8"));
|
|
91904
|
-
for (const root of new Set(roots.map((path2) =>
|
|
92312
|
+
for (const root of new Set(roots.map((path2) => resolve10(path2)))) {
|
|
91905
92313
|
const entry = config.repositories?.[root];
|
|
91906
|
-
if (!entry?.enabled || !entry.events_enabled || !entry.runtime || !
|
|
91907
|
-
if (!entry.snapshots?.length || !entry.snapshots.every((path2) => snapshots.includes(
|
|
92314
|
+
if (!entry?.enabled || !entry.events_enabled || !entry.runtime || !isAbsolute4(entry.runtime) || !existsSync13(entry.runtime)) continue;
|
|
92315
|
+
if (!entry.snapshots?.length || !entry.snapshots.every((path2) => snapshots.includes(resolve10(path2)))) continue;
|
|
91908
92316
|
const child = spawn3("python3", [entry.runtime, "serve", "--repository", root], {
|
|
91909
92317
|
cwd: root,
|
|
91910
92318
|
env: { ...process.env, OPENMATES_STATE_DIR: stateRoot },
|
|
@@ -92086,11 +92494,11 @@ import {
|
|
|
92086
92494
|
} from "fs";
|
|
92087
92495
|
import { spawn as spawn7 } from "child_process";
|
|
92088
92496
|
import { createHash as createHash28 } from "crypto";
|
|
92089
|
-
import { extname as extname4, join as join25, resolve as
|
|
92497
|
+
import { extname as extname4, join as join25, resolve as resolve16, relative as relative11 } from "path";
|
|
92090
92498
|
|
|
92091
92499
|
// src/projectSourceRootPolicy.ts
|
|
92092
92500
|
import { existsSync as existsSync15, realpathSync as realpathSync2, statSync as statSync2 } from "fs";
|
|
92093
|
-
import { basename as basename4, dirname as dirname11, relative as relative3, resolve as
|
|
92501
|
+
import { basename as basename4, dirname as dirname11, relative as relative3, resolve as resolve11 } from "path";
|
|
92094
92502
|
function canonicalProjectSourceRoot(sourceRoot, options = {}) {
|
|
92095
92503
|
const root = realpathSync2(sourceRoot);
|
|
92096
92504
|
if (!statSync2(root).isDirectory()) throw new Error("Project source root is not a directory");
|
|
@@ -92104,15 +92512,15 @@ function canonicalOpenMatesStateDirectory(stateDirectory = resolveStateDir()) {
|
|
|
92104
92512
|
return canonicalizePotentialPath(stateDirectory);
|
|
92105
92513
|
}
|
|
92106
92514
|
function canonicalizePotentialPath(value) {
|
|
92107
|
-
let existing =
|
|
92515
|
+
let existing = resolve11(value);
|
|
92108
92516
|
const suffix = [];
|
|
92109
92517
|
while (!existsSync15(existing)) {
|
|
92110
92518
|
const parent = dirname11(existing);
|
|
92111
|
-
if (parent === existing) return
|
|
92519
|
+
if (parent === existing) return resolve11(value);
|
|
92112
92520
|
suffix.unshift(basename4(existing));
|
|
92113
92521
|
existing = parent;
|
|
92114
92522
|
}
|
|
92115
|
-
return
|
|
92523
|
+
return resolve11(realpathSync2(existing), ...suffix);
|
|
92116
92524
|
}
|
|
92117
92525
|
function isEqualOrInside(parent, candidate) {
|
|
92118
92526
|
const path2 = relative3(parent, candidate);
|
|
@@ -92140,7 +92548,7 @@ import {
|
|
|
92140
92548
|
unlinkSync,
|
|
92141
92549
|
writeSync
|
|
92142
92550
|
} from "fs";
|
|
92143
|
-
import { dirname as dirname12, isAbsolute as
|
|
92551
|
+
import { dirname as dirname12, isAbsolute as isAbsolute5, join as join19, relative as relative4, resolve as resolve12 } from "path";
|
|
92144
92552
|
var DEFAULT_MAX_IGNORE_FILES = 128;
|
|
92145
92553
|
var DEFAULT_MAX_IGNORE_BYTES = 1024 * 1024;
|
|
92146
92554
|
var MAX_POLICY_ENTRIES = 5e4;
|
|
@@ -92187,13 +92595,13 @@ function loadProjectPathPolicy(sourceRoot, options = {}) {
|
|
|
92187
92595
|
builtin_private_paths: PROJECT_BUILTIN_PRIVATE_PATHS,
|
|
92188
92596
|
private_paths: stickyPrivatePaths
|
|
92189
92597
|
}));
|
|
92190
|
-
const
|
|
92598
|
+
const digest4 = sha2562(stableJson2({
|
|
92191
92599
|
private_digest: privateDigest,
|
|
92192
92600
|
ignore_files: ignoreFiles.map((file) => ({ path: file.path, digest: sha2562(file.content) }))
|
|
92193
92601
|
}));
|
|
92194
92602
|
const policy = {
|
|
92195
92603
|
sourceRoot: root,
|
|
92196
|
-
digest:
|
|
92604
|
+
digest: digest4,
|
|
92197
92605
|
privateDigest,
|
|
92198
92606
|
isIgnored(path2, isDirectory = false) {
|
|
92199
92607
|
const normalized = normalizeSourceRelativePath(path2);
|
|
@@ -92266,7 +92674,7 @@ function collectIgnoreFiles(policyRoot, sourceRoot, limits) {
|
|
|
92266
92674
|
for (const directory of chain.reverse()) add(join19(directory, ".gitignore"));
|
|
92267
92675
|
for (const target of limits.targetPaths) {
|
|
92268
92676
|
const normalized = target === "." ? "" : normalizeSourceRelativePath(target);
|
|
92269
|
-
const absolute = normalized ?
|
|
92677
|
+
const absolute = normalized ? resolve12(sourceRoot, normalized) : sourceRoot;
|
|
92270
92678
|
if (!isInside2(sourceRoot, absolute)) throw new Error("Project policy target escapes its source root");
|
|
92271
92679
|
const targetIsDirectory = existsSync16(absolute) && lstatSync4(absolute).isDirectory();
|
|
92272
92680
|
let directory = targetIsDirectory ? absolute : dirname12(absolute);
|
|
@@ -92306,7 +92714,7 @@ function collectIgnoreFiles(policyRoot, sourceRoot, limits) {
|
|
|
92306
92714
|
return files;
|
|
92307
92715
|
}
|
|
92308
92716
|
function updateStickyPrivatePaths(sourceRoot, additions, stateDirectory) {
|
|
92309
|
-
const stateRoot =
|
|
92717
|
+
const stateRoot = resolve12(stateDirectory, POLICY_STATE_DIRECTORY);
|
|
92310
92718
|
if (isInside2(sourceRoot, stateRoot) || isInside2(stateRoot, sourceRoot)) {
|
|
92311
92719
|
throw new Error("Project path policy state must stay outside the source root");
|
|
92312
92720
|
}
|
|
@@ -92380,7 +92788,7 @@ function preparePrivateDirectory(path2) {
|
|
|
92380
92788
|
if (!statSync3(path2).isDirectory()) throw new Error("Project path policy state is not a directory");
|
|
92381
92789
|
}
|
|
92382
92790
|
function normalizeSourceRelativePath(value) {
|
|
92383
|
-
if (typeof value !== "string" || !value || value.includes("\\") ||
|
|
92791
|
+
if (typeof value !== "string" || !value || value.includes("\\") || isAbsolute5(value) || value.split("/").some((part) => !part || part === "." || part === "..") || [...value].some((character) => character.charCodeAt(0) < 32 || character.charCodeAt(0) === 127)) {
|
|
92384
92792
|
throw new ProjectPathPolicyError(`Project path is invalid: ${String(value)}`);
|
|
92385
92793
|
}
|
|
92386
92794
|
return value;
|
|
@@ -92388,7 +92796,7 @@ function normalizeSourceRelativePath(value) {
|
|
|
92388
92796
|
function normalizeRelative(root, target) {
|
|
92389
92797
|
const result = relative4(root, target).split("\\").join("/");
|
|
92390
92798
|
if (!result || result === ".") return "";
|
|
92391
|
-
if (result.startsWith("../") || result === ".." ||
|
|
92799
|
+
if (result.startsWith("../") || result === ".." || isAbsolute5(result)) throw new Error("Project policy path escapes its root");
|
|
92392
92800
|
return result;
|
|
92393
92801
|
}
|
|
92394
92802
|
function boundedInteger(value, fallback2, label3) {
|
|
@@ -92397,8 +92805,8 @@ function boundedInteger(value, fallback2, label3) {
|
|
|
92397
92805
|
return result;
|
|
92398
92806
|
}
|
|
92399
92807
|
function isInside2(root, candidate) {
|
|
92400
|
-
const relation = relative4(
|
|
92401
|
-
return relation === "" || !relation.startsWith("..") && !
|
|
92808
|
+
const relation = relative4(resolve12(root), resolve12(candidate));
|
|
92809
|
+
return relation === "" || !relation.startsWith("..") && !isAbsolute5(relation);
|
|
92402
92810
|
}
|
|
92403
92811
|
function sha2562(value) {
|
|
92404
92812
|
return createHash23("sha256").update(value).digest("hex");
|
|
@@ -92431,7 +92839,7 @@ import {
|
|
|
92431
92839
|
writeFileSync as writeFileSync9
|
|
92432
92840
|
} from "fs";
|
|
92433
92841
|
import { tmpdir as tmpdir5 } from "os";
|
|
92434
|
-
import { basename as basename5, dirname as dirname13, isAbsolute as
|
|
92842
|
+
import { basename as basename5, dirname as dirname13, isAbsolute as isAbsolute6, join as join21, relative as relative5, resolve as resolve13 } from "path";
|
|
92435
92843
|
import lockfile6 from "proper-lockfile";
|
|
92436
92844
|
|
|
92437
92845
|
// src/projectFileRisk.ts
|
|
@@ -92791,7 +93199,7 @@ function validateMutation(input) {
|
|
|
92791
93199
|
return { ...parsed, path: validateRelativePath(parsed.path) };
|
|
92792
93200
|
}
|
|
92793
93201
|
function validateRelativePath(value) {
|
|
92794
|
-
if (typeof value !== "string" || value.length === 0 || value.length > 4096 ||
|
|
93202
|
+
if (typeof value !== "string" || value.length === 0 || value.length > 4096 || isAbsolute6(value) || value.includes("\\") || [...value].some((character) => character.charCodeAt(0) < 32 || character.charCodeAt(0) === 127) || value.split("/").some((part) => !part || part === "." || part === "..")) {
|
|
92795
93203
|
throw new RemoteFileMutationError("invalid_path", "Project file path must be a strict root-relative POSIX path");
|
|
92796
93204
|
}
|
|
92797
93205
|
return value;
|
|
@@ -93084,7 +93492,7 @@ function temporaryName() {
|
|
|
93084
93492
|
}
|
|
93085
93493
|
function isInside3(root, candidate) {
|
|
93086
93494
|
const relation = relative5(root, candidate);
|
|
93087
|
-
return relation === "" || !relation.startsWith("..") && !
|
|
93495
|
+
return relation === "" || !relation.startsWith("..") && !isAbsolute6(relation) && resolve13(root, relation) === resolve13(candidate);
|
|
93088
93496
|
}
|
|
93089
93497
|
|
|
93090
93498
|
// src/remoteFileTransfers.ts
|
|
@@ -93361,19 +93769,19 @@ async function executeRemoteFileTransfer(input) {
|
|
|
93361
93769
|
|
|
93362
93770
|
// src/remoteCommandSource.ts
|
|
93363
93771
|
import { existsSync as existsSync21, realpathSync as realpathSync10, statSync as statSync9 } from "fs";
|
|
93364
|
-
import { basename as basename7, dirname as dirname14, relative as relative10, resolve as
|
|
93772
|
+
import { basename as basename7, dirname as dirname14, relative as relative10, resolve as resolve15 } from "path";
|
|
93365
93773
|
|
|
93366
93774
|
// src/remoteCommandRuntime.ts
|
|
93367
93775
|
import { createHash as createHash26, randomUUID as randomUUID21 } from "crypto";
|
|
93368
93776
|
import { spawn as spawn6, spawnSync as spawnSync4 } from "child_process";
|
|
93369
93777
|
import { existsSync as existsSync19, lstatSync as lstatSync9, readdirSync as readdirSync11, realpathSync as realpathSync7, statSync as statSync6 } from "fs";
|
|
93370
|
-
import { isAbsolute as
|
|
93778
|
+
import { isAbsolute as isAbsolute8, join as join22, relative as relative7, resolve as resolve14, sep } from "path";
|
|
93371
93779
|
|
|
93372
93780
|
// src/remoteCommandAppArmor.ts
|
|
93373
93781
|
import { createHash as createHash25 } from "crypto";
|
|
93374
93782
|
import { spawn as spawn5 } from "child_process";
|
|
93375
93783
|
import { lstatSync as lstatSync8, readFileSync as readFileSync17, realpathSync as realpathSync6, statSync as statSync5 } from "fs";
|
|
93376
|
-
import { isAbsolute as
|
|
93784
|
+
import { isAbsolute as isAbsolute7, relative as relative6 } from "path";
|
|
93377
93785
|
var REMOTE_COMMAND_APPARMOR_BROKER = "/usr/libexec/openmates-command-apparmor";
|
|
93378
93786
|
var REMOTE_COMMAND_APPARMOR_EXEC = "/usr/bin/aa-exec";
|
|
93379
93787
|
var REMOTE_COMMAND_BWRAP = "/usr/libexec/openmates-bwrap";
|
|
@@ -93555,7 +93963,7 @@ function validatePolicyGlob(value, context) {
|
|
|
93555
93963
|
return normalized;
|
|
93556
93964
|
}
|
|
93557
93965
|
function validateProjectPath(value, context) {
|
|
93558
|
-
if (typeof value !== "string" || !value || Buffer.byteLength(value) > MAX_POLICY_PATH_BYTES ||
|
|
93966
|
+
if (typeof value !== "string" || !value || Buffer.byteLength(value) > MAX_POLICY_PATH_BYTES || isAbsolute7(value) || value.includes("\\") || value.includes("*") || value.includes("?") || value.split("/").some((part) => !part || part === "." || part === "..") || hasControl2(value)) {
|
|
93559
93967
|
throw new Error(`Invalid AppArmor ${context} path`);
|
|
93560
93968
|
}
|
|
93561
93969
|
return value;
|
|
@@ -93578,7 +93986,7 @@ function brokerIdentifier(value, context, pattern) {
|
|
|
93578
93986
|
}
|
|
93579
93987
|
function isInside4(root, candidate) {
|
|
93580
93988
|
const path2 = relative6(root, candidate);
|
|
93581
|
-
return path2 === "" || !path2.startsWith("..") && !
|
|
93989
|
+
return path2 === "" || !path2.startsWith("..") && !isAbsolute7(path2);
|
|
93582
93990
|
}
|
|
93583
93991
|
function hasControl2(value) {
|
|
93584
93992
|
return [...value].some((character) => {
|
|
@@ -93831,7 +94239,7 @@ var RemoteCommandRuntime = class {
|
|
|
93831
94239
|
}
|
|
93832
94240
|
if (prepared.sandbox_command) {
|
|
93833
94241
|
const command = prepared.sandbox_command;
|
|
93834
|
-
if (!
|
|
94242
|
+
if (!isAbsolute8(command.executable) || command.executable.includes("\0") || !Array.isArray(command.args) || command.args.some((argument) => typeof argument !== "string" || argument.includes("\0"))) {
|
|
93835
94243
|
throw new RemoteCommandError("network_profile_unavailable", "Network transport returned an invalid sandbox bridge command");
|
|
93836
94244
|
}
|
|
93837
94245
|
}
|
|
@@ -94155,7 +94563,7 @@ function prepareSandboxLaunch(preflight, authority, capability, network, appArmo
|
|
|
94155
94563
|
}
|
|
94156
94564
|
}
|
|
94157
94565
|
const appArmorEnvironment = appArmor.sandbox_environment;
|
|
94158
|
-
if (!appArmorEnvironment || Object.keys(appArmorEnvironment).length !== 1 || typeof appArmorEnvironment.LD_PRELOAD !== "string" || !
|
|
94566
|
+
if (!appArmorEnvironment || Object.keys(appArmorEnvironment).length !== 1 || typeof appArmorEnvironment.LD_PRELOAD !== "string" || !isAbsolute8(appArmorEnvironment.LD_PRELOAD) || appArmorEnvironment.LD_PRELOAD.includes("\0")) {
|
|
94159
94567
|
throw new RemoteCommandError("confinement_unavailable", "AppArmor confinement returned an invalid Git config compatibility library");
|
|
94160
94568
|
}
|
|
94161
94569
|
const environment = { ...SAFE_ENVIRONMENT, ...networkEnvironment, ...appArmorEnvironment };
|
|
@@ -94239,7 +94647,7 @@ function validatePolicy2(policy) {
|
|
|
94239
94647
|
if (policy.source_access !== "read_only" && policy.source_access !== "read_write") throw new RemoteCommandError("invalid_request", "Invalid source access");
|
|
94240
94648
|
if (policy.mode === "background" && policy.source_access !== "read_only") throw new RemoteCommandError("invalid_request", "Background commands must use read-only source access");
|
|
94241
94649
|
if (!Number.isSafeInteger(policy.deadline_ms) || policy.deadline_ms < MIN_DEADLINE_MS2 || policy.deadline_ms > MAX_DEADLINE_MS2) throw new RemoteCommandError("invalid_request", "Invalid command deadline");
|
|
94242
|
-
if (
|
|
94650
|
+
if (isAbsolute8(policy.cwd) || policy.cwd.includes("\0") || policy.cwd.split(/[\\/]/).includes("..")) throw new RemoteCommandError("invalid_request", "Command cwd must stay inside the Project");
|
|
94243
94651
|
for (const [name, value] of [["writable_profiles", policy.writable_profiles], ["credential_profiles", policy.credential_profiles]]) {
|
|
94244
94652
|
if (!Array.isArray(value) || value.some((id) => typeof id !== "string" || !/^[a-z][a-z0-9-]{0,63}$/.test(id))) throw new RemoteCommandError("invalid_request", `Invalid ${name}`);
|
|
94245
94653
|
assertUnique2(value, name);
|
|
@@ -94344,7 +94752,7 @@ function assertCapability(capability) {
|
|
|
94344
94752
|
}
|
|
94345
94753
|
function canonicalDirectory(path2) {
|
|
94346
94754
|
const canonical = realpath(path2);
|
|
94347
|
-
if (canonical ===
|
|
94755
|
+
if (canonical === resolve14("/")) throw new RemoteCommandError("invalid_request", "The host filesystem root cannot be mounted as a command resource");
|
|
94348
94756
|
if (!statSync6(canonical).isDirectory()) throw new RemoteCommandError("invalid_request", `Command resource is not a directory: ${path2}`);
|
|
94349
94757
|
return canonical;
|
|
94350
94758
|
}
|
|
@@ -94413,7 +94821,7 @@ function assertUnique2(values, context) {
|
|
|
94413
94821
|
}
|
|
94414
94822
|
function isInside5(root, candidate) {
|
|
94415
94823
|
const path2 = relative7(root, candidate);
|
|
94416
|
-
return path2 === "" || !path2.startsWith("..") && !
|
|
94824
|
+
return path2 === "" || !path2.startsWith("..") && !isAbsolute8(path2);
|
|
94417
94825
|
}
|
|
94418
94826
|
function truncateUtf8(value, maximum) {
|
|
94419
94827
|
const bytes2 = Buffer.from(value);
|
|
@@ -94443,7 +94851,7 @@ import { lookup as dnsLookup } from "dns/promises";
|
|
|
94443
94851
|
import { chmodSync as chmodSync10, mkdtempSync as mkdtempSync4, realpathSync as realpathSync8, rmSync as rmSync9, statSync as statSync7, writeFileSync as writeFileSync10 } from "fs";
|
|
94444
94852
|
import { isIP as isIP2, createConnection, createServer } from "net";
|
|
94445
94853
|
import { tmpdir as tmpdir6 } from "os";
|
|
94446
|
-
import { isAbsolute as
|
|
94854
|
+
import { isAbsolute as isAbsolute9, join as join23, relative as relative8 } from "path";
|
|
94447
94855
|
var DEFAULT_BRIDGE_PORT = 43117;
|
|
94448
94856
|
var MAX_CONNECT_HEADER_BYTES = 8 * 1024;
|
|
94449
94857
|
var CONNECT_HEADER_TIMEOUT_MS = 1e4;
|
|
@@ -94647,7 +95055,7 @@ function createPrivateControlDirectory(preflight, configuredRoots) {
|
|
|
94647
95055
|
const roots = configuredRoots ?? [process.env.XDG_RUNTIME_DIR, tmpdir6()].filter((value) => Boolean(value));
|
|
94648
95056
|
for (const candidate of roots) {
|
|
94649
95057
|
try {
|
|
94650
|
-
if (!
|
|
95058
|
+
if (!isAbsolute9(candidate) || !statSync7(candidate).isDirectory()) continue;
|
|
94651
95059
|
const root = realpathSync8(candidate);
|
|
94652
95060
|
const directory = mkdtempSync4(join23(root, "openmates-command-network-"));
|
|
94653
95061
|
chmodSync10(directory, 448);
|
|
@@ -94684,7 +95092,7 @@ function ipv6Words(address) {
|
|
|
94684
95092
|
}
|
|
94685
95093
|
function isInside6(root, candidate) {
|
|
94686
95094
|
const path2 = relative8(root, candidate);
|
|
94687
|
-
return path2 === "" || !path2.startsWith("..") && !
|
|
95095
|
+
return path2 === "" || !path2.startsWith("..") && !isAbsolute9(path2);
|
|
94688
95096
|
}
|
|
94689
95097
|
function listenUnix(server2, path2) {
|
|
94690
95098
|
return new Promise((resolvePromise, reject) => {
|
|
@@ -94708,7 +95116,7 @@ function capabilityError(message) {
|
|
|
94708
95116
|
// src/remoteCommandResourceGrants.ts
|
|
94709
95117
|
import { createHash as createHash27 } from "crypto";
|
|
94710
95118
|
import { chmodSync as chmodSync11, existsSync as existsSync20, lstatSync as lstatSync10, mkdirSync as mkdirSync17, readFileSync as readFileSync18, realpathSync as realpathSync9, renameSync as renameSync8, statSync as statSync8, writeFileSync as writeFileSync11 } from "fs";
|
|
94711
|
-
import { isAbsolute as
|
|
95119
|
+
import { isAbsolute as isAbsolute10, join as join24, relative as relative9 } from "path";
|
|
94712
95120
|
var STORE_FILE = "remote-command-resource-grants.json";
|
|
94713
95121
|
var ID = /^[a-z][a-z0-9-]{0,63}$/;
|
|
94714
95122
|
var ENV = /^[A-Z_][A-Z0-9_]{0,127}$/;
|
|
@@ -94721,7 +95129,7 @@ function listRemoteCommandResourceGrants(projectId, sourceId) {
|
|
|
94721
95129
|
function enableRemoteCommandWritableGrant(input) {
|
|
94722
95130
|
const definition = input.permissions.resource_profiles.writable.find((item) => item.id === input.profileId);
|
|
94723
95131
|
if (!definition) throw new Error(`Unknown writable profile: ${input.profileId}`);
|
|
94724
|
-
if (!
|
|
95132
|
+
if (!isAbsolute10(input.hostPath)) throw new Error("--host-path must be absolute");
|
|
94725
95133
|
const root = realpathSync9(input.projectRoot);
|
|
94726
95134
|
const hostPath = realpathSync9(input.hostPath);
|
|
94727
95135
|
if (!statSync8(hostPath).isDirectory()) throw new Error("Writable profile host path must be a directory");
|
|
@@ -94834,7 +95242,7 @@ function validateIdentity(projectId, sourceId, profileId) {
|
|
|
94834
95242
|
}
|
|
94835
95243
|
function isInside7(parent, child) {
|
|
94836
95244
|
const value = relative9(parent, child);
|
|
94837
|
-
return value !== "" && !value.startsWith("..") && !
|
|
95245
|
+
return value !== "" && !value.startsWith("..") && !isAbsolute10(value);
|
|
94838
95246
|
}
|
|
94839
95247
|
function pathsOverlap2(left, right) {
|
|
94840
95248
|
return left === right || isInside7(left, right) || isInside7(right, left);
|
|
@@ -95097,8 +95505,8 @@ var RemoteCommandSourceController = class {
|
|
|
95097
95505
|
if (!plaintext) throw new Error("Remote command request authentication failed");
|
|
95098
95506
|
const portable = parsePortableRequest(plaintext);
|
|
95099
95507
|
assertPortableBinding(portable, claimed);
|
|
95100
|
-
const
|
|
95101
|
-
if (
|
|
95508
|
+
const digest4 = await remoteCommandPortableRequestDigest(binding.projectKey, portable);
|
|
95509
|
+
if (digest4 !== claimed.request_digest) throw new Error("Remote command request HMAC mismatch");
|
|
95102
95510
|
state.portable = portable;
|
|
95103
95511
|
const request = await this.#buildRuntimeRequest(binding, portable.policy, portable.execution_id);
|
|
95104
95512
|
const preflight = createRemoteCommandPreflight(request);
|
|
@@ -95493,7 +95901,7 @@ function validateSummary(value) {
|
|
|
95493
95901
|
chat_id: identifier4(item.chat_id, "chat_id"),
|
|
95494
95902
|
project_id: identifier4(item.project_id, "project_id"),
|
|
95495
95903
|
source_id: identifier4(item.source_id, "source_id"),
|
|
95496
|
-
state:
|
|
95904
|
+
state: text6(item.state, "state"),
|
|
95497
95905
|
last_sequence: integer3(item.last_sequence ?? -1, "last_sequence", -1),
|
|
95498
95906
|
lease_expires_at: integer3(item.lease_expires_at ?? 0, "lease_expires_at", 0)
|
|
95499
95907
|
};
|
|
@@ -95509,12 +95917,12 @@ function validateClaimedRequest(value, summary, binding, sourceSessionId) {
|
|
|
95509
95917
|
chat_id: identifier4(item.chat_id, "chat_id"),
|
|
95510
95918
|
project_id: identifier4(item.project_id, "project_id"),
|
|
95511
95919
|
source_id: identifier4(item.source_id, "source_id"),
|
|
95512
|
-
state:
|
|
95513
|
-
encrypted_request:
|
|
95514
|
-
request_digest:
|
|
95920
|
+
state: text6(item.state, "state"),
|
|
95921
|
+
encrypted_request: text6(item.encrypted_request, "encrypted_request"),
|
|
95922
|
+
request_digest: text6(item.request_digest, "request_digest"),
|
|
95515
95923
|
approval,
|
|
95516
95924
|
key_epoch: integer3(item.key_epoch, "key_epoch", 1),
|
|
95517
|
-
lease_token:
|
|
95925
|
+
lease_token: text6(item.lease_token, "lease_token"),
|
|
95518
95926
|
lease_generation: integer3(item.lease_generation, "lease_generation", 1),
|
|
95519
95927
|
lease_expires_at: integer3(item.lease_expires_at, "lease_expires_at", 1),
|
|
95520
95928
|
last_sequence: integer3(item.last_sequence ?? -1, "last_sequence", -1),
|
|
@@ -95527,7 +95935,7 @@ function validateLeaseResponse(value, executionId) {
|
|
|
95527
95935
|
return {
|
|
95528
95936
|
...item,
|
|
95529
95937
|
execution_id: executionId,
|
|
95530
|
-
lease_token:
|
|
95938
|
+
lease_token: text6(item.lease_token, "lease_token"),
|
|
95531
95939
|
lease_generation: integer3(item.lease_generation, "lease_generation", 1),
|
|
95532
95940
|
lease_expires_at: integer3(item.lease_expires_at, "lease_expires_at", 1),
|
|
95533
95941
|
last_sequence: integer3(item.last_sequence ?? -1, "last_sequence", -1),
|
|
@@ -95571,12 +95979,12 @@ function parsePolicy(value) {
|
|
|
95571
95979
|
if (!Array.isArray(policy.credential_profiles) || policy.credential_profiles.some((item) => typeof item !== "string")) throw new Error("Invalid credential profiles");
|
|
95572
95980
|
return {
|
|
95573
95981
|
argv: [...policy.argv],
|
|
95574
|
-
cwd:
|
|
95982
|
+
cwd: text6(policy.cwd, "cwd"),
|
|
95575
95983
|
mode: oneOf3(policy.mode, ["foreground", "background"], "mode"),
|
|
95576
95984
|
source_access: oneOf3(policy.source_access, ["read_only", "read_write"], "source_access"),
|
|
95577
95985
|
deadline_ms: integer3(policy.deadline_ms, "deadline_ms", 100),
|
|
95578
95986
|
writable_profiles: [...policy.writable_profiles],
|
|
95579
|
-
network_profile: policy.network_profile === null ? null :
|
|
95987
|
+
network_profile: policy.network_profile === null ? null : text6(policy.network_profile, "network_profile"),
|
|
95580
95988
|
credential_profiles: [...policy.credential_profiles]
|
|
95581
95989
|
};
|
|
95582
95990
|
}
|
|
@@ -95606,7 +96014,7 @@ function validateTrustedGrants(value) {
|
|
|
95606
96014
|
const result = {
|
|
95607
96015
|
writable_targets: value.writable_targets.map((item) => ({
|
|
95608
96016
|
profile_id: identifier4(item.profile_id, "writable profile"),
|
|
95609
|
-
host_path:
|
|
96017
|
+
host_path: text6(item.host_path, "writable host path")
|
|
95610
96018
|
})),
|
|
95611
96019
|
network_profiles: value.network_profiles.map((item) => {
|
|
95612
96020
|
if (!Array.isArray(item.destinations) || item.destinations.some((destination) => typeof destination !== "string")) {
|
|
@@ -95614,7 +96022,7 @@ function validateTrustedGrants(value) {
|
|
|
95614
96022
|
}
|
|
95615
96023
|
return {
|
|
95616
96024
|
profile_id: identifier4(item.profile_id, "network profile"),
|
|
95617
|
-
destinations: item.destinations.map((destination) =>
|
|
96025
|
+
destinations: item.destinations.map((destination) => text6(destination, "network destination"))
|
|
95618
96026
|
};
|
|
95619
96027
|
}),
|
|
95620
96028
|
credential_profiles: value.credential_profiles.map((item) => {
|
|
@@ -95675,14 +96083,14 @@ function canonicalStateDirectory() {
|
|
|
95675
96083
|
const path2 = resolveStateDir();
|
|
95676
96084
|
if (existsSync21(path2)) return realpathSync10(path2);
|
|
95677
96085
|
const tail = [];
|
|
95678
|
-
let parent =
|
|
96086
|
+
let parent = resolve15(path2);
|
|
95679
96087
|
while (!existsSync21(parent)) {
|
|
95680
96088
|
const next = dirname14(parent);
|
|
95681
96089
|
if (next === parent) break;
|
|
95682
96090
|
tail.unshift(basename7(parent));
|
|
95683
96091
|
parent = next;
|
|
95684
96092
|
}
|
|
95685
|
-
return
|
|
96093
|
+
return resolve15(realpathSync10(parent), ...tail);
|
|
95686
96094
|
}
|
|
95687
96095
|
function pathsOverlap3(left, right) {
|
|
95688
96096
|
return left === right || isInsideDirectory(left, right) || isInsideDirectory(right, left);
|
|
@@ -95705,7 +96113,7 @@ function identifier4(value, context) {
|
|
|
95705
96113
|
if (typeof value !== "string" || !IDENTIFIER3.test(value)) throw new Error(`Invalid ${context}`);
|
|
95706
96114
|
return value;
|
|
95707
96115
|
}
|
|
95708
|
-
function
|
|
96116
|
+
function text6(value, context) {
|
|
95709
96117
|
if (typeof value !== "string" || !value || value.length > 1048576 || value.includes("\0")) throw new Error(`Invalid ${context}`);
|
|
95710
96118
|
return value;
|
|
95711
96119
|
}
|
|
@@ -95775,7 +96183,7 @@ function resolveRemoteAccessRoots(pathFlag, cwd = process.cwd()) {
|
|
|
95775
96183
|
}
|
|
95776
96184
|
const roots = [];
|
|
95777
96185
|
for (const value of requested) {
|
|
95778
|
-
const candidate =
|
|
96186
|
+
const candidate = resolve16(cwd, value);
|
|
95779
96187
|
if (!existsSync22(candidate) || !statSync10(candidate).isDirectory()) {
|
|
95780
96188
|
throw new Error(`Remote source path does not exist or is not a directory: ${candidate}`);
|
|
95781
96189
|
}
|
|
@@ -96547,7 +96955,7 @@ function resolveRemoteCachePath(sourceId, homeDirectory) {
|
|
|
96547
96955
|
}
|
|
96548
96956
|
function startRemoteAccessSource(input) {
|
|
96549
96957
|
assertSafeSourceId(input.sourceId);
|
|
96550
|
-
const requestedRootPath =
|
|
96958
|
+
const requestedRootPath = resolve16(input.rootPath);
|
|
96551
96959
|
if (!existsSync22(requestedRootPath) || !statSync10(requestedRootPath).isDirectory()) {
|
|
96552
96960
|
throw new Error(`Remote source path does not exist or is not a directory: ${requestedRootPath}`);
|
|
96553
96961
|
}
|
|
@@ -97067,9 +97475,9 @@ function minimalRgEnvironment() {
|
|
|
97067
97475
|
return env;
|
|
97068
97476
|
}
|
|
97069
97477
|
function isPathInsideRoot(sourceRoot, relativePath2) {
|
|
97070
|
-
const resolvedPath =
|
|
97478
|
+
const resolvedPath = resolve16(sourceRoot, relativePath2);
|
|
97071
97479
|
const relation = relative11(sourceRoot, resolvedPath);
|
|
97072
|
-
return relation === "" || !relation.startsWith("..") && !
|
|
97480
|
+
return relation === "" || !relation.startsWith("..") && !resolve16(relation).startsWith("/..");
|
|
97073
97481
|
}
|
|
97074
97482
|
function isBinaryPath(path2) {
|
|
97075
97483
|
const lowerPath = path2.toLowerCase();
|
|
@@ -97108,7 +97516,7 @@ function hasControlCharacters3(value) {
|
|
|
97108
97516
|
}
|
|
97109
97517
|
function resolveApprovedPath(sourceRoot, relativePath2) {
|
|
97110
97518
|
if (!relativePath2 || relativePath2.includes("\0")) throw new Error("Remote source path is invalid");
|
|
97111
|
-
const lexical =
|
|
97519
|
+
const lexical = resolve16(sourceRoot, relativePath2);
|
|
97112
97520
|
assertInsideRoot(sourceRoot, lexical);
|
|
97113
97521
|
const relation = relative11(sourceRoot, lexical);
|
|
97114
97522
|
let current = sourceRoot;
|
|
@@ -97122,7 +97530,7 @@ function resolveApprovedPath(sourceRoot, relativePath2) {
|
|
|
97122
97530
|
}
|
|
97123
97531
|
function assertInsideRoot(sourceRoot, path2) {
|
|
97124
97532
|
const relation = relative11(sourceRoot, path2);
|
|
97125
|
-
if (relation.startsWith("..") ||
|
|
97533
|
+
if (relation.startsWith("..") || resolve16(sourceRoot, relation) !== resolve16(path2)) {
|
|
97126
97534
|
throw new Error("Remote source path escapes the approved source root");
|
|
97127
97535
|
}
|
|
97128
97536
|
}
|
|
@@ -97250,10 +97658,10 @@ async function ensureRemoteCommandSetup(options, dependencies = {}) {
|
|
|
97250
97658
|
return { installed: true, capability: installed };
|
|
97251
97659
|
}
|
|
97252
97660
|
function inheritedInstaller(executable, args) {
|
|
97253
|
-
return new Promise((
|
|
97661
|
+
return new Promise((resolve18, reject) => {
|
|
97254
97662
|
const child = spawn8(executable, args, { stdio: "inherit" });
|
|
97255
97663
|
child.once("error", reject);
|
|
97256
|
-
child.once("close", (code, signal) =>
|
|
97664
|
+
child.once("close", (code, signal) => resolve18({ code, signal }));
|
|
97257
97665
|
});
|
|
97258
97666
|
}
|
|
97259
97667
|
|
|
@@ -97635,7 +98043,7 @@ import { execFileSync as execFileSync5 } from "child_process";
|
|
|
97635
98043
|
import { createSign, randomUUID as randomUUID22 } from "crypto";
|
|
97636
98044
|
import { chmodSync as chmodSync13, existsSync as existsSync23, mkdirSync as mkdirSync21, readFileSync as readFileSync21 } from "fs";
|
|
97637
98045
|
import { homedir as homedir6 } from "os";
|
|
97638
|
-
import { join as join27, resolve as
|
|
98046
|
+
import { join as join27, resolve as resolve17 } from "path";
|
|
97639
98047
|
var REVOLUT_BUSINESS_CERTIFICATE_DOCS_URL = "https://developer.revolut.com/docs/guides/manage-accounts/get-started/make-your-first-api-request#generate-a-private-and-a-public-certificate";
|
|
97640
98048
|
var REVOLUT_BUSINESS_DEFAULT_SANDBOX_REDIRECT_URI = "https://app.dev.openmates.org/oauth/revolut-business/callback";
|
|
97641
98049
|
var REVOLUT_BUSINESS_DEFAULT_PRODUCTION_REDIRECT_URI = "https://openmates.org/oauth/revolut-business/callback";
|
|
@@ -97716,7 +98124,7 @@ function generateRevolutBusinessClientAssertion(options) {
|
|
|
97716
98124
|
}
|
|
97717
98125
|
function generateRevolutBusinessCertificate(options = {}) {
|
|
97718
98126
|
const environment = options.environment ?? "sandbox";
|
|
97719
|
-
const outputDir =
|
|
98127
|
+
const outputDir = resolve17(options.outputDir ?? defaultRevolutBusinessCertificateDir(environment));
|
|
97720
98128
|
const title = (options.title ?? REVOLUT_BUSINESS_DEFAULT_CERTIFICATE_TITLE).trim();
|
|
97721
98129
|
const redirectUri = (options.redirectUri ?? defaultRevolutBusinessRedirectUri(environment)).trim();
|
|
97722
98130
|
if (!title) throw new Error("Revolut certificate title must not be empty.");
|
|
@@ -98009,7 +98417,7 @@ async function main() {
|
|
|
98009
98417
|
return;
|
|
98010
98418
|
}
|
|
98011
98419
|
if (command === "update" || command === "upgrade") {
|
|
98012
|
-
handleSelfUpdate(command, parsed.flags);
|
|
98420
|
+
await handleSelfUpdate(command, parsed.flags);
|
|
98013
98421
|
return;
|
|
98014
98422
|
}
|
|
98015
98423
|
if (command === "login") {
|
|
@@ -98223,7 +98631,15 @@ function handleSupport(flags) {
|
|
|
98223
98631
|
}
|
|
98224
98632
|
console.log(renderSupportInfo());
|
|
98225
98633
|
}
|
|
98226
|
-
function handleSelfUpdate(command, flags) {
|
|
98634
|
+
async function handleSelfUpdate(command, flags) {
|
|
98635
|
+
if (flags["caddy-config"] === true) throw new Error("Provide --caddy-config <file>.");
|
|
98636
|
+
const reportCaddy = async () => {
|
|
98637
|
+
const caddy = await updateCaddyAfterCliUpgrade(flags);
|
|
98638
|
+
if (caddy) {
|
|
98639
|
+
console.log(`Caddy: ${caddy.status}`);
|
|
98640
|
+
if ("retryCommand" in caddy) console.log(`Run: ${caddy.retryCommand}`);
|
|
98641
|
+
}
|
|
98642
|
+
};
|
|
98227
98643
|
let plan = buildSelfUpdatePlan(flags);
|
|
98228
98644
|
const status = checkSelfUpdateStatus(plan);
|
|
98229
98645
|
if (status.checkError) throw new Error(`Update check failed: ${status.checkError}`);
|
|
@@ -98234,6 +98650,7 @@ function handleSelfUpdate(command, flags) {
|
|
|
98234
98650
|
if (flags.json === true) {
|
|
98235
98651
|
if (!plan.dryRun && shouldInstall) runSelfUpdate(plan, { verbose: flags.verbose === true });
|
|
98236
98652
|
persistSelfUpdateChannel(plan);
|
|
98653
|
+
const caddy = await updateCaddyAfterCliUpgrade(flags);
|
|
98237
98654
|
printJson2({
|
|
98238
98655
|
command,
|
|
98239
98656
|
channel: plan.channel,
|
|
@@ -98245,7 +98662,8 @@ function handleSelfUpdate(command, flags) {
|
|
|
98245
98662
|
package_manager: plan.packageManager,
|
|
98246
98663
|
package: plan.packageSpec,
|
|
98247
98664
|
run: [plan.command, ...plan.args],
|
|
98248
|
-
dry_run: plan.dryRun
|
|
98665
|
+
dry_run: plan.dryRun,
|
|
98666
|
+
...caddy ? { caddy } : {}
|
|
98249
98667
|
});
|
|
98250
98668
|
return;
|
|
98251
98669
|
}
|
|
@@ -98263,22 +98681,26 @@ function handleSelfUpdate(command, flags) {
|
|
|
98263
98681
|
if (plan.dryRun) {
|
|
98264
98682
|
if (status.updateAvailable === false) {
|
|
98265
98683
|
console.log("OpenMates CLI is already up to date.");
|
|
98684
|
+
await reportCaddy();
|
|
98266
98685
|
return;
|
|
98267
98686
|
}
|
|
98268
98687
|
console.log(`Would run: ${[plan.command, ...plan.args].join(" ")}`);
|
|
98688
|
+
await reportCaddy();
|
|
98269
98689
|
return;
|
|
98270
98690
|
}
|
|
98271
98691
|
if (status.updateAvailable === false) {
|
|
98272
98692
|
persistSelfUpdateChannel(plan);
|
|
98273
98693
|
console.log("OpenMates CLI is already up to date.");
|
|
98694
|
+
await reportCaddy();
|
|
98274
98695
|
return;
|
|
98275
98696
|
}
|
|
98276
98697
|
console.log(`Updating OpenMates CLI with ${plan.packageManager}...`);
|
|
98277
98698
|
runSelfUpdate(plan, { verbose: flags.verbose === true });
|
|
98278
98699
|
persistSelfUpdateChannel(plan);
|
|
98279
98700
|
console.log(`Installed OpenMates CLI ${status.latestVersion ?? plan.target}.`);
|
|
98701
|
+
await reportCaddy();
|
|
98280
98702
|
console.log("");
|
|
98281
|
-
console.log("OpenMates is up to date.");
|
|
98703
|
+
console.log("OpenMates CLI is up to date.");
|
|
98282
98704
|
}
|
|
98283
98705
|
function handleCliVersion(flags) {
|
|
98284
98706
|
const planFlags = { ...flags, "dry-run": true };
|
|
@@ -99715,10 +100137,10 @@ async function handlePlans(client2, subcommand, rest, flags, redactor) {
|
|
|
99715
100137
|
else console.log(`Plan success criterion updated: ${updated.criterion_id}`);
|
|
99716
100138
|
return;
|
|
99717
100139
|
}
|
|
99718
|
-
const
|
|
100140
|
+
const text7 = requiredStringFlag(flags.text ?? rest.slice(2).join(" "), "--text <criterion>");
|
|
99719
100141
|
const criterion = await buildCreatePlanCriterionInput(plan, masterKey, {
|
|
99720
100142
|
criterionId: typeof flags.id === "string" ? flags.id : void 0,
|
|
99721
|
-
text:
|
|
100143
|
+
text: text7,
|
|
99722
100144
|
type: typeof flags.type === "string" ? flags.type : void 0,
|
|
99723
100145
|
status: typeof flags.status === "string" ? flags.status : void 0,
|
|
99724
100146
|
required: flags.required === true ? true : flags.optional === true ? false : void 0,
|
|
@@ -101891,11 +102313,11 @@ async function handleIdeaBucket(client2, subcommand, rest, flags) {
|
|
|
101891
102313
|
return;
|
|
101892
102314
|
}
|
|
101893
102315
|
if (subcommand === "add") {
|
|
101894
|
-
const
|
|
101895
|
-
if (!
|
|
102316
|
+
const text7 = rest.join(" ").trim();
|
|
102317
|
+
if (!text7) throw new Error("Missing IdeaBucket text for add.");
|
|
101896
102318
|
const scheduledSendAt = typeof flags["scheduled-at"] === "string" ? parseUnixSecondsFlag(flags["scheduled-at"], "--scheduled-at") : void 0;
|
|
101897
102319
|
printJson2(await client2.addIdeaBucketText({
|
|
101898
|
-
text:
|
|
102320
|
+
text: text7,
|
|
101899
102321
|
chatId: typeof flags.chat === "string" ? flags.chat : void 0,
|
|
101900
102322
|
bucketId: typeof flags.bucket === "string" ? flags.bucket : void 0,
|
|
101901
102323
|
scheduledSendAt,
|
|
@@ -101989,11 +102411,11 @@ function renderRemoteCommandEvent(event) {
|
|
|
101989
102411
|
if (event.event_kind === "output") {
|
|
101990
102412
|
const raw = typeof event.payload.text === "string" ? event.payload.text : "";
|
|
101991
102413
|
const limit = 24e3;
|
|
101992
|
-
const
|
|
102414
|
+
const text7 = escapeTerminalControls(raw.slice(0, limit));
|
|
101993
102415
|
const omitted = raw.length > limit ? `
|
|
101994
102416
|
[${raw.length - limit} characters omitted from this display]` : "";
|
|
101995
102417
|
return `Unreviewed command output (inert) ${identity2}:
|
|
101996
|
-
${
|
|
102418
|
+
${text7}${omitted}`;
|
|
101997
102419
|
}
|
|
101998
102420
|
if (event.event_kind === "output_truncated") {
|
|
101999
102421
|
return `Command output was truncated upstream (${identity2}); displayed output does not cover the full process transcript.`;
|
|
@@ -102541,10 +102963,10 @@ Run 'openmates chats show ` + chatId + "' to check if suggestions have been save
|
|
|
102541
102963
|
input: process.stdin,
|
|
102542
102964
|
output: process.stdout
|
|
102543
102965
|
});
|
|
102544
|
-
const answer = await new Promise((
|
|
102966
|
+
const answer = await new Promise((resolve18) => {
|
|
102545
102967
|
iface.question(
|
|
102546
102968
|
`Delete ${resolved.length} chat(s)? This cannot be undone. [y/N] `,
|
|
102547
|
-
|
|
102969
|
+
resolve18
|
|
102548
102970
|
);
|
|
102549
102971
|
});
|
|
102550
102972
|
iface.close();
|
|
@@ -102672,19 +103094,19 @@ ${deleted}/${resolved.length} chat(s) deleted.`);
|
|
|
102672
103094
|
if (embed.type === "app_skill_use" && embed.appId === "videos" && (embed.skillId === "get_transcript" || embed.skillId === "get-transcript") && embed.content) {
|
|
102673
103095
|
const results = embed.content.results ?? embed.content.data ?? [];
|
|
102674
103096
|
if (Array.isArray(results) && results.length > 0) {
|
|
102675
|
-
let
|
|
103097
|
+
let text7 = "";
|
|
102676
103098
|
for (const r of results) {
|
|
102677
103099
|
const meta = r.metadata;
|
|
102678
|
-
if (meta?.title)
|
|
103100
|
+
if (meta?.title) text7 += `# ${meta.title}
|
|
102679
103101
|
|
|
102680
103102
|
`;
|
|
102681
|
-
if (r.url)
|
|
103103
|
+
if (r.url) text7 += `Source: ${r.url}
|
|
102682
103104
|
|
|
102683
103105
|
`;
|
|
102684
|
-
|
|
103106
|
+
text7 += String(
|
|
102685
103107
|
r.transcript ?? r.formatted_transcript ?? r.text ?? r.content ?? ""
|
|
102686
103108
|
);
|
|
102687
|
-
|
|
103109
|
+
text7 += "\n\n---\n\n";
|
|
102688
103110
|
}
|
|
102689
103111
|
let fname = `${eid.slice(0, 8)}_transcript.md`;
|
|
102690
103112
|
const firstMeta = results[0]?.metadata;
|
|
@@ -102694,7 +103116,7 @@ ${deleted}/${resolved.length} chat(s) deleted.`);
|
|
|
102694
103116
|
transcriptEmbeds.push({
|
|
102695
103117
|
embedId: eid,
|
|
102696
103118
|
filename: fname,
|
|
102697
|
-
content:
|
|
103119
|
+
content: text7
|
|
102698
103120
|
});
|
|
102699
103121
|
}
|
|
102700
103122
|
}
|
|
@@ -103296,7 +103718,7 @@ async function waitForWorkflowRun(client2, workflowId, initialRun, options = {})
|
|
|
103296
103718
|
clearTimeout(timer);
|
|
103297
103719
|
}
|
|
103298
103720
|
}
|
|
103299
|
-
const pause = () => withinBudget(() => new Promise((
|
|
103721
|
+
const pause = () => withinBudget(() => new Promise((resolve18) => setTimeout(resolve18, Math.min(options.pollIntervalMs ?? 2e3, deadline - Date.now()))));
|
|
103300
103722
|
const refresh = async () => {
|
|
103301
103723
|
run = await withinBudget(() => client2.getWorkflowRun(workflowId, runId));
|
|
103302
103724
|
};
|
|
@@ -103377,8 +103799,8 @@ async function syncCliBoundWorkflowFiles(client2, workflow, flags) {
|
|
|
103377
103799
|
const contents = await client2.listProjectItems(project.projectId, context);
|
|
103378
103800
|
for (const item of contents.items.filter((item2) => item2.item_type === "workflow")) {
|
|
103379
103801
|
if (await decryptOptionalProjectField2(item.target_id_encrypted, project.projectKey) !== workflow.id) continue;
|
|
103380
|
-
const
|
|
103381
|
-
const metadata =
|
|
103802
|
+
const text7 = await decryptOptionalProjectField2(item.encrypted_metadata, project.projectKey);
|
|
103803
|
+
const metadata = text7 ? JSON.parse(text7) : {};
|
|
103382
103804
|
const binding = metadata.remote_workflow_file;
|
|
103383
103805
|
if (!binding) continue;
|
|
103384
103806
|
const source = (await client2.listProjectSources(project.projectId, context)).find((item2) => item2.source_id === binding.source_id);
|
|
@@ -103668,10 +104090,10 @@ async function handleWorkflows(client2, subcommand, rest, flags, redactor) {
|
|
|
103668
104090
|
return;
|
|
103669
104091
|
}
|
|
103670
104092
|
if (subcommand === "input") {
|
|
103671
|
-
const
|
|
103672
|
-
if (!
|
|
104093
|
+
const text7 = typeof flags.text === "string" ? flags.text : rest.join(" ").trim();
|
|
104094
|
+
if (!text7) throw new Error('Missing workflow input text. Example: openmates workflows ask "alert me if it rains"');
|
|
103673
104095
|
const session = await client2.startWorkflowInput({
|
|
103674
|
-
text:
|
|
104096
|
+
text: text7,
|
|
103675
104097
|
selectedWorkflowId: typeof flags["workflow-id"] === "string" ? flags["workflow-id"] : void 0,
|
|
103676
104098
|
selectedProjectId: typeof flags["project-id"] === "string" ? flags["project-id"] : void 0,
|
|
103677
104099
|
timezone: typeof flags.timezone === "string" ? flags.timezone : Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
@@ -103718,9 +104140,9 @@ async function handleWorkflows(client2, subcommand, rest, flags, redactor) {
|
|
|
103718
104140
|
}
|
|
103719
104141
|
if (subcommand === "input-follow-up") {
|
|
103720
104142
|
const sessionId = rest[0];
|
|
103721
|
-
const
|
|
103722
|
-
if (!sessionId || !
|
|
103723
|
-
const session = await client2.followUpWorkflowInput(sessionId,
|
|
104143
|
+
const text7 = typeof flags.text === "string" ? flags.text : rest.slice(1).join(" ").trim();
|
|
104144
|
+
if (!sessionId || !text7) throw new Error('Missing session ID or text. Example: openmates workflows input-follow-up <session-id> "make it weekdays only"');
|
|
104145
|
+
const session = await client2.followUpWorkflowInput(sessionId, text7);
|
|
103724
104146
|
if (flags.json === true) {
|
|
103725
104147
|
printJson2(session);
|
|
103726
104148
|
} else {
|
|
@@ -104904,7 +105326,7 @@ async function handleCodeRun(client2, flags, apiKey) {
|
|
|
104904
105326
|
}
|
|
104905
105327
|
}
|
|
104906
105328
|
async function streamCodeRunToTerminal(url, jsonMode) {
|
|
104907
|
-
return await new Promise((
|
|
105329
|
+
return await new Promise((resolve18, reject) => {
|
|
104908
105330
|
const ws = new WebSocket3(url);
|
|
104909
105331
|
let lastStatus = {};
|
|
104910
105332
|
ws.on("message", (data) => {
|
|
@@ -104913,17 +105335,17 @@ async function streamCodeRunToTerminal(url, jsonMode) {
|
|
|
104913
105335
|
const payload = message.payload ?? {};
|
|
104914
105336
|
if (message.type === "code_run_event") {
|
|
104915
105337
|
const kind = String(payload.kind ?? "status");
|
|
104916
|
-
const
|
|
105338
|
+
const text7 = String(payload.text ?? "");
|
|
104917
105339
|
if (!jsonMode) {
|
|
104918
|
-
if (kind === "stdout") process.stdout.write(
|
|
104919
|
-
else process.stderr.write(
|
|
105340
|
+
if (kind === "stdout") process.stdout.write(text7);
|
|
105341
|
+
else process.stderr.write(text7);
|
|
104920
105342
|
}
|
|
104921
105343
|
} else if (message.type === "code_run_update") {
|
|
104922
105344
|
lastStatus = { ...lastStatus, ...payload };
|
|
104923
105345
|
const status = String(payload.status ?? "");
|
|
104924
105346
|
if (["finished", "failed", "timeout", "cancelled"].includes(status)) {
|
|
104925
105347
|
ws.close();
|
|
104926
|
-
|
|
105348
|
+
resolve18(lastStatus);
|
|
104927
105349
|
}
|
|
104928
105350
|
}
|
|
104929
105351
|
} catch (err) {
|
|
@@ -104933,7 +105355,7 @@ async function streamCodeRunToTerminal(url, jsonMode) {
|
|
|
104933
105355
|
});
|
|
104934
105356
|
ws.on("error", () => reject(new Error("Code Run stream failed.")));
|
|
104935
105357
|
ws.on("close", () => {
|
|
104936
|
-
if (Object.keys(lastStatus).length > 0)
|
|
105358
|
+
if (Object.keys(lastStatus).length > 0) resolve18(lastStatus);
|
|
104937
105359
|
});
|
|
104938
105360
|
});
|
|
104939
105361
|
}
|
|
@@ -104944,7 +105366,7 @@ async function pollCodeRunStatus(client2, statusPath, apiKey, jsonMode) {
|
|
|
104944
105366
|
if (!jsonMode && value) process.stderr.write(`Code Run status: ${value}
|
|
104945
105367
|
`);
|
|
104946
105368
|
if (["finished", "failed", "timeout", "cancelled"].includes(value)) return status;
|
|
104947
|
-
await new Promise((
|
|
105369
|
+
await new Promise((resolve18) => setTimeout(resolve18, 1e3));
|
|
104948
105370
|
}
|
|
104949
105371
|
}
|
|
104950
105372
|
async function suggestAppOrSkill(client2, app, skill, apiKey) {
|
|
@@ -105226,7 +105648,7 @@ async function waitForApplicationPreview(client2, started, flags) {
|
|
|
105226
105648
|
while (Date.now() < deadline) {
|
|
105227
105649
|
const status = String(current.status ?? "");
|
|
105228
105650
|
if (["running", "failed", "timeout", "cancelled", "stopped"].includes(status)) return current;
|
|
105229
|
-
await new Promise((
|
|
105651
|
+
await new Promise((resolve18) => setTimeout(resolve18, 1e3));
|
|
105230
105652
|
current = await client2.getApplicationPreviewStatus(started.session_id);
|
|
105231
105653
|
}
|
|
105232
105654
|
throw new Error(`Application preview did not reach a terminal or running state within ${timeoutSeconds}s`);
|
|
@@ -105831,7 +106253,7 @@ function printMateInfo(mateId, json) {
|
|
|
105831
106253
|
async function confirmOrExit(question) {
|
|
105832
106254
|
const rl = await import("readline");
|
|
105833
106255
|
const iface = rl.createInterface({ input: process.stdin, output: process.stdout });
|
|
105834
|
-
const answer = await new Promise((
|
|
106256
|
+
const answer = await new Promise((resolve18) => iface.question(question, resolve18));
|
|
105835
106257
|
iface.close();
|
|
105836
106258
|
if (answer.trim().toLowerCase() !== "y") {
|
|
105837
106259
|
console.log("Aborted.");
|
|
@@ -105841,7 +106263,7 @@ async function confirmOrExit(question) {
|
|
|
105841
106263
|
async function promptLine(question) {
|
|
105842
106264
|
const rl = await import("readline");
|
|
105843
106265
|
const iface = rl.createInterface({ input: process.stdin, output: process.stdout });
|
|
105844
|
-
const answer = await new Promise((
|
|
106266
|
+
const answer = await new Promise((resolve18) => iface.question(question, resolve18));
|
|
105845
106267
|
iface.close();
|
|
105846
106268
|
return answer.trim();
|
|
105847
106269
|
}
|
|
@@ -105849,7 +106271,7 @@ async function promptSecret(question) {
|
|
|
105849
106271
|
if (!process.stdin.isTTY) {
|
|
105850
106272
|
return promptLine(question);
|
|
105851
106273
|
}
|
|
105852
|
-
return new Promise((
|
|
106274
|
+
return new Promise((resolve18) => {
|
|
105853
106275
|
const stdin4 = process.stdin;
|
|
105854
106276
|
const wasRaw = stdin4.isRaw;
|
|
105855
106277
|
let value = "";
|
|
@@ -105862,7 +106284,7 @@ async function promptSecret(question) {
|
|
|
105862
106284
|
stdin4.off("data", onData);
|
|
105863
106285
|
stdin4.setRawMode(wasRaw);
|
|
105864
106286
|
process.stdout.write("\n");
|
|
105865
|
-
|
|
106287
|
+
resolve18(value);
|
|
105866
106288
|
return;
|
|
105867
106289
|
}
|
|
105868
106290
|
if (char === "") {
|
|
@@ -106302,7 +106724,7 @@ function decodeBase32(input) {
|
|
|
106302
106724
|
}
|
|
106303
106725
|
return Buffer.from(bytes2);
|
|
106304
106726
|
}
|
|
106305
|
-
async function waitForSafeE2ETotpWindow(now = Date.now, sleep4 = (milliseconds) => new Promise((
|
|
106727
|
+
async function waitForSafeE2ETotpWindow(now = Date.now, sleep4 = (milliseconds) => new Promise((resolve18) => setTimeout(resolve18, milliseconds))) {
|
|
106306
106728
|
const millisecondsRemaining = 3e4 - now() % 3e4;
|
|
106307
106729
|
if (millisecondsRemaining < 2e3) {
|
|
106308
106730
|
await sleep4(millisecondsRemaining + 50);
|
|
@@ -107389,8 +107811,8 @@ function resolveApiKey(flags) {
|
|
|
107389
107811
|
function printJson2(value) {
|
|
107390
107812
|
console.log(JSON.stringify(value, null, 2));
|
|
107391
107813
|
}
|
|
107392
|
-
function header(
|
|
107393
|
-
process.stdout.write(`\x1B[1m${
|
|
107814
|
+
function header(text7) {
|
|
107815
|
+
process.stdout.write(`\x1B[1m${text7}\x1B[0m
|
|
107394
107816
|
`);
|
|
107395
107817
|
}
|
|
107396
107818
|
function kv(key, value, keyWidth = 16) {
|
|
@@ -108156,15 +108578,15 @@ async function acceptChatTaskProposals(client2, chatId, proposals, fallbackText)
|
|
|
108156
108578
|
}
|
|
108157
108579
|
return accepted;
|
|
108158
108580
|
}
|
|
108159
|
-
function buildTaskProposalFallbackText(
|
|
108581
|
+
function buildTaskProposalFallbackText(text7) {
|
|
108160
108582
|
const seen = /* @__PURE__ */ new Set();
|
|
108161
|
-
const bulletLines =
|
|
108583
|
+
const bulletLines = text7.split("\n").map((line) => line.trim()).filter((line) => /^[-*•]\s+/.test(line)).map((line) => line.replace(/^([-*•]\s*)\[[ xX]\]\s*/, "$1")).filter((line) => {
|
|
108162
108584
|
const key = line.replace(/^[-*•]\s+/, "").trim().toLowerCase();
|
|
108163
108585
|
if (seen.has(key)) return false;
|
|
108164
108586
|
seen.add(key);
|
|
108165
108587
|
return true;
|
|
108166
108588
|
});
|
|
108167
|
-
return bulletLines.length > 0 ? bulletLines.join("\n") :
|
|
108589
|
+
return bulletLines.length > 0 ? bulletLines.join("\n") : text7;
|
|
108168
108590
|
}
|
|
108169
108591
|
function printIncognitoNoHistoryNotice(json) {
|
|
108170
108592
|
const message = "Incognito chats are not stored. There is no incognito history to show or clear.";
|
|
@@ -108198,8 +108620,8 @@ function renderEmbedFromMeta(embedId, meta) {
|
|
|
108198
108620
|
process.stdout.write(`\x1B[2m\u2514\u2500 openmates embeds show ${shortId}\x1B[0m
|
|
108199
108621
|
`);
|
|
108200
108622
|
}
|
|
108201
|
-
async function renderMessageText(
|
|
108202
|
-
const lines =
|
|
108623
|
+
async function renderMessageText(text7, embedRefIndex, client2) {
|
|
108624
|
+
const lines = text7.split("\n");
|
|
108203
108625
|
const outputLines = [];
|
|
108204
108626
|
for (const line of lines) {
|
|
108205
108627
|
const blockMatch = line.match(/^\s*\[!?\]\(embed:([^)]+)\)\s*$/);
|
|
@@ -108456,6 +108878,12 @@ ${data.description}
|
|
|
108456
108878
|
}
|
|
108457
108879
|
console.log();
|
|
108458
108880
|
}
|
|
108881
|
+
if (data.memories?.length) {
|
|
108882
|
+
console.log("Memories \xB7 App-provided \xB7 Read-only \xB7 Loaded automatically when relevant");
|
|
108883
|
+
for (const memory of data.memories) console.log(` ${memory.title} (${memory.id})
|
|
108884
|
+
${memory.description}`);
|
|
108885
|
+
console.log();
|
|
108886
|
+
}
|
|
108459
108887
|
const focuses = data.focus_modes ?? [];
|
|
108460
108888
|
if (focuses.length > 0) {
|
|
108461
108889
|
process.stdout.write(`\x1B[1mFocus modes\x1B[0m
|
|
@@ -108623,8 +109051,8 @@ No example chats are linked to ${label3} yet.`);
|
|
|
108623
109051
|
console.log(`All examples: openmates apps examples ${appId}${skillId ? ` ${skillId}` : ""}`);
|
|
108624
109052
|
}
|
|
108625
109053
|
}
|
|
108626
|
-
function wrapText(
|
|
108627
|
-
const words =
|
|
109054
|
+
function wrapText(text7, width) {
|
|
109055
|
+
const words = text7.split(" ");
|
|
108628
109056
|
const lines = [];
|
|
108629
109057
|
let current = "";
|
|
108630
109058
|
for (const w of words) {
|
|
@@ -109562,6 +109990,10 @@ Options:
|
|
|
109562
109990
|
--channel <dev|stable|main> Save release channel (dev uses npm alpha; stable/main uses latest)
|
|
109563
109991
|
--allow-downgrade Explicitly allow installing an older version
|
|
109564
109992
|
--verbose Stream package-manager output during installation
|
|
109993
|
+
--path <installation> Also update this server's Caddy configuration from its installed release
|
|
109994
|
+
--role <core|upload|preview> Server role for the Caddy update (default: saved role or core)
|
|
109995
|
+
--caddy-config <file> Active host Caddyfile; otherwise detect the running service
|
|
109996
|
+
--caddy-profile <name> Use official-upload for the shared production/development upload host
|
|
109565
109997
|
--json Output the update plan/result as JSON`);
|
|
109566
109998
|
}
|
|
109567
109999
|
function printRemoteAccessHelp() {
|