openmates 0.11.0-alpha.16 → 0.11.0-alpha.18
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.
|
@@ -23,6 +23,49 @@ function getUploadOrigin(apiUrl) {
|
|
|
23
23
|
}
|
|
24
24
|
return "https://app.openmates.org";
|
|
25
25
|
}
|
|
26
|
+
function getUploadMimeType(filename) {
|
|
27
|
+
const ext = extname(filename).toLowerCase();
|
|
28
|
+
switch (ext) {
|
|
29
|
+
case ".jpg":
|
|
30
|
+
case ".jpeg":
|
|
31
|
+
return "image/jpeg";
|
|
32
|
+
case ".png":
|
|
33
|
+
return "image/png";
|
|
34
|
+
case ".webp":
|
|
35
|
+
return "image/webp";
|
|
36
|
+
case ".gif":
|
|
37
|
+
return "image/gif";
|
|
38
|
+
case ".heic":
|
|
39
|
+
return "image/heic";
|
|
40
|
+
case ".heif":
|
|
41
|
+
return "image/heif";
|
|
42
|
+
case ".bmp":
|
|
43
|
+
return "image/bmp";
|
|
44
|
+
case ".tif":
|
|
45
|
+
case ".tiff":
|
|
46
|
+
return "image/tiff";
|
|
47
|
+
case ".svg":
|
|
48
|
+
return "image/svg+xml";
|
|
49
|
+
case ".pdf":
|
|
50
|
+
return "application/pdf";
|
|
51
|
+
case ".mp3":
|
|
52
|
+
return "audio/mpeg";
|
|
53
|
+
case ".m4a":
|
|
54
|
+
case ".mp4":
|
|
55
|
+
return "audio/mp4";
|
|
56
|
+
case ".wav":
|
|
57
|
+
return "audio/wav";
|
|
58
|
+
case ".webm":
|
|
59
|
+
return "audio/webm";
|
|
60
|
+
case ".ogg":
|
|
61
|
+
case ".oga":
|
|
62
|
+
return "audio/ogg";
|
|
63
|
+
case ".aac":
|
|
64
|
+
return "audio/aac";
|
|
65
|
+
default:
|
|
66
|
+
return "application/octet-stream";
|
|
67
|
+
}
|
|
68
|
+
}
|
|
26
69
|
async function uploadFile(filePath, session) {
|
|
27
70
|
const filename = basename(filePath);
|
|
28
71
|
const fileBytes = readFileSync(filePath);
|
|
@@ -36,7 +79,7 @@ async function uploadFile(filePath, session) {
|
|
|
36
79
|
let lastError;
|
|
37
80
|
for (let attempt = 1; attempt <= UPLOAD_MAX_ATTEMPTS; attempt++) {
|
|
38
81
|
try {
|
|
39
|
-
const blob = new Blob([fileBytes]);
|
|
82
|
+
const blob = new Blob([fileBytes], { type: getUploadMimeType(filename) });
|
|
40
83
|
const formData = new FormData();
|
|
41
84
|
formData.append("file", blob, filename);
|
|
42
85
|
response = await fetch(uploadUrl, {
|
|
@@ -89,6 +132,73 @@ async function uploadFile(filePath, session) {
|
|
|
89
132
|
const data = await response.json();
|
|
90
133
|
return data;
|
|
91
134
|
}
|
|
135
|
+
async function transcribeUploadedAudio(uploadResult, filename, session, options = {}) {
|
|
136
|
+
const s3Key = uploadResult.files?.original?.s3_key ?? Object.values(uploadResult.files ?? {})[0]?.s3_key;
|
|
137
|
+
if (!s3Key) {
|
|
138
|
+
throw new Error("Upload succeeded but no audio file key was returned.");
|
|
139
|
+
}
|
|
140
|
+
const cookies = [];
|
|
141
|
+
if (session.cookies?.auth_refresh_token) {
|
|
142
|
+
cookies.push(`auth_refresh_token=${session.cookies.auth_refresh_token}`);
|
|
143
|
+
}
|
|
144
|
+
const requestItem = {
|
|
145
|
+
id: options.requestId ?? uploadResult.embed_id,
|
|
146
|
+
embed_id: uploadResult.embed_id,
|
|
147
|
+
s3_key: s3Key,
|
|
148
|
+
s3_base_url: uploadResult.s3_base_url,
|
|
149
|
+
aes_key: uploadResult.aes_key,
|
|
150
|
+
aes_nonce: uploadResult.aes_nonce,
|
|
151
|
+
vault_wrapped_aes_key: uploadResult.vault_wrapped_aes_key,
|
|
152
|
+
filename,
|
|
153
|
+
mime_type: uploadResult.content_type
|
|
154
|
+
};
|
|
155
|
+
if (options.chatId) {
|
|
156
|
+
requestItem.chat_id = options.chatId;
|
|
157
|
+
}
|
|
158
|
+
const response = await fetch(
|
|
159
|
+
`${session.apiUrl.replace(/\/$/, "")}/v1/apps/audio/skills/transcribe`,
|
|
160
|
+
{
|
|
161
|
+
method: "POST",
|
|
162
|
+
headers: {
|
|
163
|
+
Accept: "application/json",
|
|
164
|
+
"Content-Type": "application/json",
|
|
165
|
+
...cookies.length > 0 ? { Cookie: cookies.join("; ") } : {}
|
|
166
|
+
},
|
|
167
|
+
body: JSON.stringify({ requests: [requestItem] }),
|
|
168
|
+
signal: AbortSignal.timeout(10 * 60 * 1e3)
|
|
169
|
+
}
|
|
170
|
+
);
|
|
171
|
+
if (!response.ok) {
|
|
172
|
+
let detail = `Transcription failed (HTTP ${response.status}).`;
|
|
173
|
+
try {
|
|
174
|
+
const data2 = await response.json();
|
|
175
|
+
detail = data2.detail ?? data2.error ?? detail;
|
|
176
|
+
} catch {
|
|
177
|
+
}
|
|
178
|
+
throw new Error(detail);
|
|
179
|
+
}
|
|
180
|
+
const data = await response.json();
|
|
181
|
+
if (data.success === false) {
|
|
182
|
+
throw new Error(data.error ?? "Transcription failed.");
|
|
183
|
+
}
|
|
184
|
+
const requestId = options.requestId ?? uploadResult.embed_id;
|
|
185
|
+
const group = data.data?.results?.find((item) => item.id === requestId) ?? data.data?.results?.[0];
|
|
186
|
+
const result = group?.results?.[0];
|
|
187
|
+
if (!result) {
|
|
188
|
+
throw new Error(group?.error ?? "Transcription response did not include a result.");
|
|
189
|
+
}
|
|
190
|
+
if (result.error) {
|
|
191
|
+
throw new Error(result.error);
|
|
192
|
+
}
|
|
193
|
+
return {
|
|
194
|
+
transcript: result.transcript ?? null,
|
|
195
|
+
transcript_original: result.transcript_original ?? null,
|
|
196
|
+
transcript_corrected: result.transcript_corrected ?? null,
|
|
197
|
+
use_corrected: result.use_corrected ?? null,
|
|
198
|
+
correction_model: result.correction_model ?? null,
|
|
199
|
+
model: result.model ?? null
|
|
200
|
+
};
|
|
201
|
+
}
|
|
92
202
|
function getProfileImageMime(filename) {
|
|
93
203
|
const ext = extname(filename).toLowerCase();
|
|
94
204
|
if (ext === ".jpg" || ext === ".jpeg") return "image/jpeg";
|
|
@@ -127,5 +237,6 @@ async function uploadProfileImage(filePath, session) {
|
|
|
127
237
|
|
|
128
238
|
export {
|
|
129
239
|
uploadFile,
|
|
240
|
+
transcribeUploadedAudio,
|
|
130
241
|
uploadProfileImage
|
|
131
242
|
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
|
+
transcribeUploadedAudio,
|
|
2
3
|
uploadFile
|
|
3
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-AXNRPVLE.js";
|
|
4
5
|
|
|
5
6
|
// src/client.ts
|
|
6
7
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
@@ -2687,6 +2688,15 @@ var OpenMatesClient = class _OpenMatesClient {
|
|
|
2687
2688
|
}
|
|
2688
2689
|
}
|
|
2689
2690
|
}
|
|
2691
|
+
if (params.preparedEmbeds && params.preparedEmbeds.length > 0) {
|
|
2692
|
+
messagePayload.embeds = params.preparedEmbeds.map((embed) => ({
|
|
2693
|
+
embed_id: embed.embedId,
|
|
2694
|
+
type: embed.type,
|
|
2695
|
+
content: embed.content,
|
|
2696
|
+
status: embed.status,
|
|
2697
|
+
text_preview: embed.textPreview
|
|
2698
|
+
}));
|
|
2699
|
+
}
|
|
2690
2700
|
const encryptedEmbeds = [...params.encryptedEmbeds ?? []];
|
|
2691
2701
|
if (!params.incognito && params.preparedEmbeds && params.preparedEmbeds.length > 0) {
|
|
2692
2702
|
const masterKey = this.getMasterKeyBytes();
|
|
@@ -3328,7 +3338,7 @@ var OpenMatesClient = class _OpenMatesClient {
|
|
|
3328
3338
|
return this.settingsPost("user/username", { username });
|
|
3329
3339
|
}
|
|
3330
3340
|
async updateProfileImage(filePath) {
|
|
3331
|
-
const { uploadProfileImage } = await import("./uploadService-
|
|
3341
|
+
const { uploadProfileImage } = await import("./uploadService-S464XJRA.js");
|
|
3332
3342
|
const result = await uploadProfileImage(filePath, this.requireSession());
|
|
3333
3343
|
if (result.status === "rejected") {
|
|
3334
3344
|
throw new Error(result.detail ?? "Profile image rejected by content safety checks.");
|
|
@@ -5100,6 +5110,16 @@ var IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
5100
5110
|
"tif",
|
|
5101
5111
|
"svg"
|
|
5102
5112
|
]);
|
|
5113
|
+
var AUDIO_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
5114
|
+
"mp3",
|
|
5115
|
+
"m4a",
|
|
5116
|
+
"mp4",
|
|
5117
|
+
"wav",
|
|
5118
|
+
"webm",
|
|
5119
|
+
"ogg",
|
|
5120
|
+
"oga",
|
|
5121
|
+
"aac"
|
|
5122
|
+
]);
|
|
5103
5123
|
function isEnvFile(filename) {
|
|
5104
5124
|
const lower = filename.toLowerCase();
|
|
5105
5125
|
return lower === ".env" || lower.startsWith(".env.") || lower === ".envrc";
|
|
@@ -5120,6 +5140,9 @@ function isImageFile(filename) {
|
|
|
5120
5140
|
function isPDFFile(filename) {
|
|
5121
5141
|
return getExt(filename) === "pdf";
|
|
5122
5142
|
}
|
|
5143
|
+
function isAudioFile(filename) {
|
|
5144
|
+
return AUDIO_EXTENSIONS.has(getExt(filename));
|
|
5145
|
+
}
|
|
5123
5146
|
var LANGUAGE_MAP = {
|
|
5124
5147
|
ts: "typescript",
|
|
5125
5148
|
tsx: "typescript",
|
|
@@ -5264,10 +5287,14 @@ function processFiles(filePaths, redactor) {
|
|
|
5264
5287
|
const result = processPDFFile(resolvedPath, filename);
|
|
5265
5288
|
if (result) embeds.push(result);
|
|
5266
5289
|
else errors.push({ path: rawPath, error: "Failed to process PDF" });
|
|
5290
|
+
} else if (isAudioFile(filename)) {
|
|
5291
|
+
const result = processAudioFile(resolvedPath, filename);
|
|
5292
|
+
if (result) embeds.push(result);
|
|
5293
|
+
else errors.push({ path: rawPath, error: "Failed to process audio" });
|
|
5267
5294
|
} else {
|
|
5268
5295
|
errors.push({
|
|
5269
5296
|
path: rawPath,
|
|
5270
|
-
error: `Unsupported file type: .${ext}. Supported: code/text, images, PDFs.`
|
|
5297
|
+
error: `Unsupported file type: .${ext}. Supported: code/text, images, PDFs, audio.`
|
|
5271
5298
|
});
|
|
5272
5299
|
}
|
|
5273
5300
|
}
|
|
@@ -5396,6 +5423,40 @@ function processPDFFile(filePath, filename) {
|
|
|
5396
5423
|
return null;
|
|
5397
5424
|
}
|
|
5398
5425
|
}
|
|
5426
|
+
function processAudioFile(filePath, filename) {
|
|
5427
|
+
try {
|
|
5428
|
+
const embedId = generateEmbedId();
|
|
5429
|
+
const embedContent = toonEncodeContent({
|
|
5430
|
+
app_id: "audio",
|
|
5431
|
+
skill_id: "transcribe",
|
|
5432
|
+
type: "audio-recording",
|
|
5433
|
+
status: "uploading",
|
|
5434
|
+
filename
|
|
5435
|
+
});
|
|
5436
|
+
const embed = {
|
|
5437
|
+
embedId,
|
|
5438
|
+
type: "audio-recording",
|
|
5439
|
+
content: embedContent,
|
|
5440
|
+
textPreview: filename,
|
|
5441
|
+
status: "processing"
|
|
5442
|
+
};
|
|
5443
|
+
return {
|
|
5444
|
+
embed,
|
|
5445
|
+
referenceBlock: createEmbedReferenceBlock("audio-recording", embedId),
|
|
5446
|
+
displayName: filename,
|
|
5447
|
+
secretsRedacted: false,
|
|
5448
|
+
zeroKnowledge: false,
|
|
5449
|
+
requiresUpload: true,
|
|
5450
|
+
localPath: filePath
|
|
5451
|
+
};
|
|
5452
|
+
} catch (e) {
|
|
5453
|
+
process.stderr.write(
|
|
5454
|
+
`\x1B[31mError:\x1B[0m Failed to process ${filename}: ${e instanceof Error ? e.message : String(e)}
|
|
5455
|
+
`
|
|
5456
|
+
);
|
|
5457
|
+
return null;
|
|
5458
|
+
}
|
|
5459
|
+
}
|
|
5399
5460
|
function formatEmbedsForMessage(embeds) {
|
|
5400
5461
|
if (embeds.length === 0) return "";
|
|
5401
5462
|
return "\n" + embeds.map((e) => e.referenceBlock).join("\n");
|
|
@@ -6514,7 +6575,8 @@ function formatTs(ts) {
|
|
|
6514
6575
|
|
|
6515
6576
|
// src/server.ts
|
|
6516
6577
|
import { execSync, spawn as nodeSpawn } from "child_process";
|
|
6517
|
-
import {
|
|
6578
|
+
import { randomBytes as randomBytes2 } from "crypto";
|
|
6579
|
+
import { copyFileSync, existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync5, rmSync as rmSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
6518
6580
|
import { createInterface as createInterface2 } from "readline";
|
|
6519
6581
|
import { homedir as homedir5 } from "os";
|
|
6520
6582
|
import { join as join3, resolve as resolve3 } from "path";
|
|
@@ -6552,16 +6614,17 @@ function removeServerConfig() {
|
|
|
6552
6614
|
rmSync2(filePath);
|
|
6553
6615
|
}
|
|
6554
6616
|
}
|
|
6555
|
-
var
|
|
6617
|
+
var SOURCE_COMPOSE_MARKER = join2("backend", "core", "docker-compose.yml");
|
|
6618
|
+
var IMAGE_COMPOSE_MARKER = join2("backend", "core", "docker-compose.selfhost.yml");
|
|
6556
6619
|
function isOpenMatesDir(dir) {
|
|
6557
|
-
return existsSync4(join2(dir,
|
|
6620
|
+
return existsSync4(join2(dir, SOURCE_COMPOSE_MARKER)) || existsSync4(join2(dir, IMAGE_COMPOSE_MARKER));
|
|
6558
6621
|
}
|
|
6559
6622
|
function resolveServerPath(flags) {
|
|
6560
6623
|
if (typeof flags.path === "string" && flags.path) {
|
|
6561
6624
|
const explicit = resolve2(flags.path);
|
|
6562
6625
|
if (!isOpenMatesDir(explicit)) {
|
|
6563
6626
|
throw new Error(
|
|
6564
|
-
`${explicit} does not appear to be an OpenMates installation (missing ${
|
|
6627
|
+
`${explicit} does not appear to be an OpenMates installation (missing ${SOURCE_COMPOSE_MARKER} or ${IMAGE_COMPOSE_MARKER}).`
|
|
6565
6628
|
);
|
|
6566
6629
|
}
|
|
6567
6630
|
return explicit;
|
|
@@ -6580,11 +6643,68 @@ function resolveServerPath(flags) {
|
|
|
6580
6643
|
}
|
|
6581
6644
|
|
|
6582
6645
|
// src/server.ts
|
|
6583
|
-
var
|
|
6646
|
+
var SOURCE_COMPOSE_FILE = join3("backend", "core", "docker-compose.yml");
|
|
6647
|
+
var IMAGE_COMPOSE_FILE = join3("backend", "core", "docker-compose.selfhost.yml");
|
|
6584
6648
|
var COMPOSE_OVERRIDE = join3("backend", "core", "docker-compose.override.yml");
|
|
6585
6649
|
var DEFAULT_INSTALL_PATH = join3(homedir5(), "openmates");
|
|
6586
6650
|
var REPO_URL = "https://github.com/glowingkitty/OpenMates.git";
|
|
6587
6651
|
var DEV_BRANCH = "dev";
|
|
6652
|
+
var DEFAULT_IMAGE_REGISTRY = "ghcr.io/glowingkitty";
|
|
6653
|
+
var MINIMAL_ENV_TEMPLATE = `# OpenMates self-host image-mode environment
|
|
6654
|
+
SECRET__MISTRAL_AI__API_KEY=
|
|
6655
|
+
SECRET__CEREBRAS__API_KEY=
|
|
6656
|
+
SECRET__GROQ__API_KEY=
|
|
6657
|
+
SECRET__OPENAI__API_KEY=
|
|
6658
|
+
SECRET__ANTHROPIC__API_KEY=
|
|
6659
|
+
SECRET__GOOGLE_AI_STUDIO__API_KEY=
|
|
6660
|
+
SECRET__OPENROUTER__API_KEY=
|
|
6661
|
+
SECRET__TOGETHER__API_KEY=
|
|
6662
|
+
SECRET__BRAVE__API_KEY=
|
|
6663
|
+
SECRET__FIRECRAWL__API_KEY=
|
|
6664
|
+
SECRET__CONTEXT7__API_KEY=
|
|
6665
|
+
DATABASE_ADMIN_EMAIL=admin@example.com
|
|
6666
|
+
DATABASE_ADMIN_PASSWORD=
|
|
6667
|
+
DATABASE_NAME=directus
|
|
6668
|
+
DATABASE_USERNAME=directus
|
|
6669
|
+
DATABASE_PASSWORD=
|
|
6670
|
+
DIRECTUS_TOKEN=
|
|
6671
|
+
DIRECTUS_SECRET=
|
|
6672
|
+
DRAGONFLY_PASSWORD=
|
|
6673
|
+
OPENOBSERVE_ROOT_EMAIL=admin@openmates.internal
|
|
6674
|
+
OPENOBSERVE_ROOT_PASSWORD=
|
|
6675
|
+
INTERNAL_API_SHARED_TOKEN=
|
|
6676
|
+
TUNNEL_TRIGGER_SECRET=<PLACEHOLDER>
|
|
6677
|
+
SERVER_ENVIRONMENT=production
|
|
6678
|
+
FRONTEND_URLS="http://localhost:5173"
|
|
6679
|
+
PRODUCTION_URL="http://localhost:5173"
|
|
6680
|
+
TRUSTED_PROXY_IPS="172.16.0.0/12"
|
|
6681
|
+
CORE_SIDECAR_URL=http://admin-sidecar:8001
|
|
6682
|
+
CLEAR_CACHE_ON_UPDATE=true
|
|
6683
|
+
SIGNUP_LIMIT=20
|
|
6684
|
+
SELF_HOST_SIGNUP_MODE=invite_only
|
|
6685
|
+
SELF_HOST_SIGNUP_ALLOWED_DOMAINS=
|
|
6686
|
+
SELF_HOST_FIRST_INVITE_CODE=
|
|
6687
|
+
APPLICATION_PREVIEW_ORIGIN=
|
|
6688
|
+
OPENMATES_IMAGE_REGISTRY=${DEFAULT_IMAGE_REGISTRY}
|
|
6689
|
+
OPENMATES_IMAGE_TAG=
|
|
6690
|
+
GIT_WORK_DIR=
|
|
6691
|
+
DOCKER_GID=999
|
|
6692
|
+
`;
|
|
6693
|
+
var VAULT_CONFIG_TEMPLATE = `# Minimal Vault configuration
|
|
6694
|
+
listener "tcp" {
|
|
6695
|
+
address = "0.0.0.0:8200"
|
|
6696
|
+
tls_disable = true
|
|
6697
|
+
}
|
|
6698
|
+
|
|
6699
|
+
storage "file" {
|
|
6700
|
+
path = "/vault/file"
|
|
6701
|
+
}
|
|
6702
|
+
|
|
6703
|
+
api_addr = "http://0.0.0.0:8200"
|
|
6704
|
+
ui = false
|
|
6705
|
+
disable_mlock = true
|
|
6706
|
+
log_level = "info"
|
|
6707
|
+
`;
|
|
6588
6708
|
var LLM_PROVIDER_ENV_KEYS = /* @__PURE__ */ new Set([
|
|
6589
6709
|
"SECRET__MISTRAL_AI__API_KEY",
|
|
6590
6710
|
"SECRET__CEREBRAS__API_KEY",
|
|
@@ -6605,8 +6725,21 @@ function runInteractive(cmd, args, cwd) {
|
|
|
6605
6725
|
child.on("error", reject);
|
|
6606
6726
|
});
|
|
6607
6727
|
}
|
|
6608
|
-
function
|
|
6609
|
-
const
|
|
6728
|
+
function loadConfigForInstallPath(installPath) {
|
|
6729
|
+
const config = loadServerConfig();
|
|
6730
|
+
return config?.installPath === installPath ? config : null;
|
|
6731
|
+
}
|
|
6732
|
+
function getInstallMode(installPath, config = loadConfigForInstallPath(installPath)) {
|
|
6733
|
+
if (config?.installMode) return config.installMode;
|
|
6734
|
+
if (existsSync5(join3(installPath, IMAGE_COMPOSE_FILE))) return "image";
|
|
6735
|
+
return "source";
|
|
6736
|
+
}
|
|
6737
|
+
function shouldPullImages() {
|
|
6738
|
+
return process.env.OPENMATES_SKIP_IMAGE_PULL !== "1";
|
|
6739
|
+
}
|
|
6740
|
+
function composeArgs(installPath, withOverrides, installMode = getInstallMode(installPath)) {
|
|
6741
|
+
const composeFile = installMode === "image" ? IMAGE_COMPOSE_FILE : SOURCE_COMPOSE_FILE;
|
|
6742
|
+
const args = ["compose", "--env-file", ".env", "-f", composeFile];
|
|
6610
6743
|
if (withOverrides && existsSync5(join3(installPath, COMPOSE_OVERRIDE))) {
|
|
6611
6744
|
args.push("-f", COMPOSE_OVERRIDE);
|
|
6612
6745
|
}
|
|
@@ -6651,6 +6784,80 @@ function getPackageVersion() {
|
|
|
6651
6784
|
return "";
|
|
6652
6785
|
}
|
|
6653
6786
|
}
|
|
6787
|
+
function getDefaultImageTag() {
|
|
6788
|
+
const version = getPackageVersion();
|
|
6789
|
+
return version ? `v${version}` : "dev";
|
|
6790
|
+
}
|
|
6791
|
+
function defaultTemplateRefForVersion(version) {
|
|
6792
|
+
return /-(alpha|beta|rc)(\.|\d|$)/.test(version) ? DEV_BRANCH : `v${version}`;
|
|
6793
|
+
}
|
|
6794
|
+
function randomHex(bytes) {
|
|
6795
|
+
return randomBytes2(bytes).toString("hex");
|
|
6796
|
+
}
|
|
6797
|
+
function generateInviteCode() {
|
|
6798
|
+
const digits = Array.from(randomBytes2(12), (byte) => String(byte % 10)).join("");
|
|
6799
|
+
return `${digits.slice(0, 4)}-${digits.slice(4, 8)}-${digits.slice(8, 12)}`;
|
|
6800
|
+
}
|
|
6801
|
+
function getEnvVar(content, name) {
|
|
6802
|
+
const match = content.match(new RegExp(`^${name}=(.*)$`, "m"));
|
|
6803
|
+
return match?.[1]?.replace(/^"|"$/g, "") ?? "";
|
|
6804
|
+
}
|
|
6805
|
+
function setEnvVar(content, name, value) {
|
|
6806
|
+
const line = `${name}=${value}`;
|
|
6807
|
+
const pattern = new RegExp(`^${name}=.*$`, "m");
|
|
6808
|
+
if (pattern.test(content)) {
|
|
6809
|
+
return content.replace(pattern, line);
|
|
6810
|
+
}
|
|
6811
|
+
const separator = content.endsWith("\n") ? "" : "\n";
|
|
6812
|
+
return `${content}${separator}${line}
|
|
6813
|
+
`;
|
|
6814
|
+
}
|
|
6815
|
+
function setEnvIfEmpty(content, name, value) {
|
|
6816
|
+
return getEnvVar(content, name) ? content : setEnvVar(content, name, value);
|
|
6817
|
+
}
|
|
6818
|
+
async function fetchText(url) {
|
|
6819
|
+
const response = await fetch(url);
|
|
6820
|
+
if (!response.ok) {
|
|
6821
|
+
throw new Error(`Failed to download ${url}: HTTP ${response.status}`);
|
|
6822
|
+
}
|
|
6823
|
+
return response.text();
|
|
6824
|
+
}
|
|
6825
|
+
async function loadSelfHostComposeTemplate(version) {
|
|
6826
|
+
const templateDir = process.env.OPENMATES_SELFHOST_TEMPLATE_DIR;
|
|
6827
|
+
if (templateDir) {
|
|
6828
|
+
return readFileSync5(join3(resolve3(templateDir), IMAGE_COMPOSE_FILE), "utf-8");
|
|
6829
|
+
}
|
|
6830
|
+
const overrideUrl = process.env.OPENMATES_SELFHOST_COMPOSE_URL;
|
|
6831
|
+
if (overrideUrl) {
|
|
6832
|
+
return fetchText(overrideUrl);
|
|
6833
|
+
}
|
|
6834
|
+
const ref = defaultTemplateRefForVersion(version);
|
|
6835
|
+
return fetchText(
|
|
6836
|
+
`https://raw.githubusercontent.com/glowingkitty/OpenMates/${ref}/backend/core/docker-compose.selfhost.yml`
|
|
6837
|
+
);
|
|
6838
|
+
}
|
|
6839
|
+
async function writeImageModeRuntimeFiles(installPath, imageTag) {
|
|
6840
|
+
const coreDir = join3(installPath, "backend", "core");
|
|
6841
|
+
const vaultConfigDir = join3(coreDir, "vault", "config");
|
|
6842
|
+
mkdirSync3(vaultConfigDir, { recursive: true });
|
|
6843
|
+
writeFileSync3(join3(coreDir, "docker-compose.selfhost.yml"), await loadSelfHostComposeTemplate(getPackageVersion()));
|
|
6844
|
+
writeFileSync3(join3(vaultConfigDir, "vault.hcl"), VAULT_CONFIG_TEMPLATE);
|
|
6845
|
+
const envPath = join3(installPath, ".env");
|
|
6846
|
+
let envContent = existsSync5(envPath) ? readFileSync5(envPath, "utf-8") : MINIMAL_ENV_TEMPLATE;
|
|
6847
|
+
envContent = setEnvIfEmpty(envContent, "DATABASE_ADMIN_PASSWORD", randomHex(12));
|
|
6848
|
+
envContent = setEnvIfEmpty(envContent, "DATABASE_PASSWORD", randomHex(12));
|
|
6849
|
+
envContent = setEnvIfEmpty(envContent, "DIRECTUS_TOKEN", randomHex(32));
|
|
6850
|
+
envContent = setEnvIfEmpty(envContent, "DIRECTUS_SECRET", randomHex(32));
|
|
6851
|
+
envContent = setEnvIfEmpty(envContent, "DRAGONFLY_PASSWORD", randomHex(12));
|
|
6852
|
+
envContent = setEnvIfEmpty(envContent, "OPENOBSERVE_ROOT_PASSWORD", randomHex(32));
|
|
6853
|
+
envContent = setEnvIfEmpty(envContent, "INTERNAL_API_SHARED_TOKEN", randomHex(32));
|
|
6854
|
+
envContent = setEnvIfEmpty(envContent, "SELF_HOST_FIRST_INVITE_CODE", generateInviteCode());
|
|
6855
|
+
envContent = setEnvVar(envContent, "OPENMATES_IMAGE_TAG", imageTag);
|
|
6856
|
+
envContent = setEnvVar(envContent, "OPENMATES_IMAGE_REGISTRY", DEFAULT_IMAGE_REGISTRY);
|
|
6857
|
+
envContent = setEnvVar(envContent, "GIT_WORK_DIR", installPath);
|
|
6858
|
+
writeFileSync3(envPath, envContent.endsWith("\n") ? envContent : `${envContent}
|
|
6859
|
+
`);
|
|
6860
|
+
}
|
|
6654
6861
|
function defaultCloneBranchForVersion(version) {
|
|
6655
6862
|
return /-(alpha|beta|rc)(\.|\d|$)/.test(version) ? DEV_BRANCH : null;
|
|
6656
6863
|
}
|
|
@@ -6700,9 +6907,9 @@ async function serverStatus(flags) {
|
|
|
6700
6907
|
requireDocker();
|
|
6701
6908
|
const installPath = resolveServerPath(flags);
|
|
6702
6909
|
ensureGitWorkDirEnv(installPath);
|
|
6703
|
-
const config =
|
|
6910
|
+
const config = loadConfigForInstallPath(installPath);
|
|
6704
6911
|
const withOverrides = config?.composeProfile === "full";
|
|
6705
|
-
const args = [...composeArgs(installPath, withOverrides), "ps"];
|
|
6912
|
+
const args = [...composeArgs(installPath, withOverrides, getInstallMode(installPath, config)), "ps"];
|
|
6706
6913
|
if (flags.json === true) {
|
|
6707
6914
|
args.push("--format", "json");
|
|
6708
6915
|
}
|
|
@@ -6715,13 +6922,20 @@ async function serverStart(flags) {
|
|
|
6715
6922
|
ensureGitWorkDirEnv(installPath);
|
|
6716
6923
|
warnIfMissingLlmCredentials(installPath);
|
|
6717
6924
|
const withOverrides = flags["with-overrides"] === true;
|
|
6718
|
-
const
|
|
6719
|
-
const
|
|
6925
|
+
const config = loadConfigForInstallPath(installPath);
|
|
6926
|
+
const installMode = getInstallMode(installPath, config);
|
|
6927
|
+
const pullArgs = [...composeArgs(installPath, withOverrides, installMode), "pull"];
|
|
6928
|
+
const args = [...composeArgs(installPath, withOverrides, installMode), "up", "-d"];
|
|
6720
6929
|
if (config && withOverrides && config.composeProfile !== "full") {
|
|
6721
6930
|
saveServerConfig({ ...config, composeProfile: "full" });
|
|
6722
6931
|
}
|
|
6723
6932
|
console.error("Starting OpenMates server...");
|
|
6724
|
-
|
|
6933
|
+
let code = 0;
|
|
6934
|
+
if (installMode === "image" && shouldPullImages()) {
|
|
6935
|
+
code = await runInteractive("docker", pullArgs, installPath);
|
|
6936
|
+
if (code !== 0) process.exit(code);
|
|
6937
|
+
}
|
|
6938
|
+
code = await runInteractive("docker", args, installPath);
|
|
6725
6939
|
if (code !== 0) process.exit(code);
|
|
6726
6940
|
if (flags.json === true) {
|
|
6727
6941
|
printJson({ command: "start", status: "success", path: installPath });
|
|
@@ -6739,9 +6953,9 @@ async function serverStop(flags) {
|
|
|
6739
6953
|
requireDocker();
|
|
6740
6954
|
const installPath = resolveServerPath(flags);
|
|
6741
6955
|
ensureGitWorkDirEnv(installPath);
|
|
6742
|
-
const config =
|
|
6956
|
+
const config = loadConfigForInstallPath(installPath);
|
|
6743
6957
|
const withOverrides = config?.composeProfile === "full";
|
|
6744
|
-
const args = [...composeArgs(installPath, withOverrides), "down"];
|
|
6958
|
+
const args = [...composeArgs(installPath, withOverrides, getInstallMode(installPath, config)), "down"];
|
|
6745
6959
|
console.error("Stopping OpenMates server...");
|
|
6746
6960
|
const code = await runInteractive("docker", args, installPath);
|
|
6747
6961
|
if (code !== 0) process.exit(code);
|
|
@@ -6755,26 +6969,32 @@ async function serverRestart(flags) {
|
|
|
6755
6969
|
requireDocker();
|
|
6756
6970
|
const installPath = resolveServerPath(flags);
|
|
6757
6971
|
ensureGitWorkDirEnv(installPath);
|
|
6758
|
-
const config =
|
|
6972
|
+
const config = loadConfigForInstallPath(installPath);
|
|
6759
6973
|
const withOverrides = config?.composeProfile === "full";
|
|
6974
|
+
const installMode = getInstallMode(installPath, config);
|
|
6760
6975
|
if (flags.rebuild === true) {
|
|
6976
|
+
if (installMode === "image") {
|
|
6977
|
+
throw new Error(
|
|
6978
|
+
"Image-mode installs use prebuilt images and cannot rebuild locally. Run 'openmates server update' to pull newer images, or reinstall with --from-source to build from source."
|
|
6979
|
+
);
|
|
6980
|
+
}
|
|
6761
6981
|
console.error("Rebuilding OpenMates server (this may take a few minutes)...");
|
|
6762
|
-
const downArgs = [...composeArgs(installPath, withOverrides), "down"];
|
|
6982
|
+
const downArgs = [...composeArgs(installPath, withOverrides, installMode), "down"];
|
|
6763
6983
|
let code = await runInteractive("docker", downArgs, installPath);
|
|
6764
6984
|
if (code !== 0) process.exit(code);
|
|
6765
6985
|
try {
|
|
6766
6986
|
exec("docker volume rm openmates-cache-data", installPath);
|
|
6767
6987
|
} catch {
|
|
6768
6988
|
}
|
|
6769
|
-
const buildArgs = [...composeArgs(installPath, withOverrides), "build"];
|
|
6989
|
+
const buildArgs = [...composeArgs(installPath, withOverrides, installMode), "build"];
|
|
6770
6990
|
code = await runInteractive("docker", buildArgs, installPath);
|
|
6771
6991
|
if (code !== 0) process.exit(code);
|
|
6772
|
-
const upArgs = [...composeArgs(installPath, withOverrides), "up", "-d"];
|
|
6992
|
+
const upArgs = [...composeArgs(installPath, withOverrides, installMode), "up", "-d"];
|
|
6773
6993
|
code = await runInteractive("docker", upArgs, installPath);
|
|
6774
6994
|
if (code !== 0) process.exit(code);
|
|
6775
6995
|
} else {
|
|
6776
6996
|
console.error("Restarting OpenMates server...");
|
|
6777
|
-
const args = [...composeArgs(installPath, withOverrides), "restart"];
|
|
6997
|
+
const args = [...composeArgs(installPath, withOverrides, installMode), "restart"];
|
|
6778
6998
|
const code = await runInteractive("docker", args, installPath);
|
|
6779
6999
|
if (code !== 0) process.exit(code);
|
|
6780
7000
|
}
|
|
@@ -6788,9 +7008,9 @@ async function serverLogs(flags) {
|
|
|
6788
7008
|
requireDocker();
|
|
6789
7009
|
const installPath = resolveServerPath(flags);
|
|
6790
7010
|
ensureGitWorkDirEnv(installPath);
|
|
6791
|
-
const config =
|
|
7011
|
+
const config = loadConfigForInstallPath(installPath);
|
|
6792
7012
|
const withOverrides = config?.composeProfile === "full";
|
|
6793
|
-
const args = [...composeArgs(installPath, withOverrides), "logs"];
|
|
7013
|
+
const args = [...composeArgs(installPath, withOverrides, getInstallMode(installPath, config)), "logs"];
|
|
6794
7014
|
if (flags.follow === true || flags.f === true) {
|
|
6795
7015
|
args.push("--follow");
|
|
6796
7016
|
}
|
|
@@ -6808,14 +7028,56 @@ async function serverLogs(flags) {
|
|
|
6808
7028
|
if (code !== 0) process.exit(code);
|
|
6809
7029
|
}
|
|
6810
7030
|
async function serverInstall(flags) {
|
|
6811
|
-
requireGit();
|
|
6812
7031
|
const installPath = typeof flags.path === "string" ? resolve3(flags.path) : DEFAULT_INSTALL_PATH;
|
|
6813
7032
|
const sourcePath = typeof flags["source-path"] === "string" ? resolve3(flags["source-path"]) : null;
|
|
6814
|
-
|
|
7033
|
+
const fromSource = flags["from-source"] === true || sourcePath !== null;
|
|
7034
|
+
if (existsSync5(join3(installPath, SOURCE_COMPOSE_FILE)) || existsSync5(join3(installPath, IMAGE_COMPOSE_FILE))) {
|
|
6815
7035
|
console.error(`OpenMates already exists at ${installPath}.`);
|
|
6816
7036
|
console.error("Use 'openmates server update' to update, or choose a different --path.");
|
|
6817
7037
|
process.exit(1);
|
|
6818
7038
|
}
|
|
7039
|
+
if (!fromSource) {
|
|
7040
|
+
requireDocker();
|
|
7041
|
+
mkdirSync3(installPath, { recursive: true });
|
|
7042
|
+
if (typeof flags["env-path"] === "string") {
|
|
7043
|
+
const envSource = resolve3(flags["env-path"]);
|
|
7044
|
+
if (!existsSync5(envSource)) {
|
|
7045
|
+
throw new Error(`Env file not found: ${envSource}`);
|
|
7046
|
+
}
|
|
7047
|
+
copyFileSync(envSource, join3(installPath, ".env"));
|
|
7048
|
+
console.error(`Copied ${envSource} to ${installPath}/.env`);
|
|
7049
|
+
}
|
|
7050
|
+
const imageTag = typeof flags["image-tag"] === "string" ? flags["image-tag"] : getDefaultImageTag();
|
|
7051
|
+
console.error(`Preparing OpenMates image-mode install at ${installPath}...`);
|
|
7052
|
+
await writeImageModeRuntimeFiles(installPath, imageTag);
|
|
7053
|
+
try {
|
|
7054
|
+
exec("docker network create openmates", installPath);
|
|
7055
|
+
} catch {
|
|
7056
|
+
}
|
|
7057
|
+
saveServerConfig({
|
|
7058
|
+
installPath,
|
|
7059
|
+
installedAt: Date.now(),
|
|
7060
|
+
composeProfile: "core",
|
|
7061
|
+
installMode: "image",
|
|
7062
|
+
imageTag
|
|
7063
|
+
});
|
|
7064
|
+
if (flags.json === true) {
|
|
7065
|
+
printJson({ command: "install", status: "success", path: installPath, mode: "image", imageTag });
|
|
7066
|
+
} else {
|
|
7067
|
+
const firstInvite = getEnvVar(readFileSync5(join3(installPath, ".env"), "utf-8"), "SELF_HOST_FIRST_INVITE_CODE");
|
|
7068
|
+
console.log(`
|
|
7069
|
+
OpenMates installed at ${installPath}`);
|
|
7070
|
+
console.log(`Mode: image (${DEFAULT_IMAGE_REGISTRY}, tag ${imageTag})`);
|
|
7071
|
+
console.log("\nNext steps:");
|
|
7072
|
+
console.log(" 1. Run: openmates server start");
|
|
7073
|
+
console.log(" 2. Open http://localhost:5173");
|
|
7074
|
+
if (firstInvite) console.log(` 3. Sign up with invite code: ${firstInvite}`);
|
|
7075
|
+
console.log(" 4. After signup, make yourself admin: openmates server make-admin your@email.com");
|
|
7076
|
+
console.log("\nOptional: edit .env first to add LLM provider API keys. Source builds are available with --from-source.");
|
|
7077
|
+
}
|
|
7078
|
+
return;
|
|
7079
|
+
}
|
|
7080
|
+
requireGit();
|
|
6819
7081
|
const cloneSource = sourcePath ?? REPO_URL;
|
|
6820
7082
|
const cloneBranch = sourcePath ? null : defaultCloneBranchForVersion(getPackageVersion());
|
|
6821
7083
|
const cloneArgs = ["clone"];
|
|
@@ -6856,10 +7118,11 @@ async function serverInstall(flags) {
|
|
|
6856
7118
|
saveServerConfig({
|
|
6857
7119
|
installPath,
|
|
6858
7120
|
installedAt: Date.now(),
|
|
6859
|
-
composeProfile: "core"
|
|
7121
|
+
composeProfile: "core",
|
|
7122
|
+
installMode: "source"
|
|
6860
7123
|
});
|
|
6861
7124
|
if (flags.json === true) {
|
|
6862
|
-
printJson({ command: "install", status: "success", path: installPath });
|
|
7125
|
+
printJson({ command: "install", status: "success", path: installPath, mode: "source" });
|
|
6863
7126
|
} else {
|
|
6864
7127
|
console.log(`
|
|
6865
7128
|
OpenMates installed at ${installPath}`);
|
|
@@ -6871,11 +7134,29 @@ OpenMates installed at ${installPath}`);
|
|
|
6871
7134
|
}
|
|
6872
7135
|
}
|
|
6873
7136
|
async function serverUpdate(flags) {
|
|
6874
|
-
requireGit();
|
|
6875
7137
|
requireDocker();
|
|
6876
7138
|
const installPath = resolveServerPath(flags);
|
|
6877
7139
|
ensureGitWorkDirEnv(installPath);
|
|
6878
7140
|
console.error("Updating OpenMates...");
|
|
7141
|
+
const config = loadConfigForInstallPath(installPath);
|
|
7142
|
+
const withOverrides = config?.composeProfile === "full";
|
|
7143
|
+
const installMode = getInstallMode(installPath, config);
|
|
7144
|
+
if (installMode === "image") {
|
|
7145
|
+
const pullArgs = [...composeArgs(installPath, withOverrides, installMode), "pull"];
|
|
7146
|
+
console.error("Pulling prebuilt images...");
|
|
7147
|
+
let code2 = await runInteractive("docker", pullArgs, installPath);
|
|
7148
|
+
if (code2 !== 0) process.exit(code2);
|
|
7149
|
+
const upArgs2 = [...composeArgs(installPath, withOverrides, installMode), "up", "-d"];
|
|
7150
|
+
code2 = await runInteractive("docker", upArgs2, installPath);
|
|
7151
|
+
if (code2 !== 0) process.exit(code2);
|
|
7152
|
+
if (flags.json === true) {
|
|
7153
|
+
printJson({ command: "update", status: "success", path: installPath, mode: "image" });
|
|
7154
|
+
} else {
|
|
7155
|
+
console.log("Server images pulled and containers restarted.");
|
|
7156
|
+
}
|
|
7157
|
+
return;
|
|
7158
|
+
}
|
|
7159
|
+
requireGit();
|
|
6879
7160
|
if (flags.force === true) {
|
|
6880
7161
|
console.error("Stashing local changes...");
|
|
6881
7162
|
try {
|
|
@@ -6903,13 +7184,11 @@ async function serverUpdate(flags) {
|
|
|
6903
7184
|
} catch {
|
|
6904
7185
|
}
|
|
6905
7186
|
}
|
|
6906
|
-
const
|
|
6907
|
-
const withOverrides = config?.composeProfile === "full";
|
|
6908
|
-
const buildArgs = [...composeArgs(installPath, withOverrides), "build"];
|
|
7187
|
+
const buildArgs = [...composeArgs(installPath, withOverrides, installMode), "build"];
|
|
6909
7188
|
console.error("Rebuilding containers...");
|
|
6910
7189
|
let code = await runInteractive("docker", buildArgs, installPath);
|
|
6911
7190
|
if (code !== 0) process.exit(code);
|
|
6912
|
-
const upArgs = [...composeArgs(installPath, withOverrides), "up", "-d"];
|
|
7191
|
+
const upArgs = [...composeArgs(installPath, withOverrides, installMode), "up", "-d"];
|
|
6913
7192
|
code = await runInteractive("docker", upArgs, installPath);
|
|
6914
7193
|
if (code !== 0) process.exit(code);
|
|
6915
7194
|
if (flags.json === true) {
|
|
@@ -6922,8 +7201,9 @@ async function serverReset(flags) {
|
|
|
6922
7201
|
requireDocker();
|
|
6923
7202
|
const installPath = resolveServerPath(flags);
|
|
6924
7203
|
ensureGitWorkDirEnv(installPath);
|
|
6925
|
-
const config =
|
|
7204
|
+
const config = loadConfigForInstallPath(installPath);
|
|
6926
7205
|
const withOverrides = config?.composeProfile === "full";
|
|
7206
|
+
const installMode = getInstallMode(installPath, config);
|
|
6927
7207
|
const userDataOnly = flags["delete-user-data-only"] === true;
|
|
6928
7208
|
if (userDataOnly) {
|
|
6929
7209
|
console.error("\nWARNING: This will delete all user data (database and cache).");
|
|
@@ -6943,24 +7223,26 @@ async function serverReset(flags) {
|
|
|
6943
7223
|
}
|
|
6944
7224
|
console.error("Resetting server...");
|
|
6945
7225
|
if (userDataOnly) {
|
|
6946
|
-
const downArgs = [...composeArgs(installPath, withOverrides), "down"];
|
|
7226
|
+
const downArgs = [...composeArgs(installPath, withOverrides, installMode), "down"];
|
|
6947
7227
|
let code = await runInteractive("docker", downArgs, installPath);
|
|
6948
7228
|
if (code !== 0) process.exit(code);
|
|
6949
|
-
for (const vol of ["openmates-cache-data", "openmates-cms-database-data"]) {
|
|
7229
|
+
for (const vol of ["openmates-cache-data", "openmates-postgres-data", "openmates-cms-database-data"]) {
|
|
6950
7230
|
try {
|
|
6951
7231
|
exec(`docker volume rm ${vol}`, installPath);
|
|
6952
7232
|
console.error(` Removed volume: ${vol}`);
|
|
6953
7233
|
} catch {
|
|
6954
7234
|
}
|
|
6955
7235
|
}
|
|
6956
|
-
|
|
6957
|
-
|
|
6958
|
-
|
|
6959
|
-
|
|
7236
|
+
if (installMode === "source") {
|
|
7237
|
+
const buildArgs = [...composeArgs(installPath, withOverrides, installMode), "build"];
|
|
7238
|
+
code = await runInteractive("docker", buildArgs, installPath);
|
|
7239
|
+
if (code !== 0) process.exit(code);
|
|
7240
|
+
}
|
|
7241
|
+
const upArgs = [...composeArgs(installPath, withOverrides, installMode), "up", "-d"];
|
|
6960
7242
|
code = await runInteractive("docker", upArgs, installPath);
|
|
6961
7243
|
if (code !== 0) process.exit(code);
|
|
6962
7244
|
} else {
|
|
6963
|
-
const args = [...composeArgs(installPath, withOverrides), "down", "-v"];
|
|
7245
|
+
const args = [...composeArgs(installPath, withOverrides, installMode), "down", "-v"];
|
|
6964
7246
|
const code = await runInteractive("docker", args, installPath);
|
|
6965
7247
|
if (code !== 0) process.exit(code);
|
|
6966
7248
|
}
|
|
@@ -7003,7 +7285,7 @@ async function serverUninstall(flags) {
|
|
|
7003
7285
|
requireDocker();
|
|
7004
7286
|
const installPath = resolveServerPath(flags);
|
|
7005
7287
|
ensureGitWorkDirEnv(installPath);
|
|
7006
|
-
const config =
|
|
7288
|
+
const config = loadConfigForInstallPath(installPath);
|
|
7007
7289
|
const withOverrides = config?.composeProfile === "full";
|
|
7008
7290
|
const keepData = flags["keep-data"] === true;
|
|
7009
7291
|
console.error("\nWARNING: This will completely uninstall OpenMates:");
|
|
@@ -7025,7 +7307,7 @@ async function serverUninstall(flags) {
|
|
|
7025
7307
|
}
|
|
7026
7308
|
}
|
|
7027
7309
|
console.error("Uninstalling OpenMates...");
|
|
7028
|
-
const downArgs = [...composeArgs(installPath, withOverrides), "down", "--rmi", "local"];
|
|
7310
|
+
const downArgs = [...composeArgs(installPath, withOverrides, getInstallMode(installPath, config)), "down", "--rmi", "local"];
|
|
7029
7311
|
if (!keepData) {
|
|
7030
7312
|
downArgs.push("-v");
|
|
7031
7313
|
}
|
|
@@ -7058,13 +7340,13 @@ OpenMates Server Management
|
|
|
7058
7340
|
Usage: openmates server <command> [options]
|
|
7059
7341
|
|
|
7060
7342
|
Commands:
|
|
7061
|
-
install Install OpenMates server (
|
|
7343
|
+
install Install OpenMates server (prebuilt GHCR images by default)
|
|
7062
7344
|
start Start the server
|
|
7063
7345
|
stop Stop the server
|
|
7064
7346
|
restart Restart the server
|
|
7065
7347
|
status Show server status (container health)
|
|
7066
7348
|
logs Display server logs
|
|
7067
|
-
update Update to latest version (git pull + rebuild)
|
|
7349
|
+
update Update to latest version (pull images, or git pull + rebuild for source installs)
|
|
7068
7350
|
make-admin Grant admin privileges to a user
|
|
7069
7351
|
reset Reset server data (requires confirmation)
|
|
7070
7352
|
uninstall Completely remove OpenMates (requires confirmation)
|
|
@@ -7078,7 +7360,9 @@ Command Options:
|
|
|
7078
7360
|
install:
|
|
7079
7361
|
--path <dir> Install directory (default: ~/openmates)
|
|
7080
7362
|
--env-path <file> Copy a pre-existing .env file during install
|
|
7081
|
-
--
|
|
7363
|
+
--image-tag <tag> Prebuilt image tag (default: CLI version tag)
|
|
7364
|
+
--from-source Clone/build from source instead of using prebuilt GHCR images
|
|
7365
|
+
--source-path <dir> Clone from a local checkout instead of GitHub (implies --from-source)
|
|
7082
7366
|
|
|
7083
7367
|
start:
|
|
7084
7368
|
--with-overrides Include admin UIs (Directus CMS, Grafana)
|
|
@@ -9338,8 +9622,44 @@ async function sendMessageStreaming(client, params, redactor) {
|
|
|
9338
9622
|
try {
|
|
9339
9623
|
const session = client.getSession();
|
|
9340
9624
|
const uploadResult = await uploadFile(fe.localPath, session);
|
|
9341
|
-
fe.embed.
|
|
9342
|
-
|
|
9625
|
+
const embedType = fe.embed.type;
|
|
9626
|
+
const audioTranscription = embedType === "audio-recording" ? await transcribeUploadedAudio(
|
|
9627
|
+
uploadResult,
|
|
9628
|
+
fe.displayName,
|
|
9629
|
+
session,
|
|
9630
|
+
{ chatId: params.chatId, requestId: uploadResult.embed_id }
|
|
9631
|
+
) : null;
|
|
9632
|
+
const uploadedContent = embedType === "audio-recording" ? {
|
|
9633
|
+
app_id: "audio",
|
|
9634
|
+
skill_id: "transcribe",
|
|
9635
|
+
type: "audio-recording",
|
|
9636
|
+
status: "finished",
|
|
9637
|
+
filename: fe.displayName,
|
|
9638
|
+
mime_type: uploadResult.content_type,
|
|
9639
|
+
transcript: audioTranscription?.transcript ?? null,
|
|
9640
|
+
transcript_original: audioTranscription?.transcript_original ?? null,
|
|
9641
|
+
transcript_corrected: audioTranscription?.transcript_corrected ?? null,
|
|
9642
|
+
use_corrected: audioTranscription?.use_corrected ?? null,
|
|
9643
|
+
correction_model: audioTranscription?.correction_model ?? null,
|
|
9644
|
+
model: audioTranscription?.model ?? null,
|
|
9645
|
+
s3_base_url: uploadResult.s3_base_url,
|
|
9646
|
+
files: uploadResult.files,
|
|
9647
|
+
aes_key: uploadResult.aes_key,
|
|
9648
|
+
aes_nonce: uploadResult.aes_nonce,
|
|
9649
|
+
vault_wrapped_aes_key: uploadResult.vault_wrapped_aes_key
|
|
9650
|
+
} : embedType === "pdf" ? {
|
|
9651
|
+
type: "pdf",
|
|
9652
|
+
status: "processing",
|
|
9653
|
+
filename: fe.displayName,
|
|
9654
|
+
page_count: uploadResult.page_count ?? null,
|
|
9655
|
+
content_hash: uploadResult.content_hash,
|
|
9656
|
+
s3_base_url: uploadResult.s3_base_url,
|
|
9657
|
+
files: uploadResult.files,
|
|
9658
|
+
aes_key: uploadResult.aes_key,
|
|
9659
|
+
aes_nonce: uploadResult.aes_nonce,
|
|
9660
|
+
vault_wrapped_aes_key: uploadResult.vault_wrapped_aes_key
|
|
9661
|
+
} : {
|
|
9662
|
+
type: "image",
|
|
9343
9663
|
app_id: "images",
|
|
9344
9664
|
skill_id: "upload",
|
|
9345
9665
|
status: "finished",
|
|
@@ -9351,10 +9671,15 @@ async function sendMessageStreaming(client, params, redactor) {
|
|
|
9351
9671
|
aes_nonce: uploadResult.aes_nonce,
|
|
9352
9672
|
vault_wrapped_aes_key: uploadResult.vault_wrapped_aes_key,
|
|
9353
9673
|
ai_detection: uploadResult.ai_detection
|
|
9354
|
-
}
|
|
9355
|
-
fe.embed.
|
|
9674
|
+
};
|
|
9675
|
+
fe.embed.content = toonEncodeContent(uploadedContent);
|
|
9676
|
+
fe.embed.status = embedType === "pdf" ? "processing" : "finished";
|
|
9356
9677
|
fe.embed.contentHash = uploadResult.content_hash;
|
|
9357
9678
|
fe.embed.embedId = uploadResult.embed_id;
|
|
9679
|
+
fe.referenceBlock = createEmbedReferenceBlock(
|
|
9680
|
+
embedType,
|
|
9681
|
+
uploadResult.embed_id
|
|
9682
|
+
);
|
|
9358
9683
|
if (!params.json) {
|
|
9359
9684
|
process.stderr.write(
|
|
9360
9685
|
`\x1B[32m \u2713\x1B[0m \x1B[2m${fe.displayName} uploaded\x1B[0m
|
package/dist/cli.js
CHANGED
package/dist/index.js
CHANGED