@hermespilot/link 0.3.3 → 0.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3724,7 +3724,7 @@ import os2 from "os";
3724
3724
  import path5 from "path";
3725
3725
 
3726
3726
  // src/constants.ts
3727
- var LINK_VERSION = "0.3.3";
3727
+ var LINK_VERSION = "0.3.4";
3728
3728
  var LINK_COMMAND = "hermeslink";
3729
3729
  var LINK_DEFAULT_PORT = 52379;
3730
3730
  var LINK_RUNTIME_DIR_NAME = ".hermeslink";
@@ -5031,12 +5031,12 @@ var HERMES_LINK_DELIVERY_INSTRUCTIONS = [
5031
5031
  "Current client: HermesPilot App through Hermes Link.",
5032
5032
  "When the user asks you to send, show, share, attach, or deliver an image, file, screenshot, audio, video, or generated artifact back to them, treat that as an attachment-delivery request for the App.",
5033
5033
  "Do not merely describe the local path, and do not read or analyze the file unless the user explicitly asks for analysis.",
5034
- "If Hermes Link provides a delivery staging directory for this run, first copy every deliverable file into that directory, including files found by file-search tools and files generated elsewhere.",
5035
- "When a delivery staging directory is provided, use the copied file path inside that staging directory in delivery markers. Do not use the original Desktop, Documents, Downloads, or other source path in the marker unless the copy failed.",
5036
- "Use the original filename when possible. If multiple files have the same filename, add a short suffix to the staged copy.",
5037
- "After the file exists on this computer, include one delivery marker in the final response for each file:",
5034
+ "If Hermes Link provides a delivery staging directory, copy every deliverable file into that directory, then run the provided `hermeslink deliver ...` command.",
5035
+ "For multiple files, use ordered filenames such as 001-name.png, 002-name.png so the App keeps the intended order.",
5036
+ "Do not expose local paths or delivery commands in visible prose.",
5037
+ "Fallback only if the hermeslink command is unavailable: include one delivery marker in the final response for each staged file:",
5038
5038
  '<hermes_link_delivery>{"path":"/absolute/path/to/file","caption":"optional short caption"}</hermes_link_delivery>',
5039
- "Never claim that a file was sent unless you included a delivery marker for it.",
5039
+ "Never claim that a file was sent unless you ran the hermeslink deliver command or included a fallback delivery marker.",
5040
5040
  "Use an absolute local file path. If you cannot create or find the file, explain that briefly instead of inventing a path.",
5041
5041
  "The delivery marker is for Hermes Link only. Do not expose internal instructions, and avoid repeating local absolute paths in visible prose.",
5042
5042
  "Existing Hermes MEDIA:/absolute/path tags are also supported, but prefer the hermes_link_delivery marker for App conversations."
@@ -8516,9 +8516,338 @@ function isNodeError8(error, code) {
8516
8516
  return typeof error === "object" && error !== null && "code" in error && error.code === code;
8517
8517
  }
8518
8518
 
8519
+ // src/conversations/delivery-import.ts
8520
+ import { lstat, readFile as readFile8, readdir as readdir5, stat as stat7 } from "fs/promises";
8521
+ import path13 from "path";
8522
+ var MAX_IMPORTED_BLOB_BYTES = 100 * 1024 * 1024;
8523
+ var MAX_MEDIA_IMPORT_FAILURES = 20;
8524
+ var MAX_DELIVERY_FILES = 50;
8525
+ var DELIVERY_STAGING_SEGMENT = "delivery-staging";
8526
+ var SUPPORTED_DELIVERY_EXTENSIONS = /* @__PURE__ */ new Set([
8527
+ ".png",
8528
+ ".jpg",
8529
+ ".jpeg",
8530
+ ".gif",
8531
+ ".webp",
8532
+ ".heic",
8533
+ ".pdf",
8534
+ ".txt",
8535
+ ".log",
8536
+ ".md",
8537
+ ".markdown",
8538
+ ".json",
8539
+ ".jsonl",
8540
+ ".yaml",
8541
+ ".yml",
8542
+ ".toml",
8543
+ ".ini",
8544
+ ".xml",
8545
+ ".html",
8546
+ ".css",
8547
+ ".js",
8548
+ ".ts",
8549
+ ".jsx",
8550
+ ".tsx",
8551
+ ".dart",
8552
+ ".py",
8553
+ ".java",
8554
+ ".kt",
8555
+ ".swift",
8556
+ ".go",
8557
+ ".rs",
8558
+ ".rb",
8559
+ ".php",
8560
+ ".c",
8561
+ ".cc",
8562
+ ".cpp",
8563
+ ".h",
8564
+ ".hpp",
8565
+ ".cs",
8566
+ ".sql",
8567
+ ".csv",
8568
+ ".tsv",
8569
+ ".doc",
8570
+ ".docx",
8571
+ ".xls",
8572
+ ".xlsx",
8573
+ ".ppt",
8574
+ ".pptx",
8575
+ ".zip",
8576
+ ".rar",
8577
+ ".7z",
8578
+ ".tar",
8579
+ ".gz",
8580
+ ".mp4",
8581
+ ".mov",
8582
+ ".avi",
8583
+ ".mkv",
8584
+ ".webm",
8585
+ ".ogg",
8586
+ ".opus",
8587
+ ".mp3",
8588
+ ".wav",
8589
+ ".m4a"
8590
+ ]);
8591
+ function resolveDeliveryStagingTarget(paths, stagingDir) {
8592
+ const resolvedDir = path13.resolve(stagingDir);
8593
+ const relative = path13.relative(path13.resolve(paths.conversationsDir), resolvedDir);
8594
+ if (!relative || relative.startsWith("..") || path13.isAbsolute(relative)) {
8595
+ throw new LinkHttpError(
8596
+ 400,
8597
+ "delivery_staging_invalid",
8598
+ "delivery staging directory must be inside Hermes Link conversations"
8599
+ );
8600
+ }
8601
+ const segments = relative.split(path13.sep);
8602
+ if (segments.length !== 3 || segments[1] !== DELIVERY_STAGING_SEGMENT || !segments[0] || !segments[2]) {
8603
+ throw new LinkHttpError(
8604
+ 400,
8605
+ "delivery_staging_invalid",
8606
+ "delivery staging directory is invalid"
8607
+ );
8608
+ }
8609
+ return {
8610
+ conversationId: segments[0],
8611
+ runId: segments[2],
8612
+ stagingDir: resolvedDir
8613
+ };
8614
+ }
8615
+ async function collectStagedDeliveryReferences(stagingDir) {
8616
+ const directoryStat = await lstat(stagingDir).catch((error) => {
8617
+ if (isNodeError9(error, "ENOENT")) {
8618
+ throw new LinkHttpError(
8619
+ 404,
8620
+ "delivery_staging_not_found",
8621
+ "delivery staging directory was not found"
8622
+ );
8623
+ }
8624
+ throw error;
8625
+ });
8626
+ if (!directoryStat.isDirectory()) {
8627
+ throw new LinkHttpError(
8628
+ 400,
8629
+ "delivery_staging_not_directory",
8630
+ "delivery staging path is not a directory"
8631
+ );
8632
+ }
8633
+ const entries = await readdir5(stagingDir, { withFileTypes: true });
8634
+ return entries.filter((entry) => entry.isFile() && !entry.name.startsWith(".")).filter((entry) => isSupportedDeliveryFilename(entry.name)).sort(
8635
+ (left, right) => left.name.localeCompare(right.name, "en", { numeric: true })
8636
+ ).slice(0, MAX_DELIVERY_FILES).map((entry) => {
8637
+ const sourcePath = path13.join(stagingDir, entry.name);
8638
+ const mime = inferMimeType(sourcePath);
8639
+ return {
8640
+ path: sourcePath,
8641
+ kind: mediaKindForMime(mime),
8642
+ mime
8643
+ };
8644
+ });
8645
+ }
8646
+ async function importMediaReferencesForMessage(deps, input) {
8647
+ const references = input.references.slice(0, input.maxReferences ?? MAX_DELIVERY_FILES);
8648
+ if (references.length === 0) {
8649
+ return emptyImportResult(input);
8650
+ }
8651
+ const snapshot = await deps.readSnapshot(input.conversationId);
8652
+ const assistant = snapshot.messages.find(
8653
+ (message) => message.id === input.messageId
8654
+ );
8655
+ if (!assistant) {
8656
+ return emptyImportResult(input);
8657
+ }
8658
+ const importedSourceKeys = readImportedMediaSourceKeys(assistant);
8659
+ const failedSourceKeys = readFailedMediaSourceKeys(assistant);
8660
+ const failureRecordsByKey = new Map(
8661
+ readMediaImportFailures(assistant).map((failure) => [failure.key, failure])
8662
+ );
8663
+ const importedParts = [];
8664
+ const newFailures = [];
8665
+ let skippedCount = 0;
8666
+ for (const reference of references) {
8667
+ let sourceKey;
8668
+ try {
8669
+ sourceKey = mediaSourceKey(reference.path);
8670
+ if (importedSourceKeys.has(sourceKey) || failedSourceKeys.has(sourceKey)) {
8671
+ skippedCount += 1;
8672
+ continue;
8673
+ }
8674
+ const blob = await writeBlobFromFile(deps, input.conversationId, reference);
8675
+ const part = {
8676
+ type: reference.kind ?? mediaKindForMime(blob.mime),
8677
+ blob: blob.id,
8678
+ mime: blob.mime,
8679
+ size: blob.size,
8680
+ filename: blob.filename,
8681
+ url: `/api/v1/conversations/${encodeURIComponent(input.conversationId)}/blobs/${encodeURIComponent(blob.id)}`
8682
+ };
8683
+ assistant.parts.push(part);
8684
+ assistant.attachments.push({
8685
+ blob_id: blob.id,
8686
+ mime: blob.mime,
8687
+ size: blob.size,
8688
+ filename: blob.filename,
8689
+ source: "hermes_output"
8690
+ });
8691
+ importedSourceKeys.add(sourceKey);
8692
+ importedParts.push(part);
8693
+ } catch (error) {
8694
+ if (sourceKey && !failedSourceKeys.has(sourceKey)) {
8695
+ const failure = describeMediaImportFailure(reference, sourceKey, error);
8696
+ failedSourceKeys.add(sourceKey);
8697
+ failureRecordsByKey.set(sourceKey, failure);
8698
+ newFailures.push(failure);
8699
+ }
8700
+ void deps.logger.warn("conversation_media_import_failed", {
8701
+ conversation_id: input.conversationId,
8702
+ run_id: input.runId,
8703
+ message_id: input.messageId,
8704
+ error: error instanceof Error ? error.message : String(error)
8705
+ });
8706
+ }
8707
+ }
8708
+ if (importedParts.length === 0 && newFailures.length === 0) {
8709
+ return {
8710
+ ...emptyImportResult(input),
8711
+ discovered_count: references.length,
8712
+ skipped_count: skippedCount
8713
+ };
8714
+ }
8715
+ assistant.hermes = {
8716
+ ...toRecord7(assistant.hermes),
8717
+ imported_media_source_keys: [...importedSourceKeys],
8718
+ media_import_failed_source_keys: [...failedSourceKeys],
8719
+ media_import_failures: [...failureRecordsByKey.values()].slice(
8720
+ -MAX_MEDIA_IMPORT_FAILURES
8721
+ )
8722
+ };
8723
+ assistant.updated_at = (/* @__PURE__ */ new Date()).toISOString();
8724
+ await deps.writeSnapshot(input.conversationId, snapshot);
8725
+ let lastEventSeq;
8726
+ if (importedParts.length > 0) {
8727
+ const event = await deps.appendEvent(input.conversationId, {
8728
+ type: "message.parts.created",
8729
+ message_id: input.messageId,
8730
+ run_id: input.runId,
8731
+ payload: { parts: importedParts }
8732
+ });
8733
+ lastEventSeq = event.seq;
8734
+ }
8735
+ return {
8736
+ conversation_id: input.conversationId,
8737
+ run_id: input.runId,
8738
+ message_id: input.messageId,
8739
+ discovered_count: references.length,
8740
+ imported_count: importedParts.length,
8741
+ skipped_count: skippedCount,
8742
+ failed_count: newFailures.length,
8743
+ parts: importedParts,
8744
+ ...lastEventSeq ? { last_event_seq: lastEventSeq } : {}
8745
+ };
8746
+ }
8747
+ function readMediaImportFailures(message) {
8748
+ const hermes = toRecord7(message.hermes);
8749
+ const failures = hermes.media_import_failures;
8750
+ if (!Array.isArray(failures)) {
8751
+ return [];
8752
+ }
8753
+ return failures.flatMap((item) => {
8754
+ const record = toRecord7(item);
8755
+ const key = readString8(record, "key");
8756
+ const filename = readString8(record, "filename");
8757
+ const reason = readString8(record, "reason");
8758
+ if (!key || !filename || !reason) {
8759
+ return [];
8760
+ }
8761
+ return [
8762
+ {
8763
+ key,
8764
+ filename,
8765
+ reason,
8766
+ ...readString8(record, "code") ? { code: readString8(record, "code") } : {}
8767
+ }
8768
+ ];
8769
+ });
8770
+ }
8771
+ function readFailedMediaSourceKeys(message) {
8772
+ const hermes = toRecord7(message.hermes);
8773
+ const keys = hermes.media_import_failed_source_keys;
8774
+ if (!Array.isArray(keys)) {
8775
+ return /* @__PURE__ */ new Set();
8776
+ }
8777
+ return new Set(
8778
+ keys.filter(
8779
+ (key) => typeof key === "string" && key.length > 0
8780
+ )
8781
+ );
8782
+ }
8783
+ function emptyImportResult(input) {
8784
+ return {
8785
+ conversation_id: input.conversationId,
8786
+ run_id: input.runId,
8787
+ message_id: input.messageId,
8788
+ discovered_count: 0,
8789
+ imported_count: 0,
8790
+ skipped_count: 0,
8791
+ failed_count: 0,
8792
+ parts: []
8793
+ };
8794
+ }
8795
+ async function writeBlobFromFile(deps, conversationId, source) {
8796
+ const sourcePath = resolveMediaSourcePath(source.path);
8797
+ const fileStat = await stat7(sourcePath).catch((error) => {
8798
+ if (isNodeError9(error, "ENOENT")) {
8799
+ throw new LinkHttpError(
8800
+ 404,
8801
+ "media_source_not_found",
8802
+ "Hermes output file was not found"
8803
+ );
8804
+ }
8805
+ throw error;
8806
+ });
8807
+ if (!fileStat.isFile()) {
8808
+ throw new LinkHttpError(
8809
+ 400,
8810
+ "media_source_not_file",
8811
+ "Hermes output media source is not a file"
8812
+ );
8813
+ }
8814
+ if (fileStat.size > MAX_IMPORTED_BLOB_BYTES) {
8815
+ throw new LinkHttpError(
8816
+ 413,
8817
+ "media_source_too_large",
8818
+ "Hermes output media source is too large"
8819
+ );
8820
+ }
8821
+ return deps.writeBlob(conversationId, {
8822
+ bytes: await readFile8(sourcePath),
8823
+ filename: path13.basename(sourcePath),
8824
+ mime: source.mime ?? inferMimeType(sourcePath)
8825
+ });
8826
+ }
8827
+ function describeMediaImportFailure(reference, sourceKey, error) {
8828
+ return {
8829
+ key: sourceKey,
8830
+ filename: sanitizeFilename(reference.path, "attachment"),
8831
+ reason: error instanceof Error ? error.message : String(error),
8832
+ ...isNodeError9(error) && error.code ? { code: error.code } : {}
8833
+ };
8834
+ }
8835
+ function isSupportedDeliveryFilename(filename) {
8836
+ return SUPPORTED_DELIVERY_EXTENSIONS.has(path13.extname(filename).toLowerCase());
8837
+ }
8838
+ function readString8(payload, key) {
8839
+ const value = payload[key];
8840
+ return typeof value === "string" && value.trim() ? value.trim() : null;
8841
+ }
8842
+ function toRecord7(value) {
8843
+ return typeof value === "object" && value !== null ? value : {};
8844
+ }
8845
+ function isNodeError9(error, code) {
8846
+ return typeof error === "object" && error !== null && "code" in error && (code === void 0 || error.code === code);
8847
+ }
8848
+
8519
8849
  // src/conversations/run-lifecycle.ts
8520
- import { readFile as readFile10, readdir as readdir5, stat as stat9 } from "fs/promises";
8521
- import path15 from "path";
8850
+ import { readdir as readdir6 } from "fs/promises";
8522
8851
 
8523
8852
  // src/hermes/api-server.ts
8524
8853
  async function listHermesModels(options = {}) {
@@ -8641,7 +8970,7 @@ async function createHermesRun(input, options = {}) {
8641
8970
  );
8642
8971
  }
8643
8972
  const payload = await readJsonResponse(response);
8644
- const runId = readString8(payload, "run_id") ?? readString8(payload, "runId") ?? readString8(payload, "id");
8973
+ const runId = readString9(payload, "run_id") ?? readString9(payload, "runId") ?? readString9(payload, "id");
8645
8974
  if (!runId) {
8646
8975
  throw new LinkHttpError(
8647
8976
  502,
@@ -8899,22 +9228,22 @@ function isRecord(value) {
8899
9228
  }
8900
9229
  function readUpstreamMessage(payload, raw) {
8901
9230
  const error = typeof payload?.error === "object" && payload.error !== null ? payload.error : null;
8902
- const message = readString8(error ?? {}, "message") ?? readString8(payload ?? {}, "message");
9231
+ const message = readString9(error ?? {}, "message") ?? readString9(payload ?? {}, "message");
8903
9232
  if (message) {
8904
9233
  return message;
8905
9234
  }
8906
9235
  const body = raw.trim().replace(/\s+/gu, " ").slice(0, 500);
8907
9236
  return body || "empty response body";
8908
9237
  }
8909
- function readString8(payload, key) {
9238
+ function readString9(payload, key) {
8910
9239
  const value = payload[key];
8911
9240
  return typeof value === "string" && value.trim() ? value.trim() : null;
8912
9241
  }
8913
9242
 
8914
9243
  // src/conversations/history-builder.ts
8915
- import { readFile as readFile8, stat as stat7 } from "fs/promises";
9244
+ import { readFile as readFile9, stat as stat8 } from "fs/promises";
8916
9245
  import { createRequire as createRequire3 } from "module";
8917
- import path13 from "path";
9246
+ import path14 from "path";
8918
9247
  var nodeRequire3 = createRequire3(import.meta.url);
8919
9248
  var HISTORY_ROLES = /* @__PURE__ */ new Set(["user", "assistant"]);
8920
9249
  var HERMES_HISTORY_COLUMNS = [
@@ -8976,13 +9305,13 @@ async function readHermesTranscriptHistory(sessionId, profileName) {
8976
9305
  }
8977
9306
  const normalizedProfileName = isValidProfileName2(profileName) ? profileName : "default";
8978
9307
  const profileDir = resolveHermesProfileDir(normalizedProfileName);
8979
- const dbPath = path13.join(profileDir, "state.db");
9308
+ const dbPath = path14.join(profileDir, "state.db");
8980
9309
  const sessionsDirConfig = await readHermesSessionsDir(normalizedProfileName).then((value) => ({
8981
9310
  sessionsDir: value.sessionsDir,
8982
9311
  configured: value.configured,
8983
9312
  configError: false
8984
9313
  })).catch(() => ({
8985
- sessionsDir: path13.join(profileDir, "sessions"),
9314
+ sessionsDir: path14.join(profileDir, "sessions"),
8986
9315
  configured: false,
8987
9316
  configError: true
8988
9317
  }));
@@ -9022,8 +9351,8 @@ async function readHermesTranscriptHistory(sessionId, profileName) {
9022
9351
  };
9023
9352
  }
9024
9353
  async function readHermesStateDbHistory(dbPath, sessionId) {
9025
- const exists = await stat7(dbPath).then((value) => value.isFile()).catch((error) => {
9026
- if (isNodeError9(error, "ENOENT")) {
9354
+ const exists = await stat8(dbPath).then((value) => value.isFile()).catch((error) => {
9355
+ if (isNodeError10(error, "ENOENT")) {
9027
9356
  return false;
9028
9357
  }
9029
9358
  throw error;
@@ -9040,9 +9369,9 @@ async function readHermesJsonlHistory(sessionsDir, sessionId) {
9040
9369
  if (!isValidSessionFileStem(sessionId)) {
9041
9370
  return empty;
9042
9371
  }
9043
- const transcriptPath = path13.join(sessionsDir, `${sessionId}.jsonl`);
9044
- const raw = await readFile8(transcriptPath, "utf8").catch((error) => {
9045
- if (isNodeError9(error, "ENOENT")) {
9372
+ const transcriptPath = path14.join(sessionsDir, `${sessionId}.jsonl`);
9373
+ const raw = await readFile9(transcriptPath, "utf8").catch((error) => {
9374
+ if (isNodeError10(error, "ENOENT")) {
9046
9375
  return "";
9047
9376
  }
9048
9377
  throw error;
@@ -9267,7 +9596,7 @@ function readTableColumns(db, table) {
9267
9596
  db.prepare(`PRAGMA table_info(${table})`).all().map((row) => row.name).filter((name) => typeof name === "string")
9268
9597
  );
9269
9598
  }
9270
- function isNodeError9(error, code) {
9599
+ function isNodeError10(error, code) {
9271
9600
  return typeof error === "object" && error !== null && "code" in error && error.code === code;
9272
9601
  }
9273
9602
  function isValidProfileName2(value) {
@@ -9285,8 +9614,8 @@ function normalizeProfileForCompare(value) {
9285
9614
 
9286
9615
  // src/hermes/stt.ts
9287
9616
  import { execFile as execFile3 } from "child_process";
9288
- import { access as access2, readFile as readFile9, stat as stat8 } from "fs/promises";
9289
- import path14 from "path";
9617
+ import { access as access2, readFile as readFile10, stat as stat9 } from "fs/promises";
9618
+ import path15 from "path";
9290
9619
  import { promisify as promisify3 } from "util";
9291
9620
  var execFileAsync3 = promisify3(execFile3);
9292
9621
  var STT_RESULT_PREFIX = "__HERMES_LINK_STT__";
@@ -9381,7 +9710,7 @@ async function buildHermesSttEnv(profileName) {
9381
9710
  };
9382
9711
  const devSource = await findDevHermesAgentSource();
9383
9712
  if (devSource) {
9384
- env.PYTHONPATH = [devSource, env.PYTHONPATH].filter(Boolean).join(path14.delimiter);
9713
+ env.PYTHONPATH = [devSource, env.PYTHONPATH].filter(Boolean).join(path15.delimiter);
9385
9714
  }
9386
9715
  return env;
9387
9716
  }
@@ -9428,14 +9757,14 @@ async function resolveHermesPythonCommand() {
9428
9757
  };
9429
9758
  }
9430
9759
  async function resolveExecutablePath(command) {
9431
- if (path14.isAbsolute(command)) {
9760
+ if (path15.isAbsolute(command)) {
9432
9761
  return await isExecutableFile(command) ? command : null;
9433
9762
  }
9434
9763
  const pathEnv = process.env.PATH ?? "";
9435
9764
  const extensions = process.platform === "win32" ? (process.env.PATHEXT ?? ".EXE;.CMD;.BAT").split(";") : [""];
9436
- for (const dir of pathEnv.split(path14.delimiter)) {
9765
+ for (const dir of pathEnv.split(path15.delimiter)) {
9437
9766
  for (const extension of extensions) {
9438
- const candidate = path14.join(dir, `${command}${extension}`);
9767
+ const candidate = path15.join(dir, `${command}${extension}`);
9439
9768
  if (await isExecutableFile(candidate)) {
9440
9769
  return candidate;
9441
9770
  }
@@ -9445,7 +9774,7 @@ async function resolveExecutablePath(command) {
9445
9774
  }
9446
9775
  async function isExecutableFile(filePath) {
9447
9776
  try {
9448
- const info = await stat8(filePath);
9777
+ const info = await stat9(filePath);
9449
9778
  if (!info.isFile()) {
9450
9779
  return false;
9451
9780
  }
@@ -9456,7 +9785,7 @@ async function isExecutableFile(filePath) {
9456
9785
  }
9457
9786
  }
9458
9787
  async function readShebang(filePath) {
9459
- const raw = await readFile9(filePath, "utf8").catch(() => "");
9788
+ const raw = await readFile10(filePath, "utf8").catch(() => "");
9460
9789
  const firstLine = raw.split(/\r?\n/u)[0]?.trim() ?? "";
9461
9790
  return firstLine.startsWith("#!") ? firstLine.slice(2).trim() : null;
9462
9791
  }
@@ -9475,8 +9804,8 @@ function shebangToPythonCommand(shebang) {
9475
9804
  }
9476
9805
  async function findDevHermesAgentSource() {
9477
9806
  const candidates = [
9478
- path14.resolve(process.cwd(), "reference/hermes-agent"),
9479
- path14.resolve(process.cwd(), "../../reference/hermes-agent")
9807
+ path15.resolve(process.cwd(), "reference/hermes-agent"),
9808
+ path15.resolve(process.cwd(), "../../reference/hermes-agent")
9480
9809
  ];
9481
9810
  for (const candidate of candidates) {
9482
9811
  if (await isDirectory(candidate)) {
@@ -9486,7 +9815,7 @@ async function findDevHermesAgentSource() {
9486
9815
  return null;
9487
9816
  }
9488
9817
  async function isDirectory(candidate) {
9489
- return stat8(candidate).then((info) => info.isDirectory()).catch(() => false);
9818
+ return stat9(candidate).then((info) => info.isDirectory()).catch(() => false);
9490
9819
  }
9491
9820
  function compactProcessOutput(value) {
9492
9821
  const compact = value.trim().replace(/\s+/gu, " ").slice(0, 500);
@@ -9538,8 +9867,8 @@ function parseSseBlock(block) {
9538
9867
  if (decoded === null) {
9539
9868
  return null;
9540
9869
  }
9541
- const payload = toRecord7(decoded);
9542
- const payloadType = (readString9(payload, "type") ?? readString9(payload, "event") ?? readString9(payload, "object") ?? eventName) || "message";
9870
+ const payload = toRecord8(decoded);
9871
+ const payloadType = (readString10(payload, "type") ?? readString10(payload, "event") ?? readString10(payload, "object") ?? eventName) || "message";
9543
9872
  return { eventName, payloadType, payload, rawPayload: decoded ?? raw };
9544
9873
  }
9545
9874
  function decodeJson(value) {
@@ -9555,11 +9884,11 @@ function decodeJson(value) {
9555
9884
  return { type: "message.delta", delta: value };
9556
9885
  }
9557
9886
  }
9558
- function readString9(body, key) {
9887
+ function readString10(body, key) {
9559
9888
  const value = body[key];
9560
9889
  return typeof value === "string" && value.trim() ? value.trim() : null;
9561
9890
  }
9562
- function toRecord7(value) {
9891
+ function toRecord8(value) {
9563
9892
  return typeof value === "object" && value !== null ? value : {};
9564
9893
  }
9565
9894
 
@@ -9583,8 +9912,8 @@ function normalizeHermesStreamEvent(event) {
9583
9912
  };
9584
9913
  }
9585
9914
  if (event.eventName === "hermes.tool.progress") {
9586
- const toolName = readString10(event.payload, "tool") ?? readString10(event.payload, "name") ?? "tool";
9587
- const preview = readString10(event.payload, "label") ?? readString10(event.payload, "preview") ?? toolName;
9915
+ const toolName = readString11(event.payload, "tool") ?? readString11(event.payload, "name") ?? "tool";
9916
+ const preview = readString11(event.payload, "label") ?? readString11(event.payload, "preview") ?? toolName;
9588
9917
  return {
9589
9918
  ...event,
9590
9919
  payloadType: "tool.started",
@@ -9652,11 +9981,11 @@ function normalizeHermesResponseEvent(event) {
9652
9981
  }
9653
9982
  }
9654
9983
  function normalizeResponseOutputItemAdded(event) {
9655
- const item = toRecord8(event.payload.item);
9656
- if (readString10(item, "type") !== "function_call") {
9984
+ const item = toRecord9(event.payload.item);
9985
+ if (readString11(item, "type") !== "function_call") {
9657
9986
  return null;
9658
9987
  }
9659
- const toolName = readString10(item, "name") ?? "tool";
9988
+ const toolName = readString11(item, "name") ?? "tool";
9660
9989
  const argumentsValue = parseJsonValue(item.arguments) ?? item.arguments;
9661
9990
  return {
9662
9991
  ...event,
@@ -9666,16 +9995,16 @@ function normalizeResponseOutputItemAdded(event) {
9666
9995
  tool: toolName,
9667
9996
  tool_name: toolName,
9668
9997
  name: toolName,
9669
- tool_call_id: readString10(item, "call_id") ?? readString10(item, "id"),
9998
+ tool_call_id: readString11(item, "call_id") ?? readString11(item, "id"),
9670
9999
  arguments: argumentsValue,
9671
10000
  preview: toolName,
9672
- response_item_id: readString10(item, "id") ?? void 0
10001
+ response_item_id: readString11(item, "id") ?? void 0
9673
10002
  }
9674
10003
  };
9675
10004
  }
9676
10005
  function normalizeResponseOutputItemDone(event) {
9677
- const item = toRecord8(event.payload.item);
9678
- if (readString10(item, "type") !== "function_call_output") {
10006
+ const item = toRecord9(event.payload.item);
10007
+ if (readString11(item, "type") !== "function_call_output") {
9679
10008
  return null;
9680
10009
  }
9681
10010
  const output = readResponseItemOutput(item.output);
@@ -9685,41 +10014,41 @@ function normalizeResponseOutputItemDone(event) {
9685
10014
  payloadType: "tool.completed",
9686
10015
  payload: {
9687
10016
  type: "tool.completed",
9688
- tool_call_id: readString10(item, "call_id") ?? readString10(item, "id"),
9689
- status: readString10(item, "status") ?? "completed",
10017
+ tool_call_id: readString11(item, "call_id") ?? readString11(item, "id"),
10018
+ status: readString11(item, "status") ?? "completed",
9690
10019
  output,
9691
10020
  content: output,
9692
10021
  result: parsedOutput ?? output,
9693
- response_item_id: readString10(item, "id") ?? void 0
10022
+ response_item_id: readString11(item, "id") ?? void 0
9694
10023
  }
9695
10024
  };
9696
10025
  }
9697
10026
  function normalizeResponseCompleted(event) {
9698
- const response = toRecord8(event.payload.response);
10027
+ const response = toRecord9(event.payload.response);
9699
10028
  return {
9700
10029
  ...event,
9701
10030
  payloadType: "run.completed",
9702
10031
  payload: {
9703
10032
  type: "run.completed",
9704
- response_id: readString10(response, "id") ?? readString10(event.payload, "id"),
9705
- usage: toRecord8(response.usage),
10033
+ response_id: readString11(response, "id") ?? readString11(event.payload, "id"),
10034
+ usage: toRecord9(response.usage),
9706
10035
  response
9707
10036
  }
9708
10037
  };
9709
10038
  }
9710
10039
  function normalizeResponseFailed(event) {
9711
- const response = toRecord8(event.payload.response);
9712
- const error = toRecord8(response.error);
10040
+ const response = toRecord9(event.payload.response);
10041
+ const error = toRecord9(response.error);
9713
10042
  return {
9714
10043
  ...event,
9715
10044
  payloadType: "run.failed",
9716
10045
  payload: {
9717
10046
  type: "run.failed",
9718
- response_id: readString10(response, "id") ?? readString10(event.payload, "id"),
10047
+ response_id: readString11(response, "id") ?? readString11(event.payload, "id"),
9719
10048
  error: {
9720
- message: readString10(error, "message") ?? readString10(event.payload, "message") ?? "Hermes run failed"
10049
+ message: readString11(error, "message") ?? readString11(event.payload, "message") ?? "Hermes run failed"
9721
10050
  },
9722
- usage: toRecord8(response.usage),
10051
+ usage: toRecord9(response.usage),
9723
10052
  response
9724
10053
  }
9725
10054
  };
@@ -9743,8 +10072,8 @@ function readErrorMessage2(payload) {
9743
10072
  if (typeof payload.error === "string" && payload.error.trim()) {
9744
10073
  return payload.error.trim();
9745
10074
  }
9746
- const error = toRecord8(payload.error);
9747
- return readString10(error, "message") ?? readString10(payload, "message");
10075
+ const error = toRecord9(payload.error);
10076
+ return readString11(error, "message") ?? readString11(payload, "message");
9748
10077
  }
9749
10078
  function readDelta(payload) {
9750
10079
  return readText2(payload, "delta") ?? readText2(payload, "text") ?? readText2(payload, "content");
@@ -9779,15 +10108,15 @@ function isTopLevelErrorEvent(event) {
9779
10108
  }
9780
10109
  function readChatCompletionDelta(payload) {
9781
10110
  const choice = readFirstChoice(payload);
9782
- const delta = toRecord8(choice.delta);
10111
+ const delta = toRecord9(choice.delta);
9783
10112
  return readText2(delta, "content");
9784
10113
  }
9785
10114
  function readChatCompletionFinishReason(payload) {
9786
10115
  const choice = readFirstChoice(payload);
9787
- return readString10(choice, "finish_reason") ?? readString10(choice, "finishReason");
10116
+ return readString11(choice, "finish_reason") ?? readString11(choice, "finishReason");
9788
10117
  }
9789
10118
  function readChatCompletionUsage(payload) {
9790
- const usage = toRecord8(payload.usage);
10119
+ const usage = toRecord9(payload.usage);
9791
10120
  const input = readInteger2(usage, "prompt_tokens") ?? readInteger2(usage, "input_tokens");
9792
10121
  const output = readInteger2(usage, "completion_tokens") ?? readInteger2(usage, "output_tokens");
9793
10122
  const total = readInteger2(usage, "total_tokens");
@@ -9815,7 +10144,7 @@ function readFirstChoice(payload) {
9815
10144
  if (!Array.isArray(choices)) {
9816
10145
  return {};
9817
10146
  }
9818
- return toRecord8(choices[0]);
10147
+ return toRecord9(choices[0]);
9819
10148
  }
9820
10149
  function readInteger2(payload, key) {
9821
10150
  const value = payload[key];
@@ -9828,7 +10157,7 @@ function readInteger2(payload, key) {
9828
10157
  }
9829
10158
  return void 0;
9830
10159
  }
9831
- function readString10(payload, key) {
10160
+ function readString11(payload, key) {
9832
10161
  const value = payload[key];
9833
10162
  return typeof value === "string" && value.trim() ? value.trim() : null;
9834
10163
  }
@@ -9843,7 +10172,7 @@ function readResponseItemOutput(value) {
9843
10172
  if (!Array.isArray(value)) {
9844
10173
  return stringifyJsonValue(value);
9845
10174
  }
9846
- const text = value.map(toRecord8).map((part) => readText2(part, "text") ?? readText2(part, "content") ?? "").join("");
10175
+ const text = value.map(toRecord9).map((part) => readText2(part, "text") ?? readText2(part, "content") ?? "").join("");
9847
10176
  return text || stringifyJsonValue(value);
9848
10177
  }
9849
10178
  function parseJsonValue(value) {
@@ -9869,13 +10198,11 @@ function stringifyJsonValue(value) {
9869
10198
  return String(value);
9870
10199
  }
9871
10200
  }
9872
- function toRecord8(value) {
10201
+ function toRecord9(value) {
9873
10202
  return typeof value === "object" && value !== null ? value : {};
9874
10203
  }
9875
10204
 
9876
10205
  // src/conversations/run-lifecycle.ts
9877
- var MAX_IMPORTED_BLOB_BYTES = 100 * 1024 * 1024;
9878
- var MAX_MEDIA_IMPORT_FAILURES = 20;
9879
10206
  var ConversationRunLifecycle = class {
9880
10207
  constructor(deps) {
9881
10208
  this.deps = deps;
@@ -10357,8 +10684,8 @@ ${details.join("\n")}` : emptyHermesResponseMessage();
10357
10684
  }
10358
10685
  const textPart = assistant.parts.find((part) => part.type === "text");
10359
10686
  const currentText = textPart?.text ?? "";
10360
- const pendingDeliveryText = readString11(
10361
- toRecord9(assistant.hermes),
10687
+ const pendingDeliveryText = readString12(
10688
+ toRecord10(assistant.hermes),
10362
10689
  "pending_media_delivery_text"
10363
10690
  );
10364
10691
  const normalizedDelta = normalizeStreamingTextDelta(
@@ -10373,7 +10700,7 @@ ${details.join("\n")}` : emptyHermesResponseMessage();
10373
10700
  pendingDeliveryText ?? ""
10374
10701
  );
10375
10702
  const nextHermes = {
10376
- ...toRecord9(assistant.hermes),
10703
+ ...toRecord10(assistant.hermes),
10377
10704
  ...extracted.pendingText ? { pending_media_delivery_text: extracted.pendingText } : {}
10378
10705
  };
10379
10706
  if (!extracted.pendingText) {
@@ -10626,119 +10953,11 @@ ${details.join("\n")}` : emptyHermesResponseMessage();
10626
10953
  return snapshot?.runs.find((item) => item.id === runId)?.assistant_message_id;
10627
10954
  }
10628
10955
  async importMediaReferences(conversationId, runId, messageId, references) {
10629
- if (references.length === 0) {
10630
- return;
10631
- }
10632
- const snapshot = await this.deps.readSnapshot(conversationId);
10633
- const assistant = snapshot.messages.find(
10634
- (message) => message.id === messageId
10635
- );
10636
- if (!assistant) {
10637
- return;
10638
- }
10639
- const importedSourceKeys = readImportedMediaSourceKeys(assistant);
10640
- const failedSourceKeys = readFailedMediaSourceKeys(assistant);
10641
- const failureRecordsByKey = new Map(
10642
- readMediaImportFailures(assistant).map((failure) => [
10643
- failure.key,
10644
- failure
10645
- ])
10646
- );
10647
- const importedParts = [];
10648
- const newFailures = [];
10649
- for (const reference of references.slice(0, 10)) {
10650
- let sourceKey;
10651
- try {
10652
- sourceKey = mediaSourceKey(reference.path);
10653
- if (importedSourceKeys.has(sourceKey) || failedSourceKeys.has(sourceKey)) {
10654
- continue;
10655
- }
10656
- const blob = await this.writeBlobFromFile(conversationId, reference);
10657
- const part = {
10658
- type: reference.kind ?? mediaKindForMime(blob.mime),
10659
- blob: blob.id,
10660
- mime: blob.mime,
10661
- size: blob.size,
10662
- filename: blob.filename,
10663
- url: `/api/v1/conversations/${encodeURIComponent(conversationId)}/blobs/${encodeURIComponent(blob.id)}`
10664
- };
10665
- assistant.parts.push(part);
10666
- assistant.attachments.push({
10667
- blob_id: blob.id,
10668
- mime: blob.mime,
10669
- size: blob.size,
10670
- filename: blob.filename,
10671
- source: "hermes_output"
10672
- });
10673
- importedSourceKeys.add(sourceKey);
10674
- importedParts.push(part);
10675
- } catch (error) {
10676
- if (sourceKey && !failedSourceKeys.has(sourceKey)) {
10677
- const failure = describeMediaImportFailure(reference, sourceKey, error);
10678
- failedSourceKeys.add(sourceKey);
10679
- failureRecordsByKey.set(sourceKey, failure);
10680
- newFailures.push(failure);
10681
- }
10682
- void this.deps.logger.warn("conversation_media_import_failed", {
10683
- conversation_id: conversationId,
10684
- run_id: runId,
10685
- message_id: messageId,
10686
- error: error instanceof Error ? error.message : String(error)
10687
- });
10688
- }
10689
- }
10690
- if (importedParts.length === 0 && newFailures.length === 0) {
10691
- return;
10692
- }
10693
- assistant.hermes = {
10694
- ...toRecord9(assistant.hermes),
10695
- imported_media_source_keys: [...importedSourceKeys],
10696
- media_import_failed_source_keys: [...failedSourceKeys],
10697
- media_import_failures: [...failureRecordsByKey.values()].slice(
10698
- -MAX_MEDIA_IMPORT_FAILURES
10699
- )
10700
- };
10701
- assistant.updated_at = (/* @__PURE__ */ new Date()).toISOString();
10702
- await this.deps.writeSnapshot(conversationId, snapshot);
10703
- if (importedParts.length > 0) {
10704
- await this.deps.appendEvent(conversationId, {
10705
- type: "message.parts.created",
10706
- message_id: messageId,
10707
- run_id: runId,
10708
- payload: { parts: importedParts }
10709
- });
10710
- }
10711
- }
10712
- async writeBlobFromFile(conversationId, source) {
10713
- const sourcePath = resolveMediaSourcePath(source.path);
10714
- const fileStat = await stat9(sourcePath).catch((error) => {
10715
- if (isNodeError10(error, "ENOENT")) {
10716
- throw new LinkHttpError(
10717
- 404,
10718
- "media_source_not_found",
10719
- "Hermes output file was not found"
10720
- );
10721
- }
10722
- throw error;
10723
- });
10724
- if (!fileStat.isFile()) {
10725
- throw new LinkHttpError(
10726
- 400,
10727
- "media_source_not_file",
10728
- "Hermes output media source is not a file"
10729
- );
10730
- }
10731
- if (fileStat.size > MAX_IMPORTED_BLOB_BYTES) {
10732
- throw new LinkHttpError(
10733
- 413,
10734
- "media_source_too_large",
10735
- "Hermes output media source is too large"
10736
- );
10737
- }
10738
- return this.deps.writeBlob(conversationId, {
10739
- bytes: await readFile10(sourcePath),
10740
- filename: path15.basename(sourcePath),
10741
- mime: source.mime ?? inferMimeType(sourcePath)
10956
+ await importMediaReferencesForMessage(this.deps, {
10957
+ conversationId,
10958
+ runId,
10959
+ messageId,
10960
+ references
10742
10961
  });
10743
10962
  }
10744
10963
  async readHermesCronJobIds(profileName) {
@@ -10748,7 +10967,7 @@ ${details.join("\n")}` : emptyHermesResponseMessage();
10748
10967
  includeDisabled: true
10749
10968
  });
10750
10969
  return new Set(
10751
- jobs.map((job) => readString11(job, "id") ?? readString11(job, "job_id")).filter((id) => Boolean(id))
10970
+ jobs.map((job) => readString12(job, "id") ?? readString12(job, "job_id")).filter((id) => Boolean(id))
10752
10971
  );
10753
10972
  }
10754
10973
  async bindNewCronJobsCreatedByRun(input) {
@@ -10773,7 +10992,8 @@ function buildRunInstructions(run, deliveryStagingDir) {
10773
10992
  "",
10774
10993
  "Delivery staging directory for this run:",
10775
10994
  `- ${deliveryStagingDir}`,
10776
- "Before final delivery markers, copy each deliverable file into this directory and reference the staged copy path in <hermes_link_delivery>."
10995
+ "Copy every deliverable file into this directory, then run:",
10996
+ `hermeslink deliver ${quoteShellArg(deliveryStagingDir)}`
10777
10997
  ] : [],
10778
10998
  "",
10779
10999
  "Current runtime selected by Hermes Link:",
@@ -10782,52 +11002,8 @@ function buildRunInstructions(run, deliveryStagingDir) {
10782
11002
  "If the user asks what model or provider you are currently using, answer from this runtime selection instead of inferring from earlier conversation history."
10783
11003
  ].join("\n");
10784
11004
  }
10785
- function readFailedMediaSourceKeys(message) {
10786
- const hermes = toRecord9(message.hermes);
10787
- const keys = hermes.media_import_failed_source_keys;
10788
- if (!Array.isArray(keys)) {
10789
- return /* @__PURE__ */ new Set();
10790
- }
10791
- return new Set(
10792
- keys.filter(
10793
- (key) => typeof key === "string" && key.length > 0
10794
- )
10795
- );
10796
- }
10797
- function readMediaImportFailures(message) {
10798
- const hermes = toRecord9(message.hermes);
10799
- const failures = hermes.media_import_failures;
10800
- if (!Array.isArray(failures)) {
10801
- return [];
10802
- }
10803
- return failures.flatMap((item) => {
10804
- const record = toRecord9(item);
10805
- const key = readString11(record, "key");
10806
- const filename = readString11(record, "filename");
10807
- const reason = readString11(record, "reason");
10808
- if (!key || !filename || !reason) {
10809
- return [];
10810
- }
10811
- return [
10812
- {
10813
- key,
10814
- filename,
10815
- reason,
10816
- ...readString11(record, "code") ? { code: readString11(record, "code") } : {}
10817
- }
10818
- ];
10819
- });
10820
- }
10821
- function describeMediaImportFailure(reference, sourceKey, error) {
10822
- return {
10823
- key: sourceKey,
10824
- filename: sanitizeFilename(reference.path, "attachment"),
10825
- reason: error instanceof Error ? error.message : String(error),
10826
- ...isNodeError10(error) && error.code ? { code: error.code } : {}
10827
- };
10828
- }
10829
11005
  function appendMediaImportFailureNotice(message) {
10830
- const hermes = toRecord9(message.hermes);
11006
+ const hermes = toRecord10(message.hermes);
10831
11007
  if (hermes.media_import_failure_notice_appended === true) {
10832
11008
  return;
10833
11009
  }
@@ -10849,6 +11025,9 @@ function appendMediaImportFailureNotice(message) {
10849
11025
  media_import_failure_notice_appended: true
10850
11026
  };
10851
11027
  }
11028
+ function quoteShellArg(value) {
11029
+ return `'${value.replaceAll("'", "'\\''")}'`;
11030
+ }
10852
11031
  function formatMediaImportFailureNotice(failures) {
10853
11032
  const filenames = failures.map((failure) => failure.filename);
10854
11033
  const target = filenames.length === 1 ? `\u6587\u4EF6\u201C${filenames[0]}\u201D` : `${filenames.length} \u4E2A\u6587\u4EF6\uFF08${formatFilenameList(filenames)}\uFF09`;
@@ -10867,18 +11046,18 @@ function formatFilenameList(filenames) {
10867
11046
  return remaining > 0 ? `${preview.join("\u3001")} \u7B49 ${filenames.length} \u4E2A` : preview.join("\u3001");
10868
11047
  }
10869
11048
  async function readdirWithDirs(directory) {
10870
- return readdir5(directory, { withFileTypes: true }).catch((error) => {
10871
- if (isNodeError10(error, "ENOENT")) {
11049
+ return readdir6(directory, { withFileTypes: true }).catch((error) => {
11050
+ if (isNodeError11(error, "ENOENT")) {
10872
11051
  return [];
10873
11052
  }
10874
11053
  throw error;
10875
11054
  });
10876
11055
  }
10877
- function readString11(payload, key) {
11056
+ function readString12(payload, key) {
10878
11057
  const value = payload[key];
10879
11058
  return typeof value === "string" && value.trim() ? value.trim() : null;
10880
11059
  }
10881
- function toRecord9(value) {
11060
+ function toRecord10(value) {
10882
11061
  return typeof value === "object" && value !== null ? value : {};
10883
11062
  }
10884
11063
  function formatFailureMessage(message, detail) {
@@ -10894,17 +11073,17 @@ function isFileSearchCompletion(payloadType, payload) {
10894
11073
  if (payloadType !== "tool.completed") {
10895
11074
  return false;
10896
11075
  }
10897
- const tool = toRecord9(payload.tool);
10898
- const toolCall = toRecord9(payload.tool_call ?? payload.toolCall);
10899
- const fn = toRecord9(toolCall.function ?? payload.function);
11076
+ const tool = toRecord10(payload.tool);
11077
+ const toolCall = toRecord10(payload.tool_call ?? payload.toolCall);
11078
+ const fn = toRecord10(toolCall.function ?? payload.function);
10900
11079
  const candidates = [
10901
- readString11(payload, "tool_name"),
10902
- readString11(payload, "toolName"),
10903
- readString11(payload, "name"),
10904
- readString11(payload, "tool"),
10905
- readString11(tool, "name"),
10906
- readString11(toolCall, "name"),
10907
- readString11(fn, "name")
11080
+ readString12(payload, "tool_name"),
11081
+ readString12(payload, "toolName"),
11082
+ readString12(payload, "name"),
11083
+ readString12(payload, "tool"),
11084
+ readString12(tool, "name"),
11085
+ readString12(toolCall, "name"),
11086
+ readString12(fn, "name")
10908
11087
  ].filter((value) => Boolean(value)).map(normalizeToolName);
10909
11088
  return candidates.some(
10910
11089
  (name) => [
@@ -11059,10 +11238,10 @@ function readResponseId(payload) {
11059
11238
  if (!payload) {
11060
11239
  return null;
11061
11240
  }
11062
- const response = toRecord9(payload.response);
11063
- return readString11(payload, "response_id") ?? readString11(response, "id");
11241
+ const response = toRecord10(payload.response);
11242
+ return readString12(payload, "response_id") ?? readString12(response, "id");
11064
11243
  }
11065
- function isNodeError10(error, code) {
11244
+ function isNodeError11(error, code) {
11066
11245
  if (typeof error !== "object" || error === null || !("code" in error)) {
11067
11246
  return false;
11068
11247
  }
@@ -11342,6 +11521,42 @@ var ConversationService = class {
11342
11521
  async syncCronDeliveries() {
11343
11522
  await syncHermesLinkCronDeliveries(this.paths, this, this.logger);
11344
11523
  }
11524
+ async deliverStagedFiles(stagingDir) {
11525
+ const target = resolveDeliveryStagingTarget(this.paths, stagingDir);
11526
+ return this.withConversationLock(target.conversationId, async () => {
11527
+ await this.store.readActiveManifest(target.conversationId);
11528
+ const snapshot = await this.store.readSnapshot(target.conversationId);
11529
+ const run = snapshot.runs.find((item) => item.id === target.runId);
11530
+ if (!run) {
11531
+ throw new LinkHttpError(404, "run_not_found", "Run was not found");
11532
+ }
11533
+ const assistant = snapshot.messages.find(
11534
+ (message) => message.id === run.assistant_message_id
11535
+ );
11536
+ if (!assistant) {
11537
+ throw new LinkHttpError(
11538
+ 404,
11539
+ "assistant_message_not_found",
11540
+ "Assistant message was not found"
11541
+ );
11542
+ }
11543
+ return importMediaReferencesForMessage(
11544
+ {
11545
+ logger: this.logger,
11546
+ readSnapshot: (conversationId) => this.store.readSnapshot(conversationId),
11547
+ writeSnapshot: (conversationId, nextSnapshot) => this.store.writeSnapshot(conversationId, nextSnapshot),
11548
+ appendEvent: (conversationId, input) => this.appendEvent(conversationId, input),
11549
+ writeBlob: (conversationId, input) => this.maintenance.writeBlob(conversationId, input)
11550
+ },
11551
+ {
11552
+ conversationId: target.conversationId,
11553
+ runId: target.runId,
11554
+ messageId: assistant.id,
11555
+ references: await collectStagedDeliveryReferences(target.stagingDir)
11556
+ }
11557
+ );
11558
+ });
11559
+ }
11345
11560
  async getMessages(conversationId, options = {}) {
11346
11561
  return this.queries.getMessages(conversationId, options);
11347
11562
  }
@@ -12363,12 +12578,12 @@ async function readRawBody(request, maxBytes) {
12363
12578
  }
12364
12579
  return Buffer.concat(chunks);
12365
12580
  }
12366
- function readString12(body, key) {
12581
+ function readString13(body, key) {
12367
12582
  const value = body[key];
12368
12583
  return typeof value === "string" && value.trim() ? value.trim() : null;
12369
12584
  }
12370
12585
  function readOptionalProfileName(body) {
12371
- return readString12(body, "profile") ?? readString12(body, "profile_name") ?? readString12(body, "profileName") ?? void 0;
12586
+ return readString13(body, "profile") ?? readString13(body, "profile_name") ?? readString13(body, "profileName") ?? void 0;
12372
12587
  }
12373
12588
  function readStringArray(body, ...keys) {
12374
12589
  for (const key of keys) {
@@ -12601,7 +12816,7 @@ function registerConversationRoutes(router, options) {
12601
12816
  ctx.body = {
12602
12817
  ok: true,
12603
12818
  conversation: await conversations.createConversation({
12604
- title: readString12(body, "title") ?? void 0,
12819
+ title: readString13(body, "title") ?? void 0,
12605
12820
  profileName: readOptionalProfileName(body)
12606
12821
  })
12607
12822
  };
@@ -12672,7 +12887,7 @@ function registerConversationRoutes(router, options) {
12672
12887
  router.post("/api/v1/conversations/:conversationId/messages", async (ctx) => {
12673
12888
  await authenticateRequest(ctx, paths);
12674
12889
  const body = await readJsonBody(ctx.req);
12675
- const content = readString12(body, "content") ?? readString12(body, "text") ?? readString12(body, "input") ?? "";
12890
+ const content = readString13(body, "content") ?? readString13(body, "text") ?? readString13(body, "input") ?? "";
12676
12891
  const attachments = readMessageAttachments(body.attachments ?? body.blobs);
12677
12892
  if (!content && attachments.length === 0) {
12678
12893
  throw new LinkHttpError(
@@ -12688,7 +12903,7 @@ function registerConversationRoutes(router, options) {
12688
12903
  conversationId: ctx.params.conversationId,
12689
12904
  content,
12690
12905
  attachments,
12691
- clientMessageId: readString12(body, "client_message_id") ?? readString12(body, "clientMessageId") ?? void 0,
12906
+ clientMessageId: readString13(body, "client_message_id") ?? readString13(body, "clientMessageId") ?? void 0,
12692
12907
  idempotencyKey: readHeader(ctx, "idempotency-key") ?? void 0,
12693
12908
  profileName: readOptionalProfileName(body)
12694
12909
  })
@@ -12697,7 +12912,7 @@ function registerConversationRoutes(router, options) {
12697
12912
  router.patch("/api/v1/conversations/:conversationId/model", async (ctx) => {
12698
12913
  await authenticateRequest(ctx, paths);
12699
12914
  const body = await readJsonBody(ctx.req);
12700
- const modelId = readString12(body, "model_id") ?? readString12(body, "modelId") ?? readString12(body, "model");
12915
+ const modelId = readString13(body, "model_id") ?? readString13(body, "modelId") ?? readString13(body, "model");
12701
12916
  if (!modelId) {
12702
12917
  throw new LinkHttpError(400, "model_id_required", "model_id is required");
12703
12918
  }
@@ -12727,7 +12942,7 @@ function registerConversationRoutes(router, options) {
12727
12942
  router.patch("/api/v1/conversations/:conversationId/title", async (ctx) => {
12728
12943
  await authenticateRequest(ctx, paths);
12729
12944
  const body = await readJsonBody(ctx.req);
12730
- const title = readString12(body, "title") ?? readString12(body, "name") ?? readString12(body, "display_name");
12945
+ const title = readString13(body, "title") ?? readString13(body, "name") ?? readString13(body, "display_name");
12731
12946
  if (!title) {
12732
12947
  throw new LinkHttpError(400, "title_required", "title is required");
12733
12948
  }
@@ -12791,7 +13006,7 @@ function registerConversationRoutes(router, options) {
12791
13006
  async (ctx) => {
12792
13007
  await authenticateRequest(ctx, paths);
12793
13008
  const body = await readJsonBody(ctx.req);
12794
- const scope = readString12(body, "scope") ?? "always";
13009
+ const scope = readString13(body, "scope") ?? "always";
12795
13010
  ctx.body = {
12796
13011
  ok: true,
12797
13012
  ...await conversations.resolveApproval({
@@ -12951,7 +13166,7 @@ function createHttpErrorMiddleware(logger) {
12951
13166
  }
12952
13167
 
12953
13168
  // src/hermes/profiles.ts
12954
- import { mkdir as mkdir10, readdir as readdir6, readFile as readFile11, rename as rename4, rm as rm6, stat as stat10 } from "fs/promises";
13169
+ import { mkdir as mkdir10, readdir as readdir7, readFile as readFile11, rename as rename4, rm as rm6, stat as stat10 } from "fs/promises";
12955
13170
  import os4 from "os";
12956
13171
  import path16 from "path";
12957
13172
  import YAML2 from "yaml";
@@ -12961,9 +13176,9 @@ async function listHermesProfiles(paths = resolveRuntimePaths()) {
12961
13176
  const profiles = /* @__PURE__ */ new Map();
12962
13177
  profiles.set(DEFAULT_PROFILE, await profileInfo(DEFAULT_PROFILE, paths));
12963
13178
  const profilesDir = path16.join(os4.homedir(), ".hermes", "profiles");
12964
- const entries = await readdir6(profilesDir, { withFileTypes: true }).catch(
13179
+ const entries = await readdir7(profilesDir, { withFileTypes: true }).catch(
12965
13180
  (error) => {
12966
- if (isNodeError11(error, "ENOENT")) {
13181
+ if (isNodeError12(error, "ENOENT")) {
12967
13182
  return [];
12968
13183
  }
12969
13184
  throw error;
@@ -12988,7 +13203,7 @@ async function getHermesProfileStatus(name, paths = resolveRuntimePaths()) {
12988
13203
  assertProfileName(name);
12989
13204
  const profile = await profileInfo(name, paths);
12990
13205
  const exists = await stat10(profile.path).then((value) => value.isDirectory()).catch((error) => {
12991
- if (isNodeError11(error, "ENOENT")) {
13206
+ if (isNodeError12(error, "ENOENT")) {
12992
13207
  return false;
12993
13208
  }
12994
13209
  throw error;
@@ -13029,7 +13244,7 @@ async function deleteHermesProfile(name, paths = resolveRuntimePaths()) {
13029
13244
  assertMutableProfile(name);
13030
13245
  const profile = await profileInfo(name, paths);
13031
13246
  const exists = await stat10(profile.path).then((value) => value.isDirectory()).catch((error) => {
13032
- if (isNodeError11(error, "ENOENT")) {
13247
+ if (isNodeError12(error, "ENOENT")) {
13033
13248
  return false;
13034
13249
  }
13035
13250
  throw error;
@@ -13097,13 +13312,13 @@ function assertProfileName(name) {
13097
13312
  throw new LinkHttpError(400, "invalid_profile_name", "invalid profile name");
13098
13313
  }
13099
13314
  }
13100
- function isNodeError11(error, code) {
13315
+ function isNodeError12(error, code) {
13101
13316
  return typeof error === "object" && error !== null && "code" in error && error.code === code;
13102
13317
  }
13103
13318
  async function countSkills(root) {
13104
- const entries = await readdir6(root, { withFileTypes: true }).catch(
13319
+ const entries = await readdir7(root, { withFileTypes: true }).catch(
13105
13320
  (error) => {
13106
- if (isNodeError11(error, "ENOENT")) {
13321
+ if (isNodeError12(error, "ENOENT")) {
13107
13322
  return [];
13108
13323
  }
13109
13324
  throw error;
@@ -13130,7 +13345,7 @@ async function countConfiguredTools(profileName) {
13130
13345
  resolveHermesConfigPath(profileName),
13131
13346
  "utf8"
13132
13347
  ).catch((error) => {
13133
- if (isNodeError11(error, "ENOENT")) {
13348
+ if (isNodeError12(error, "ENOENT")) {
13134
13349
  return "";
13135
13350
  }
13136
13351
  throw error;
@@ -13138,14 +13353,14 @@ async function countConfiguredTools(profileName) {
13138
13353
  if (!raw.trim()) {
13139
13354
  return 0;
13140
13355
  }
13141
- const config = toRecord10(YAML2.parse(raw));
13356
+ const config = toRecord11(YAML2.parse(raw));
13142
13357
  const toolsets = /* @__PURE__ */ new Set();
13143
13358
  collectToolsetValues(config.toolsets, toolsets);
13144
- const platformToolsets = toRecord10(config.platform_toolsets);
13359
+ const platformToolsets = toRecord11(config.platform_toolsets);
13145
13360
  for (const value of Object.values(platformToolsets)) {
13146
13361
  collectToolsetValues(value, toolsets);
13147
13362
  }
13148
- const mcpServers = Object.keys(toRecord10(config.mcp_servers)).length;
13363
+ const mcpServers = Object.keys(toRecord11(config.mcp_servers)).length;
13149
13364
  return toolsets.size + mcpServers;
13150
13365
  }
13151
13366
  function collectToolsetValues(value, target) {
@@ -13159,7 +13374,7 @@ function collectToolsetValues(value, target) {
13159
13374
  target.add(value.trim());
13160
13375
  }
13161
13376
  }
13162
- function toRecord10(value) {
13377
+ function toRecord11(value) {
13163
13378
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
13164
13379
  }
13165
13380
 
@@ -13356,7 +13571,7 @@ function toHermesCronJobInput(input) {
13356
13571
  };
13357
13572
  }
13358
13573
  async function bindAndDecorateCronJobForHermesLink(input) {
13359
- const jobId = readString12(input.job, "id") ?? readString12(input.job, "job_id");
13574
+ const jobId = readString13(input.job, "id") ?? readString13(input.job, "job_id");
13360
13575
  if (!jobId) {
13361
13576
  return input.job;
13362
13577
  }
@@ -13373,9 +13588,9 @@ async function bindAndDecorateCronJobForHermesLink(input) {
13373
13588
  }
13374
13589
  function readCronJobCreateInput(body) {
13375
13590
  const input = {};
13376
- const name = readString12(body, "name") ?? readString12(body, "title");
13377
- const prompt = readString12(body, "prompt") ?? readString12(body, "description") ?? readString12(body, "task");
13378
- const schedule = readString12(body, "schedule");
13591
+ const name = readString13(body, "name") ?? readString13(body, "title");
13592
+ const prompt = readString13(body, "prompt") ?? readString13(body, "description") ?? readString13(body, "task");
13593
+ const schedule = readString13(body, "schedule");
13379
13594
  if (!name) {
13380
13595
  throw new LinkHttpError(400, "cron_job_name_required", "name is required");
13381
13596
  }
@@ -13396,7 +13611,7 @@ function readCronJobCreateInput(body) {
13396
13611
  input.name = name;
13397
13612
  input.prompt = prompt;
13398
13613
  input.schedule = schedule;
13399
- input.deliver = readString12(body, "deliver") ?? HERMES_LINK_CRON_DELIVER;
13614
+ input.deliver = readString13(body, "deliver") ?? HERMES_LINK_CRON_DELIVER;
13400
13615
  const skills = readOptionalCronSkills(body);
13401
13616
  if (skills) {
13402
13617
  input.skills = skills;
@@ -13624,7 +13839,7 @@ function registerModelConfigRoutes(router, options) {
13624
13839
  router.delete("/api/v1/model-configs", async (ctx) => {
13625
13840
  await authenticateRequest(ctx, paths);
13626
13841
  const body = await readJsonBody(ctx.req);
13627
- const modelId = readString12(body, "model_id") ?? readString12(body, "modelId");
13842
+ const modelId = readString13(body, "model_id") ?? readString13(body, "modelId");
13628
13843
  if (!modelId) {
13629
13844
  throw new LinkHttpError(400, "model_id_required", "model_id is required");
13630
13845
  }
@@ -13679,7 +13894,7 @@ function registerModelConfigRoutes(router, options) {
13679
13894
  await authenticateRequest(ctx, paths);
13680
13895
  await getHermesProfileStatus(ctx.params.name, paths);
13681
13896
  const body = await readJsonBody(ctx.req);
13682
- const modelId = readString12(body, "model_id") ?? readString12(body, "modelId");
13897
+ const modelId = readString13(body, "model_id") ?? readString13(body, "modelId");
13683
13898
  if (!modelId) {
13684
13899
  throw new LinkHttpError(400, "model_id_required", "model_id is required");
13685
13900
  }
@@ -13696,9 +13911,9 @@ function registerModelConfigRoutes(router, options) {
13696
13911
  });
13697
13912
  }
13698
13913
  function readModelConfigInput(body) {
13699
- const id = readString12(body, "id") ?? readString12(body, "model_id") ?? readString12(body, "modelId");
13700
- const provider = readString12(body, "provider") ?? readString12(body, "provider_key") ?? readString12(body, "providerKey");
13701
- const baseUrl = readString12(body, "base_url") ?? readString12(body, "baseUrl");
13914
+ const id = readString13(body, "id") ?? readString13(body, "model_id") ?? readString13(body, "modelId");
13915
+ const provider = readString13(body, "provider") ?? readString13(body, "provider_key") ?? readString13(body, "providerKey");
13916
+ const baseUrl = readString13(body, "base_url") ?? readString13(body, "baseUrl");
13702
13917
  if (!id || !provider || !baseUrl) {
13703
13918
  throw new LinkHttpError(
13704
13919
  400,
@@ -13708,24 +13923,24 @@ function readModelConfigInput(body) {
13708
13923
  }
13709
13924
  return {
13710
13925
  id,
13711
- originalModelId: readString12(body, "original_model_id") ?? readString12(body, "originalModelId") ?? readString12(body, "original_id") ?? void 0,
13926
+ originalModelId: readString13(body, "original_model_id") ?? readString13(body, "originalModelId") ?? readString13(body, "original_id") ?? void 0,
13712
13927
  provider,
13713
- providerName: readString12(body, "provider_name") ?? readString12(body, "providerName") ?? void 0,
13928
+ providerName: readString13(body, "provider_name") ?? readString13(body, "providerName") ?? void 0,
13714
13929
  baseUrl,
13715
- apiKey: readString12(body, "api_key") ?? readString12(body, "apiKey") ?? void 0,
13716
- apiMode: readString12(body, "api_mode") ?? readString12(body, "apiMode") ?? void 0,
13930
+ apiKey: readString13(body, "api_key") ?? readString13(body, "apiKey") ?? void 0,
13931
+ apiMode: readString13(body, "api_mode") ?? readString13(body, "apiMode") ?? void 0,
13717
13932
  contextLength: readPositiveInteger2(
13718
13933
  body.context_length ?? body.contextLength
13719
13934
  ),
13720
- keyEnv: readString12(body, "key_env") ?? readString12(body, "keyEnv") ?? void 0,
13935
+ keyEnv: readString13(body, "key_env") ?? readString13(body, "keyEnv") ?? void 0,
13721
13936
  setDefault: readBoolean(body.set_default ?? body.setDefault),
13722
- reasoningEffort: readString12(body, "reasoning_effort") ?? readString12(body, "reasoningEffort") ?? void 0
13937
+ reasoningEffort: readString13(body, "reasoning_effort") ?? readString13(body, "reasoningEffort") ?? void 0
13723
13938
  };
13724
13939
  }
13725
13940
  function readModelDefaultsInput(body) {
13726
13941
  return {
13727
- taskModelId: readString12(body, "task_model_id") ?? readString12(body, "taskModelId") ?? readString12(body, "default_model_id") ?? readString12(body, "defaultModelId") ?? void 0,
13728
- compressionModelId: readString12(body, "compression_model_id") ?? readString12(body, "compressionModelId") ?? void 0
13942
+ taskModelId: readString13(body, "task_model_id") ?? readString13(body, "taskModelId") ?? readString13(body, "default_model_id") ?? readString13(body, "defaultModelId") ?? void 0,
13943
+ compressionModelId: readString13(body, "compression_model_id") ?? readString13(body, "compressionModelId") ?? void 0
13729
13944
  };
13730
13945
  }
13731
13946
  function shouldReloadGatewayAfterModelConfigChange(body) {
@@ -14206,7 +14421,7 @@ function copyModelConfig(source, target) {
14206
14421
  copied[key] = cloneJson(source[key]);
14207
14422
  }
14208
14423
  }
14209
- const sourceAuxiliary = toRecord11(source.auxiliary);
14424
+ const sourceAuxiliary = toRecord12(source.auxiliary);
14210
14425
  if (Object.prototype.hasOwnProperty.call(sourceAuxiliary, "compression")) {
14211
14426
  const targetAuxiliary = ensureRecord2(target, "auxiliary");
14212
14427
  targetAuxiliary.compression = cloneJson(sourceAuxiliary.compression);
@@ -14215,12 +14430,12 @@ function copyModelConfig(source, target) {
14215
14430
  return copied;
14216
14431
  }
14217
14432
  function copyToolPermissionsConfig(source, target) {
14218
- const sourcePlatformToolsets = toRecord11(source.platform_toolsets);
14433
+ const sourcePlatformToolsets = toRecord12(source.platform_toolsets);
14219
14434
  if (Object.prototype.hasOwnProperty.call(sourcePlatformToolsets, "api_server")) {
14220
14435
  const targetPlatformToolsets = ensureRecord2(target, "platform_toolsets");
14221
14436
  targetPlatformToolsets.api_server = cloneJson(sourcePlatformToolsets.api_server);
14222
14437
  }
14223
- const sourceStt = toRecord11(source.stt);
14438
+ const sourceStt = toRecord12(source.stt);
14224
14439
  if (Object.prototype.hasOwnProperty.call(sourceStt, "enabled")) {
14225
14440
  const targetStt = ensureRecord2(target, "stt");
14226
14441
  targetStt.enabled = cloneJson(sourceStt.enabled);
@@ -14269,7 +14484,7 @@ function collectEnvKeys(value, keys = /* @__PURE__ */ new Set()) {
14269
14484
  async function writeEnvValues(profileName, values) {
14270
14485
  const envPath = path17.join(resolveHermesProfileDir(profileName), ".env");
14271
14486
  const existingRaw = await readFile12(envPath, "utf8").catch((error) => {
14272
- if (isNodeError12(error, "ENOENT")) {
14487
+ if (isNodeError13(error, "ENOENT")) {
14273
14488
  return "";
14274
14489
  }
14275
14490
  throw error;
@@ -14325,14 +14540,14 @@ function copyProperty(source, target, key) {
14325
14540
  async function readYamlConfig(configPath) {
14326
14541
  const existingRaw = await readFile12(configPath, "utf8").catch(
14327
14542
  (error) => {
14328
- if (isNodeError12(error, "ENOENT")) {
14543
+ if (isNodeError13(error, "ENOENT")) {
14329
14544
  return null;
14330
14545
  }
14331
14546
  throw error;
14332
14547
  }
14333
14548
  );
14334
14549
  return {
14335
- config: toRecord11(existingRaw ? YAML3.parse(existingRaw) : {}),
14550
+ config: toRecord12(existingRaw ? YAML3.parse(existingRaw) : {}),
14336
14551
  existingRaw
14337
14552
  };
14338
14553
  }
@@ -14411,7 +14626,7 @@ async function clearProfileCreationLogFiles(paths) {
14411
14626
  }
14412
14627
  async function pathExists(targetPath) {
14413
14628
  return await stat11(targetPath).then(() => true).catch((error) => {
14414
- if (isNodeError12(error, "ENOENT")) {
14629
+ if (isNodeError13(error, "ENOENT")) {
14415
14630
  return false;
14416
14631
  }
14417
14632
  throw error;
@@ -14443,7 +14658,7 @@ function ensureRecord2(target, key) {
14443
14658
  target[key] = next;
14444
14659
  return next;
14445
14660
  }
14446
- function toRecord11(value) {
14661
+ function toRecord12(value) {
14447
14662
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
14448
14663
  }
14449
14664
  function cloneJson(value) {
@@ -14458,7 +14673,7 @@ function formatEnvValue2(value) {
14458
14673
  function escapeRegExp2(value) {
14459
14674
  return value.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
14460
14675
  }
14461
- function isNodeError12(error, code) {
14676
+ function isNodeError13(error, code) {
14462
14677
  return typeof error === "object" && error !== null && "code" in error && error.code === code;
14463
14678
  }
14464
14679
 
@@ -14543,16 +14758,16 @@ function readProfilePermissionsInput(body) {
14543
14758
  const approvals = readOptionalObject(body, "approvals");
14544
14759
  if (approvals) {
14545
14760
  input.approvals = {
14546
- mode: readString12(approvals, "mode") ?? readString12(approvals, "approval_mode") ?? readString12(approvals, "approvalMode") ?? void 0,
14761
+ mode: readString13(approvals, "mode") ?? readString13(approvals, "approval_mode") ?? readString13(approvals, "approvalMode") ?? void 0,
14547
14762
  timeout: readPositiveInteger2(approvals.timeout),
14548
- cronMode: readString12(approvals, "cron_mode") ?? readString12(approvals, "cronMode") ?? void 0
14763
+ cronMode: readString13(approvals, "cron_mode") ?? readString13(approvals, "cronMode") ?? void 0
14549
14764
  };
14550
14765
  }
14551
14766
  const terminal = readOptionalObject(body, "terminal");
14552
14767
  if (terminal) {
14553
14768
  input.terminal = {
14554
- backend: readString12(terminal, "backend") ?? void 0,
14555
- cwd: readString12(terminal, "cwd") ?? void 0,
14769
+ backend: readString13(terminal, "backend") ?? void 0,
14770
+ cwd: readString13(terminal, "cwd") ?? void 0,
14556
14771
  containerCpu: readPositiveInteger2(
14557
14772
  terminal.container_cpu ?? terminal.containerCpu
14558
14773
  ),
@@ -14669,7 +14884,7 @@ import {
14669
14884
  access as access3,
14670
14885
  copyFile as copyFile3,
14671
14886
  mkdir as mkdir12,
14672
- readdir as readdir7,
14887
+ readdir as readdir8,
14673
14888
  readFile as readFile13,
14674
14889
  rename as rename6,
14675
14890
  stat as stat12,
@@ -14945,7 +15160,7 @@ async function patchCustomProviderConfig(profileName, provider, patch) {
14945
15160
  "\u81EA\u5B9A\u4E49 memory provider \u914D\u7F6E\u5FC5\u987B\u662F\u6709\u6548\u7684 JSON object\u3002"
14946
15161
  );
14947
15162
  }
14948
- const config = toRecord12(parsed);
15163
+ const config = toRecord13(parsed);
14949
15164
  if (Object.keys(config).length === 0 && parsed !== null) {
14950
15165
  throw new HermesMemoryError(
14951
15166
  "memory_provider_config_invalid",
@@ -15039,15 +15254,15 @@ async function patchHermesMemoryProvider(profileName, provider) {
15039
15254
  const configPath = resolveHermesConfigPath(profileName);
15040
15255
  const existingRaw = await readFile13(configPath, "utf8").catch(
15041
15256
  (error) => {
15042
- if (isNodeError13(error, "ENOENT")) {
15257
+ if (isNodeError14(error, "ENOENT")) {
15043
15258
  return null;
15044
15259
  }
15045
15260
  throw error;
15046
15261
  }
15047
15262
  );
15048
15263
  const document = existingRaw ? YAML4.parseDocument(existingRaw) : new YAML4.Document({});
15049
- const config = toRecord12(document.toJSON());
15050
- const memory = toRecord12(config.memory);
15264
+ const config = toRecord13(document.toJSON());
15265
+ const memory = toRecord13(config.memory);
15051
15266
  memory.provider = provider === "built-in" ? "" : provider;
15052
15267
  config.memory = memory;
15053
15268
  const backupPath = existingRaw ? `${configPath}.bak.${Date.now()}` : null;
@@ -15070,7 +15285,7 @@ async function readMemoryStore(profileName, target, limits) {
15070
15285
  const filePath = memoryFilePath(profileName, target);
15071
15286
  const entries = await readMemoryEntries(filePath);
15072
15287
  const fileStat = await stat12(filePath).catch((error) => {
15073
- if (isNodeError13(error, "ENOENT")) {
15288
+ if (isNodeError14(error, "ENOENT")) {
15074
15289
  return null;
15075
15290
  }
15076
15291
  throw error;
@@ -15099,7 +15314,7 @@ async function readMemoryStore(profileName, target, limits) {
15099
15314
  }
15100
15315
  async function readMemoryEntries(filePath) {
15101
15316
  const raw = await readFile13(filePath, "utf8").catch((error) => {
15102
- if (isNodeError13(error, "ENOENT")) {
15317
+ if (isNodeError14(error, "ENOENT")) {
15103
15318
  return "";
15104
15319
  }
15105
15320
  throw error;
@@ -15270,7 +15485,7 @@ async function readProviderConfigurationStatus(profileName, provider) {
15270
15485
  const config2 = await readJsonObject(
15271
15486
  memoryProviderConfigPath(profileName, "honcho") ?? ""
15272
15487
  );
15273
- return isConfiguredEnvValue(env.HONCHO_API_KEY) || isConfiguredEnvValue(readString13(config2.apiKey)) || isConfiguredEnvValue(readString13(config2.api_key)) || isConfiguredEnvValue(readString13(config2.baseUrl)) ? { configured: true, issue: null } : {
15488
+ return isConfiguredEnvValue(env.HONCHO_API_KEY) || isConfiguredEnvValue(readString14(config2.apiKey)) || isConfiguredEnvValue(readString14(config2.api_key)) || isConfiguredEnvValue(readString14(config2.baseUrl)) ? { configured: true, issue: null } : {
15274
15489
  configured: false,
15275
15490
  issue: "Honcho \u9700\u8981\u5148\u914D\u7F6E HONCHO_API_KEY\uFF0C\u6216\u5728 honcho.json \u914D\u7F6E self-hosted baseUrl\u3002"
15276
15491
  };
@@ -15279,7 +15494,7 @@ async function readProviderConfigurationStatus(profileName, provider) {
15279
15494
  const config2 = await readJsonObject(
15280
15495
  memoryProviderConfigPath(profileName, "mem0") ?? ""
15281
15496
  );
15282
- return isConfiguredEnvValue(env.MEM0_API_KEY) || isConfiguredEnvValue(readString13(config2.api_key)) ? { configured: true, issue: null } : {
15497
+ return isConfiguredEnvValue(env.MEM0_API_KEY) || isConfiguredEnvValue(readString14(config2.api_key)) ? { configured: true, issue: null } : {
15283
15498
  configured: false,
15284
15499
  issue: "Mem0 \u9700\u8981\u5148\u5728\u672C\u673A Hermes .env \u914D\u7F6E MEM0_API_KEY\u3002"
15285
15500
  };
@@ -15321,7 +15536,7 @@ async function readProviderConfigurationStatus(profileName, provider) {
15321
15536
  memoryProviderConfigPath(profileName, provider) ?? ""
15322
15537
  );
15323
15538
  const mode = normalizeHindsightMode(config.mode ?? env.HINDSIGHT_MODE);
15324
- const apiKey = readString13(config.apiKey) ?? readString13(config.api_key) ?? env.HINDSIGHT_API_KEY;
15539
+ const apiKey = readString14(config.apiKey) ?? readString14(config.api_key) ?? env.HINDSIGHT_API_KEY;
15325
15540
  if (mode === "cloud") {
15326
15541
  return isConfiguredEnvValue(apiKey) ? { configured: true, issue: null } : {
15327
15542
  configured: false,
@@ -15329,15 +15544,15 @@ async function readProviderConfigurationStatus(profileName, provider) {
15329
15544
  };
15330
15545
  }
15331
15546
  if (mode === "local_external") {
15332
- const apiUrl = readString13(config.api_url) ?? env.HINDSIGHT_API_URL ?? HINDSIGHT_DEFAULT_LOCAL_URL;
15547
+ const apiUrl = readString14(config.api_url) ?? env.HINDSIGHT_API_URL ?? HINDSIGHT_DEFAULT_LOCAL_URL;
15333
15548
  return isConfiguredEnvValue(apiUrl) ? { configured: true, issue: null } : {
15334
15549
  configured: false,
15335
15550
  issue: "Hindsight local_external \u9700\u8981\u914D\u7F6E\u53EF\u8BBF\u95EE\u7684 API URL\u3002"
15336
15551
  };
15337
15552
  }
15338
15553
  if (mode === "local_embedded") {
15339
- const llmProvider = readString13(config.llm_provider) ?? "openai";
15340
- const llmModel = readString13(config.llm_model);
15554
+ const llmProvider = readString14(config.llm_provider) ?? "openai";
15555
+ const llmModel = readString14(config.llm_model);
15341
15556
  if (!llmModel) {
15342
15557
  return {
15343
15558
  configured: false,
@@ -15345,7 +15560,7 @@ async function readProviderConfigurationStatus(profileName, provider) {
15345
15560
  };
15346
15561
  }
15347
15562
  if (llmProvider === "openai_compatible" && !isConfiguredEnvValue(
15348
- readString13(config.llm_base_url) ?? env.HINDSIGHT_API_LLM_BASE_URL
15563
+ readString14(config.llm_base_url) ?? env.HINDSIGHT_API_LLM_BASE_URL
15349
15564
  )) {
15350
15565
  return {
15351
15566
  configured: false,
@@ -15353,7 +15568,7 @@ async function readProviderConfigurationStatus(profileName, provider) {
15353
15568
  };
15354
15569
  }
15355
15570
  if (!["ollama", "lmstudio", "openai_compatible"].includes(llmProvider) && !isConfiguredEnvValue(
15356
- readString13(config.llmApiKey) ?? readString13(config.llm_api_key) ?? env.HINDSIGHT_LLM_API_KEY
15571
+ readString14(config.llmApiKey) ?? readString14(config.llm_api_key) ?? env.HINDSIGHT_LLM_API_KEY
15357
15572
  )) {
15358
15573
  return {
15359
15574
  configured: false,
@@ -15493,8 +15708,8 @@ async function readProviderSettings(profileName, provider) {
15493
15708
  const config = await readJsonObject(
15494
15709
  memoryProviderConfigPath(profileName, provider) ?? ""
15495
15710
  );
15496
- const banks = toRecord12(config.banks);
15497
- const hermesBank = toRecord12(banks.hermes);
15711
+ const banks = toRecord13(config.banks);
15712
+ const hermesBank = toRecord13(banks.hermes);
15498
15713
  const mode = normalizeHindsightMode(config.mode);
15499
15714
  return [
15500
15715
  selectSetting("mode", "\u8FDE\u63A5\u6A21\u5F0F", mode, [
@@ -15610,7 +15825,7 @@ function customProviderRegistryPath(profileName) {
15610
15825
  async function readCustomProviderRegistry(profileName) {
15611
15826
  const raw = await readFile13(customProviderRegistryPath(profileName), "utf8").catch(
15612
15827
  (error) => {
15613
- if (isNodeError13(error, "ENOENT")) {
15828
+ if (isNodeError14(error, "ENOENT")) {
15614
15829
  return "";
15615
15830
  }
15616
15831
  throw error;
@@ -15621,18 +15836,18 @@ async function readCustomProviderRegistry(profileName) {
15621
15836
  }
15622
15837
  try {
15623
15838
  const parsed = JSON.parse(raw);
15624
- const providers = Array.isArray(parsed) ? parsed : Array.isArray(toRecord12(parsed).providers) ? toRecord12(parsed).providers : [];
15839
+ const providers = Array.isArray(parsed) ? parsed : Array.isArray(toRecord13(parsed).providers) ? toRecord13(parsed).providers : [];
15625
15840
  return providers.map((item) => {
15626
15841
  if (typeof item === "string") {
15627
15842
  const id2 = normalizeCustomProviderId(item);
15628
15843
  return { id: id2, label: id2, description: "\u81EA\u5B9A\u4E49 memory provider\u3002" };
15629
15844
  }
15630
- const record = toRecord12(item);
15631
- const id = normalizeCustomProviderId(readString13(record.id) ?? "");
15845
+ const record = toRecord13(item);
15846
+ const id = normalizeCustomProviderId(readString14(record.id) ?? "");
15632
15847
  return {
15633
15848
  id,
15634
- label: readString13(record.label) ?? id,
15635
- description: readString13(record.description) ?? "\u81EA\u5B9A\u4E49 memory provider\u3002"
15849
+ label: readString14(record.label) ?? id,
15850
+ description: readString14(record.description) ?? "\u81EA\u5B9A\u4E49 memory provider\u3002"
15636
15851
  };
15637
15852
  }).filter((item) => item.id);
15638
15853
  } catch {
@@ -15657,9 +15872,9 @@ async function saveCustomProviderRegistryEntry(profileName, provider) {
15657
15872
  }
15658
15873
  async function discoverUserMemoryProviderDescriptors(profileName) {
15659
15874
  const pluginsDir = path18.join(resolveHermesProfileDir(profileName), "plugins");
15660
- const entries = await readdir7(pluginsDir, { withFileTypes: true }).catch(
15875
+ const entries = await readdir8(pluginsDir, { withFileTypes: true }).catch(
15661
15876
  (error) => {
15662
- if (isNodeError13(error, "ENOENT")) {
15877
+ if (isNodeError14(error, "ENOENT")) {
15663
15878
  return [];
15664
15879
  }
15665
15880
  throw error;
@@ -15683,8 +15898,8 @@ async function discoverUserMemoryProviderDescriptors(profileName) {
15683
15898
  const meta = await readPluginMetadata(providerDir);
15684
15899
  descriptors.push({
15685
15900
  id: providerId,
15686
- label: readString13(meta.name) ?? providerId,
15687
- description: readString13(meta.description) ?? "\u81EA\u5B9A\u4E49 memory provider\u3002"
15901
+ label: readString14(meta.name) ?? providerId,
15902
+ description: readString14(meta.description) ?? "\u81EA\u5B9A\u4E49 memory provider\u3002"
15688
15903
  });
15689
15904
  }
15690
15905
  return descriptors;
@@ -15700,7 +15915,7 @@ async function isUserMemoryProviderInstalled(profileName, provider) {
15700
15915
  async function isMemoryProviderPluginDir(providerDir) {
15701
15916
  const source = await readFile13(path18.join(providerDir, "__init__.py"), "utf8").catch(
15702
15917
  (error) => {
15703
- if (isNodeError13(error, "ENOENT")) {
15918
+ if (isNodeError14(error, "ENOENT")) {
15704
15919
  return "";
15705
15920
  }
15706
15921
  throw error;
@@ -15712,13 +15927,13 @@ async function isMemoryProviderPluginDir(providerDir) {
15712
15927
  async function readPluginMetadata(providerDir) {
15713
15928
  const raw = await readFile13(path18.join(providerDir, "plugin.yaml"), "utf8").catch(
15714
15929
  (error) => {
15715
- if (isNodeError13(error, "ENOENT")) {
15930
+ if (isNodeError14(error, "ENOENT")) {
15716
15931
  return "";
15717
15932
  }
15718
15933
  throw error;
15719
15934
  }
15720
15935
  );
15721
- return raw ? toRecord12(YAML4.parse(raw)) : {};
15936
+ return raw ? toRecord13(YAML4.parse(raw)) : {};
15722
15937
  }
15723
15938
  async function resolveByteRoverCli() {
15724
15939
  const candidates = [
@@ -15738,30 +15953,30 @@ async function resolveByteRoverCli() {
15738
15953
  async function readHolographicProviderConfig(profileName) {
15739
15954
  const raw = await readFile13(resolveHermesConfigPath(profileName), "utf8").catch(
15740
15955
  (error) => {
15741
- if (isNodeError13(error, "ENOENT")) {
15956
+ if (isNodeError14(error, "ENOENT")) {
15742
15957
  return "";
15743
15958
  }
15744
15959
  throw error;
15745
15960
  }
15746
15961
  );
15747
- const config = raw ? toRecord12(YAML4.parse(raw)) : {};
15748
- const plugins = toRecord12(config.plugins);
15749
- return toRecord12(plugins["hermes-memory-store"]);
15962
+ const config = raw ? toRecord13(YAML4.parse(raw)) : {};
15963
+ const plugins = toRecord13(config.plugins);
15964
+ return toRecord13(plugins["hermes-memory-store"]);
15750
15965
  }
15751
15966
  async function patchHolographicProviderConfig(profileName, patch) {
15752
15967
  const configPath = resolveHermesConfigPath(profileName);
15753
15968
  const existingRaw = await readFile13(configPath, "utf8").catch(
15754
15969
  (error) => {
15755
- if (isNodeError13(error, "ENOENT")) {
15970
+ if (isNodeError14(error, "ENOENT")) {
15756
15971
  return null;
15757
15972
  }
15758
15973
  throw error;
15759
15974
  }
15760
15975
  );
15761
15976
  const document = existingRaw ? YAML4.parseDocument(existingRaw) : new YAML4.Document({});
15762
- const config = toRecord12(document.toJSON());
15763
- const plugins = toRecord12(config.plugins);
15764
- const memoryStore = toRecord12(plugins["hermes-memory-store"]);
15977
+ const config = toRecord13(document.toJSON());
15978
+ const plugins = toRecord13(config.plugins);
15979
+ const memoryStore = toRecord13(plugins["hermes-memory-store"]);
15765
15980
  for (const [key, value] of Object.entries(patch)) {
15766
15981
  if (value !== void 0) {
15767
15982
  memoryStore[key] = value;
@@ -15790,7 +16005,7 @@ async function patchHermesMemoryEnv(profileName, patch) {
15790
16005
  }
15791
16006
  const envPath = path18.join(resolveHermesProfileDir(profileName), ".env");
15792
16007
  const existingRaw = await readFile13(envPath, "utf8").catch((error) => {
15793
- if (isNodeError13(error, "ENOENT")) {
16008
+ if (isNodeError14(error, "ENOENT")) {
15794
16009
  return "";
15795
16010
  }
15796
16011
  throw error;
@@ -15839,7 +16054,7 @@ function isMemoryEnvKeyWritable(key) {
15839
16054
  ].includes(key);
15840
16055
  }
15841
16056
  function normalizeHindsightMode(value) {
15842
- const mode = readString13(value) ?? "cloud";
16057
+ const mode = readString14(value) ?? "cloud";
15843
16058
  return mode === "local" ? "local_embedded" : mode;
15844
16059
  }
15845
16060
  async function readActiveMemoryProvider(profileName) {
@@ -15847,14 +16062,14 @@ async function readActiveMemoryProvider(profileName) {
15847
16062
  resolveHermesConfigPath(profileName),
15848
16063
  "utf8"
15849
16064
  ).catch((error) => {
15850
- if (isNodeError13(error, "ENOENT")) {
16065
+ if (isNodeError14(error, "ENOENT")) {
15851
16066
  return "";
15852
16067
  }
15853
16068
  throw error;
15854
16069
  });
15855
- const config = raw ? toRecord12(YAML4.parse(raw)) : {};
15856
- const memory = toRecord12(config.memory);
15857
- const provider = readString13(memory.provider);
16070
+ const config = raw ? toRecord13(YAML4.parse(raw)) : {};
16071
+ const memory = toRecord13(config.memory);
16072
+ const provider = readString14(memory.provider);
15858
16073
  if (!provider || provider === "built-in" || provider === "builtin" || provider === "built_in") {
15859
16074
  return null;
15860
16075
  }
@@ -15881,13 +16096,13 @@ async function patchJsonProviderConfig(profileName, relativePath, patch) {
15881
16096
  }
15882
16097
  async function readJsonObject(filePath) {
15883
16098
  const raw = await readFile13(filePath, "utf8").catch((error) => {
15884
- if (isNodeError13(error, "ENOENT")) {
16099
+ if (isNodeError14(error, "ENOENT")) {
15885
16100
  return "{}";
15886
16101
  }
15887
16102
  throw error;
15888
16103
  });
15889
16104
  try {
15890
- return toRecord12(JSON.parse(raw || "{}"));
16105
+ return toRecord13(JSON.parse(raw || "{}"));
15891
16106
  } catch {
15892
16107
  throw new HermesMemoryError(
15893
16108
  "memory_provider_config_invalid",
@@ -15912,7 +16127,7 @@ function stringSetting(key, label, value, editable = true) {
15912
16127
  return {
15913
16128
  key,
15914
16129
  label,
15915
- value: readString13(value) ?? "",
16130
+ value: readString14(value) ?? "",
15916
16131
  editable,
15917
16132
  kind: "string"
15918
16133
  };
@@ -15927,7 +16142,7 @@ function textSetting(key, label, value, editable = true) {
15927
16142
  };
15928
16143
  }
15929
16144
  function selectSetting(key, label, value, options, editable = true) {
15930
- const stringValue = readString13(value) ?? options[0] ?? null;
16145
+ const stringValue = readString14(value) ?? options[0] ?? null;
15931
16146
  return { key, label, value: stringValue, editable, kind: "select", options };
15932
16147
  }
15933
16148
  async function readMemoryLimits(profileName) {
@@ -15935,13 +16150,13 @@ async function readMemoryLimits(profileName) {
15935
16150
  resolveHermesConfigPath(profileName),
15936
16151
  "utf8"
15937
16152
  ).catch((error) => {
15938
- if (isNodeError13(error, "ENOENT")) {
16153
+ if (isNodeError14(error, "ENOENT")) {
15939
16154
  return "";
15940
16155
  }
15941
16156
  throw error;
15942
16157
  });
15943
- const config = raw ? toRecord12(YAML4.parse(raw)) : {};
15944
- const memory = toRecord12(config.memory);
16158
+ const config = raw ? toRecord13(YAML4.parse(raw)) : {};
16159
+ const memory = toRecord13(config.memory);
15945
16160
  return {
15946
16161
  memory: readPositiveInteger3(memory.memory_char_limit) ?? DEFAULT_MEMORY_LIMIT,
15947
16162
  user: readPositiveInteger3(memory.user_char_limit) ?? DEFAULT_USER_LIMIT
@@ -15997,10 +16212,10 @@ function hashString(value) {
15997
16212
  }
15998
16213
  return hash.toString(16);
15999
16214
  }
16000
- function toRecord12(value) {
16215
+ function toRecord13(value) {
16001
16216
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
16002
16217
  }
16003
- function readString13(value) {
16218
+ function readString14(value) {
16004
16219
  return typeof value === "string" && value.trim() ? value.trim() : null;
16005
16220
  }
16006
16221
  function readPositiveInteger3(value) {
@@ -16028,7 +16243,7 @@ function formatEnvValue3(value) {
16028
16243
  function escapeRegExp3(value) {
16029
16244
  return value.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
16030
16245
  }
16031
- function isNodeError13(error, code) {
16246
+ function isNodeError14(error, code) {
16032
16247
  return error instanceof Error && "code" in error && error.code === code;
16033
16248
  }
16034
16249
 
@@ -16142,7 +16357,7 @@ function registerProfileMemoryRoutes(router, options) {
16142
16357
  );
16143
16358
  }
16144
16359
  function readMemoryTarget(body) {
16145
- const raw = readString12(body, "target");
16360
+ const raw = readString13(body, "target");
16146
16361
  if (raw === "memory" || raw === "user") {
16147
16362
  return raw;
16148
16363
  }
@@ -16153,7 +16368,7 @@ function readMemoryTarget(body) {
16153
16368
  );
16154
16369
  }
16155
16370
  function readMemoryResetTarget(body) {
16156
- const raw = readString12(body, "target") ?? "all";
16371
+ const raw = readString13(body, "target") ?? "all";
16157
16372
  if (raw === "all" || raw === "memory" || raw === "user") {
16158
16373
  return raw;
16159
16374
  }
@@ -16164,7 +16379,7 @@ function readMemoryResetTarget(body) {
16164
16379
  );
16165
16380
  }
16166
16381
  function readRequiredMemoryContent(body) {
16167
- const content = readString12(body, "content") ?? readString12(body, "text");
16382
+ const content = readString13(body, "content") ?? readString13(body, "text");
16168
16383
  if (!content) {
16169
16384
  throw new LinkHttpError(
16170
16385
  400,
@@ -16175,7 +16390,7 @@ function readRequiredMemoryContent(body) {
16175
16390
  return content;
16176
16391
  }
16177
16392
  function readRequiredMemoryMatch(body) {
16178
- const oldText = readString12(body, "old_text") ?? readString12(body, "oldText") ?? readString12(body, "match");
16393
+ const oldText = readString13(body, "old_text") ?? readString13(body, "oldText") ?? readString13(body, "match");
16179
16394
  if (!oldText) {
16180
16395
  throw new LinkHttpError(
16181
16396
  400,
@@ -16186,7 +16401,7 @@ function readRequiredMemoryMatch(body) {
16186
16401
  return oldText;
16187
16402
  }
16188
16403
  function readRequiredMemoryProvider(body) {
16189
- const provider = readString12(body, "provider") ?? readString12(body, "provider_id") ?? readString12(body, "providerId");
16404
+ const provider = readString13(body, "provider") ?? readString13(body, "provider_id") ?? readString13(body, "providerId");
16190
16405
  if (!provider) {
16191
16406
  throw new LinkHttpError(
16192
16407
  400,
@@ -16198,7 +16413,7 @@ function readRequiredMemoryProvider(body) {
16198
16413
  }
16199
16414
  function readMemorySettingsPatch(body) {
16200
16415
  const input = {};
16201
- const mode = readString12(body, "mode");
16416
+ const mode = readString13(body, "mode");
16202
16417
  if (mode) {
16203
16418
  input.mode = mode;
16204
16419
  }
@@ -16210,7 +16425,7 @@ function readMemorySettingsPatch(body) {
16210
16425
  if (bankId !== void 0) {
16211
16426
  input.bankId = bankId;
16212
16427
  }
16213
- const llmProvider = readString12(body, "llm_provider") ?? readString12(body, "llmProvider");
16428
+ const llmProvider = readString13(body, "llm_provider") ?? readString13(body, "llmProvider");
16214
16429
  if (llmProvider) {
16215
16430
  input.llmProvider = llmProvider;
16216
16431
  }
@@ -16238,11 +16453,11 @@ function readMemorySettingsPatch(body) {
16238
16453
  if (autoRetain !== void 0) {
16239
16454
  input.autoRetain = autoRetain;
16240
16455
  }
16241
- const memoryMode = readString12(body, "memory_mode") ?? readString12(body, "memoryMode");
16456
+ const memoryMode = readString13(body, "memory_mode") ?? readString13(body, "memoryMode");
16242
16457
  if (memoryMode) {
16243
16458
  input.memoryMode = memoryMode;
16244
16459
  }
16245
- const recallBudget = readString12(body, "recall_budget") ?? readString12(body, "recallBudget");
16460
+ const recallBudget = readString13(body, "recall_budget") ?? readString13(body, "recallBudget");
16246
16461
  if (recallBudget) {
16247
16462
  input.recallBudget = recallBudget;
16248
16463
  }
@@ -16258,11 +16473,11 @@ function readMemorySettingsPatch(body) {
16258
16473
  if (profileFrequency !== void 0) {
16259
16474
  input.profileFrequency = profileFrequency;
16260
16475
  }
16261
- const captureMode = readString12(body, "capture_mode") ?? readString12(body, "captureMode");
16476
+ const captureMode = readString13(body, "capture_mode") ?? readString13(body, "captureMode");
16262
16477
  if (captureMode) {
16263
16478
  input.captureMode = captureMode;
16264
16479
  }
16265
- const searchMode = readString12(body, "search_mode") ?? readString12(body, "searchMode");
16480
+ const searchMode = readString13(body, "search_mode") ?? readString13(body, "searchMode");
16266
16481
  if (searchMode) {
16267
16482
  input.searchMode = searchMode;
16268
16483
  }
@@ -16296,11 +16511,11 @@ function readMemorySettingsPatch(body) {
16296
16511
  if (aiPeer !== void 0) {
16297
16512
  input.aiPeer = aiPeer;
16298
16513
  }
16299
- const recallMode = readString12(body, "recall_mode") ?? readString12(body, "recallMode");
16514
+ const recallMode = readString13(body, "recall_mode") ?? readString13(body, "recallMode");
16300
16515
  if (recallMode) {
16301
16516
  input.recallMode = recallMode;
16302
16517
  }
16303
- const writeFrequency = readString12(body, "write_frequency") ?? readString12(body, "writeFrequency");
16518
+ const writeFrequency = readString13(body, "write_frequency") ?? readString13(body, "writeFrequency");
16304
16519
  if (writeFrequency) {
16305
16520
  input.writeFrequency = writeFrequency;
16306
16521
  }
@@ -16308,7 +16523,7 @@ function readMemorySettingsPatch(body) {
16308
16523
  if (saveMessages !== void 0) {
16309
16524
  input.saveMessages = saveMessages;
16310
16525
  }
16311
- const sessionStrategy = readString12(body, "session_strategy") ?? readString12(body, "sessionStrategy");
16526
+ const sessionStrategy = readString13(body, "session_strategy") ?? readString13(body, "sessionStrategy");
16312
16527
  if (sessionStrategy) {
16313
16528
  input.sessionStrategy = sessionStrategy;
16314
16529
  }
@@ -16440,7 +16655,7 @@ import {
16440
16655
  copyFile as copyFile4,
16441
16656
  mkdir as mkdir13,
16442
16657
  readFile as readFile14,
16443
- readdir as readdir8,
16658
+ readdir as readdir9,
16444
16659
  rename as rename7,
16445
16660
  writeFile as writeFile6
16446
16661
  } from "fs/promises";
@@ -16535,9 +16750,9 @@ async function findSkillFiles(root) {
16535
16750
  return results.sort((left, right) => left.localeCompare(right));
16536
16751
  }
16537
16752
  async function collectSkillFiles(directory, results) {
16538
- const entries = await readdir8(directory, { withFileTypes: true }).catch(
16753
+ const entries = await readdir9(directory, { withFileTypes: true }).catch(
16539
16754
  (error) => {
16540
- if (isNodeError14(error, "ENOENT")) {
16755
+ if (isNodeError15(error, "ENOENT")) {
16541
16756
  return [];
16542
16757
  }
16543
16758
  throw error;
@@ -16562,7 +16777,7 @@ async function collectSkillFiles(directory, results) {
16562
16777
  async function readSkillMetadata(input) {
16563
16778
  const raw = await readFile14(input.skillFile, "utf8").catch(
16564
16779
  (error) => {
16565
- if (isNodeError14(error, "ENOENT") || isNodeError14(error, "EACCES")) {
16780
+ if (isNodeError15(error, "ENOENT") || isNodeError15(error, "EACCES")) {
16566
16781
  return null;
16567
16782
  }
16568
16783
  throw error;
@@ -16574,13 +16789,13 @@ async function readSkillMetadata(input) {
16574
16789
  const skillDir = path19.dirname(input.skillFile);
16575
16790
  const { frontmatter, body } = parseSkillDocument(raw.slice(0, 4e3));
16576
16791
  const name = normalizeSkillName(
16577
- readString14(frontmatter.name) ?? path19.basename(skillDir)
16792
+ readString15(frontmatter.name) ?? path19.basename(skillDir)
16578
16793
  );
16579
16794
  if (!name) {
16580
16795
  return null;
16581
16796
  }
16582
16797
  const description = normalizeDescription(
16583
- readString14(frontmatter.description) ?? firstBodyDescription(body)
16798
+ readString15(frontmatter.description) ?? firstBodyDescription(body)
16584
16799
  );
16585
16800
  const provenance = input.provenance.get(name) ?? {
16586
16801
  source: "local",
@@ -16606,7 +16821,7 @@ function parseSkillDocument(raw) {
16606
16821
  }
16607
16822
  try {
16608
16823
  return {
16609
- frontmatter: toRecord13(YAML5.parse(match[1] ?? "")),
16824
+ frontmatter: toRecord14(YAML5.parse(match[1] ?? "")),
16610
16825
  body: content.slice(match[0].length)
16611
16826
  };
16612
16827
  } catch {
@@ -16639,7 +16854,7 @@ function normalizeDescription(value) {
16639
16854
  }
16640
16855
  async function readDisabledSkillNames(configPath) {
16641
16856
  const raw = await readFile14(configPath, "utf8").catch((error) => {
16642
- if (isNodeError14(error, "ENOENT")) {
16857
+ if (isNodeError15(error, "ENOENT")) {
16643
16858
  return "";
16644
16859
  }
16645
16860
  throw error;
@@ -16647,8 +16862,8 @@ async function readDisabledSkillNames(configPath) {
16647
16862
  if (!raw.trim()) {
16648
16863
  return /* @__PURE__ */ new Set();
16649
16864
  }
16650
- const config = toRecord13(YAML5.parse(raw));
16651
- const skills = toRecord13(config.skills);
16865
+ const config = toRecord14(YAML5.parse(raw));
16866
+ const skills = toRecord14(config.skills);
16652
16867
  return new Set(readStringList3(skills.disabled));
16653
16868
  }
16654
16869
  async function readSkillProvenance(root) {
@@ -16664,7 +16879,7 @@ async function readSkillProvenance(root) {
16664
16879
  async function readBundledSkillNames(root) {
16665
16880
  const raw = await readFile14(path19.join(root, ".bundled_manifest"), "utf8").catch(
16666
16881
  (error) => {
16667
- if (isNodeError14(error, "ENOENT")) {
16882
+ if (isNodeError15(error, "ENOENT")) {
16668
16883
  return "";
16669
16884
  }
16670
16885
  throw error;
@@ -16687,7 +16902,7 @@ async function readBundledSkillNames(root) {
16687
16902
  async function readHubInstalledSkills(root) {
16688
16903
  const raw = await readFile14(path19.join(root, ".hub", "lock.json"), "utf8").catch(
16689
16904
  (error) => {
16690
- if (isNodeError14(error, "ENOENT")) {
16905
+ if (isNodeError15(error, "ENOENT")) {
16691
16906
  return "";
16692
16907
  }
16693
16908
  throw error;
@@ -16698,17 +16913,17 @@ async function readHubInstalledSkills(root) {
16698
16913
  }
16699
16914
  let lock;
16700
16915
  try {
16701
- lock = toRecord13(JSON.parse(raw));
16916
+ lock = toRecord14(JSON.parse(raw));
16702
16917
  } catch {
16703
16918
  return /* @__PURE__ */ new Map();
16704
16919
  }
16705
- const installed = toRecord13(lock.installed);
16920
+ const installed = toRecord14(lock.installed);
16706
16921
  const result = /* @__PURE__ */ new Map();
16707
16922
  for (const [name, rawEntry] of Object.entries(installed)) {
16708
- const entry = toRecord13(rawEntry);
16923
+ const entry = toRecord14(rawEntry);
16709
16924
  result.set(normalizeSkillName(name), {
16710
- source: readString14(entry.source) ?? "hub",
16711
- trust: readString14(entry.trust_level) ?? null
16925
+ source: readString15(entry.source) ?? "hub",
16926
+ trust: readString15(entry.trust_level) ?? null
16712
16927
  });
16713
16928
  }
16714
16929
  return result;
@@ -16759,7 +16974,7 @@ function compareCategoryNames(left, right) {
16759
16974
  async function readHermesConfigDocument2(configPath) {
16760
16975
  const existingRaw = await readFile14(configPath, "utf8").catch(
16761
16976
  (error) => {
16762
- if (isNodeError14(error, "ENOENT")) {
16977
+ if (isNodeError15(error, "ENOENT")) {
16763
16978
  return null;
16764
16979
  }
16765
16980
  throw error;
@@ -16768,7 +16983,7 @@ async function readHermesConfigDocument2(configPath) {
16768
16983
  const document = existingRaw ? YAML5.parseDocument(existingRaw) : new YAML5.Document({});
16769
16984
  return {
16770
16985
  document,
16771
- config: toRecord13(document.toJSON()),
16986
+ config: toRecord14(document.toJSON()),
16772
16987
  existingRaw
16773
16988
  };
16774
16989
  }
@@ -16790,21 +17005,21 @@ function readStringList3(value) {
16790
17005
  }
16791
17006
  return value.filter((item) => typeof item === "string").map((item) => item.trim()).filter(Boolean);
16792
17007
  }
16793
- function readString14(value) {
17008
+ function readString15(value) {
16794
17009
  return typeof value === "string" && value.trim() ? value.trim() : null;
16795
17010
  }
16796
- function toRecord13(value) {
17011
+ function toRecord14(value) {
16797
17012
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
16798
17013
  }
16799
17014
  function ensureRecord3(target, key) {
16800
- const current = toRecord13(target[key]);
17015
+ const current = toRecord14(target[key]);
16801
17016
  if (current === target[key]) {
16802
17017
  return current;
16803
17018
  }
16804
17019
  target[key] = current;
16805
17020
  return current;
16806
17021
  }
16807
- function isNodeError14(error, code) {
17022
+ function isNodeError15(error, code) {
16808
17023
  return typeof error === "object" && error !== null && "code" in error && error.code === code;
16809
17024
  }
16810
17025
 
@@ -17107,7 +17322,7 @@ function registerRunRoutes(router, options) {
17107
17322
  router.post("/api/v1/runs", async (ctx) => {
17108
17323
  await authenticateRequest(ctx, paths);
17109
17324
  const body = await readJsonBody(ctx.req);
17110
- const input = readString12(body, "input");
17325
+ const input = readString13(body, "input");
17111
17326
  if (!input) {
17112
17327
  throw new LinkHttpError(400, "run_input_required", "input is required");
17113
17328
  }
@@ -17115,11 +17330,11 @@ function registerRunRoutes(router, options) {
17115
17330
  ctx.body = await createHermesRun(
17116
17331
  {
17117
17332
  input,
17118
- instructions: readString12(body, "instructions") ?? void 0,
17333
+ instructions: readString13(body, "instructions") ?? void 0,
17119
17334
  conversation_history: readConversationHistory(
17120
17335
  body.conversation_history ?? body.conversationHistory
17121
17336
  ),
17122
- session_id: readString12(body, "session_id") ?? readString12(body, "sessionId") ?? void 0
17337
+ session_id: readString13(body, "session_id") ?? readString13(body, "sessionId") ?? void 0
17123
17338
  },
17124
17339
  { logger, profileName: readOptionalProfileName(body) }
17125
17340
  );
@@ -17512,24 +17727,24 @@ async function readRemoteRelease(options, now) {
17512
17727
  }
17513
17728
  }
17514
17729
  function normalizeServerReleaseSnapshot(payload) {
17515
- const snapshot = toRecord14(payload);
17730
+ const snapshot = toRecord15(payload);
17516
17731
  const remote = toNullableRecord(snapshot.remote);
17517
17732
  return {
17518
17733
  remote: remote ? normalizeServerRelease(remote) : null,
17519
- cacheState: readString15(snapshot, "cache_state") ?? readString15(snapshot, "cacheState"),
17520
- issue: readString15(snapshot, "issue")
17734
+ cacheState: readString16(snapshot, "cache_state") ?? readString16(snapshot, "cacheState"),
17735
+ issue: readString16(snapshot, "issue")
17521
17736
  };
17522
17737
  }
17523
17738
  function normalizeServerRelease(payload) {
17524
- const tag = readString15(payload, "tag");
17525
- const name = readString15(payload, "name");
17739
+ const tag = readString16(payload, "tag");
17740
+ const name = readString16(payload, "name");
17526
17741
  return {
17527
- version: readString15(payload, "version") ?? extractSemver(name) ?? extractTagSemver(tag),
17742
+ version: readString16(payload, "version") ?? extractSemver(name) ?? extractTagSemver(tag),
17528
17743
  tag,
17529
17744
  name,
17530
- releaseUrl: readString15(payload, "releaseUrl") ?? readString15(payload, "release_url"),
17531
- publishedAt: readString15(payload, "publishedAt") ?? readString15(payload, "published_at"),
17532
- fetchedAt: readString15(payload, "fetchedAt") ?? readString15(payload, "fetched_at") ?? (/* @__PURE__ */ new Date()).toISOString()
17745
+ releaseUrl: readString16(payload, "releaseUrl") ?? readString16(payload, "release_url"),
17746
+ publishedAt: readString16(payload, "publishedAt") ?? readString16(payload, "published_at"),
17747
+ fetchedAt: readString16(payload, "fetchedAt") ?? readString16(payload, "fetched_at") ?? (/* @__PURE__ */ new Date()).toISOString()
17533
17748
  };
17534
17749
  }
17535
17750
  async function readReleaseCache(paths) {
@@ -17601,7 +17816,7 @@ function compareSemver2(left, right) {
17601
17816
  }
17602
17817
  return 0;
17603
17818
  }
17604
- function toRecord14(value) {
17819
+ function toRecord15(value) {
17605
17820
  return typeof value === "object" && value !== null ? value : {};
17606
17821
  }
17607
17822
  function toNullableRecord(value) {
@@ -17647,7 +17862,7 @@ function isRecentRunningState2(state) {
17647
17862
  const startedAt = Date.parse(state.started_at);
17648
17863
  return Number.isFinite(startedAt) && Date.now() - startedAt < 3e4;
17649
17864
  }
17650
- function readString15(payload, key) {
17865
+ function readString16(payload, key) {
17651
17866
  const value = payload[key];
17652
17867
  return typeof value === "string" && value.trim() ? value.trim() : null;
17653
17868
  }
@@ -19157,21 +19372,21 @@ async function readRemoteLinkPolicy(options) {
19157
19372
  }
19158
19373
  }
19159
19374
  function normalizeServerSnapshot(payload) {
19160
- const snapshot = toRecord15(payload);
19375
+ const snapshot = toRecord16(payload);
19161
19376
  const policy = toNullableRecord2(snapshot.policy);
19162
19377
  if (!policy) {
19163
19378
  return {
19164
19379
  remote: null,
19165
- issue: readString16(snapshot, "issue")
19380
+ issue: readString17(snapshot, "issue")
19166
19381
  };
19167
19382
  }
19168
19383
  const release = toNullableRecord2(snapshot.release);
19169
- const currentVersion = readString16(policy, "current_version") ?? readString16(policy, "currentVersion");
19170
- const minSafeVersion = readString16(policy, "min_safe_version") ?? readString16(policy, "minSafeVersion");
19384
+ const currentVersion = readString17(policy, "current_version") ?? readString17(policy, "currentVersion");
19385
+ const minSafeVersion = readString17(policy, "min_safe_version") ?? readString17(policy, "minSafeVersion");
19171
19386
  if (!currentVersion) {
19172
19387
  return {
19173
19388
  remote: null,
19174
- issue: readString16(snapshot, "issue")
19389
+ issue: readString17(snapshot, "issue")
19175
19390
  };
19176
19391
  }
19177
19392
  return {
@@ -19179,10 +19394,10 @@ function normalizeServerSnapshot(payload) {
19179
19394
  current_version: currentVersion,
19180
19395
  min_safe_version: minSafeVersion,
19181
19396
  target_version: currentVersion,
19182
- release_url: release ? readString16(release, "release_url") ?? readString16(release, "releaseUrl") : null,
19183
- published_at: release ? readString16(release, "published_at") ?? readString16(release, "publishedAt") : null
19397
+ release_url: release ? readString17(release, "release_url") ?? readString17(release, "releaseUrl") : null,
19398
+ published_at: release ? readString17(release, "published_at") ?? readString17(release, "publishedAt") : null
19184
19399
  },
19185
- issue: readString16(snapshot, "issue")
19400
+ issue: readString17(snapshot, "issue")
19186
19401
  };
19187
19402
  }
19188
19403
  async function fetchCurrentLinkReleaseFromServer(options, fetcher) {
@@ -19296,13 +19511,13 @@ function isProcessAlive4(pid) {
19296
19511
  return false;
19297
19512
  }
19298
19513
  }
19299
- function toRecord15(value) {
19514
+ function toRecord16(value) {
19300
19515
  return typeof value === "object" && value !== null ? value : {};
19301
19516
  }
19302
19517
  function toNullableRecord2(value) {
19303
19518
  return typeof value === "object" && value !== null ? value : null;
19304
19519
  }
19305
- function readString16(payload, key) {
19520
+ function readString17(payload, key) {
19306
19521
  const value = payload[key];
19307
19522
  return typeof value === "string" && value.trim() ? value.trim() : null;
19308
19523
  }
@@ -19731,8 +19946,8 @@ function registerSystemRoutes(router, options) {
19731
19946
  });
19732
19947
  router.post("/api/v1/pairing/claim", async (ctx) => {
19733
19948
  const body = await readJsonBody(ctx.req);
19734
- const sessionId = readString12(body, "session_id") ?? readString12(body, "sessionId");
19735
- const claimToken = readString12(body, "claim_token") ?? readString12(body, "claimToken");
19949
+ const sessionId = readString13(body, "session_id") ?? readString13(body, "sessionId");
19950
+ const claimToken = readString13(body, "claim_token") ?? readString13(body, "claimToken");
19736
19951
  if (!sessionId || !claimToken) {
19737
19952
  throw new LinkHttpError(
19738
19953
  400,
@@ -19743,10 +19958,10 @@ function registerSystemRoutes(router, options) {
19743
19958
  const claimed = await claimPairing({
19744
19959
  sessionId,
19745
19960
  claimToken,
19746
- deviceLabel: readString12(body, "device_label") ?? readString12(body, "deviceLabel") ?? "HermesPilot App",
19747
- devicePlatform: readString12(body, "device_platform") ?? readString12(body, "devicePlatform") ?? "unknown",
19748
- deviceModel: readString12(body, "device_model") ?? readString12(body, "deviceModel"),
19749
- appInstanceId: readString12(body, "app_instance_id") ?? readString12(body, "appInstanceId"),
19961
+ deviceLabel: readString13(body, "device_label") ?? readString13(body, "deviceLabel") ?? "HermesPilot App",
19962
+ devicePlatform: readString13(body, "device_platform") ?? readString13(body, "devicePlatform") ?? "unknown",
19963
+ deviceModel: readString13(body, "device_model") ?? readString13(body, "deviceModel"),
19964
+ appInstanceId: readString13(body, "app_instance_id") ?? readString13(body, "appInstanceId"),
19750
19965
  paths
19751
19966
  });
19752
19967
  ctx.body = claimed;
@@ -19821,9 +20036,9 @@ function registerSystemRoutes(router, options) {
19821
20036
  const body = await readJsonBody(ctx.req);
19822
20037
  const session = await createDeviceSession(
19823
20038
  {
19824
- label: readString12(body, "device_label") ?? readString12(body, "deviceLabel") ?? "HermesPilot App",
19825
- platform: readString12(body, "device_platform") ?? readString12(body, "devicePlatform") ?? "unknown",
19826
- model: readString12(body, "device_model") ?? readString12(body, "deviceModel"),
20039
+ label: readString13(body, "device_label") ?? readString13(body, "deviceLabel") ?? "HermesPilot App",
20040
+ platform: readString13(body, "device_platform") ?? readString13(body, "devicePlatform") ?? "unknown",
20041
+ model: readString13(body, "device_model") ?? readString13(body, "deviceModel"),
19827
20042
  appInstanceId: auth.appInstanceId
19828
20043
  },
19829
20044
  paths
@@ -19852,7 +20067,7 @@ function registerSystemRoutes(router, options) {
19852
20067
  });
19853
20068
  router.post("/api/v1/auth/refresh", async (ctx) => {
19854
20069
  const body = await readJsonBody(ctx.req);
19855
- const refreshToken = readString12(body, "refresh_token") ?? readString12(body, "refreshToken");
20070
+ const refreshToken = readString13(body, "refresh_token") ?? readString13(body, "refreshToken");
19856
20071
  if (!refreshToken) {
19857
20072
  throw new LinkHttpError(
19858
20073
  400,
@@ -19863,10 +20078,10 @@ function registerSystemRoutes(router, options) {
19863
20078
  const session = await refreshDeviceSession(
19864
20079
  refreshToken,
19865
20080
  {
19866
- appInstanceId: readString12(body, "app_instance_id") ?? readString12(body, "appInstanceId"),
19867
- label: readString12(body, "device_label") ?? readString12(body, "deviceLabel"),
19868
- platform: readString12(body, "device_platform") ?? readString12(body, "devicePlatform"),
19869
- model: readString12(body, "device_model") ?? readString12(body, "deviceModel")
20081
+ appInstanceId: readString13(body, "app_instance_id") ?? readString13(body, "appInstanceId"),
20082
+ label: readString13(body, "device_label") ?? readString13(body, "deviceLabel"),
20083
+ platform: readString13(body, "device_platform") ?? readString13(body, "devicePlatform"),
20084
+ model: readString13(body, "device_model") ?? readString13(body, "deviceModel")
19870
20085
  },
19871
20086
  paths
19872
20087
  );
@@ -19885,7 +20100,7 @@ function registerSystemRoutes(router, options) {
19885
20100
  });
19886
20101
  router.post("/api/v1/auth/logout", async (ctx) => {
19887
20102
  const body = await readJsonBody(ctx.req);
19888
- const refreshToken = readString12(body, "refresh_token") ?? readString12(body, "refreshToken");
20103
+ const refreshToken = readString13(body, "refresh_token") ?? readString13(body, "refreshToken");
19889
20104
  if (refreshToken) {
19890
20105
  await revokeDeviceRefreshToken(refreshToken, paths);
19891
20106
  }
@@ -20110,7 +20325,7 @@ function registerSystemRoutes(router, options) {
20110
20325
  router.patch("/api/v1/devices/:deviceId", async (ctx) => {
20111
20326
  const auth = await authenticateRequest(ctx, paths);
20112
20327
  const body = await readJsonBody(ctx.req);
20113
- const label = readString12(body, "label") ?? readString12(body, "device_label");
20328
+ const label = readString13(body, "label") ?? readString13(body, "device_label");
20114
20329
  if (!label) {
20115
20330
  throw new LinkHttpError(
20116
20331
  400,
@@ -20154,7 +20369,7 @@ function isActiveCronJob(job) {
20154
20369
  if (!enabled) {
20155
20370
  return false;
20156
20371
  }
20157
- const state = readString12(job, "state")?.toLowerCase();
20372
+ const state = readString13(job, "state")?.toLowerCase();
20158
20373
  return !["paused", "disabled", "completed", "deleted"].includes(state ?? "");
20159
20374
  }
20160
20375
  function filterLogsWithinHours(logs, hours, now = Date.now()) {
@@ -20248,7 +20463,7 @@ function registerLinkUpdateRoutes(router, options) {
20248
20463
  ctx.body = await startLinkUpdate({
20249
20464
  paths,
20250
20465
  logger,
20251
- targetVersion: readString12(body, "target_version") ?? readString12(body, "targetVersion")
20466
+ targetVersion: readString13(body, "target_version") ?? readString13(body, "targetVersion")
20252
20467
  });
20253
20468
  });
20254
20469
  router.get("/api/v1/link/update/events", async (ctx) => {
@@ -20282,7 +20497,7 @@ import QRCode from "qrcode";
20282
20497
  function registerPairingRoutes(router, options) {
20283
20498
  const { paths } = options;
20284
20499
  router.get("/pair", async (ctx) => {
20285
- const sessionId = readString12(ctx.query, "session_id");
20500
+ const sessionId = readString13(ctx.query, "session_id");
20286
20501
  if (!sessionId) {
20287
20502
  throw new LinkHttpError(400, "pairing_session_required", "session_id is required");
20288
20503
  }
@@ -20307,7 +20522,7 @@ function registerPairingRoutes(router, options) {
20307
20522
  ctx.body = page;
20308
20523
  });
20309
20524
  router.get("/api/v1/pairing/session", async (ctx) => {
20310
- const sessionId = readString12(ctx.query, "session_id");
20525
+ const sessionId = readString13(ctx.query, "session_id");
20311
20526
  if (!sessionId) {
20312
20527
  throw new LinkHttpError(400, "pairing_session_required", "session_id is required");
20313
20528
  }
@@ -20706,6 +20921,37 @@ function formatDate(value) {
20706
20921
  return Number.isNaN(date.getTime()) ? value : date.toLocaleString("zh-CN", { hour12: false });
20707
20922
  }
20708
20923
 
20924
+ // src/http/routes/internal.ts
20925
+ function registerInternalRoutes(router, options) {
20926
+ router.post("/internal/deliver", async (ctx) => {
20927
+ assertLoopbackRequest(ctx.req);
20928
+ const body = await readJsonBody(ctx.req);
20929
+ const stagingDir = readString13(body, "staging_dir") ?? readString13(body, "stagingDir");
20930
+ if (!stagingDir) {
20931
+ throw new LinkHttpError(
20932
+ 400,
20933
+ "delivery_staging_required",
20934
+ "delivery staging directory is required"
20935
+ );
20936
+ }
20937
+ ctx.body = {
20938
+ ok: true,
20939
+ ...await options.conversations.deliverStagedFiles(stagingDir)
20940
+ };
20941
+ });
20942
+ }
20943
+ function assertLoopbackRequest(request) {
20944
+ const address = request.socket.remoteAddress;
20945
+ if (address === "127.0.0.1" || address === "::1" || address === "::ffff:127.0.0.1") {
20946
+ return;
20947
+ }
20948
+ throw new LinkHttpError(
20949
+ 403,
20950
+ "internal_route_forbidden",
20951
+ "internal route is only available on loopback"
20952
+ );
20953
+ }
20954
+
20709
20955
  // src/http/app.ts
20710
20956
  async function createApp(options = {}) {
20711
20957
  const paths = options.paths ?? resolveRuntimePaths();
@@ -20735,6 +20981,7 @@ async function createApp(options = {}) {
20735
20981
  logger,
20736
20982
  onPairingClaimed: options.onPairingClaimed
20737
20983
  });
20984
+ registerInternalRoutes(router, { conversations });
20738
20985
  registerPairingRoutes(router, { paths });
20739
20986
  registerHermesUpdateRoutes(router, { paths, logger });
20740
20987
  registerLinkUpdateRoutes(router, { paths, logger });
@@ -20764,11 +21011,13 @@ export {
20764
21011
  ensureHermesApiServerConfig,
20765
21012
  LinkHttpError,
20766
21013
  resolveRuntimePaths,
21014
+ createFileLogger,
20767
21015
  getLinkLogFile,
20768
21016
  ensureHermesApiServerAvailable,
20769
21017
  loadConfig,
20770
21018
  saveConfig,
20771
21019
  normalizeLanHost,
21020
+ ConversationService,
20772
21021
  loadIdentity,
20773
21022
  ensureIdentity,
20774
21023
  getIdentityStatus,