@hermespilot/link 0.3.4 → 0.3.5

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.
@@ -4,7 +4,7 @@ import Router from "@koa/router";
4
4
 
5
5
  // src/conversations/conversation-service.ts
6
6
  import { EventEmitter } from "events";
7
- import { randomUUID as randomUUID6 } from "crypto";
7
+ import { randomUUID as randomUUID7 } from "crypto";
8
8
 
9
9
  // src/database/link-database.ts
10
10
  import { mkdir } from "fs/promises";
@@ -3637,7 +3637,7 @@ async function listCronOutputFiles(profileName, jobId) {
3637
3637
  mtimeMs: fileStat.mtimeMs
3638
3638
  });
3639
3639
  }
3640
- return files.sort((left, right) => left.mtimeMs - right.mtimeMs).map(({ path: path24, mtime }) => ({ path: path24, mtime }));
3640
+ return files.sort((left, right) => left.mtimeMs - right.mtimeMs).map(({ path: path25, mtime }) => ({ path: path25, mtime }));
3641
3641
  }
3642
3642
  async function readCronOutput(outputPath) {
3643
3643
  const content = await readFile3(outputPath, "utf8");
@@ -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.4";
3727
+ var LINK_VERSION = "0.3.5";
3728
3728
  var LINK_COMMAND = "hermeslink";
3729
3729
  var LINK_DEFAULT_PORT = 52379;
3730
3730
  var LINK_RUNTIME_DIR_NAME = ".hermeslink";
@@ -8485,40 +8485,1198 @@ var ConversationStore = class {
8485
8485
  }
8486
8486
  return manifest;
8487
8487
  }
8488
- async isConversationActive(conversationId) {
8489
- const manifest = await this.readManifest(conversationId).catch(() => null);
8490
- return manifest?.status === "active";
8488
+ async isConversationActive(conversationId) {
8489
+ const manifest = await this.readManifest(conversationId).catch(() => null);
8490
+ return manifest?.status === "active";
8491
+ }
8492
+ removeConversationAttachments(conversationId) {
8493
+ return rm5(path12.join(this.conversationDir(conversationId), "attachments"), {
8494
+ recursive: true,
8495
+ force: true
8496
+ });
8497
+ }
8498
+ conversationDir(conversationId) {
8499
+ assertValidConversationId(conversationId);
8500
+ return path12.join(this.paths.conversationsDir, conversationId);
8501
+ }
8502
+ manifestPath(conversationId) {
8503
+ return path12.join(this.conversationDir(conversationId), "manifest.json");
8504
+ }
8505
+ snapshotPath(conversationId) {
8506
+ return path12.join(this.conversationDir(conversationId), "snapshot.json");
8507
+ }
8508
+ eventsPath(conversationId) {
8509
+ return path12.join(this.conversationDir(conversationId), "events.ndjson");
8510
+ }
8511
+ };
8512
+ function createEmptySnapshot2() {
8513
+ return { schema_version: 1, messages: [], runs: [] };
8514
+ }
8515
+ function isNodeError8(error, code) {
8516
+ return typeof error === "object" && error !== null && "code" in error && error.code === code;
8517
+ }
8518
+
8519
+ // src/conversations/hermes-session-sync.ts
8520
+ import { randomUUID as randomUUID6 } from "crypto";
8521
+ import { readdir as readdir5, readFile as readFile8, stat as stat7 } from "fs/promises";
8522
+ import { createRequire as createRequire3 } from "module";
8523
+ import os4 from "os";
8524
+ import path13 from "path";
8525
+ var nodeRequire3 = createRequire3(import.meta.url);
8526
+ var PROFILE_NAME_PATTERN3 = /^[a-zA-Z0-9._-]{1,64}$/u;
8527
+ var DEFAULT_PROFILE_NAME = "default";
8528
+ var MAX_IMPORTABLE_SESSIONS = 100;
8529
+ var HIDDEN_SESSION_SOURCES = /* @__PURE__ */ new Set(["tool"]);
8530
+ var HERMES_IMPORT_PROJECTION_VERSION = "turn_blocks_v2";
8531
+ var MESSAGE_COLUMNS = [
8532
+ "id",
8533
+ "session_id",
8534
+ "role",
8535
+ "content",
8536
+ "tool_call_id",
8537
+ "tool_calls",
8538
+ "tool_name",
8539
+ "timestamp",
8540
+ "token_count",
8541
+ "finish_reason",
8542
+ "reasoning",
8543
+ "reasoning_content",
8544
+ "reasoning_details",
8545
+ "codex_reasoning_items"
8546
+ ];
8547
+ async function syncHermesSessionsIntoConversations(paths, logger, options = {}) {
8548
+ const maxImports = options.maxImports ?? MAX_IMPORTABLE_SESSIONS;
8549
+ const store = new ConversationStore(paths);
8550
+ const knownHermesSessions = await readKnownHermesSessions(store);
8551
+ const profileNames = await discoverHermesProfileNames();
8552
+ const result = {
8553
+ scanned_profiles: profileNames.length,
8554
+ scanned_sessions: 0,
8555
+ eligible_sessions: 0,
8556
+ imported_count: 0,
8557
+ reprojected_count: 0,
8558
+ skipped_existing: 0,
8559
+ skipped_hidden: 0,
8560
+ skipped_deleted: 0,
8561
+ skipped_over_limit: 0,
8562
+ errors: []
8563
+ };
8564
+ const candidates = [];
8565
+ for (const profileName of profileNames) {
8566
+ const profileDir = resolveHermesProfileDir(profileName);
8567
+ const dbPath = path13.join(profileDir, "state.db");
8568
+ const sessions = await listProfileSessions(dbPath).catch((error) => {
8569
+ result.errors.push({
8570
+ profile: profileName,
8571
+ message: error instanceof Error ? error.message : String(error)
8572
+ });
8573
+ return [];
8574
+ });
8575
+ result.scanned_sessions += sessions.length;
8576
+ for (const session of sessions) {
8577
+ if (isDeletedSession(session)) {
8578
+ result.skipped_deleted += 1;
8579
+ continue;
8580
+ }
8581
+ if (isHiddenSession(session)) {
8582
+ result.skipped_hidden += 1;
8583
+ continue;
8584
+ }
8585
+ result.eligible_sessions += 1;
8586
+ candidates.push({ profileName, profileDir, dbPath, session });
8587
+ }
8588
+ }
8589
+ candidates.sort((left, right) => {
8590
+ const rightTime = readNumber2(right.session.last_active) ?? 0;
8591
+ const leftTime = readNumber2(left.session.last_active) ?? 0;
8592
+ return rightTime - leftTime;
8593
+ });
8594
+ const importableCandidates = candidates.slice(0, maxImports);
8595
+ result.skipped_over_limit = Math.max(0, candidates.length - maxImports);
8596
+ for (const candidate of importableCandidates) {
8597
+ if (knownHermesSessions.ids.has(candidate.session.id)) {
8598
+ result.skipped_existing += 1;
8599
+ const reprojected = await reprojectExistingHermesConversation({
8600
+ paths,
8601
+ store,
8602
+ candidate,
8603
+ conversationIds: knownHermesSessions.conversationIdsBySessionId.get(
8604
+ candidate.session.id
8605
+ ) ?? []
8606
+ }).catch((error) => {
8607
+ result.errors.push({
8608
+ profile: candidate.profileName,
8609
+ message: error instanceof Error ? error.message : String(error)
8610
+ });
8611
+ return false;
8612
+ });
8613
+ if (reprojected) {
8614
+ result.reprojected_count += 1;
8615
+ }
8616
+ continue;
8617
+ }
8618
+ const imported = await importHermesSession({
8619
+ paths,
8620
+ store,
8621
+ candidate,
8622
+ existingHermesSessionIds: knownHermesSessions.ids
8623
+ }).catch((error) => {
8624
+ result.errors.push({
8625
+ profile: candidate.profileName,
8626
+ message: error instanceof Error ? error.message : String(error)
8627
+ });
8628
+ return false;
8629
+ });
8630
+ if (imported) {
8631
+ result.imported_count += 1;
8632
+ }
8633
+ }
8634
+ if (result.imported_count > 0 || result.reprojected_count > 0 || result.errors.length > 0) {
8635
+ void logger.info("hermes_session_sync_completed", { ...result });
8636
+ } else {
8637
+ void logger.debug("hermes_session_sync_completed", { ...result });
8638
+ }
8639
+ return result;
8640
+ }
8641
+ async function importHermesSession(input) {
8642
+ const { paths, store, candidate, existingHermesSessionIds } = input;
8643
+ const profile = await resolveConversationProfileTarget(
8644
+ paths,
8645
+ candidate.profileName
8646
+ );
8647
+ const sessionId = candidate.session.id;
8648
+ const messages = await readHermesSessionMessages(candidate);
8649
+ const now = (/* @__PURE__ */ new Date()).toISOString();
8650
+ const createdAt = isoFromHermesTime(candidate.session.started_at) ?? now;
8651
+ const updatedAt = isoFromHermesTime(candidate.session.last_active) ?? isoFromHermesTime(messages.at(-1)?.timestamp) ?? createdAt;
8652
+ const conversationId = createConversationId();
8653
+ const snapshot = {
8654
+ schema_version: 1,
8655
+ messages: toLinkMessages({
8656
+ conversationId,
8657
+ profileName: profile.profileName,
8658
+ profileUid: profile.profileUid,
8659
+ profileDisplayName: profile.profileDisplayName,
8660
+ sessionId,
8661
+ messages
8662
+ }),
8663
+ runs: []
8664
+ };
8665
+ const title = readString8(candidate.session, "title") ?? firstUserText(snapshot);
8666
+ const manifest = {
8667
+ id: conversationId,
8668
+ schema_version: 1,
8669
+ kind: "direct",
8670
+ title: normalizeTitle(title),
8671
+ title_source: title ? "hermes" : "default",
8672
+ status: "active",
8673
+ hermes_session_id: sessionId,
8674
+ hermes_session_ids: [sessionId],
8675
+ profile_uid: profile.profileUid,
8676
+ profile_name_snapshot: profile.profileName,
8677
+ profile: profile.profileName,
8678
+ created_at: createdAt,
8679
+ updated_at: updatedAt,
8680
+ last_event_seq: 0
8681
+ };
8682
+ await store.createConversation(manifest, snapshot);
8683
+ await store.appendEvent(conversationId, {
8684
+ type: "conversation.created",
8685
+ payload: {
8686
+ imported_from: "hermes",
8687
+ hermes_session_id: sessionId,
8688
+ profile: {
8689
+ uid: profile.profileUid,
8690
+ name: profile.profileName,
8691
+ display_name: profile.profileDisplayName,
8692
+ avatar_url: profile.profileAvatarUrl
8693
+ }
8694
+ }
8695
+ });
8696
+ for (const message of snapshot.messages) {
8697
+ await store.appendEvent(conversationId, {
8698
+ type: "message.created",
8699
+ message_id: message.id,
8700
+ payload: { message, imported_from: "hermes" },
8701
+ raw: message.raw
8702
+ });
8703
+ }
8704
+ const stats = buildConversationStats(
8705
+ await store.readManifest(conversationId),
8706
+ snapshot
8707
+ );
8708
+ await store.writeManifest({
8709
+ ...await store.readManifest(conversationId),
8710
+ stats
8711
+ });
8712
+ await upsertConversationStats(
8713
+ paths,
8714
+ toStatsIndexRecord(await store.readManifest(conversationId), stats)
8715
+ );
8716
+ existingHermesSessionIds.add(sessionId);
8717
+ return true;
8718
+ }
8719
+ async function reprojectExistingHermesConversation(input) {
8720
+ let changed = false;
8721
+ for (const conversationId of input.conversationIds) {
8722
+ const manifest = await input.store.readManifest(conversationId).catch(() => null);
8723
+ if (!manifest || manifest.status !== "active") {
8724
+ continue;
8725
+ }
8726
+ const snapshot = await input.store.readSnapshot(conversationId).catch(() => null);
8727
+ if (!snapshot) {
8728
+ continue;
8729
+ }
8730
+ const prefix = collectImportedHermesPrefix(snapshot);
8731
+ if (!prefix?.needsUpgrade || prefix.messages.length === 0) {
8732
+ continue;
8733
+ }
8734
+ const profile = await resolveConversationProfileTarget(
8735
+ input.paths,
8736
+ manifest.profile_name_snapshot ?? manifest.profile ?? input.candidate.profileName
8737
+ );
8738
+ const nextSnapshot = {
8739
+ ...snapshot,
8740
+ messages: [
8741
+ ...toLinkMessages({
8742
+ conversationId,
8743
+ profileName: profile.profileName,
8744
+ profileUid: profile.profileUid,
8745
+ profileDisplayName: profile.profileDisplayName,
8746
+ sessionId: input.candidate.session.id,
8747
+ messages: prefix.messages
8748
+ }),
8749
+ ...snapshot.messages.slice(prefix.endIndex)
8750
+ ]
8751
+ };
8752
+ const stats = buildConversationStats(manifest, nextSnapshot);
8753
+ await input.store.writeSnapshot(conversationId, nextSnapshot);
8754
+ await input.store.writeManifest({ ...manifest, stats });
8755
+ await upsertConversationStats(
8756
+ input.paths,
8757
+ toStatsIndexRecord({ ...manifest, stats }, stats)
8758
+ );
8759
+ changed = true;
8760
+ }
8761
+ return changed;
8762
+ }
8763
+ function collectImportedHermesPrefix(snapshot) {
8764
+ const rows = [];
8765
+ const seen = /* @__PURE__ */ new Set();
8766
+ let needsProjectionVersion = false;
8767
+ let hasToolMetadata = false;
8768
+ let endIndex = 0;
8769
+ for (; endIndex < snapshot.messages.length; endIndex += 1) {
8770
+ const message = snapshot.messages[endIndex];
8771
+ if (!isHermesImportedMessage(message)) {
8772
+ break;
8773
+ }
8774
+ if (message.hermes?.import_projection !== HERMES_IMPORT_PROJECTION_VERSION) {
8775
+ needsProjectionVersion = true;
8776
+ }
8777
+ if (message.role === "tool") {
8778
+ hasToolMetadata = true;
8779
+ }
8780
+ for (const row of readHermesRawMessageRows(message.raw)) {
8781
+ appendHermesRowOnce(rows, seen, row);
8782
+ if (hasHermesToolMetadata(row)) {
8783
+ hasToolMetadata = true;
8784
+ }
8785
+ }
8786
+ for (const event of message.agent_events ?? []) {
8787
+ for (const row of readHermesRowsFromAgentEvent(event)) {
8788
+ appendHermesRowOnce(rows, seen, row);
8789
+ if (hasHermesToolMetadata(row)) {
8790
+ hasToolMetadata = true;
8791
+ }
8792
+ }
8793
+ }
8794
+ }
8795
+ if (rows.length === 0 || endIndex === 0) {
8796
+ return null;
8797
+ }
8798
+ return {
8799
+ endIndex,
8800
+ messages: rows,
8801
+ needsUpgrade: needsProjectionVersion && hasToolMetadata
8802
+ };
8803
+ }
8804
+ function isHermesImportedMessage(message) {
8805
+ return message.hermes?.imported_from === "hermes" || message.raw?.format === "hermes-message" || message.raw?.format === "hermes-message-group";
8806
+ }
8807
+ function readHermesRowsFromAgentEvent(event) {
8808
+ if (event.raw?.format !== "hermes-message" && event.raw?.format !== "hermes-message-group") {
8809
+ return [];
8810
+ }
8811
+ const payload = toRecord7(event.raw.payload);
8812
+ const message = toRecord7(payload.message);
8813
+ if (normalizeMessageRole(readString8(message, "role") ?? void 0) === "tool") {
8814
+ return [message];
8815
+ }
8816
+ return readHermesRawMessageRows(event.raw).filter(
8817
+ (row) => Boolean(readString8(row, "role"))
8818
+ );
8819
+ }
8820
+ function appendHermesRowOnce(rows, seen, row) {
8821
+ const key = hermesRowKey(row, rows.length);
8822
+ if (seen.has(key)) {
8823
+ return;
8824
+ }
8825
+ seen.add(key);
8826
+ rows.push(row);
8827
+ }
8828
+ function hermesRowKey(row, fallbackIndex) {
8829
+ if (row.id !== void 0 && row.id !== null) {
8830
+ return `id:${row.id}`;
8831
+ }
8832
+ return `fallback:${fallbackIndex}:${row.role ?? ""}:${row.timestamp ?? ""}:${normalizeContent(row.content)}`;
8833
+ }
8834
+ function hasHermesToolMetadata(row) {
8835
+ return normalizeMessageRole(row.role) === "tool" || readHermesToolCalls(row).length > 0 || Boolean(readString8(row, "tool_call_id")) || Boolean(readString8(row, "tool_name"));
8836
+ }
8837
+ function toLinkMessages(input) {
8838
+ const linkMessages = [];
8839
+ let pendingToolCalls = [];
8840
+ const toolCallsById = /* @__PURE__ */ new Map();
8841
+ let currentAssistant = null;
8842
+ const finishAssistantTurn = () => {
8843
+ if (!currentAssistant) {
8844
+ return;
8845
+ }
8846
+ pendingToolCalls.forEach((pending, index) => {
8847
+ const event = projectHermesToolCallWithoutOutputEvent({
8848
+ conversationId: input.conversationId,
8849
+ messageId: pending.message.id,
8850
+ pending,
8851
+ index
8852
+ });
8853
+ if (event) {
8854
+ attachAgentEventToMessage(pending.message, event, event.created_at);
8855
+ }
8856
+ });
8857
+ pendingToolCalls = [];
8858
+ toolCallsById.clear();
8859
+ currentAssistant = null;
8860
+ };
8861
+ input.messages.forEach((message, index) => {
8862
+ const role = normalizeMessageRole(message.role);
8863
+ if (role === "tool") {
8864
+ const pending = consumePendingToolCall({
8865
+ toolMessage: message,
8866
+ pendingToolCalls,
8867
+ toolCallsById
8868
+ });
8869
+ let target = pending?.message ?? currentAssistant;
8870
+ let createdSynthetic = false;
8871
+ if (!target) {
8872
+ target = createSyntheticToolAssistantMessage({
8873
+ ...input,
8874
+ message,
8875
+ index
8876
+ });
8877
+ linkMessages.push(target);
8878
+ currentAssistant = target;
8879
+ createdSynthetic = true;
8880
+ }
8881
+ if (!createdSynthetic) {
8882
+ appendHermesRawMessage(target, message);
8883
+ rememberHermesMessageId(target, message);
8884
+ }
8885
+ const event = projectHermesToolCompletedEvent({
8886
+ conversationId: input.conversationId,
8887
+ messageId: target.id,
8888
+ sourceMessage: message,
8889
+ pending,
8890
+ index
8891
+ });
8892
+ if (event) {
8893
+ attachAgentEventToMessage(target, event, event.created_at);
8894
+ }
8895
+ return;
8896
+ }
8897
+ if (role === "assistant") {
8898
+ if (!currentAssistant) {
8899
+ currentAssistant = toLinkMessage({
8900
+ conversationId: input.conversationId,
8901
+ profileName: input.profileName,
8902
+ profileUid: input.profileUid,
8903
+ profileDisplayName: input.profileDisplayName,
8904
+ sessionId: input.sessionId,
8905
+ message,
8906
+ index
8907
+ });
8908
+ linkMessages.push(currentAssistant);
8909
+ } else {
8910
+ appendHermesRawMessage(currentAssistant, message);
8911
+ rememberHermesMessageId(currentAssistant, message);
8912
+ appendAssistantTextToMessage({
8913
+ message: currentAssistant,
8914
+ text: normalizeContent(message.content),
8915
+ updatedAt: isoFromHermesTime(message.timestamp) ?? currentAssistant.updated_at
8916
+ });
8917
+ }
8918
+ for (const toolCall of readHermesToolCalls(message)) {
8919
+ const pending = { message: currentAssistant, toolCall };
8920
+ pendingToolCalls.push(pending);
8921
+ if (toolCall.id) {
8922
+ toolCallsById.set(toolCall.id, pending);
8923
+ }
8924
+ const event = projectHermesToolStartedEvent({
8925
+ conversationId: input.conversationId,
8926
+ messageId: currentAssistant.id,
8927
+ sourceMessage: message,
8928
+ toolCall,
8929
+ index
8930
+ });
8931
+ if (event) {
8932
+ attachAgentEventToMessage(currentAssistant, event, event.created_at);
8933
+ }
8934
+ }
8935
+ return;
8936
+ }
8937
+ finishAssistantTurn();
8938
+ const linkMessage = toLinkMessage({
8939
+ conversationId: input.conversationId,
8940
+ profileName: input.profileName,
8941
+ profileUid: input.profileUid,
8942
+ profileDisplayName: input.profileDisplayName,
8943
+ sessionId: input.sessionId,
8944
+ message,
8945
+ index
8946
+ });
8947
+ linkMessages.push(linkMessage);
8948
+ });
8949
+ finishAssistantTurn();
8950
+ return linkMessages;
8951
+ }
8952
+ function consumePendingToolCall(input) {
8953
+ const toolCallId = readString8(input.toolMessage, "tool_call_id");
8954
+ const toolName = readString8(input.toolMessage, "tool_name");
8955
+ let pending = toolCallId ? input.toolCallsById.get(toolCallId) : void 0;
8956
+ if (!pending && toolName) {
8957
+ pending = input.pendingToolCalls.find(
8958
+ (item) => item.toolCall.name === toolName
8959
+ );
8960
+ }
8961
+ if (!pending && !toolCallId) {
8962
+ pending = input.pendingToolCalls[0];
8963
+ }
8964
+ if (!pending) {
8965
+ return void 0;
8966
+ }
8967
+ const index = input.pendingToolCalls.indexOf(pending);
8968
+ if (index >= 0) {
8969
+ input.pendingToolCalls.splice(index, 1);
8970
+ }
8971
+ if (pending.toolCall.id) {
8972
+ input.toolCallsById.delete(pending.toolCall.id);
8973
+ }
8974
+ return pending;
8975
+ }
8976
+ function createSyntheticToolAssistantMessage(input) {
8977
+ const message = toLinkMessage({
8978
+ conversationId: input.conversationId,
8979
+ profileName: input.profileName,
8980
+ profileUid: input.profileUid,
8981
+ profileDisplayName: input.profileDisplayName,
8982
+ sessionId: input.sessionId,
8983
+ message: {
8984
+ ...input.message,
8985
+ role: "assistant",
8986
+ content: null
8987
+ },
8988
+ index: input.index
8989
+ });
8990
+ message.raw = {
8991
+ format: "hermes-message",
8992
+ payload: input.message
8993
+ };
8994
+ return message;
8995
+ }
8996
+ function readHermesToolCalls(message) {
8997
+ const decoded = parseJsonValue(message.tool_calls) ?? message.tool_calls;
8998
+ const values = Array.isArray(decoded) ? decoded : decoded ? [decoded] : [];
8999
+ return values.map((value) => normalizeHermesToolCall(value)).filter(
9000
+ (toolCall) => Boolean(toolCall)
9001
+ );
9002
+ }
9003
+ function normalizeHermesToolCall(value) {
9004
+ const record = toRecord7(value);
9005
+ if (Object.keys(record).length === 0) {
9006
+ return null;
9007
+ }
9008
+ const fn = toRecord7(record.function);
9009
+ const id = readString8(record, "id") ?? readString8(record, "call_id") ?? readString8(record, "tool_call_id") ?? readString8(fn, "id") ?? void 0;
9010
+ const name = readString8(fn, "name") ?? readString8(record, "name") ?? readString8(record, "tool_name") ?? readString8(record, "tool") ?? "tool";
9011
+ const rawArguments = fn.arguments ?? record.arguments ?? record.args ?? record.input;
9012
+ return {
9013
+ ...id ? { id } : {},
9014
+ name,
9015
+ ...rawArguments === void 0 ? {} : { arguments: parseJsonValue(rawArguments) ?? rawArguments },
9016
+ raw: value
9017
+ };
9018
+ }
9019
+ function projectHermesToolStartedEvent(input) {
9020
+ const createdAt = isoFromHermesTime(input.sourceMessage.timestamp) ?? new Date(Date.now() + input.index).toISOString();
9021
+ return projectHermesAgentEvent({
9022
+ conversationId: input.conversationId,
9023
+ messageId: input.messageId,
9024
+ type: "tool.started",
9025
+ createdAt,
9026
+ seq: input.index + 1,
9027
+ payload: {
9028
+ type: "tool.started",
9029
+ tool: input.toolCall.name,
9030
+ tool_name: input.toolCall.name,
9031
+ name: input.toolCall.name,
9032
+ ...input.toolCall.id ? { tool_call_id: input.toolCall.id, id: input.toolCall.id } : {},
9033
+ ...input.toolCall.arguments === void 0 ? {} : { arguments: input.toolCall.arguments },
9034
+ tool_call: input.toolCall.raw
9035
+ },
9036
+ raw: {
9037
+ format: "hermes-message",
9038
+ payload: {
9039
+ message: input.sourceMessage,
9040
+ tool_call: input.toolCall.raw
9041
+ }
9042
+ }
9043
+ });
9044
+ }
9045
+ function projectHermesToolCompletedEvent(input) {
9046
+ const createdAt = isoFromHermesTime(input.sourceMessage.timestamp) ?? new Date(Date.now() + input.index).toISOString();
9047
+ const output = normalizeContent(input.sourceMessage.content);
9048
+ const parsedOutput = parseJsonValue(output);
9049
+ const toolCallId = readString8(input.sourceMessage, "tool_call_id") ?? input.pending?.toolCall.id;
9050
+ const toolName = readString8(input.sourceMessage, "tool_name") ?? input.pending?.toolCall.name ?? "tool";
9051
+ return projectHermesAgentEvent({
9052
+ conversationId: input.conversationId,
9053
+ messageId: input.messageId,
9054
+ type: "tool.completed",
9055
+ createdAt,
9056
+ seq: input.index + 1,
9057
+ payload: {
9058
+ type: "tool.completed",
9059
+ tool: toolName,
9060
+ tool_name: toolName,
9061
+ name: toolName,
9062
+ ...toolCallId ? { tool_call_id: toolCallId, id: toolCallId } : {},
9063
+ ...input.pending?.toolCall.arguments === void 0 ? {} : { arguments: input.pending.toolCall.arguments },
9064
+ output,
9065
+ content: output,
9066
+ result: parsedOutput ?? output,
9067
+ ...input.pending ? { tool_call: input.pending.toolCall.raw } : {}
9068
+ },
9069
+ raw: {
9070
+ format: "hermes-message",
9071
+ payload: {
9072
+ message: input.sourceMessage,
9073
+ ...input.pending ? { tool_call: input.pending.toolCall.raw } : {}
9074
+ }
9075
+ }
9076
+ });
9077
+ }
9078
+ function projectHermesToolCallWithoutOutputEvent(input) {
9079
+ return projectHermesAgentEvent({
9080
+ conversationId: input.conversationId,
9081
+ messageId: input.messageId,
9082
+ type: "tool.completed",
9083
+ createdAt: input.pending.message.updated_at,
9084
+ seq: input.index + 1,
9085
+ payload: {
9086
+ type: "tool.completed",
9087
+ tool: input.pending.toolCall.name,
9088
+ tool_name: input.pending.toolCall.name,
9089
+ name: input.pending.toolCall.name,
9090
+ ...input.pending.toolCall.id ? {
9091
+ tool_call_id: input.pending.toolCall.id,
9092
+ id: input.pending.toolCall.id
9093
+ } : {},
9094
+ ...input.pending.toolCall.arguments === void 0 ? {} : { arguments: input.pending.toolCall.arguments },
9095
+ tool_call: input.pending.toolCall.raw
9096
+ },
9097
+ raw: {
9098
+ format: "hermes-tool-call",
9099
+ payload: {
9100
+ tool_call: input.pending.toolCall.raw,
9101
+ note: "tool_output_not_found"
9102
+ }
9103
+ }
9104
+ });
9105
+ }
9106
+ function projectHermesAgentEvent(input) {
9107
+ const event = {
9108
+ seq: input.seq,
9109
+ type: input.type,
9110
+ conversation_id: input.conversationId,
9111
+ message_id: input.messageId,
9112
+ created_at: input.createdAt,
9113
+ payload: input.payload,
9114
+ raw: input.raw
9115
+ };
9116
+ return projectConversationAgentEvent(event);
9117
+ }
9118
+ function attachAgentEventToMessage(message, event, updatedAt) {
9119
+ ensureTextBlockForMessage(message);
9120
+ message.agent_events = upsertAgentEventProjection(
9121
+ message.agent_events ?? [],
9122
+ event
9123
+ );
9124
+ appendAgentEventBlock(message, event, updatedAt);
9125
+ message.updated_at = latestTimestamp(message.updated_at, updatedAt);
9126
+ }
9127
+ function appendAssistantTextToMessage(input) {
9128
+ const text = input.text;
9129
+ if (!text) {
9130
+ return;
9131
+ }
9132
+ appendTextPart(input.message, text);
9133
+ if (input.message.blocks?.length) {
9134
+ appendTextBlock(input.message, text, input.updatedAt);
9135
+ }
9136
+ input.message.updated_at = latestTimestamp(
9137
+ input.message.updated_at,
9138
+ input.updatedAt
9139
+ );
9140
+ }
9141
+ function appendTextPart(message, text) {
9142
+ const existing = message.parts.find((part) => part.type === "text");
9143
+ if (existing) {
9144
+ existing.text = joinImportedText(existing.text ?? "", text);
9145
+ return;
9146
+ }
9147
+ message.parts.push({ type: "text", text });
9148
+ }
9149
+ function appendTextBlock(message, text, updatedAt) {
9150
+ const blocks = [...message.blocks ?? []];
9151
+ const last = blocks.at(-1);
9152
+ if (last?.type === "text") {
9153
+ blocks[blocks.length - 1] = {
9154
+ ...last,
9155
+ text: joinImportedText(last.text, text),
9156
+ updated_at: updatedAt
9157
+ };
9158
+ } else {
9159
+ blocks.push({
9160
+ id: `text_${blocks.length + 1}`,
9161
+ type: "text",
9162
+ text,
9163
+ created_at: updatedAt,
9164
+ updated_at: updatedAt
9165
+ });
9166
+ }
9167
+ message.blocks = blocks;
9168
+ }
9169
+ function ensureTextBlockForMessage(message) {
9170
+ if (message.blocks?.length) {
9171
+ return;
9172
+ }
9173
+ const text = message.parts.filter((part) => part.type === "text" && part.text).map((part) => part.text).join("");
9174
+ if (!text) {
9175
+ return;
9176
+ }
9177
+ message.blocks = [
9178
+ {
9179
+ id: "text_1",
9180
+ type: "text",
9181
+ text,
9182
+ created_at: message.created_at,
9183
+ updated_at: message.updated_at
9184
+ }
9185
+ ];
9186
+ }
9187
+ function appendAgentEventBlock(message, event, updatedAt) {
9188
+ const blocks = [...message.blocks ?? []];
9189
+ const matchingIndex = blocks.findIndex((block) => {
9190
+ if (block.type !== "agent_events") {
9191
+ return false;
9192
+ }
9193
+ return upsertAgentEventProjection(block.events, event).length === block.events.length;
9194
+ });
9195
+ const targetIndex = matchingIndex >= 0 ? matchingIndex : blocks.at(-1)?.type === "agent_events" ? blocks.length - 1 : -1;
9196
+ if (targetIndex >= 0) {
9197
+ const block = blocks[targetIndex];
9198
+ if (block.type === "agent_events") {
9199
+ blocks[targetIndex] = {
9200
+ ...block,
9201
+ events: upsertAgentEventProjection(block.events, event),
9202
+ updated_at: updatedAt
9203
+ };
9204
+ }
9205
+ } else {
9206
+ blocks.push({
9207
+ id: `tools_${blocks.length + 1}`,
9208
+ type: "agent_events",
9209
+ events: [event],
9210
+ created_at: updatedAt,
9211
+ updated_at: updatedAt
9212
+ });
9213
+ }
9214
+ message.blocks = blocks;
9215
+ }
9216
+ function latestTimestamp(left, right) {
9217
+ const leftTime = Date.parse(left);
9218
+ const rightTime = Date.parse(right);
9219
+ if (Number.isNaN(leftTime)) {
9220
+ return right;
9221
+ }
9222
+ if (Number.isNaN(rightTime)) {
9223
+ return left;
9224
+ }
9225
+ return leftTime >= rightTime ? left : right;
9226
+ }
9227
+ async function readKnownHermesSessions(store) {
9228
+ const ids = /* @__PURE__ */ new Set();
9229
+ const conversationIdsBySessionId = /* @__PURE__ */ new Map();
9230
+ for (const conversationId of await store.listConversationIds()) {
9231
+ const manifest = await store.readManifest(conversationId).catch(() => null);
9232
+ if (!manifest) {
9233
+ continue;
9234
+ }
9235
+ if (manifest.hermes_session_id) {
9236
+ ids.add(manifest.hermes_session_id);
9237
+ rememberKnownHermesConversation(
9238
+ conversationIdsBySessionId,
9239
+ manifest.hermes_session_id,
9240
+ conversationId
9241
+ );
9242
+ }
9243
+ for (const sessionId of manifest.hermes_session_ids ?? []) {
9244
+ ids.add(sessionId);
9245
+ rememberKnownHermesConversation(
9246
+ conversationIdsBySessionId,
9247
+ sessionId,
9248
+ conversationId
9249
+ );
9250
+ }
9251
+ }
9252
+ return { ids, conversationIdsBySessionId };
9253
+ }
9254
+ function rememberKnownHermesConversation(map, sessionId, conversationId) {
9255
+ const current = map.get(sessionId) ?? [];
9256
+ if (!current.includes(conversationId)) {
9257
+ map.set(sessionId, [...current, conversationId]);
9258
+ }
9259
+ }
9260
+ async function discoverHermesProfileNames() {
9261
+ const names = /* @__PURE__ */ new Set([DEFAULT_PROFILE_NAME]);
9262
+ const profilesDir = path13.join(os4.homedir(), ".hermes", "profiles");
9263
+ const entries = await readdir5(profilesDir, { withFileTypes: true }).catch(
9264
+ (error) => {
9265
+ if (isNodeError9(error, "ENOENT")) {
9266
+ return [];
9267
+ }
9268
+ throw error;
9269
+ }
9270
+ );
9271
+ for (const entry of entries) {
9272
+ if (entry.isDirectory() && PROFILE_NAME_PATTERN3.test(entry.name)) {
9273
+ names.add(entry.name);
9274
+ }
9275
+ }
9276
+ return [...names].sort((left, right) => {
9277
+ if (left === DEFAULT_PROFILE_NAME) {
9278
+ return -1;
9279
+ }
9280
+ if (right === DEFAULT_PROFILE_NAME) {
9281
+ return 1;
9282
+ }
9283
+ return left.localeCompare(right);
9284
+ });
9285
+ }
9286
+ async function listProfileSessions(dbPath) {
9287
+ if (!await isFile(dbPath)) {
9288
+ return [];
9289
+ }
9290
+ let db = null;
9291
+ try {
9292
+ const { DatabaseSync } = nodeRequire3(
9293
+ "node:sqlite"
9294
+ );
9295
+ db = new DatabaseSync(dbPath, {
9296
+ readOnly: true,
9297
+ timeout: 1e3
9298
+ });
9299
+ const sessionColumns = readTableColumns(db, "sessions");
9300
+ if (!sessionColumns.has("id")) {
9301
+ return [];
9302
+ }
9303
+ const messageColumns = readTableColumns(db, "messages");
9304
+ const selectColumns = [...sessionColumns].map((column) => `s.${quoteIdentifier(column)}`).join(", ");
9305
+ const lastActiveSql = messageColumns.has("timestamp") ? `COALESCE(
9306
+ (SELECT MAX(m.timestamp) FROM messages m WHERE m.session_id = s.id),
9307
+ s.started_at,
9308
+ 0
9309
+ ) AS last_active` : "COALESCE(s.started_at, 0) AS last_active";
9310
+ const rows = db.prepare(
9311
+ `
9312
+ SELECT ${selectColumns}, ${lastActiveSql}
9313
+ FROM sessions s
9314
+ ORDER BY last_active DESC
9315
+ `
9316
+ ).all();
9317
+ return projectCompressionTips(rows);
9318
+ } finally {
9319
+ db?.close();
9320
+ }
9321
+ }
9322
+ function appendHermesRawMessage(message, row) {
9323
+ const rows = readHermesRawMessageRows(message.raw);
9324
+ message.raw = rows.length === 0 ? {
9325
+ format: "hermes-message",
9326
+ payload: row
9327
+ } : {
9328
+ format: "hermes-message-group",
9329
+ payload: { messages: [...rows, row] }
9330
+ };
9331
+ }
9332
+ function readHermesRawMessageRows(raw) {
9333
+ if (!raw) {
9334
+ return [];
9335
+ }
9336
+ if (raw.format === "hermes-message-group") {
9337
+ const payload = toRecord7(raw.payload);
9338
+ return Array.isArray(payload.messages) ? payload.messages.filter(
9339
+ (item) => typeof item === "object" && item !== null
9340
+ ) : [];
9341
+ }
9342
+ if (raw.format === "hermes-message") {
9343
+ return typeof raw.payload === "object" && raw.payload !== null ? [raw.payload] : [];
9344
+ }
9345
+ return [];
9346
+ }
9347
+ function rememberHermesMessageId(message, row) {
9348
+ if (row.id === void 0 || row.id === null) {
9349
+ return;
9350
+ }
9351
+ const existing = Array.isArray(message.hermes?.message_ids) ? message.hermes.message_ids : message.hermes?.message_id === void 0 ? [] : [message.hermes.message_id];
9352
+ const id = row.id;
9353
+ message.hermes = {
9354
+ ...message.hermes ?? {},
9355
+ message_ids: existing.includes(id) ? existing : [...existing, id]
9356
+ };
9357
+ }
9358
+ function joinImportedText(left, right) {
9359
+ if (!left) {
9360
+ return right;
9361
+ }
9362
+ if (!right) {
9363
+ return left;
9364
+ }
9365
+ if (/\s$/u.test(left) || /^\s/u.test(right)) {
9366
+ return `${left}${right}`;
9367
+ }
9368
+ return `${left}
9369
+
9370
+ ${right}`;
9371
+ }
9372
+ function projectCompressionTips(rows) {
9373
+ const byId = /* @__PURE__ */ new Map();
9374
+ const childrenByParent = /* @__PURE__ */ new Map();
9375
+ for (const row of rows) {
9376
+ const id = readString8(row, "id");
9377
+ if (!id) {
9378
+ continue;
9379
+ }
9380
+ byId.set(id, row);
9381
+ const parentId = readString8(row, "parent_session_id");
9382
+ if (parentId) {
9383
+ const children = childrenByParent.get(parentId) ?? [];
9384
+ children.push(row);
9385
+ childrenByParent.set(parentId, children);
9386
+ }
9387
+ }
9388
+ const projected = [];
9389
+ for (const row of rows) {
9390
+ const id = readString8(row, "id");
9391
+ if (!id || readString8(row, "parent_session_id")) {
9392
+ continue;
9393
+ }
9394
+ let tip = row;
9395
+ const visited = /* @__PURE__ */ new Set([id]);
9396
+ while (readString8(tip, "end_reason") === "compression") {
9397
+ const tipId2 = readString8(tip, "id");
9398
+ if (!tipId2) {
9399
+ break;
9400
+ }
9401
+ const next = (childrenByParent.get(tipId2) ?? []).filter((child) => readString8(child, "id")).sort(
9402
+ (left, right) => (readNumber2(right.last_active) ?? 0) - (readNumber2(left.last_active) ?? 0)
9403
+ )[0];
9404
+ const nextId = next ? readString8(next, "id") : null;
9405
+ if (!next || !nextId || visited.has(nextId)) {
9406
+ break;
9407
+ }
9408
+ tip = next;
9409
+ visited.add(nextId);
9410
+ }
9411
+ const tipId = readString8(tip, "id");
9412
+ if (tipId) {
9413
+ projected.push({
9414
+ ...tip,
9415
+ id: tipId,
9416
+ _lineage_root_id: id,
9417
+ started_at: readNumber2(row.started_at) ?? readNumber2(tip.started_at)
9418
+ });
9419
+ }
9420
+ }
9421
+ return projected;
9422
+ }
9423
+ async function readHermesSessionMessages(candidate) {
9424
+ const [dbMessages, jsonlMessages] = await Promise.all([
9425
+ readStateDbMessages(candidate.dbPath, candidate.session.id),
9426
+ readJsonlMessages(candidate.profileName, candidate.session.id)
9427
+ ]);
9428
+ return jsonlMessages.length > dbMessages.length ? jsonlMessages : dbMessages;
9429
+ }
9430
+ async function readStateDbMessages(dbPath, sessionId) {
9431
+ if (!await isFile(dbPath)) {
9432
+ return [];
9433
+ }
9434
+ let db = null;
9435
+ try {
9436
+ const { DatabaseSync } = nodeRequire3(
9437
+ "node:sqlite"
9438
+ );
9439
+ db = new DatabaseSync(dbPath, {
9440
+ readOnly: true,
9441
+ timeout: 1e3
9442
+ });
9443
+ const columns = readTableColumns(db, "messages");
9444
+ if (!columns.has("session_id") || !columns.has("role")) {
9445
+ return [];
9446
+ }
9447
+ const selectColumns = MESSAGE_COLUMNS.map(
9448
+ (column) => columns.has(column) ? quoteIdentifier(column) : `NULL AS ${column}`
9449
+ ).join(", ");
9450
+ return db.prepare(
9451
+ `
9452
+ SELECT ${selectColumns}
9453
+ FROM messages
9454
+ WHERE session_id = ?
9455
+ ORDER BY timestamp, id
9456
+ `
9457
+ ).all(sessionId);
9458
+ } catch {
9459
+ return [];
9460
+ } finally {
9461
+ db?.close();
9462
+ }
9463
+ }
9464
+ async function readJsonlMessages(profileName, sessionId) {
9465
+ if (!/^[A-Za-z0-9._:-]{1,160}$/u.test(sessionId)) {
9466
+ return [];
9467
+ }
9468
+ const profileDir = resolveHermesProfileDir(profileName);
9469
+ const sessionsDir = await readHermesSessionsDir(profileName).then((value) => value.sessionsDir).catch(() => path13.join(profileDir, "sessions"));
9470
+ const transcriptPath = path13.join(sessionsDir, `${sessionId}.jsonl`);
9471
+ const raw = await readFile8(transcriptPath, "utf8").catch((error) => {
9472
+ if (isNodeError9(error, "ENOENT")) {
9473
+ return "";
9474
+ }
9475
+ throw error;
9476
+ });
9477
+ if (!raw.trim()) {
9478
+ return [];
9479
+ }
9480
+ const rows = [];
9481
+ for (const line of raw.split(/\r?\n/u)) {
9482
+ if (!line.trim()) {
9483
+ continue;
9484
+ }
9485
+ try {
9486
+ const parsed = JSON.parse(line);
9487
+ const normalized = normalizeJsonlMessage(parsed);
9488
+ if (normalized) {
9489
+ rows.push(normalized);
9490
+ }
9491
+ } catch {
9492
+ continue;
9493
+ }
9494
+ }
9495
+ return rows;
9496
+ }
9497
+ function normalizeJsonlMessage(row) {
9498
+ const role = readString8(row, "role");
9499
+ if (!role) {
9500
+ return null;
9501
+ }
9502
+ const content = normalizeContent(row.content);
9503
+ const timestamp = readNumber2(row.timestamp) ?? readNumber2(row.created_at) ?? readNumber2(row.createdAt);
9504
+ return {
9505
+ ...row,
9506
+ role,
9507
+ content,
9508
+ timestamp: timestamp ?? void 0
9509
+ };
9510
+ }
9511
+ function toLinkMessage(input) {
9512
+ const role = normalizeMessageRole(input.message.role);
9513
+ const text = normalizeContent(input.message.content);
9514
+ const createdAt = isoFromHermesTime(input.message.timestamp) ?? new Date(Date.now() + input.index).toISOString();
9515
+ return {
9516
+ id: `msg_${randomUUID6().replaceAll("-", "")}`,
9517
+ schema_version: 1,
9518
+ conversation_id: input.conversationId,
9519
+ role,
9520
+ status: "completed",
9521
+ created_at: createdAt,
9522
+ updated_at: createdAt,
9523
+ sender: senderForRole({
9524
+ role,
9525
+ profileName: input.profileName,
9526
+ profileUid: input.profileUid,
9527
+ profileDisplayName: input.profileDisplayName
9528
+ }),
9529
+ parts: text ? [{ type: "text", text }] : [],
9530
+ attachments: [],
9531
+ hermes: {
9532
+ session_id: input.sessionId,
9533
+ message_id: input.message.id,
9534
+ imported_from: "hermes",
9535
+ import_projection: HERMES_IMPORT_PROJECTION_VERSION
9536
+ },
9537
+ raw: {
9538
+ format: "hermes-message",
9539
+ payload: input.message
9540
+ }
9541
+ };
9542
+ }
9543
+ function senderForRole(input) {
9544
+ switch (input.role) {
9545
+ case "user":
9546
+ return { id: "hermes_user", type: "human", display_name: "Me" };
9547
+ case "assistant":
9548
+ return {
9549
+ id: `agent_${input.profileName}`,
9550
+ type: "agent",
9551
+ display_name: input.profileDisplayName,
9552
+ profile_uid: input.profileUid,
9553
+ profile: input.profileName
9554
+ };
9555
+ case "tool":
9556
+ return { id: "hermes_tool", type: "tool", display_name: "Tool" };
9557
+ case "system":
9558
+ return { id: "hermes_system", type: "system", display_name: "System" };
9559
+ }
9560
+ }
9561
+ function firstUserText(snapshot) {
9562
+ return snapshot.messages.find((message) => message.role === "user")?.parts.find((part) => part.type === "text")?.text?.slice(0, 80);
9563
+ }
9564
+ function normalizeTitle(value) {
9565
+ const normalized = value?.replace(/\s+/gu, " ").trim();
9566
+ return normalized || DEFAULT_CONVERSATION_TITLE;
9567
+ }
9568
+ function normalizeMessageRole(value) {
9569
+ switch (value?.trim().toLowerCase()) {
9570
+ case "user":
9571
+ return "user";
9572
+ case "assistant":
9573
+ return "assistant";
9574
+ case "tool":
9575
+ return "tool";
9576
+ case "system":
9577
+ return "system";
9578
+ default:
9579
+ return "system";
9580
+ }
9581
+ }
9582
+ function normalizeContent(value) {
9583
+ if (typeof value === "string") {
9584
+ return value;
9585
+ }
9586
+ if (Array.isArray(value)) {
9587
+ return value.map((item) => {
9588
+ if (typeof item === "string") {
9589
+ return item;
9590
+ }
9591
+ if (typeof item === "object" && item !== null) {
9592
+ return readString8(item, "text") ?? "";
9593
+ }
9594
+ return "";
9595
+ }).filter(Boolean).join("");
9596
+ }
9597
+ return "";
9598
+ }
9599
+ function parseJsonValue(value) {
9600
+ if (typeof value !== "string") {
9601
+ return void 0;
9602
+ }
9603
+ const trimmed = value.trim();
9604
+ if (!trimmed) {
9605
+ return void 0;
8491
9606
  }
8492
- removeConversationAttachments(conversationId) {
8493
- return rm5(path12.join(this.conversationDir(conversationId), "attachments"), {
8494
- recursive: true,
8495
- force: true
8496
- });
9607
+ try {
9608
+ return JSON.parse(trimmed);
9609
+ } catch {
9610
+ return void 0;
8497
9611
  }
8498
- conversationDir(conversationId) {
8499
- assertValidConversationId(conversationId);
8500
- return path12.join(this.paths.conversationsDir, conversationId);
9612
+ }
9613
+ function toRecord7(value) {
9614
+ return typeof value === "object" && value !== null ? value : {};
9615
+ }
9616
+ function isDeletedSession(session) {
9617
+ return readBoolean(session.deleted) || readBoolean(session.is_deleted) || Boolean(readString8(session, "deleted_at")) || ["deleted", "removed"].includes(readString8(session, "status") ?? "");
9618
+ }
9619
+ function isHiddenSession(session) {
9620
+ const source = readString8(session, "source")?.toLowerCase();
9621
+ const status = readString8(session, "status")?.toLowerCase();
9622
+ const visibility = readString8(session, "visibility")?.toLowerCase();
9623
+ return Boolean(source && HIDDEN_SESSION_SOURCES.has(source)) || readBoolean(session.hidden) || readBoolean(session.archived) || Boolean(readString8(session, "archived_at")) || status === "hidden" || status === "archived" || visibility === "hidden" || visibility === "hide";
9624
+ }
9625
+ function readTableColumns(db, tableName) {
9626
+ try {
9627
+ const rows = db.prepare(`PRAGMA table_info(${quoteIdentifier(tableName)})`).all();
9628
+ return new Set(
9629
+ rows.map((row) => typeof row.name === "string" ? row.name : "").filter(Boolean)
9630
+ );
9631
+ } catch {
9632
+ return /* @__PURE__ */ new Set();
8501
9633
  }
8502
- manifestPath(conversationId) {
8503
- return path12.join(this.conversationDir(conversationId), "manifest.json");
9634
+ }
9635
+ function quoteIdentifier(value) {
9636
+ return `"${value.replaceAll('"', '""')}"`;
9637
+ }
9638
+ async function isFile(filePath) {
9639
+ return stat7(filePath).then((value) => value.isFile()).catch((error) => {
9640
+ if (isNodeError9(error, "ENOENT")) {
9641
+ return false;
9642
+ }
9643
+ throw error;
9644
+ });
9645
+ }
9646
+ function createConversationId() {
9647
+ return `conv_${randomUUID6().replaceAll("-", "")}`;
9648
+ }
9649
+ function isoFromHermesTime(value) {
9650
+ const numeric = readNumber2(value);
9651
+ if (!numeric || numeric <= 0) {
9652
+ return void 0;
8504
9653
  }
8505
- snapshotPath(conversationId) {
8506
- return path12.join(this.conversationDir(conversationId), "snapshot.json");
9654
+ const millis = numeric > 1e10 ? numeric : numeric * 1e3;
9655
+ return new Date(millis).toISOString();
9656
+ }
9657
+ function readString8(payload, key) {
9658
+ const value = payload[key];
9659
+ return typeof value === "string" && value.trim() ? value.trim() : null;
9660
+ }
9661
+ function readNumber2(value) {
9662
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
9663
+ }
9664
+ function readBoolean(value) {
9665
+ if (value === true || value === 1) {
9666
+ return true;
8507
9667
  }
8508
- eventsPath(conversationId) {
8509
- return path12.join(this.conversationDir(conversationId), "events.ndjson");
9668
+ if (typeof value === "string") {
9669
+ return ["1", "true", "yes", "on"].includes(value.trim().toLowerCase());
8510
9670
  }
8511
- };
8512
- function createEmptySnapshot2() {
8513
- return { schema_version: 1, messages: [], runs: [] };
9671
+ return false;
8514
9672
  }
8515
- function isNodeError8(error, code) {
9673
+ function isNodeError9(error, code) {
8516
9674
  return typeof error === "object" && error !== null && "code" in error && error.code === code;
8517
9675
  }
8518
9676
 
8519
9677
  // 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";
9678
+ import { lstat, readFile as readFile9, readdir as readdir6, stat as stat8 } from "fs/promises";
9679
+ import path14 from "path";
8522
9680
  var MAX_IMPORTED_BLOB_BYTES = 100 * 1024 * 1024;
8523
9681
  var MAX_MEDIA_IMPORT_FAILURES = 20;
8524
9682
  var MAX_DELIVERY_FILES = 50;
@@ -8589,16 +9747,16 @@ var SUPPORTED_DELIVERY_EXTENSIONS = /* @__PURE__ */ new Set([
8589
9747
  ".m4a"
8590
9748
  ]);
8591
9749
  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)) {
9750
+ const resolvedDir = path14.resolve(stagingDir);
9751
+ const relative = path14.relative(path14.resolve(paths.conversationsDir), resolvedDir);
9752
+ if (!relative || relative.startsWith("..") || path14.isAbsolute(relative)) {
8595
9753
  throw new LinkHttpError(
8596
9754
  400,
8597
9755
  "delivery_staging_invalid",
8598
9756
  "delivery staging directory must be inside Hermes Link conversations"
8599
9757
  );
8600
9758
  }
8601
- const segments = relative.split(path13.sep);
9759
+ const segments = relative.split(path14.sep);
8602
9760
  if (segments.length !== 3 || segments[1] !== DELIVERY_STAGING_SEGMENT || !segments[0] || !segments[2]) {
8603
9761
  throw new LinkHttpError(
8604
9762
  400,
@@ -8614,7 +9772,7 @@ function resolveDeliveryStagingTarget(paths, stagingDir) {
8614
9772
  }
8615
9773
  async function collectStagedDeliveryReferences(stagingDir) {
8616
9774
  const directoryStat = await lstat(stagingDir).catch((error) => {
8617
- if (isNodeError9(error, "ENOENT")) {
9775
+ if (isNodeError10(error, "ENOENT")) {
8618
9776
  throw new LinkHttpError(
8619
9777
  404,
8620
9778
  "delivery_staging_not_found",
@@ -8630,11 +9788,11 @@ async function collectStagedDeliveryReferences(stagingDir) {
8630
9788
  "delivery staging path is not a directory"
8631
9789
  );
8632
9790
  }
8633
- const entries = await readdir5(stagingDir, { withFileTypes: true });
9791
+ const entries = await readdir6(stagingDir, { withFileTypes: true });
8634
9792
  return entries.filter((entry) => entry.isFile() && !entry.name.startsWith(".")).filter((entry) => isSupportedDeliveryFilename(entry.name)).sort(
8635
9793
  (left, right) => left.name.localeCompare(right.name, "en", { numeric: true })
8636
9794
  ).slice(0, MAX_DELIVERY_FILES).map((entry) => {
8637
- const sourcePath = path13.join(stagingDir, entry.name);
9795
+ const sourcePath = path14.join(stagingDir, entry.name);
8638
9796
  const mime = inferMimeType(sourcePath);
8639
9797
  return {
8640
9798
  path: sourcePath,
@@ -8713,7 +9871,7 @@ async function importMediaReferencesForMessage(deps, input) {
8713
9871
  };
8714
9872
  }
8715
9873
  assistant.hermes = {
8716
- ...toRecord7(assistant.hermes),
9874
+ ...toRecord8(assistant.hermes),
8717
9875
  imported_media_source_keys: [...importedSourceKeys],
8718
9876
  media_import_failed_source_keys: [...failedSourceKeys],
8719
9877
  media_import_failures: [...failureRecordsByKey.values()].slice(
@@ -8745,16 +9903,16 @@ async function importMediaReferencesForMessage(deps, input) {
8745
9903
  };
8746
9904
  }
8747
9905
  function readMediaImportFailures(message) {
8748
- const hermes = toRecord7(message.hermes);
9906
+ const hermes = toRecord8(message.hermes);
8749
9907
  const failures = hermes.media_import_failures;
8750
9908
  if (!Array.isArray(failures)) {
8751
9909
  return [];
8752
9910
  }
8753
9911
  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");
9912
+ const record = toRecord8(item);
9913
+ const key = readString9(record, "key");
9914
+ const filename = readString9(record, "filename");
9915
+ const reason = readString9(record, "reason");
8758
9916
  if (!key || !filename || !reason) {
8759
9917
  return [];
8760
9918
  }
@@ -8763,13 +9921,13 @@ function readMediaImportFailures(message) {
8763
9921
  key,
8764
9922
  filename,
8765
9923
  reason,
8766
- ...readString8(record, "code") ? { code: readString8(record, "code") } : {}
9924
+ ...readString9(record, "code") ? { code: readString9(record, "code") } : {}
8767
9925
  }
8768
9926
  ];
8769
9927
  });
8770
9928
  }
8771
9929
  function readFailedMediaSourceKeys(message) {
8772
- const hermes = toRecord7(message.hermes);
9930
+ const hermes = toRecord8(message.hermes);
8773
9931
  const keys = hermes.media_import_failed_source_keys;
8774
9932
  if (!Array.isArray(keys)) {
8775
9933
  return /* @__PURE__ */ new Set();
@@ -8794,8 +9952,8 @@ function emptyImportResult(input) {
8794
9952
  }
8795
9953
  async function writeBlobFromFile(deps, conversationId, source) {
8796
9954
  const sourcePath = resolveMediaSourcePath(source.path);
8797
- const fileStat = await stat7(sourcePath).catch((error) => {
8798
- if (isNodeError9(error, "ENOENT")) {
9955
+ const fileStat = await stat8(sourcePath).catch((error) => {
9956
+ if (isNodeError10(error, "ENOENT")) {
8799
9957
  throw new LinkHttpError(
8800
9958
  404,
8801
9959
  "media_source_not_found",
@@ -8819,8 +9977,8 @@ async function writeBlobFromFile(deps, conversationId, source) {
8819
9977
  );
8820
9978
  }
8821
9979
  return deps.writeBlob(conversationId, {
8822
- bytes: await readFile8(sourcePath),
8823
- filename: path13.basename(sourcePath),
9980
+ bytes: await readFile9(sourcePath),
9981
+ filename: path14.basename(sourcePath),
8824
9982
  mime: source.mime ?? inferMimeType(sourcePath)
8825
9983
  });
8826
9984
  }
@@ -8829,25 +9987,25 @@ function describeMediaImportFailure(reference, sourceKey, error) {
8829
9987
  key: sourceKey,
8830
9988
  filename: sanitizeFilename(reference.path, "attachment"),
8831
9989
  reason: error instanceof Error ? error.message : String(error),
8832
- ...isNodeError9(error) && error.code ? { code: error.code } : {}
9990
+ ...isNodeError10(error) && error.code ? { code: error.code } : {}
8833
9991
  };
8834
9992
  }
8835
9993
  function isSupportedDeliveryFilename(filename) {
8836
- return SUPPORTED_DELIVERY_EXTENSIONS.has(path13.extname(filename).toLowerCase());
9994
+ return SUPPORTED_DELIVERY_EXTENSIONS.has(path14.extname(filename).toLowerCase());
8837
9995
  }
8838
- function readString8(payload, key) {
9996
+ function readString9(payload, key) {
8839
9997
  const value = payload[key];
8840
9998
  return typeof value === "string" && value.trim() ? value.trim() : null;
8841
9999
  }
8842
- function toRecord7(value) {
10000
+ function toRecord8(value) {
8843
10001
  return typeof value === "object" && value !== null ? value : {};
8844
10002
  }
8845
- function isNodeError9(error, code) {
10003
+ function isNodeError10(error, code) {
8846
10004
  return typeof error === "object" && error !== null && "code" in error && (code === void 0 || error.code === code);
8847
10005
  }
8848
10006
 
8849
10007
  // src/conversations/run-lifecycle.ts
8850
- import { readdir as readdir6 } from "fs/promises";
10008
+ import { readdir as readdir7 } from "fs/promises";
8851
10009
 
8852
10010
  // src/hermes/api-server.ts
8853
10011
  async function listHermesModels(options = {}) {
@@ -8970,7 +10128,7 @@ async function createHermesRun(input, options = {}) {
8970
10128
  );
8971
10129
  }
8972
10130
  const payload = await readJsonResponse(response);
8973
- const runId = readString9(payload, "run_id") ?? readString9(payload, "runId") ?? readString9(payload, "id");
10131
+ const runId = readString10(payload, "run_id") ?? readString10(payload, "runId") ?? readString10(payload, "id");
8974
10132
  if (!runId) {
8975
10133
  throw new LinkHttpError(
8976
10134
  502,
@@ -9083,10 +10241,10 @@ async function cancelHermesRun(runId, options = {}) {
9083
10241
  );
9084
10242
  }
9085
10243
  }
9086
- async function callHermesApi(path24, init, options) {
10244
+ async function callHermesApi(path25, init, options) {
9087
10245
  const method = init.method ?? "GET";
9088
10246
  const startedAt = Date.now();
9089
- void options.logger?.debug("hermes_api_request_started", { method, path: path24 });
10247
+ void options.logger?.debug("hermes_api_request_started", { method, path: path25 });
9090
10248
  const availability = await ensureHermesApiServerAvailable({
9091
10249
  fetchImpl: options.fetchImpl,
9092
10250
  logger: options.logger,
@@ -9094,21 +10252,21 @@ async function callHermesApi(path24, init, options) {
9094
10252
  });
9095
10253
  let config = availability.configResult.apiServer;
9096
10254
  const fetcher = options.fetchImpl ?? fetch;
9097
- const request = () => fetchHermesApi(fetcher, config, path24, init, options);
10255
+ const request = () => fetchHermesApi(fetcher, config, path25, init, options);
9098
10256
  let response;
9099
10257
  try {
9100
10258
  response = await request();
9101
10259
  } catch (error) {
9102
- logHermesApiError(options.logger, method, path24, startedAt, error);
10260
+ logHermesApiError(options.logger, method, path25, startedAt, error);
9103
10261
  throw error;
9104
10262
  }
9105
10263
  if (response.status !== 401) {
9106
- logHermesApiResponse(options.logger, method, path24, startedAt, response);
10264
+ logHermesApiResponse(options.logger, method, path25, startedAt, response);
9107
10265
  return response;
9108
10266
  }
9109
10267
  void options.logger?.warn("hermes_api_request_retrying_after_401", {
9110
10268
  method,
9111
- path: path24,
10269
+ path: path25,
9112
10270
  duration_ms: Date.now() - startedAt
9113
10271
  });
9114
10272
  const refreshedAvailability = await ensureHermesApiServerAvailable({
@@ -9121,20 +10279,20 @@ async function callHermesApi(path24, init, options) {
9121
10279
  try {
9122
10280
  response = await request();
9123
10281
  } catch (error) {
9124
- logHermesApiError(options.logger, method, path24, startedAt, error);
10282
+ logHermesApiError(options.logger, method, path25, startedAt, error);
9125
10283
  throw error;
9126
10284
  }
9127
- logHermesApiResponse(options.logger, method, path24, startedAt, response);
10285
+ logHermesApiResponse(options.logger, method, path25, startedAt, response);
9128
10286
  return response;
9129
10287
  }
9130
- async function fetchHermesApi(fetcher, config, path24, init, options) {
10288
+ async function fetchHermesApi(fetcher, config, path25, init, options) {
9131
10289
  const headers = new Headers(init.headers);
9132
10290
  headers.set("accept", headers.get("accept") ?? "application/json");
9133
10291
  if (config.key) {
9134
10292
  headers.set("x-api-key", config.key);
9135
10293
  headers.set("authorization", `Bearer ${config.key}`);
9136
10294
  }
9137
- return await fetcher(`http://127.0.0.1:${config.port}${path24}`, {
10295
+ return await fetcher(`http://127.0.0.1:${config.port}${path25}`, {
9138
10296
  ...init,
9139
10297
  headers
9140
10298
  }).catch((error) => {
@@ -9142,7 +10300,7 @@ async function fetchHermesApi(fetcher, config, path24, init, options) {
9142
10300
  throw error;
9143
10301
  }
9144
10302
  void options.logger?.warn("hermes_api_server_connect_failed", {
9145
- path: path24,
10303
+ path: path25,
9146
10304
  port: config.port ?? null,
9147
10305
  error: error instanceof Error ? error.message : String(error)
9148
10306
  });
@@ -9153,10 +10311,10 @@ async function fetchHermesApi(fetcher, config, path24, init, options) {
9153
10311
  );
9154
10312
  });
9155
10313
  }
9156
- function logHermesApiResponse(logger, method, path24, startedAt, response) {
10314
+ function logHermesApiResponse(logger, method, path25, startedAt, response) {
9157
10315
  const fields = {
9158
10316
  method,
9159
- path: path24,
10317
+ path: path25,
9160
10318
  status: response.status,
9161
10319
  duration_ms: Date.now() - startedAt
9162
10320
  };
@@ -9176,10 +10334,10 @@ async function logHermesApiFailureResponse(logger, fields, response) {
9176
10334
  ...upstreamError ? { upstream_error: upstreamError } : {}
9177
10335
  });
9178
10336
  }
9179
- function logHermesApiError(logger, method, path24, startedAt, error) {
10337
+ function logHermesApiError(logger, method, path25, startedAt, error) {
9180
10338
  void logger?.warn("hermes_api_request_failed", {
9181
10339
  method,
9182
- path: path24,
10340
+ path: path25,
9183
10341
  duration_ms: Date.now() - startedAt,
9184
10342
  ...error instanceof LinkHttpError ? { status: error.status, code: error.code } : {},
9185
10343
  error: error instanceof Error ? error.message : String(error)
@@ -9228,23 +10386,23 @@ function isRecord(value) {
9228
10386
  }
9229
10387
  function readUpstreamMessage(payload, raw) {
9230
10388
  const error = typeof payload?.error === "object" && payload.error !== null ? payload.error : null;
9231
- const message = readString9(error ?? {}, "message") ?? readString9(payload ?? {}, "message");
10389
+ const message = readString10(error ?? {}, "message") ?? readString10(payload ?? {}, "message");
9232
10390
  if (message) {
9233
10391
  return message;
9234
10392
  }
9235
10393
  const body = raw.trim().replace(/\s+/gu, " ").slice(0, 500);
9236
10394
  return body || "empty response body";
9237
10395
  }
9238
- function readString9(payload, key) {
10396
+ function readString10(payload, key) {
9239
10397
  const value = payload[key];
9240
10398
  return typeof value === "string" && value.trim() ? value.trim() : null;
9241
10399
  }
9242
10400
 
9243
10401
  // src/conversations/history-builder.ts
9244
- import { readFile as readFile9, stat as stat8 } from "fs/promises";
9245
- import { createRequire as createRequire3 } from "module";
9246
- import path14 from "path";
9247
- var nodeRequire3 = createRequire3(import.meta.url);
10402
+ import { readFile as readFile10, stat as stat9 } from "fs/promises";
10403
+ import { createRequire as createRequire4 } from "module";
10404
+ import path15 from "path";
10405
+ var nodeRequire4 = createRequire4(import.meta.url);
9248
10406
  var HISTORY_ROLES = /* @__PURE__ */ new Set(["user", "assistant"]);
9249
10407
  var HERMES_HISTORY_COLUMNS = [
9250
10408
  "role",
@@ -9305,13 +10463,13 @@ async function readHermesTranscriptHistory(sessionId, profileName) {
9305
10463
  }
9306
10464
  const normalizedProfileName = isValidProfileName2(profileName) ? profileName : "default";
9307
10465
  const profileDir = resolveHermesProfileDir(normalizedProfileName);
9308
- const dbPath = path14.join(profileDir, "state.db");
10466
+ const dbPath = path15.join(profileDir, "state.db");
9309
10467
  const sessionsDirConfig = await readHermesSessionsDir(normalizedProfileName).then((value) => ({
9310
10468
  sessionsDir: value.sessionsDir,
9311
10469
  configured: value.configured,
9312
10470
  configError: false
9313
10471
  })).catch(() => ({
9314
- sessionsDir: path14.join(profileDir, "sessions"),
10472
+ sessionsDir: path15.join(profileDir, "sessions"),
9315
10473
  configured: false,
9316
10474
  configError: true
9317
10475
  }));
@@ -9351,8 +10509,8 @@ async function readHermesTranscriptHistory(sessionId, profileName) {
9351
10509
  };
9352
10510
  }
9353
10511
  async function readHermesStateDbHistory(dbPath, sessionId) {
9354
- const exists = await stat8(dbPath).then((value) => value.isFile()).catch((error) => {
9355
- if (isNodeError10(error, "ENOENT")) {
10512
+ const exists = await stat9(dbPath).then((value) => value.isFile()).catch((error) => {
10513
+ if (isNodeError11(error, "ENOENT")) {
9356
10514
  return false;
9357
10515
  }
9358
10516
  throw error;
@@ -9369,9 +10527,9 @@ async function readHermesJsonlHistory(sessionsDir, sessionId) {
9369
10527
  if (!isValidSessionFileStem(sessionId)) {
9370
10528
  return empty;
9371
10529
  }
9372
- const transcriptPath = path14.join(sessionsDir, `${sessionId}.jsonl`);
9373
- const raw = await readFile9(transcriptPath, "utf8").catch((error) => {
9374
- if (isNodeError10(error, "ENOENT")) {
10530
+ const transcriptPath = path15.join(sessionsDir, `${sessionId}.jsonl`);
10531
+ const raw = await readFile10(transcriptPath, "utf8").catch((error) => {
10532
+ if (isNodeError11(error, "ENOENT")) {
9375
10533
  return "";
9376
10534
  }
9377
10535
  throw error;
@@ -9406,14 +10564,14 @@ async function readHermesJsonlHistory(sessionsDir, sessionId) {
9406
10564
  function readHistoryRows(dbPath, sessionId) {
9407
10565
  let db = null;
9408
10566
  try {
9409
- const { DatabaseSync } = nodeRequire3(
10567
+ const { DatabaseSync } = nodeRequire4(
9410
10568
  "node:sqlite"
9411
10569
  );
9412
10570
  db = new DatabaseSync(dbPath, {
9413
10571
  readOnly: true,
9414
10572
  timeout: 1e3
9415
10573
  });
9416
- const columns = readTableColumns(db, "messages");
10574
+ const columns = readTableColumns2(db, "messages");
9417
10575
  if (!columns.has("role") || !columns.has("content")) {
9418
10576
  return [];
9419
10577
  }
@@ -9518,7 +10676,7 @@ function normalizeHistoryMessage(role, content) {
9518
10676
  if (role !== "user" && role !== "assistant") {
9519
10677
  return null;
9520
10678
  }
9521
- const text = normalizeContent(content).trim();
10679
+ const text = normalizeContent2(content).trim();
9522
10680
  if (!text) {
9523
10681
  return null;
9524
10682
  }
@@ -9529,7 +10687,7 @@ function normalizeHistoryRecord(record) {
9529
10687
  if (!role) {
9530
10688
  return null;
9531
10689
  }
9532
- const content = normalizeContent(record.content);
10690
+ const content = normalizeContent2(record.content);
9533
10691
  const message = { role, content };
9534
10692
  assignString(message, "tool_call_id", record.tool_call_id);
9535
10693
  assignString(message, "tool_name", record.tool_name);
@@ -9549,7 +10707,7 @@ function normalizeHistoryRecord(record) {
9549
10707
  }
9550
10708
  return message;
9551
10709
  }
9552
- function normalizeContent(value) {
10710
+ function normalizeContent2(value) {
9553
10711
  if (typeof value === "string") {
9554
10712
  return value;
9555
10713
  }
@@ -9591,12 +10749,12 @@ function hasReplayMetadata(message) {
9591
10749
  message.tool_call_id || message.tool_name || message.tool_calls || message.reasoning || message.reasoning_content || message.reasoning_details || message.codex_reasoning_items
9592
10750
  );
9593
10751
  }
9594
- function readTableColumns(db, table) {
10752
+ function readTableColumns2(db, table) {
9595
10753
  return new Set(
9596
10754
  db.prepare(`PRAGMA table_info(${table})`).all().map((row) => row.name).filter((name) => typeof name === "string")
9597
10755
  );
9598
10756
  }
9599
- function isNodeError10(error, code) {
10757
+ function isNodeError11(error, code) {
9600
10758
  return typeof error === "object" && error !== null && "code" in error && error.code === code;
9601
10759
  }
9602
10760
  function isValidProfileName2(value) {
@@ -9614,8 +10772,8 @@ function normalizeProfileForCompare(value) {
9614
10772
 
9615
10773
  // src/hermes/stt.ts
9616
10774
  import { execFile as execFile3 } from "child_process";
9617
- import { access as access2, readFile as readFile10, stat as stat9 } from "fs/promises";
9618
- import path15 from "path";
10775
+ import { access as access2, readFile as readFile11, stat as stat10 } from "fs/promises";
10776
+ import path16 from "path";
9619
10777
  import { promisify as promisify3 } from "util";
9620
10778
  var execFileAsync3 = promisify3(execFile3);
9621
10779
  var STT_RESULT_PREFIX = "__HERMES_LINK_STT__";
@@ -9710,7 +10868,7 @@ async function buildHermesSttEnv(profileName) {
9710
10868
  };
9711
10869
  const devSource = await findDevHermesAgentSource();
9712
10870
  if (devSource) {
9713
- env.PYTHONPATH = [devSource, env.PYTHONPATH].filter(Boolean).join(path15.delimiter);
10871
+ env.PYTHONPATH = [devSource, env.PYTHONPATH].filter(Boolean).join(path16.delimiter);
9714
10872
  }
9715
10873
  return env;
9716
10874
  }
@@ -9757,14 +10915,14 @@ async function resolveHermesPythonCommand() {
9757
10915
  };
9758
10916
  }
9759
10917
  async function resolveExecutablePath(command) {
9760
- if (path15.isAbsolute(command)) {
10918
+ if (path16.isAbsolute(command)) {
9761
10919
  return await isExecutableFile(command) ? command : null;
9762
10920
  }
9763
10921
  const pathEnv = process.env.PATH ?? "";
9764
10922
  const extensions = process.platform === "win32" ? (process.env.PATHEXT ?? ".EXE;.CMD;.BAT").split(";") : [""];
9765
- for (const dir of pathEnv.split(path15.delimiter)) {
10923
+ for (const dir of pathEnv.split(path16.delimiter)) {
9766
10924
  for (const extension of extensions) {
9767
- const candidate = path15.join(dir, `${command}${extension}`);
10925
+ const candidate = path16.join(dir, `${command}${extension}`);
9768
10926
  if (await isExecutableFile(candidate)) {
9769
10927
  return candidate;
9770
10928
  }
@@ -9774,7 +10932,7 @@ async function resolveExecutablePath(command) {
9774
10932
  }
9775
10933
  async function isExecutableFile(filePath) {
9776
10934
  try {
9777
- const info = await stat9(filePath);
10935
+ const info = await stat10(filePath);
9778
10936
  if (!info.isFile()) {
9779
10937
  return false;
9780
10938
  }
@@ -9785,7 +10943,7 @@ async function isExecutableFile(filePath) {
9785
10943
  }
9786
10944
  }
9787
10945
  async function readShebang(filePath) {
9788
- const raw = await readFile10(filePath, "utf8").catch(() => "");
10946
+ const raw = await readFile11(filePath, "utf8").catch(() => "");
9789
10947
  const firstLine = raw.split(/\r?\n/u)[0]?.trim() ?? "";
9790
10948
  return firstLine.startsWith("#!") ? firstLine.slice(2).trim() : null;
9791
10949
  }
@@ -9804,8 +10962,8 @@ function shebangToPythonCommand(shebang) {
9804
10962
  }
9805
10963
  async function findDevHermesAgentSource() {
9806
10964
  const candidates = [
9807
- path15.resolve(process.cwd(), "reference/hermes-agent"),
9808
- path15.resolve(process.cwd(), "../../reference/hermes-agent")
10965
+ path16.resolve(process.cwd(), "reference/hermes-agent"),
10966
+ path16.resolve(process.cwd(), "../../reference/hermes-agent")
9809
10967
  ];
9810
10968
  for (const candidate of candidates) {
9811
10969
  if (await isDirectory(candidate)) {
@@ -9815,7 +10973,7 @@ async function findDevHermesAgentSource() {
9815
10973
  return null;
9816
10974
  }
9817
10975
  async function isDirectory(candidate) {
9818
- return stat9(candidate).then((info) => info.isDirectory()).catch(() => false);
10976
+ return stat10(candidate).then((info) => info.isDirectory()).catch(() => false);
9819
10977
  }
9820
10978
  function compactProcessOutput(value) {
9821
10979
  const compact = value.trim().replace(/\s+/gu, " ").slice(0, 500);
@@ -9867,8 +11025,8 @@ function parseSseBlock(block) {
9867
11025
  if (decoded === null) {
9868
11026
  return null;
9869
11027
  }
9870
- const payload = toRecord8(decoded);
9871
- const payloadType = (readString10(payload, "type") ?? readString10(payload, "event") ?? readString10(payload, "object") ?? eventName) || "message";
11028
+ const payload = toRecord9(decoded);
11029
+ const payloadType = (readString11(payload, "type") ?? readString11(payload, "event") ?? readString11(payload, "object") ?? eventName) || "message";
9872
11030
  return { eventName, payloadType, payload, rawPayload: decoded ?? raw };
9873
11031
  }
9874
11032
  function decodeJson(value) {
@@ -9884,11 +11042,11 @@ function decodeJson(value) {
9884
11042
  return { type: "message.delta", delta: value };
9885
11043
  }
9886
11044
  }
9887
- function readString10(body, key) {
11045
+ function readString11(body, key) {
9888
11046
  const value = body[key];
9889
11047
  return typeof value === "string" && value.trim() ? value.trim() : null;
9890
11048
  }
9891
- function toRecord8(value) {
11049
+ function toRecord9(value) {
9892
11050
  return typeof value === "object" && value !== null ? value : {};
9893
11051
  }
9894
11052
 
@@ -9912,8 +11070,8 @@ function normalizeHermesStreamEvent(event) {
9912
11070
  };
9913
11071
  }
9914
11072
  if (event.eventName === "hermes.tool.progress") {
9915
- const toolName = readString11(event.payload, "tool") ?? readString11(event.payload, "name") ?? "tool";
9916
- const preview = readString11(event.payload, "label") ?? readString11(event.payload, "preview") ?? toolName;
11073
+ const toolName = readString12(event.payload, "tool") ?? readString12(event.payload, "name") ?? "tool";
11074
+ const preview = readString12(event.payload, "label") ?? readString12(event.payload, "preview") ?? toolName;
9917
11075
  return {
9918
11076
  ...event,
9919
11077
  payloadType: "tool.started",
@@ -9981,12 +11139,12 @@ function normalizeHermesResponseEvent(event) {
9981
11139
  }
9982
11140
  }
9983
11141
  function normalizeResponseOutputItemAdded(event) {
9984
- const item = toRecord9(event.payload.item);
9985
- if (readString11(item, "type") !== "function_call") {
11142
+ const item = toRecord10(event.payload.item);
11143
+ if (readString12(item, "type") !== "function_call") {
9986
11144
  return null;
9987
11145
  }
9988
- const toolName = readString11(item, "name") ?? "tool";
9989
- const argumentsValue = parseJsonValue(item.arguments) ?? item.arguments;
11146
+ const toolName = readString12(item, "name") ?? "tool";
11147
+ const argumentsValue = parseJsonValue2(item.arguments) ?? item.arguments;
9990
11148
  return {
9991
11149
  ...event,
9992
11150
  payloadType: "tool.started",
@@ -9995,60 +11153,60 @@ function normalizeResponseOutputItemAdded(event) {
9995
11153
  tool: toolName,
9996
11154
  tool_name: toolName,
9997
11155
  name: toolName,
9998
- tool_call_id: readString11(item, "call_id") ?? readString11(item, "id"),
11156
+ tool_call_id: readString12(item, "call_id") ?? readString12(item, "id"),
9999
11157
  arguments: argumentsValue,
10000
11158
  preview: toolName,
10001
- response_item_id: readString11(item, "id") ?? void 0
11159
+ response_item_id: readString12(item, "id") ?? void 0
10002
11160
  }
10003
11161
  };
10004
11162
  }
10005
11163
  function normalizeResponseOutputItemDone(event) {
10006
- const item = toRecord9(event.payload.item);
10007
- if (readString11(item, "type") !== "function_call_output") {
11164
+ const item = toRecord10(event.payload.item);
11165
+ if (readString12(item, "type") !== "function_call_output") {
10008
11166
  return null;
10009
11167
  }
10010
11168
  const output = readResponseItemOutput(item.output);
10011
- const parsedOutput = parseJsonValue(output);
11169
+ const parsedOutput = parseJsonValue2(output);
10012
11170
  return {
10013
11171
  ...event,
10014
11172
  payloadType: "tool.completed",
10015
11173
  payload: {
10016
11174
  type: "tool.completed",
10017
- tool_call_id: readString11(item, "call_id") ?? readString11(item, "id"),
10018
- status: readString11(item, "status") ?? "completed",
11175
+ tool_call_id: readString12(item, "call_id") ?? readString12(item, "id"),
11176
+ status: readString12(item, "status") ?? "completed",
10019
11177
  output,
10020
11178
  content: output,
10021
11179
  result: parsedOutput ?? output,
10022
- response_item_id: readString11(item, "id") ?? void 0
11180
+ response_item_id: readString12(item, "id") ?? void 0
10023
11181
  }
10024
11182
  };
10025
11183
  }
10026
11184
  function normalizeResponseCompleted(event) {
10027
- const response = toRecord9(event.payload.response);
11185
+ const response = toRecord10(event.payload.response);
10028
11186
  return {
10029
11187
  ...event,
10030
11188
  payloadType: "run.completed",
10031
11189
  payload: {
10032
11190
  type: "run.completed",
10033
- response_id: readString11(response, "id") ?? readString11(event.payload, "id"),
10034
- usage: toRecord9(response.usage),
11191
+ response_id: readString12(response, "id") ?? readString12(event.payload, "id"),
11192
+ usage: toRecord10(response.usage),
10035
11193
  response
10036
11194
  }
10037
11195
  };
10038
11196
  }
10039
11197
  function normalizeResponseFailed(event) {
10040
- const response = toRecord9(event.payload.response);
10041
- const error = toRecord9(response.error);
11198
+ const response = toRecord10(event.payload.response);
11199
+ const error = toRecord10(response.error);
10042
11200
  return {
10043
11201
  ...event,
10044
11202
  payloadType: "run.failed",
10045
11203
  payload: {
10046
11204
  type: "run.failed",
10047
- response_id: readString11(response, "id") ?? readString11(event.payload, "id"),
11205
+ response_id: readString12(response, "id") ?? readString12(event.payload, "id"),
10048
11206
  error: {
10049
- message: readString11(error, "message") ?? readString11(event.payload, "message") ?? "Hermes run failed"
11207
+ message: readString12(error, "message") ?? readString12(event.payload, "message") ?? "Hermes run failed"
10050
11208
  },
10051
- usage: toRecord9(response.usage),
11209
+ usage: toRecord10(response.usage),
10052
11210
  response
10053
11211
  }
10054
11212
  };
@@ -10072,8 +11230,8 @@ function readErrorMessage2(payload) {
10072
11230
  if (typeof payload.error === "string" && payload.error.trim()) {
10073
11231
  return payload.error.trim();
10074
11232
  }
10075
- const error = toRecord9(payload.error);
10076
- return readString11(error, "message") ?? readString11(payload, "message");
11233
+ const error = toRecord10(payload.error);
11234
+ return readString12(error, "message") ?? readString12(payload, "message");
10077
11235
  }
10078
11236
  function readDelta(payload) {
10079
11237
  return readText2(payload, "delta") ?? readText2(payload, "text") ?? readText2(payload, "content");
@@ -10108,15 +11266,15 @@ function isTopLevelErrorEvent(event) {
10108
11266
  }
10109
11267
  function readChatCompletionDelta(payload) {
10110
11268
  const choice = readFirstChoice(payload);
10111
- const delta = toRecord9(choice.delta);
11269
+ const delta = toRecord10(choice.delta);
10112
11270
  return readText2(delta, "content");
10113
11271
  }
10114
11272
  function readChatCompletionFinishReason(payload) {
10115
11273
  const choice = readFirstChoice(payload);
10116
- return readString11(choice, "finish_reason") ?? readString11(choice, "finishReason");
11274
+ return readString12(choice, "finish_reason") ?? readString12(choice, "finishReason");
10117
11275
  }
10118
11276
  function readChatCompletionUsage(payload) {
10119
- const usage = toRecord9(payload.usage);
11277
+ const usage = toRecord10(payload.usage);
10120
11278
  const input = readInteger2(usage, "prompt_tokens") ?? readInteger2(usage, "input_tokens");
10121
11279
  const output = readInteger2(usage, "completion_tokens") ?? readInteger2(usage, "output_tokens");
10122
11280
  const total = readInteger2(usage, "total_tokens");
@@ -10144,7 +11302,7 @@ function readFirstChoice(payload) {
10144
11302
  if (!Array.isArray(choices)) {
10145
11303
  return {};
10146
11304
  }
10147
- return toRecord9(choices[0]);
11305
+ return toRecord10(choices[0]);
10148
11306
  }
10149
11307
  function readInteger2(payload, key) {
10150
11308
  const value = payload[key];
@@ -10157,7 +11315,7 @@ function readInteger2(payload, key) {
10157
11315
  }
10158
11316
  return void 0;
10159
11317
  }
10160
- function readString11(payload, key) {
11318
+ function readString12(payload, key) {
10161
11319
  const value = payload[key];
10162
11320
  return typeof value === "string" && value.trim() ? value.trim() : null;
10163
11321
  }
@@ -10172,10 +11330,10 @@ function readResponseItemOutput(value) {
10172
11330
  if (!Array.isArray(value)) {
10173
11331
  return stringifyJsonValue(value);
10174
11332
  }
10175
- const text = value.map(toRecord9).map((part) => readText2(part, "text") ?? readText2(part, "content") ?? "").join("");
11333
+ const text = value.map(toRecord10).map((part) => readText2(part, "text") ?? readText2(part, "content") ?? "").join("");
10176
11334
  return text || stringifyJsonValue(value);
10177
11335
  }
10178
- function parseJsonValue(value) {
11336
+ function parseJsonValue2(value) {
10179
11337
  if (typeof value !== "string" || !value.trim()) {
10180
11338
  return null;
10181
11339
  }
@@ -10198,7 +11356,7 @@ function stringifyJsonValue(value) {
10198
11356
  return String(value);
10199
11357
  }
10200
11358
  }
10201
- function toRecord9(value) {
11359
+ function toRecord10(value) {
10202
11360
  return typeof value === "object" && value !== null ? value : {};
10203
11361
  }
10204
11362
 
@@ -10615,7 +11773,7 @@ ${details.join("\n")}` : emptyHermesResponseMessage();
10615
11773
  assistant.agent_events ?? [],
10616
11774
  agentEvent
10617
11775
  );
10618
- appendAgentEventBlock(assistant, agentEvent, event.created_at);
11776
+ appendAgentEventBlock2(assistant, agentEvent, event.created_at);
10619
11777
  assistant.updated_at = event.created_at;
10620
11778
  await this.deps.writeSnapshot(conversationId, snapshot);
10621
11779
  }
@@ -10684,8 +11842,8 @@ ${details.join("\n")}` : emptyHermesResponseMessage();
10684
11842
  }
10685
11843
  const textPart = assistant.parts.find((part) => part.type === "text");
10686
11844
  const currentText = textPart?.text ?? "";
10687
- const pendingDeliveryText = readString12(
10688
- toRecord10(assistant.hermes),
11845
+ const pendingDeliveryText = readString13(
11846
+ toRecord11(assistant.hermes),
10689
11847
  "pending_media_delivery_text"
10690
11848
  );
10691
11849
  const normalizedDelta = normalizeStreamingTextDelta(
@@ -10700,7 +11858,7 @@ ${details.join("\n")}` : emptyHermesResponseMessage();
10700
11858
  pendingDeliveryText ?? ""
10701
11859
  );
10702
11860
  const nextHermes = {
10703
- ...toRecord10(assistant.hermes),
11861
+ ...toRecord11(assistant.hermes),
10704
11862
  ...extracted.pendingText ? { pending_media_delivery_text: extracted.pendingText } : {}
10705
11863
  };
10706
11864
  if (!extracted.pendingText) {
@@ -10716,7 +11874,7 @@ ${details.join("\n")}` : emptyHermesResponseMessage();
10716
11874
  assistant.updated_at = (/* @__PURE__ */ new Date()).toISOString();
10717
11875
  assistant.raw = { format: "hermes-run-event", payload: event.rawPayload };
10718
11876
  if (extracted.visibleText) {
10719
- appendTextBlock(assistant, extracted.visibleText, assistant.updated_at);
11877
+ appendTextBlock2(assistant, extracted.visibleText, assistant.updated_at);
10720
11878
  }
10721
11879
  await this.deps.writeSnapshot(conversationId, snapshot);
10722
11880
  if (extracted.visibleText) {
@@ -10967,7 +12125,7 @@ ${details.join("\n")}` : emptyHermesResponseMessage();
10967
12125
  includeDisabled: true
10968
12126
  });
10969
12127
  return new Set(
10970
- jobs.map((job) => readString12(job, "id") ?? readString12(job, "job_id")).filter((id) => Boolean(id))
12128
+ jobs.map((job) => readString13(job, "id") ?? readString13(job, "job_id")).filter((id) => Boolean(id))
10971
12129
  );
10972
12130
  }
10973
12131
  async bindNewCronJobsCreatedByRun(input) {
@@ -11003,7 +12161,7 @@ function buildRunInstructions(run, deliveryStagingDir) {
11003
12161
  ].join("\n");
11004
12162
  }
11005
12163
  function appendMediaImportFailureNotice(message) {
11006
- const hermes = toRecord10(message.hermes);
12164
+ const hermes = toRecord11(message.hermes);
11007
12165
  if (hermes.media_import_failure_notice_appended === true) {
11008
12166
  return;
11009
12167
  }
@@ -11046,18 +12204,18 @@ function formatFilenameList(filenames) {
11046
12204
  return remaining > 0 ? `${preview.join("\u3001")} \u7B49 ${filenames.length} \u4E2A` : preview.join("\u3001");
11047
12205
  }
11048
12206
  async function readdirWithDirs(directory) {
11049
- return readdir6(directory, { withFileTypes: true }).catch((error) => {
11050
- if (isNodeError11(error, "ENOENT")) {
12207
+ return readdir7(directory, { withFileTypes: true }).catch((error) => {
12208
+ if (isNodeError12(error, "ENOENT")) {
11051
12209
  return [];
11052
12210
  }
11053
12211
  throw error;
11054
12212
  });
11055
12213
  }
11056
- function readString12(payload, key) {
12214
+ function readString13(payload, key) {
11057
12215
  const value = payload[key];
11058
12216
  return typeof value === "string" && value.trim() ? value.trim() : null;
11059
12217
  }
11060
- function toRecord10(value) {
12218
+ function toRecord11(value) {
11061
12219
  return typeof value === "object" && value !== null ? value : {};
11062
12220
  }
11063
12221
  function formatFailureMessage(message, detail) {
@@ -11073,17 +12231,17 @@ function isFileSearchCompletion(payloadType, payload) {
11073
12231
  if (payloadType !== "tool.completed") {
11074
12232
  return false;
11075
12233
  }
11076
- const tool = toRecord10(payload.tool);
11077
- const toolCall = toRecord10(payload.tool_call ?? payload.toolCall);
11078
- const fn = toRecord10(toolCall.function ?? payload.function);
12234
+ const tool = toRecord11(payload.tool);
12235
+ const toolCall = toRecord11(payload.tool_call ?? payload.toolCall);
12236
+ const fn = toRecord11(toolCall.function ?? payload.function);
11079
12237
  const candidates = [
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")
12238
+ readString13(payload, "tool_name"),
12239
+ readString13(payload, "toolName"),
12240
+ readString13(payload, "name"),
12241
+ readString13(payload, "tool"),
12242
+ readString13(tool, "name"),
12243
+ readString13(toolCall, "name"),
12244
+ readString13(fn, "name")
11087
12245
  ].filter((value) => Boolean(value)).map(normalizeToolName);
11088
12246
  return candidates.some(
11089
12247
  (name) => [
@@ -11126,7 +12284,7 @@ function isVoicePart(part) {
11126
12284
  function normalizeToolName(value) {
11127
12285
  return value.trim().toLowerCase().replace(/[\s-]+/gu, "_");
11128
12286
  }
11129
- function appendTextBlock(message, delta, updatedAt) {
12287
+ function appendTextBlock2(message, delta, updatedAt) {
11130
12288
  if (!delta) {
11131
12289
  return;
11132
12290
  }
@@ -11149,7 +12307,7 @@ function appendTextBlock(message, delta, updatedAt) {
11149
12307
  }
11150
12308
  message.blocks = blocks;
11151
12309
  }
11152
- function appendAgentEventBlock(message, event, updatedAt) {
12310
+ function appendAgentEventBlock2(message, event, updatedAt) {
11153
12311
  const blocks = [...message.blocks ?? []];
11154
12312
  const matchingIndex = blocks.findIndex((block) => {
11155
12313
  if (block.type !== "agent_events") {
@@ -11238,10 +12396,10 @@ function readResponseId(payload) {
11238
12396
  if (!payload) {
11239
12397
  return null;
11240
12398
  }
11241
- const response = toRecord10(payload.response);
11242
- return readString12(payload, "response_id") ?? readString12(response, "id");
12399
+ const response = toRecord11(payload.response);
12400
+ return readString13(payload, "response_id") ?? readString13(response, "id");
11243
12401
  }
11244
- function isNodeError11(error, code) {
12402
+ function isNodeError12(error, code) {
11245
12403
  if (typeof error !== "object" || error === null || !("code" in error)) {
11246
12404
  return false;
11247
12405
  }
@@ -11330,6 +12488,7 @@ var ConversationService = class {
11330
12488
  orchestration;
11331
12489
  queries;
11332
12490
  runLifecycle;
12491
+ hermesSessionSyncPromise = null;
11333
12492
  async withConversationLock(conversationId, task) {
11334
12493
  const previous = this.conversationLocks.get(conversationId) ?? Promise.resolve();
11335
12494
  let release;
@@ -11390,7 +12549,7 @@ var ConversationService = class {
11390
12549
  async createConversation(input = {}) {
11391
12550
  await this.store.ensureConversationsDir();
11392
12551
  const now = (/* @__PURE__ */ new Date()).toISOString();
11393
- const id = `conv_${randomUUID6().replaceAll("-", "")}`;
12552
+ const id = `conv_${randomUUID7().replaceAll("-", "")}`;
11394
12553
  const title = input.title?.trim() || DEFAULT_CONVERSATION_TITLE;
11395
12554
  const profile = await resolveConversationProfileTarget(
11396
12555
  this.paths,
@@ -11477,7 +12636,7 @@ var ConversationService = class {
11477
12636
  manifest.profile_name_snapshot ?? manifest.profile ?? input.profileName
11478
12637
  );
11479
12638
  const message = {
11480
- id: `msg_${randomUUID6().replaceAll("-", "")}`,
12639
+ id: `msg_${randomUUID7().replaceAll("-", "")}`,
11481
12640
  schema_version: 1,
11482
12641
  conversation_id: manifest.id,
11483
12642
  role: "assistant",
@@ -11521,6 +12680,29 @@ var ConversationService = class {
11521
12680
  async syncCronDeliveries() {
11522
12681
  await syncHermesLinkCronDeliveries(this.paths, this, this.logger);
11523
12682
  }
12683
+ async syncHermesSessions() {
12684
+ if (this.hermesSessionSyncPromise) {
12685
+ return this.hermesSessionSyncPromise;
12686
+ }
12687
+ const task = (async () => {
12688
+ const result = await syncHermesSessionsIntoConversations(
12689
+ this.paths,
12690
+ this.logger
12691
+ );
12692
+ if (result.imported_count > 0 || result.reprojected_count > 0) {
12693
+ await this.rebuildStatisticsIndex();
12694
+ }
12695
+ return result;
12696
+ })();
12697
+ this.hermesSessionSyncPromise = task;
12698
+ try {
12699
+ return await task;
12700
+ } finally {
12701
+ if (this.hermesSessionSyncPromise === task) {
12702
+ this.hermesSessionSyncPromise = null;
12703
+ }
12704
+ }
12705
+ }
11524
12706
  async deliverStagedFiles(stagingDir) {
11525
12707
  const target = resolveDeliveryStagingTarget(this.paths, stagingDir);
11526
12708
  return this.withConversationLock(target.conversationId, async () => {
@@ -12046,7 +13228,7 @@ function findApproval(snapshot, approvalId) {
12046
13228
  }
12047
13229
 
12048
13230
  // src/identity/identity.ts
12049
- import { generateKeyPairSync, randomUUID as randomUUID7, sign } from "crypto";
13231
+ import { generateKeyPairSync, randomUUID as randomUUID8, sign } from "crypto";
12050
13232
  import { mkdir as mkdir9, chmod } from "fs/promises";
12051
13233
  import { z } from "zod";
12052
13234
  var linkIdentitySchema = z.object({
@@ -12074,7 +13256,7 @@ async function ensureIdentity(paths = resolveRuntimePaths()) {
12074
13256
  const { publicKey, privateKey } = generateKeyPairSync("ed25519");
12075
13257
  const now = (/* @__PURE__ */ new Date()).toISOString();
12076
13258
  const identity = {
12077
- install_id: `install_${randomUUID7().replaceAll("-", "")}`,
13259
+ install_id: `install_${randomUUID8().replaceAll("-", "")}`,
12078
13260
  link_id: null,
12079
13261
  public_key_pem: publicKey.export({ type: "spki", format: "pem" }).toString(),
12080
13262
  private_key_pem: privateKey.export({ type: "pkcs8", format: "pem" }).toString(),
@@ -12111,7 +13293,7 @@ function getIdentityStatus(identity) {
12111
13293
  }
12112
13294
 
12113
13295
  // src/security/devices.ts
12114
- import { randomBytes as randomBytes2, randomUUID as randomUUID8, timingSafeEqual, createHash as createHash4 } from "crypto";
13296
+ import { randomBytes as randomBytes2, randomUUID as randomUUID9, timingSafeEqual, createHash as createHash4 } from "crypto";
12115
13297
  var ACCESS_TOKEN_TTL_MS = 15 * 60 * 1e3;
12116
13298
  var REFRESH_TOKEN_TTL_MS = 90 * 24 * 60 * 60 * 1e3;
12117
13299
  var DEVICE_SEEN_WRITE_INTERVAL_MS = 60 * 60 * 1e3;
@@ -12129,7 +13311,7 @@ async function createDeviceSession(input, paths = resolveRuntimePaths()) {
12129
13311
  }
12130
13312
  }
12131
13313
  const device = {
12132
- id: `dev_${randomUUID8().replaceAll("-", "")}`,
13314
+ id: `dev_${randomUUID9().replaceAll("-", "")}`,
12133
13315
  label: normalizeDeviceLabel(input.label),
12134
13316
  platform: normalizeDevicePlatform(input.platform),
12135
13317
  model: normalizeDeviceModel(input.model),
@@ -12578,12 +13760,12 @@ async function readRawBody(request, maxBytes) {
12578
13760
  }
12579
13761
  return Buffer.concat(chunks);
12580
13762
  }
12581
- function readString13(body, key) {
13763
+ function readString14(body, key) {
12582
13764
  const value = body[key];
12583
13765
  return typeof value === "string" && value.trim() ? value.trim() : null;
12584
13766
  }
12585
13767
  function readOptionalProfileName(body) {
12586
- return readString13(body, "profile") ?? readString13(body, "profile_name") ?? readString13(body, "profileName") ?? void 0;
13768
+ return readString14(body, "profile") ?? readString14(body, "profile_name") ?? readString14(body, "profileName") ?? void 0;
12587
13769
  }
12588
13770
  function readStringArray(body, ...keys) {
12589
13771
  for (const key of keys) {
@@ -12621,7 +13803,7 @@ function readPositiveInteger2(value) {
12621
13803
  }
12622
13804
  return void 0;
12623
13805
  }
12624
- function readBoolean(value) {
13806
+ function readBoolean2(value) {
12625
13807
  if (typeof value === "boolean") {
12626
13808
  return value;
12627
13809
  }
@@ -12724,7 +13906,7 @@ function readMessageAttachments(value) {
12724
13906
  }
12725
13907
  const kind = readAttachmentString(record.kind);
12726
13908
  const type = readAttachmentString(record.type);
12727
- const isVoiceNote = readBoolean(record.is_voice_note) ?? readBoolean(record.isVoiceNote);
13909
+ const isVoiceNote = readBoolean2(record.is_voice_note) ?? readBoolean2(record.isVoiceNote);
12728
13910
  const durationMs = readPositiveInteger2(record.duration_ms) ?? readPositiveInteger2(record.durationMs);
12729
13911
  const waveform = readAttachmentWaveform2(
12730
13912
  record.waveform ?? record.waveform_samples ?? record.waveformSamples
@@ -12816,7 +13998,7 @@ function registerConversationRoutes(router, options) {
12816
13998
  ctx.body = {
12817
13999
  ok: true,
12818
14000
  conversation: await conversations.createConversation({
12819
- title: readString13(body, "title") ?? void 0,
14001
+ title: readString14(body, "title") ?? void 0,
12820
14002
  profileName: readOptionalProfileName(body)
12821
14003
  })
12822
14004
  };
@@ -12887,7 +14069,7 @@ function registerConversationRoutes(router, options) {
12887
14069
  router.post("/api/v1/conversations/:conversationId/messages", async (ctx) => {
12888
14070
  await authenticateRequest(ctx, paths);
12889
14071
  const body = await readJsonBody(ctx.req);
12890
- const content = readString13(body, "content") ?? readString13(body, "text") ?? readString13(body, "input") ?? "";
14072
+ const content = readString14(body, "content") ?? readString14(body, "text") ?? readString14(body, "input") ?? "";
12891
14073
  const attachments = readMessageAttachments(body.attachments ?? body.blobs);
12892
14074
  if (!content && attachments.length === 0) {
12893
14075
  throw new LinkHttpError(
@@ -12903,7 +14085,7 @@ function registerConversationRoutes(router, options) {
12903
14085
  conversationId: ctx.params.conversationId,
12904
14086
  content,
12905
14087
  attachments,
12906
- clientMessageId: readString13(body, "client_message_id") ?? readString13(body, "clientMessageId") ?? void 0,
14088
+ clientMessageId: readString14(body, "client_message_id") ?? readString14(body, "clientMessageId") ?? void 0,
12907
14089
  idempotencyKey: readHeader(ctx, "idempotency-key") ?? void 0,
12908
14090
  profileName: readOptionalProfileName(body)
12909
14091
  })
@@ -12912,7 +14094,7 @@ function registerConversationRoutes(router, options) {
12912
14094
  router.patch("/api/v1/conversations/:conversationId/model", async (ctx) => {
12913
14095
  await authenticateRequest(ctx, paths);
12914
14096
  const body = await readJsonBody(ctx.req);
12915
- const modelId = readString13(body, "model_id") ?? readString13(body, "modelId") ?? readString13(body, "model");
14097
+ const modelId = readString14(body, "model_id") ?? readString14(body, "modelId") ?? readString14(body, "model");
12916
14098
  if (!modelId) {
12917
14099
  throw new LinkHttpError(400, "model_id_required", "model_id is required");
12918
14100
  }
@@ -12942,7 +14124,7 @@ function registerConversationRoutes(router, options) {
12942
14124
  router.patch("/api/v1/conversations/:conversationId/title", async (ctx) => {
12943
14125
  await authenticateRequest(ctx, paths);
12944
14126
  const body = await readJsonBody(ctx.req);
12945
- const title = readString13(body, "title") ?? readString13(body, "name") ?? readString13(body, "display_name");
14127
+ const title = readString14(body, "title") ?? readString14(body, "name") ?? readString14(body, "display_name");
12946
14128
  if (!title) {
12947
14129
  throw new LinkHttpError(400, "title_required", "title is required");
12948
14130
  }
@@ -13006,7 +14188,7 @@ function registerConversationRoutes(router, options) {
13006
14188
  async (ctx) => {
13007
14189
  await authenticateRequest(ctx, paths);
13008
14190
  const body = await readJsonBody(ctx.req);
13009
- const scope = readString13(body, "scope") ?? "always";
14191
+ const scope = readString14(body, "scope") ?? "always";
13010
14192
  ctx.body = {
13011
14193
  ok: true,
13012
14194
  ...await conversations.resolveApproval({
@@ -13166,26 +14348,26 @@ function createHttpErrorMiddleware(logger) {
13166
14348
  }
13167
14349
 
13168
14350
  // src/hermes/profiles.ts
13169
- import { mkdir as mkdir10, readdir as readdir7, readFile as readFile11, rename as rename4, rm as rm6, stat as stat10 } from "fs/promises";
13170
- import os4 from "os";
13171
- import path16 from "path";
14351
+ import { mkdir as mkdir10, readdir as readdir8, readFile as readFile12, rename as rename4, rm as rm6, stat as stat11 } from "fs/promises";
14352
+ import os5 from "os";
14353
+ import path17 from "path";
13172
14354
  import YAML2 from "yaml";
13173
14355
  var DEFAULT_PROFILE = "default";
13174
- var PROFILE_NAME_PATTERN3 = /^[a-zA-Z0-9._-]{1,64}$/;
14356
+ var PROFILE_NAME_PATTERN4 = /^[a-zA-Z0-9._-]{1,64}$/;
13175
14357
  async function listHermesProfiles(paths = resolveRuntimePaths()) {
13176
14358
  const profiles = /* @__PURE__ */ new Map();
13177
14359
  profiles.set(DEFAULT_PROFILE, await profileInfo(DEFAULT_PROFILE, paths));
13178
- const profilesDir = path16.join(os4.homedir(), ".hermes", "profiles");
13179
- const entries = await readdir7(profilesDir, { withFileTypes: true }).catch(
14360
+ const profilesDir = path17.join(os5.homedir(), ".hermes", "profiles");
14361
+ const entries = await readdir8(profilesDir, { withFileTypes: true }).catch(
13180
14362
  (error) => {
13181
- if (isNodeError12(error, "ENOENT")) {
14363
+ if (isNodeError13(error, "ENOENT")) {
13182
14364
  return [];
13183
14365
  }
13184
14366
  throw error;
13185
14367
  }
13186
14368
  );
13187
14369
  for (const entry of entries) {
13188
- if (entry.isDirectory() && PROFILE_NAME_PATTERN3.test(entry.name)) {
14370
+ if (entry.isDirectory() && PROFILE_NAME_PATTERN4.test(entry.name)) {
13189
14371
  profiles.set(entry.name, await profileInfo(entry.name, paths));
13190
14372
  }
13191
14373
  }
@@ -13202,8 +14384,8 @@ async function listHermesProfiles(paths = resolveRuntimePaths()) {
13202
14384
  async function getHermesProfileStatus(name, paths = resolveRuntimePaths()) {
13203
14385
  assertProfileName(name);
13204
14386
  const profile = await profileInfo(name, paths);
13205
- const exists = await stat10(profile.path).then((value) => value.isDirectory()).catch((error) => {
13206
- if (isNodeError12(error, "ENOENT")) {
14387
+ const exists = await stat11(profile.path).then((value) => value.isDirectory()).catch((error) => {
14388
+ if (isNodeError13(error, "ENOENT")) {
13207
14389
  return false;
13208
14390
  }
13209
14391
  throw error;
@@ -13243,8 +14425,8 @@ async function updateHermesProfileMetadata(name, metadata, paths = resolveRuntim
13243
14425
  async function deleteHermesProfile(name, paths = resolveRuntimePaths()) {
13244
14426
  assertMutableProfile(name);
13245
14427
  const profile = await profileInfo(name, paths);
13246
- const exists = await stat10(profile.path).then((value) => value.isDirectory()).catch((error) => {
13247
- if (isNodeError12(error, "ENOENT")) {
14428
+ const exists = await stat11(profile.path).then((value) => value.isDirectory()).catch((error) => {
14429
+ if (isNodeError13(error, "ENOENT")) {
13248
14430
  return false;
13249
14431
  }
13250
14432
  throw error;
@@ -13270,7 +14452,7 @@ async function readHermesProfileCapabilities(name) {
13270
14452
  return {
13271
14453
  defaultModel: listedModels?.defaultModel ?? null,
13272
14454
  modelCount: listedModels?.models.length ?? 0,
13273
- skillCount: await countSkills(path16.join(profileDir, "skills")).catch(
14455
+ skillCount: await countSkills(path17.join(profileDir, "skills")).catch(
13274
14456
  () => 0
13275
14457
  ),
13276
14458
  toolCount: await countConfiguredTools(name).catch(() => 0)
@@ -13308,17 +14490,17 @@ function assertMutableProfile(name) {
13308
14490
  }
13309
14491
  }
13310
14492
  function assertProfileName(name) {
13311
- if (!PROFILE_NAME_PATTERN3.test(name)) {
14493
+ if (!PROFILE_NAME_PATTERN4.test(name)) {
13312
14494
  throw new LinkHttpError(400, "invalid_profile_name", "invalid profile name");
13313
14495
  }
13314
14496
  }
13315
- function isNodeError12(error, code) {
14497
+ function isNodeError13(error, code) {
13316
14498
  return typeof error === "object" && error !== null && "code" in error && error.code === code;
13317
14499
  }
13318
14500
  async function countSkills(root) {
13319
- const entries = await readdir7(root, { withFileTypes: true }).catch(
14501
+ const entries = await readdir8(root, { withFileTypes: true }).catch(
13320
14502
  (error) => {
13321
- if (isNodeError12(error, "ENOENT")) {
14503
+ if (isNodeError13(error, "ENOENT")) {
13322
14504
  return [];
13323
14505
  }
13324
14506
  throw error;
@@ -13326,7 +14508,7 @@ async function countSkills(root) {
13326
14508
  );
13327
14509
  let count = 0;
13328
14510
  for (const entry of entries) {
13329
- const entryPath = path16.join(root, entry.name);
14511
+ const entryPath = path17.join(root, entry.name);
13330
14512
  if (entry.name === ".git" || entry.name === ".hub") {
13331
14513
  continue;
13332
14514
  }
@@ -13341,11 +14523,11 @@ async function countSkills(root) {
13341
14523
  return count;
13342
14524
  }
13343
14525
  async function countConfiguredTools(profileName) {
13344
- const raw = await readFile11(
14526
+ const raw = await readFile12(
13345
14527
  resolveHermesConfigPath(profileName),
13346
14528
  "utf8"
13347
14529
  ).catch((error) => {
13348
- if (isNodeError12(error, "ENOENT")) {
14530
+ if (isNodeError13(error, "ENOENT")) {
13349
14531
  return "";
13350
14532
  }
13351
14533
  throw error;
@@ -13353,14 +14535,14 @@ async function countConfiguredTools(profileName) {
13353
14535
  if (!raw.trim()) {
13354
14536
  return 0;
13355
14537
  }
13356
- const config = toRecord11(YAML2.parse(raw));
14538
+ const config = toRecord12(YAML2.parse(raw));
13357
14539
  const toolsets = /* @__PURE__ */ new Set();
13358
14540
  collectToolsetValues(config.toolsets, toolsets);
13359
- const platformToolsets = toRecord11(config.platform_toolsets);
14541
+ const platformToolsets = toRecord12(config.platform_toolsets);
13360
14542
  for (const value of Object.values(platformToolsets)) {
13361
14543
  collectToolsetValues(value, toolsets);
13362
14544
  }
13363
- const mcpServers = Object.keys(toRecord11(config.mcp_servers)).length;
14545
+ const mcpServers = Object.keys(toRecord12(config.mcp_servers)).length;
13364
14546
  return toolsets.size + mcpServers;
13365
14547
  }
13366
14548
  function collectToolsetValues(value, target) {
@@ -13374,7 +14556,7 @@ function collectToolsetValues(value, target) {
13374
14556
  target.add(value.trim());
13375
14557
  }
13376
14558
  }
13377
- function toRecord11(value) {
14559
+ function toRecord12(value) {
13378
14560
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
13379
14561
  }
13380
14562
 
@@ -13571,7 +14753,7 @@ function toHermesCronJobInput(input) {
13571
14753
  };
13572
14754
  }
13573
14755
  async function bindAndDecorateCronJobForHermesLink(input) {
13574
- const jobId = readString13(input.job, "id") ?? readString13(input.job, "job_id");
14756
+ const jobId = readString14(input.job, "id") ?? readString14(input.job, "job_id");
13575
14757
  if (!jobId) {
13576
14758
  return input.job;
13577
14759
  }
@@ -13588,9 +14770,9 @@ async function bindAndDecorateCronJobForHermesLink(input) {
13588
14770
  }
13589
14771
  function readCronJobCreateInput(body) {
13590
14772
  const input = {};
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");
14773
+ const name = readString14(body, "name") ?? readString14(body, "title");
14774
+ const prompt = readString14(body, "prompt") ?? readString14(body, "description") ?? readString14(body, "task");
14775
+ const schedule = readString14(body, "schedule");
13594
14776
  if (!name) {
13595
14777
  throw new LinkHttpError(400, "cron_job_name_required", "name is required");
13596
14778
  }
@@ -13611,7 +14793,7 @@ function readCronJobCreateInput(body) {
13611
14793
  input.name = name;
13612
14794
  input.prompt = prompt;
13613
14795
  input.schedule = schedule;
13614
- input.deliver = readString13(body, "deliver") ?? HERMES_LINK_CRON_DELIVER;
14796
+ input.deliver = readString14(body, "deliver") ?? HERMES_LINK_CRON_DELIVER;
13615
14797
  const skills = readOptionalCronSkills(body);
13616
14798
  if (skills) {
13617
14799
  input.skills = skills;
@@ -13669,7 +14851,7 @@ function readCronJobUpdateInput(body) {
13669
14851
  if (repeat !== void 0) {
13670
14852
  input.repeat = repeat;
13671
14853
  }
13672
- const enabled = readBoolean(body.enabled);
14854
+ const enabled = readBoolean2(body.enabled);
13673
14855
  if (enabled !== void 0) {
13674
14856
  input.enabled = enabled;
13675
14857
  }
@@ -13839,7 +15021,7 @@ function registerModelConfigRoutes(router, options) {
13839
15021
  router.delete("/api/v1/model-configs", async (ctx) => {
13840
15022
  await authenticateRequest(ctx, paths);
13841
15023
  const body = await readJsonBody(ctx.req);
13842
- const modelId = readString13(body, "model_id") ?? readString13(body, "modelId");
15024
+ const modelId = readString14(body, "model_id") ?? readString14(body, "modelId");
13843
15025
  if (!modelId) {
13844
15026
  throw new LinkHttpError(400, "model_id_required", "model_id is required");
13845
15027
  }
@@ -13894,7 +15076,7 @@ function registerModelConfigRoutes(router, options) {
13894
15076
  await authenticateRequest(ctx, paths);
13895
15077
  await getHermesProfileStatus(ctx.params.name, paths);
13896
15078
  const body = await readJsonBody(ctx.req);
13897
- const modelId = readString13(body, "model_id") ?? readString13(body, "modelId");
15079
+ const modelId = readString14(body, "model_id") ?? readString14(body, "modelId");
13898
15080
  if (!modelId) {
13899
15081
  throw new LinkHttpError(400, "model_id_required", "model_id is required");
13900
15082
  }
@@ -13911,9 +15093,9 @@ function registerModelConfigRoutes(router, options) {
13911
15093
  });
13912
15094
  }
13913
15095
  function readModelConfigInput(body) {
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");
15096
+ const id = readString14(body, "id") ?? readString14(body, "model_id") ?? readString14(body, "modelId");
15097
+ const provider = readString14(body, "provider") ?? readString14(body, "provider_key") ?? readString14(body, "providerKey");
15098
+ const baseUrl = readString14(body, "base_url") ?? readString14(body, "baseUrl");
13917
15099
  if (!id || !provider || !baseUrl) {
13918
15100
  throw new LinkHttpError(
13919
15101
  400,
@@ -13923,28 +15105,28 @@ function readModelConfigInput(body) {
13923
15105
  }
13924
15106
  return {
13925
15107
  id,
13926
- originalModelId: readString13(body, "original_model_id") ?? readString13(body, "originalModelId") ?? readString13(body, "original_id") ?? void 0,
15108
+ originalModelId: readString14(body, "original_model_id") ?? readString14(body, "originalModelId") ?? readString14(body, "original_id") ?? void 0,
13927
15109
  provider,
13928
- providerName: readString13(body, "provider_name") ?? readString13(body, "providerName") ?? void 0,
15110
+ providerName: readString14(body, "provider_name") ?? readString14(body, "providerName") ?? void 0,
13929
15111
  baseUrl,
13930
- apiKey: readString13(body, "api_key") ?? readString13(body, "apiKey") ?? void 0,
13931
- apiMode: readString13(body, "api_mode") ?? readString13(body, "apiMode") ?? void 0,
15112
+ apiKey: readString14(body, "api_key") ?? readString14(body, "apiKey") ?? void 0,
15113
+ apiMode: readString14(body, "api_mode") ?? readString14(body, "apiMode") ?? void 0,
13932
15114
  contextLength: readPositiveInteger2(
13933
15115
  body.context_length ?? body.contextLength
13934
15116
  ),
13935
- keyEnv: readString13(body, "key_env") ?? readString13(body, "keyEnv") ?? void 0,
13936
- setDefault: readBoolean(body.set_default ?? body.setDefault),
13937
- reasoningEffort: readString13(body, "reasoning_effort") ?? readString13(body, "reasoningEffort") ?? void 0
15117
+ keyEnv: readString14(body, "key_env") ?? readString14(body, "keyEnv") ?? void 0,
15118
+ setDefault: readBoolean2(body.set_default ?? body.setDefault),
15119
+ reasoningEffort: readString14(body, "reasoning_effort") ?? readString14(body, "reasoningEffort") ?? void 0
13938
15120
  };
13939
15121
  }
13940
15122
  function readModelDefaultsInput(body) {
13941
15123
  return {
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
15124
+ taskModelId: readString14(body, "task_model_id") ?? readString14(body, "taskModelId") ?? readString14(body, "default_model_id") ?? readString14(body, "defaultModelId") ?? void 0,
15125
+ compressionModelId: readString14(body, "compression_model_id") ?? readString14(body, "compressionModelId") ?? void 0
13944
15126
  };
13945
15127
  }
13946
15128
  function shouldReloadGatewayAfterModelConfigChange(body) {
13947
- const explicit = readBoolean(body.reload_gateway ?? body.reloadGateway) ?? (readBoolean(body.skip_gateway_reload ?? body.skipGatewayReload) === true ? false : void 0);
15129
+ const explicit = readBoolean2(body.reload_gateway ?? body.reloadGateway) ?? (readBoolean2(body.skip_gateway_reload ?? body.skipGatewayReload) === true ? false : void 0);
13948
15130
  return explicit ?? true;
13949
15131
  }
13950
15132
  function markModelConfigAppliedWithoutGatewayReload(result) {
@@ -14025,19 +15207,19 @@ import {
14025
15207
  copyFile as copyFile2,
14026
15208
  cp,
14027
15209
  mkdir as mkdir11,
14028
- readFile as readFile12,
15210
+ readFile as readFile13,
14029
15211
  rm as rm7,
14030
- stat as stat11,
15212
+ stat as stat12,
14031
15213
  writeFile as writeFile4,
14032
15214
  rename as rename5
14033
15215
  } from "fs/promises";
14034
- import path17 from "path";
15216
+ import path18 from "path";
14035
15217
  import YAML3 from "yaml";
14036
15218
  var PROFILE_CREATE_LOG_FILE = "profile-create.log";
14037
15219
  var PROFILE_CREATE_LOG_MAX_FILES = 3;
14038
15220
  var MAX_PROFILE_CREATE_LOG_LINES = 260;
14039
15221
  var MAX_OUTPUT_LINE_LENGTH = 1200;
14040
- var PROFILE_NAME_PATTERN4 = /^[a-z0-9][a-z0-9_-]{0,63}$/u;
15222
+ var PROFILE_NAME_PATTERN5 = /^[a-z0-9][a-z0-9_-]{0,63}$/u;
14041
15223
  var ALL_COPY_SCOPES = [
14042
15224
  "models",
14043
15225
  "skills",
@@ -14289,7 +15471,7 @@ function normalizeOptionalProfileName(value) {
14289
15471
  if (!trimmed) {
14290
15472
  return null;
14291
15473
  }
14292
- if (!PROFILE_NAME_PATTERN4.test(trimmed)) {
15474
+ if (!PROFILE_NAME_PATTERN5.test(trimmed)) {
14293
15475
  throw new LinkHttpError(
14294
15476
  400,
14295
15477
  "invalid_profile_name",
@@ -14421,7 +15603,7 @@ function copyModelConfig(source, target) {
14421
15603
  copied[key] = cloneJson(source[key]);
14422
15604
  }
14423
15605
  }
14424
- const sourceAuxiliary = toRecord12(source.auxiliary);
15606
+ const sourceAuxiliary = toRecord13(source.auxiliary);
14425
15607
  if (Object.prototype.hasOwnProperty.call(sourceAuxiliary, "compression")) {
14426
15608
  const targetAuxiliary = ensureRecord2(target, "auxiliary");
14427
15609
  targetAuxiliary.compression = cloneJson(sourceAuxiliary.compression);
@@ -14430,12 +15612,12 @@ function copyModelConfig(source, target) {
14430
15612
  return copied;
14431
15613
  }
14432
15614
  function copyToolPermissionsConfig(source, target) {
14433
- const sourcePlatformToolsets = toRecord12(source.platform_toolsets);
15615
+ const sourcePlatformToolsets = toRecord13(source.platform_toolsets);
14434
15616
  if (Object.prototype.hasOwnProperty.call(sourcePlatformToolsets, "api_server")) {
14435
15617
  const targetPlatformToolsets = ensureRecord2(target, "platform_toolsets");
14436
15618
  targetPlatformToolsets.api_server = cloneJson(sourcePlatformToolsets.api_server);
14437
15619
  }
14438
- const sourceStt = toRecord12(source.stt);
15620
+ const sourceStt = toRecord13(source.stt);
14439
15621
  if (Object.prototype.hasOwnProperty.call(sourceStt, "enabled")) {
14440
15622
  const targetStt = ensureRecord2(target, "stt");
14441
15623
  targetStt.enabled = cloneJson(sourceStt.enabled);
@@ -14482,9 +15664,9 @@ function collectEnvKeys(value, keys = /* @__PURE__ */ new Set()) {
14482
15664
  return keys;
14483
15665
  }
14484
15666
  async function writeEnvValues(profileName, values) {
14485
- const envPath = path17.join(resolveHermesProfileDir(profileName), ".env");
14486
- const existingRaw = await readFile12(envPath, "utf8").catch((error) => {
14487
- if (isNodeError13(error, "ENOENT")) {
15667
+ const envPath = path18.join(resolveHermesProfileDir(profileName), ".env");
15668
+ const existingRaw = await readFile13(envPath, "utf8").catch((error) => {
15669
+ if (isNodeError14(error, "ENOENT")) {
14488
15670
  return "";
14489
15671
  }
14490
15672
  throw error;
@@ -14509,7 +15691,7 @@ async function writeEnvValues(profileName, values) {
14509
15691
  nextLines.push(`${key}=${formatEnvValue2(value)}`);
14510
15692
  }
14511
15693
  const nextRaw = nextLines.join("\n").replace(/\n*$/u, "\n");
14512
- await mkdir11(path17.dirname(envPath), { recursive: true, mode: 448 });
15694
+ await mkdir11(path18.dirname(envPath), { recursive: true, mode: 448 });
14513
15695
  if (existingRaw) {
14514
15696
  await copyFile2(envPath, `${envPath}.bak.${Date.now()}`);
14515
15697
  }
@@ -14518,8 +15700,8 @@ async function writeEnvValues(profileName, values) {
14518
15700
  await rename5(tempPath, envPath);
14519
15701
  }
14520
15702
  async function copySkills(sourceProfile, targetProfile) {
14521
- const sourceSkills = path17.join(resolveHermesProfileDir(sourceProfile), "skills");
14522
- const targetSkills = path17.join(resolveHermesProfileDir(targetProfile), "skills");
15703
+ const sourceSkills = path18.join(resolveHermesProfileDir(sourceProfile), "skills");
15704
+ const targetSkills = path18.join(resolveHermesProfileDir(targetProfile), "skills");
14523
15705
  if (!await pathExists(sourceSkills)) {
14524
15706
  return;
14525
15707
  }
@@ -14538,21 +15720,21 @@ function copyProperty(source, target, key) {
14538
15720
  }
14539
15721
  }
14540
15722
  async function readYamlConfig(configPath) {
14541
- const existingRaw = await readFile12(configPath, "utf8").catch(
15723
+ const existingRaw = await readFile13(configPath, "utf8").catch(
14542
15724
  (error) => {
14543
- if (isNodeError13(error, "ENOENT")) {
15725
+ if (isNodeError14(error, "ENOENT")) {
14544
15726
  return null;
14545
15727
  }
14546
15728
  throw error;
14547
15729
  }
14548
15730
  );
14549
15731
  return {
14550
- config: toRecord12(existingRaw ? YAML3.parse(existingRaw) : {}),
15732
+ config: toRecord13(existingRaw ? YAML3.parse(existingRaw) : {}),
14551
15733
  existingRaw
14552
15734
  };
14553
15735
  }
14554
15736
  async function writeYamlConfig(configPath, input) {
14555
- await mkdir11(path17.dirname(configPath), { recursive: true, mode: 448 });
15737
+ await mkdir11(path18.dirname(configPath), { recursive: true, mode: 448 });
14556
15738
  if (input.existingRaw) {
14557
15739
  await copyFile2(configPath, `${configPath}.bak.${Date.now()}`);
14558
15740
  }
@@ -14600,7 +15782,7 @@ async function writeProfileCreationState(paths, state) {
14600
15782
  await writeJsonFile(profileCreationStatePath(paths), state);
14601
15783
  }
14602
15784
  async function readProfileCreationLogLines(paths) {
14603
- const raw = await readFile12(profileCreationLogPath(paths), "utf8").catch(() => "");
15785
+ const raw = await readFile13(profileCreationLogPath(paths), "utf8").catch(() => "");
14604
15786
  if (!raw.trim()) {
14605
15787
  return [];
14606
15788
  }
@@ -14609,10 +15791,10 @@ async function readProfileCreationLogLines(paths) {
14609
15791
  );
14610
15792
  }
14611
15793
  function profileCreationStatePath(paths) {
14612
- return path17.join(paths.runDir, "profile-create-state.json");
15794
+ return path18.join(paths.runDir, "profile-create-state.json");
14613
15795
  }
14614
15796
  function profileCreationLogPath(paths) {
14615
- return path17.join(paths.logsDir, PROFILE_CREATE_LOG_FILE);
15797
+ return path18.join(paths.logsDir, PROFILE_CREATE_LOG_FILE);
14616
15798
  }
14617
15799
  async function clearProfileCreationLogFiles(paths) {
14618
15800
  const primary = profileCreationLogPath(paths);
@@ -14625,8 +15807,8 @@ async function clearProfileCreationLogFiles(paths) {
14625
15807
  ]);
14626
15808
  }
14627
15809
  async function pathExists(targetPath) {
14628
- return await stat11(targetPath).then(() => true).catch((error) => {
14629
- if (isNodeError13(error, "ENOENT")) {
15810
+ return await stat12(targetPath).then(() => true).catch((error) => {
15811
+ if (isNodeError14(error, "ENOENT")) {
14630
15812
  return false;
14631
15813
  }
14632
15814
  throw error;
@@ -14658,7 +15840,7 @@ function ensureRecord2(target, key) {
14658
15840
  target[key] = next;
14659
15841
  return next;
14660
15842
  }
14661
- function toRecord12(value) {
15843
+ function toRecord13(value) {
14662
15844
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
14663
15845
  }
14664
15846
  function cloneJson(value) {
@@ -14673,7 +15855,7 @@ function formatEnvValue2(value) {
14673
15855
  function escapeRegExp2(value) {
14674
15856
  return value.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
14675
15857
  }
14676
- function isNodeError13(error, code) {
15858
+ function isNodeError14(error, code) {
14677
15859
  return typeof error === "object" && error !== null && "code" in error && error.code === code;
14678
15860
  }
14679
15861
 
@@ -14758,16 +15940,16 @@ function readProfilePermissionsInput(body) {
14758
15940
  const approvals = readOptionalObject(body, "approvals");
14759
15941
  if (approvals) {
14760
15942
  input.approvals = {
14761
- mode: readString13(approvals, "mode") ?? readString13(approvals, "approval_mode") ?? readString13(approvals, "approvalMode") ?? void 0,
15943
+ mode: readString14(approvals, "mode") ?? readString14(approvals, "approval_mode") ?? readString14(approvals, "approvalMode") ?? void 0,
14762
15944
  timeout: readPositiveInteger2(approvals.timeout),
14763
- cronMode: readString13(approvals, "cron_mode") ?? readString13(approvals, "cronMode") ?? void 0
15945
+ cronMode: readString14(approvals, "cron_mode") ?? readString14(approvals, "cronMode") ?? void 0
14764
15946
  };
14765
15947
  }
14766
15948
  const terminal = readOptionalObject(body, "terminal");
14767
15949
  if (terminal) {
14768
15950
  input.terminal = {
14769
- backend: readString13(terminal, "backend") ?? void 0,
14770
- cwd: readString13(terminal, "cwd") ?? void 0,
15951
+ backend: readString14(terminal, "backend") ?? void 0,
15952
+ cwd: readString14(terminal, "cwd") ?? void 0,
14771
15953
  containerCpu: readPositiveInteger2(
14772
15954
  terminal.container_cpu ?? terminal.containerCpu
14773
15955
  ),
@@ -14777,7 +15959,7 @@ function readProfilePermissionsInput(body) {
14777
15959
  containerDisk: readPositiveInteger2(
14778
15960
  terminal.container_disk ?? terminal.containerDisk
14779
15961
  ),
14780
- containerPersistent: readBoolean(
15962
+ containerPersistent: readBoolean2(
14781
15963
  terminal.container_persistent ?? terminal.containerPersistent
14782
15964
  )
14783
15965
  };
@@ -14789,7 +15971,7 @@ function readProfilePermissionsInput(body) {
14789
15971
  toolsets.enabled_toolsets ?? toolsets.enabledToolsets ?? toolsets.enabled,
14790
15972
  "toolsets.enabled"
14791
15973
  ) ?? void 0,
14792
- mcpEnabled: readBoolean(toolsets.mcp_enabled ?? toolsets.mcpEnabled)
15974
+ mcpEnabled: readBoolean2(toolsets.mcp_enabled ?? toolsets.mcpEnabled)
14793
15975
  };
14794
15976
  }
14795
15977
  if (Object.keys(input).length === 0) {
@@ -14884,13 +16066,13 @@ import {
14884
16066
  access as access3,
14885
16067
  copyFile as copyFile3,
14886
16068
  mkdir as mkdir12,
14887
- readdir as readdir8,
14888
- readFile as readFile13,
16069
+ readdir as readdir9,
16070
+ readFile as readFile14,
14889
16071
  rename as rename6,
14890
- stat as stat12,
16072
+ stat as stat13,
14891
16073
  writeFile as writeFile5
14892
16074
  } from "fs/promises";
14893
- import path18 from "path";
16075
+ import path19 from "path";
14894
16076
  import YAML4 from "yaml";
14895
16077
  var ENTRY_DELIMITER = "\n\xA7\n";
14896
16078
  var DEFAULT_MEMORY_LIMIT = 2200;
@@ -15107,7 +16289,7 @@ async function saveProviderSettings(profileName, provider, patch) {
15107
16289
  if (provider === "hindsight") {
15108
16290
  await patchJsonProviderConfig(
15109
16291
  profileName,
15110
- path18.join("hindsight", "config.json"),
16292
+ path19.join("hindsight", "config.json"),
15111
16293
  {
15112
16294
  mode: patch.mode,
15113
16295
  api_url: patch.apiUrl,
@@ -15160,7 +16342,7 @@ async function patchCustomProviderConfig(profileName, provider, patch) {
15160
16342
  "\u81EA\u5B9A\u4E49 memory provider \u914D\u7F6E\u5FC5\u987B\u662F\u6709\u6548\u7684 JSON object\u3002"
15161
16343
  );
15162
16344
  }
15163
- const config = toRecord13(parsed);
16345
+ const config = toRecord14(parsed);
15164
16346
  if (Object.keys(config).length === 0 && parsed !== null) {
15165
16347
  throw new HermesMemoryError(
15166
16348
  "memory_provider_config_invalid",
@@ -15201,7 +16383,7 @@ function isSensitiveConfigKey(key) {
15201
16383
  }
15202
16384
  async function writeCustomProviderConfig(profileName, provider, config) {
15203
16385
  const configPath = customProviderConfigPath(profileName, provider);
15204
- await mkdir12(path18.dirname(configPath), { recursive: true, mode: 448 });
16386
+ await mkdir12(path19.dirname(configPath), { recursive: true, mode: 448 });
15205
16387
  await writeFile5(configPath, `${JSON.stringify(config, null, 2)}
15206
16388
  `, {
15207
16389
  encoding: "utf8",
@@ -15252,21 +16434,21 @@ function normalizeCustomProviderId(provider) {
15252
16434
  }
15253
16435
  async function patchHermesMemoryProvider(profileName, provider) {
15254
16436
  const configPath = resolveHermesConfigPath(profileName);
15255
- const existingRaw = await readFile13(configPath, "utf8").catch(
16437
+ const existingRaw = await readFile14(configPath, "utf8").catch(
15256
16438
  (error) => {
15257
- if (isNodeError14(error, "ENOENT")) {
16439
+ if (isNodeError15(error, "ENOENT")) {
15258
16440
  return null;
15259
16441
  }
15260
16442
  throw error;
15261
16443
  }
15262
16444
  );
15263
16445
  const document = existingRaw ? YAML4.parseDocument(existingRaw) : new YAML4.Document({});
15264
- const config = toRecord13(document.toJSON());
15265
- const memory = toRecord13(config.memory);
16446
+ const config = toRecord14(document.toJSON());
16447
+ const memory = toRecord14(config.memory);
15266
16448
  memory.provider = provider === "built-in" ? "" : provider;
15267
16449
  config.memory = memory;
15268
16450
  const backupPath = existingRaw ? `${configPath}.bak.${Date.now()}` : null;
15269
- await mkdir12(path18.dirname(configPath), { recursive: true, mode: 448 });
16451
+ await mkdir12(path19.dirname(configPath), { recursive: true, mode: 448 });
15270
16452
  if (backupPath) {
15271
16453
  await copyFile3(configPath, backupPath);
15272
16454
  }
@@ -15279,13 +16461,13 @@ async function patchHermesMemoryProvider(profileName, provider) {
15279
16461
  await rename6(tempPath, configPath);
15280
16462
  }
15281
16463
  function resolveMemoryDir(profileName) {
15282
- return path18.join(resolveHermesProfileDir(profileName), "memories");
16464
+ return path19.join(resolveHermesProfileDir(profileName), "memories");
15283
16465
  }
15284
16466
  async function readMemoryStore(profileName, target, limits) {
15285
16467
  const filePath = memoryFilePath(profileName, target);
15286
16468
  const entries = await readMemoryEntries(filePath);
15287
- const fileStat = await stat12(filePath).catch((error) => {
15288
- if (isNodeError14(error, "ENOENT")) {
16469
+ const fileStat = await stat13(filePath).catch((error) => {
16470
+ if (isNodeError15(error, "ENOENT")) {
15289
16471
  return null;
15290
16472
  }
15291
16473
  throw error;
@@ -15313,8 +16495,8 @@ async function readMemoryStore(profileName, target, limits) {
15313
16495
  };
15314
16496
  }
15315
16497
  async function readMemoryEntries(filePath) {
15316
- const raw = await readFile13(filePath, "utf8").catch((error) => {
15317
- if (isNodeError14(error, "ENOENT")) {
16498
+ const raw = await readFile14(filePath, "utf8").catch((error) => {
16499
+ if (isNodeError15(error, "ENOENT")) {
15318
16500
  return "";
15319
16501
  }
15320
16502
  throw error;
@@ -15334,9 +16516,9 @@ async function mutateMemoryEntries(profileName, target, mutate) {
15334
16516
  async function writeMemoryEntries(profileName, target, entries) {
15335
16517
  assertWithinLimit(target, entries, await readMemoryLimits(profileName));
15336
16518
  const filePath = memoryFilePath(profileName, target);
15337
- const dir = path18.dirname(filePath);
16519
+ const dir = path19.dirname(filePath);
15338
16520
  await mkdir12(dir, { recursive: true, mode: 448 });
15339
- const tempPath = path18.join(
16521
+ const tempPath = path19.join(
15340
16522
  dir,
15341
16523
  `.mem_${process.pid}_${Date.now()}_${target}.tmp`
15342
16524
  );
@@ -15347,7 +16529,7 @@ async function writeMemoryEntries(profileName, target, entries) {
15347
16529
  await rename6(tempPath, filePath);
15348
16530
  }
15349
16531
  function memoryFilePath(profileName, target) {
15350
- return path18.join(
16532
+ return path19.join(
15351
16533
  resolveMemoryDir(profileName),
15352
16534
  target === "user" ? "USER.md" : "MEMORY.md"
15353
16535
  );
@@ -15407,7 +16589,7 @@ async function readCustomProviderSetupSummary(profileName) {
15407
16589
  configurable: true,
15408
16590
  configured: true,
15409
16591
  configurationIssue: null,
15410
- providerConfigPath: path18.join(
16592
+ providerConfigPath: path19.join(
15411
16593
  resolveHermesProfileDir(profileName),
15412
16594
  "<provider>.json"
15413
16595
  ),
@@ -15485,7 +16667,7 @@ async function readProviderConfigurationStatus(profileName, provider) {
15485
16667
  const config2 = await readJsonObject(
15486
16668
  memoryProviderConfigPath(profileName, "honcho") ?? ""
15487
16669
  );
15488
- return isConfiguredEnvValue(env.HONCHO_API_KEY) || isConfiguredEnvValue(readString14(config2.apiKey)) || isConfiguredEnvValue(readString14(config2.api_key)) || isConfiguredEnvValue(readString14(config2.baseUrl)) ? { configured: true, issue: null } : {
16670
+ return isConfiguredEnvValue(env.HONCHO_API_KEY) || isConfiguredEnvValue(readString15(config2.apiKey)) || isConfiguredEnvValue(readString15(config2.api_key)) || isConfiguredEnvValue(readString15(config2.baseUrl)) ? { configured: true, issue: null } : {
15489
16671
  configured: false,
15490
16672
  issue: "Honcho \u9700\u8981\u5148\u914D\u7F6E HONCHO_API_KEY\uFF0C\u6216\u5728 honcho.json \u914D\u7F6E self-hosted baseUrl\u3002"
15491
16673
  };
@@ -15494,7 +16676,7 @@ async function readProviderConfigurationStatus(profileName, provider) {
15494
16676
  const config2 = await readJsonObject(
15495
16677
  memoryProviderConfigPath(profileName, "mem0") ?? ""
15496
16678
  );
15497
- return isConfiguredEnvValue(env.MEM0_API_KEY) || isConfiguredEnvValue(readString14(config2.api_key)) ? { configured: true, issue: null } : {
16679
+ return isConfiguredEnvValue(env.MEM0_API_KEY) || isConfiguredEnvValue(readString15(config2.api_key)) ? { configured: true, issue: null } : {
15498
16680
  configured: false,
15499
16681
  issue: "Mem0 \u9700\u8981\u5148\u5728\u672C\u673A Hermes .env \u914D\u7F6E MEM0_API_KEY\u3002"
15500
16682
  };
@@ -15536,7 +16718,7 @@ async function readProviderConfigurationStatus(profileName, provider) {
15536
16718
  memoryProviderConfigPath(profileName, provider) ?? ""
15537
16719
  );
15538
16720
  const mode = normalizeHindsightMode(config.mode ?? env.HINDSIGHT_MODE);
15539
- const apiKey = readString14(config.apiKey) ?? readString14(config.api_key) ?? env.HINDSIGHT_API_KEY;
16721
+ const apiKey = readString15(config.apiKey) ?? readString15(config.api_key) ?? env.HINDSIGHT_API_KEY;
15540
16722
  if (mode === "cloud") {
15541
16723
  return isConfiguredEnvValue(apiKey) ? { configured: true, issue: null } : {
15542
16724
  configured: false,
@@ -15544,15 +16726,15 @@ async function readProviderConfigurationStatus(profileName, provider) {
15544
16726
  };
15545
16727
  }
15546
16728
  if (mode === "local_external") {
15547
- const apiUrl = readString14(config.api_url) ?? env.HINDSIGHT_API_URL ?? HINDSIGHT_DEFAULT_LOCAL_URL;
16729
+ const apiUrl = readString15(config.api_url) ?? env.HINDSIGHT_API_URL ?? HINDSIGHT_DEFAULT_LOCAL_URL;
15548
16730
  return isConfiguredEnvValue(apiUrl) ? { configured: true, issue: null } : {
15549
16731
  configured: false,
15550
16732
  issue: "Hindsight local_external \u9700\u8981\u914D\u7F6E\u53EF\u8BBF\u95EE\u7684 API URL\u3002"
15551
16733
  };
15552
16734
  }
15553
16735
  if (mode === "local_embedded") {
15554
- const llmProvider = readString14(config.llm_provider) ?? "openai";
15555
- const llmModel = readString14(config.llm_model);
16736
+ const llmProvider = readString15(config.llm_provider) ?? "openai";
16737
+ const llmModel = readString15(config.llm_model);
15556
16738
  if (!llmModel) {
15557
16739
  return {
15558
16740
  configured: false,
@@ -15560,7 +16742,7 @@ async function readProviderConfigurationStatus(profileName, provider) {
15560
16742
  };
15561
16743
  }
15562
16744
  if (llmProvider === "openai_compatible" && !isConfiguredEnvValue(
15563
- readString14(config.llm_base_url) ?? env.HINDSIGHT_API_LLM_BASE_URL
16745
+ readString15(config.llm_base_url) ?? env.HINDSIGHT_API_LLM_BASE_URL
15564
16746
  )) {
15565
16747
  return {
15566
16748
  configured: false,
@@ -15568,7 +16750,7 @@ async function readProviderConfigurationStatus(profileName, provider) {
15568
16750
  };
15569
16751
  }
15570
16752
  if (!["ollama", "lmstudio", "openai_compatible"].includes(llmProvider) && !isConfiguredEnvValue(
15571
- readString14(config.llmApiKey) ?? readString14(config.llm_api_key) ?? env.HINDSIGHT_LLM_API_KEY
16753
+ readString15(config.llmApiKey) ?? readString15(config.llm_api_key) ?? env.HINDSIGHT_LLM_API_KEY
15572
16754
  )) {
15573
16755
  return {
15574
16756
  configured: false,
@@ -15708,8 +16890,8 @@ async function readProviderSettings(profileName, provider) {
15708
16890
  const config = await readJsonObject(
15709
16891
  memoryProviderConfigPath(profileName, provider) ?? ""
15710
16892
  );
15711
- const banks = toRecord13(config.banks);
15712
- const hermesBank = toRecord13(banks.hermes);
16893
+ const banks = toRecord14(config.banks);
16894
+ const hermesBank = toRecord14(banks.hermes);
15713
16895
  const mode = normalizeHindsightMode(config.mode);
15714
16896
  return [
15715
16897
  selectSetting("mode", "\u8FDE\u63A5\u6A21\u5F0F", mode, [
@@ -15761,7 +16943,7 @@ async function readProviderSettings(profileName, provider) {
15761
16943
  stringSetting(
15762
16944
  "dbPath",
15763
16945
  "SQLite \u6570\u636E\u5E93\u8DEF\u5F84",
15764
- config.db_path ?? path18.join(resolveHermesProfileDir(profileName), "memory_store.db")
16946
+ config.db_path ?? path19.join(resolveHermesProfileDir(profileName), "memory_store.db")
15765
16947
  ),
15766
16948
  booleanSetting("autoExtract", "\u4F1A\u8BDD\u7ED3\u675F\u81EA\u52A8\u62BD\u53D6", config.auto_extract ?? false),
15767
16949
  numberSetting("defaultTrust", "\u9ED8\u8BA4\u4FE1\u4EFB\u5206", config.default_trust ?? 0.5),
@@ -15784,7 +16966,7 @@ async function readProviderSettings(profileName, provider) {
15784
16966
  stringSetting(
15785
16967
  "workingDirectory",
15786
16968
  "\u5DE5\u4F5C\u76EE\u5F55",
15787
- path18.join(resolveHermesProfileDir(profileName), "byterover"),
16969
+ path19.join(resolveHermesProfileDir(profileName), "byterover"),
15788
16970
  false
15789
16971
  )
15790
16972
  ];
@@ -15793,16 +16975,16 @@ async function readProviderSettings(profileName, provider) {
15793
16975
  }
15794
16976
  function memoryProviderConfigPath(profileName, provider) {
15795
16977
  if (provider === "honcho") {
15796
- return path18.join(resolveHermesProfileDir(profileName), "honcho.json");
16978
+ return path19.join(resolveHermesProfileDir(profileName), "honcho.json");
15797
16979
  }
15798
16980
  if (provider === "mem0") {
15799
- return path18.join(resolveHermesProfileDir(profileName), "mem0.json");
16981
+ return path19.join(resolveHermesProfileDir(profileName), "mem0.json");
15800
16982
  }
15801
16983
  if (provider === "supermemory") {
15802
- return path18.join(resolveHermesProfileDir(profileName), "supermemory.json");
16984
+ return path19.join(resolveHermesProfileDir(profileName), "supermemory.json");
15803
16985
  }
15804
16986
  if (provider === "hindsight") {
15805
- return path18.join(
16987
+ return path19.join(
15806
16988
  resolveHermesProfileDir(profileName),
15807
16989
  "hindsight",
15808
16990
  "config.json"
@@ -15811,21 +16993,21 @@ function memoryProviderConfigPath(profileName, provider) {
15811
16993
  return null;
15812
16994
  }
15813
16995
  function customProviderConfigPath(profileName, provider) {
15814
- return path18.join(
16996
+ return path19.join(
15815
16997
  resolveHermesProfileDir(profileName),
15816
16998
  `${normalizeCustomProviderId(provider)}.json`
15817
16999
  );
15818
17000
  }
15819
17001
  function customProviderRegistryPath(profileName) {
15820
- return path18.join(
17002
+ return path19.join(
15821
17003
  resolveHermesProfileDir(profileName),
15822
17004
  CUSTOM_PROVIDER_REGISTRY_FILE
15823
17005
  );
15824
17006
  }
15825
17007
  async function readCustomProviderRegistry(profileName) {
15826
- const raw = await readFile13(customProviderRegistryPath(profileName), "utf8").catch(
17008
+ const raw = await readFile14(customProviderRegistryPath(profileName), "utf8").catch(
15827
17009
  (error) => {
15828
- if (isNodeError14(error, "ENOENT")) {
17010
+ if (isNodeError15(error, "ENOENT")) {
15829
17011
  return "";
15830
17012
  }
15831
17013
  throw error;
@@ -15836,18 +17018,18 @@ async function readCustomProviderRegistry(profileName) {
15836
17018
  }
15837
17019
  try {
15838
17020
  const parsed = JSON.parse(raw);
15839
- const providers = Array.isArray(parsed) ? parsed : Array.isArray(toRecord13(parsed).providers) ? toRecord13(parsed).providers : [];
17021
+ const providers = Array.isArray(parsed) ? parsed : Array.isArray(toRecord14(parsed).providers) ? toRecord14(parsed).providers : [];
15840
17022
  return providers.map((item) => {
15841
17023
  if (typeof item === "string") {
15842
17024
  const id2 = normalizeCustomProviderId(item);
15843
17025
  return { id: id2, label: id2, description: "\u81EA\u5B9A\u4E49 memory provider\u3002" };
15844
17026
  }
15845
- const record = toRecord13(item);
15846
- const id = normalizeCustomProviderId(readString14(record.id) ?? "");
17027
+ const record = toRecord14(item);
17028
+ const id = normalizeCustomProviderId(readString15(record.id) ?? "");
15847
17029
  return {
15848
17030
  id,
15849
- label: readString14(record.label) ?? id,
15850
- description: readString14(record.description) ?? "\u81EA\u5B9A\u4E49 memory provider\u3002"
17031
+ label: readString15(record.label) ?? id,
17032
+ description: readString15(record.description) ?? "\u81EA\u5B9A\u4E49 memory provider\u3002"
15851
17033
  };
15852
17034
  }).filter((item) => item.id);
15853
17035
  } catch {
@@ -15862,7 +17044,7 @@ async function saveCustomProviderRegistryEntry(profileName, provider) {
15862
17044
  { id: providerId, label: providerId, description: "\u81EA\u5B9A\u4E49 memory provider\u3002" }
15863
17045
  ].sort((left, right) => left.id.localeCompare(right.id));
15864
17046
  const registryPath2 = customProviderRegistryPath(profileName);
15865
- await mkdir12(path18.dirname(registryPath2), { recursive: true, mode: 448 });
17047
+ await mkdir12(path19.dirname(registryPath2), { recursive: true, mode: 448 });
15866
17048
  await writeFile5(
15867
17049
  registryPath2,
15868
17050
  `${JSON.stringify({ providers }, null, 2)}
@@ -15871,10 +17053,10 @@ async function saveCustomProviderRegistryEntry(profileName, provider) {
15871
17053
  );
15872
17054
  }
15873
17055
  async function discoverUserMemoryProviderDescriptors(profileName) {
15874
- const pluginsDir = path18.join(resolveHermesProfileDir(profileName), "plugins");
15875
- const entries = await readdir8(pluginsDir, { withFileTypes: true }).catch(
17056
+ const pluginsDir = path19.join(resolveHermesProfileDir(profileName), "plugins");
17057
+ const entries = await readdir9(pluginsDir, { withFileTypes: true }).catch(
15876
17058
  (error) => {
15877
- if (isNodeError14(error, "ENOENT")) {
17059
+ if (isNodeError15(error, "ENOENT")) {
15878
17060
  return [];
15879
17061
  }
15880
17062
  throw error;
@@ -15891,21 +17073,21 @@ async function discoverUserMemoryProviderDescriptors(profileName) {
15891
17073
  } catch {
15892
17074
  continue;
15893
17075
  }
15894
- const providerDir = path18.join(pluginsDir, entry.name);
17076
+ const providerDir = path19.join(pluginsDir, entry.name);
15895
17077
  if (!await isMemoryProviderPluginDir(providerDir)) {
15896
17078
  continue;
15897
17079
  }
15898
17080
  const meta = await readPluginMetadata(providerDir);
15899
17081
  descriptors.push({
15900
17082
  id: providerId,
15901
- label: readString14(meta.name) ?? providerId,
15902
- description: readString14(meta.description) ?? "\u81EA\u5B9A\u4E49 memory provider\u3002"
17083
+ label: readString15(meta.name) ?? providerId,
17084
+ description: readString15(meta.description) ?? "\u81EA\u5B9A\u4E49 memory provider\u3002"
15903
17085
  });
15904
17086
  }
15905
17087
  return descriptors;
15906
17088
  }
15907
17089
  async function isUserMemoryProviderInstalled(profileName, provider) {
15908
- const providerDir = path18.join(
17090
+ const providerDir = path19.join(
15909
17091
  resolveHermesProfileDir(profileName),
15910
17092
  "plugins",
15911
17093
  normalizeCustomProviderId(provider)
@@ -15913,9 +17095,9 @@ async function isUserMemoryProviderInstalled(profileName, provider) {
15913
17095
  return isMemoryProviderPluginDir(providerDir);
15914
17096
  }
15915
17097
  async function isMemoryProviderPluginDir(providerDir) {
15916
- const source = await readFile13(path18.join(providerDir, "__init__.py"), "utf8").catch(
17098
+ const source = await readFile14(path19.join(providerDir, "__init__.py"), "utf8").catch(
15917
17099
  (error) => {
15918
- if (isNodeError14(error, "ENOENT")) {
17100
+ if (isNodeError15(error, "ENOENT")) {
15919
17101
  return "";
15920
17102
  }
15921
17103
  throw error;
@@ -15925,22 +17107,22 @@ async function isMemoryProviderPluginDir(providerDir) {
15925
17107
  return sample.includes("register_memory_provider") || sample.includes("MemoryProvider");
15926
17108
  }
15927
17109
  async function readPluginMetadata(providerDir) {
15928
- const raw = await readFile13(path18.join(providerDir, "plugin.yaml"), "utf8").catch(
17110
+ const raw = await readFile14(path19.join(providerDir, "plugin.yaml"), "utf8").catch(
15929
17111
  (error) => {
15930
- if (isNodeError14(error, "ENOENT")) {
17112
+ if (isNodeError15(error, "ENOENT")) {
15931
17113
  return "";
15932
17114
  }
15933
17115
  throw error;
15934
17116
  }
15935
17117
  );
15936
- return raw ? toRecord13(YAML4.parse(raw)) : {};
17118
+ return raw ? toRecord14(YAML4.parse(raw)) : {};
15937
17119
  }
15938
17120
  async function resolveByteRoverCli() {
15939
17121
  const candidates = [
15940
- ...(process.env.PATH ?? "").split(path18.delimiter).filter(Boolean).map((dir) => path18.join(dir, "brv")),
15941
- path18.join(process.env.HOME ?? "", ".brv-cli", "bin", "brv"),
17122
+ ...(process.env.PATH ?? "").split(path19.delimiter).filter(Boolean).map((dir) => path19.join(dir, "brv")),
17123
+ path19.join(process.env.HOME ?? "", ".brv-cli", "bin", "brv"),
15942
17124
  "/usr/local/bin/brv",
15943
- path18.join(process.env.HOME ?? "", ".npm-global", "bin", "brv")
17125
+ path19.join(process.env.HOME ?? "", ".npm-global", "bin", "brv")
15944
17126
  ].filter(Boolean);
15945
17127
  for (const candidate of candidates) {
15946
17128
  const found = await access3(candidate).then(() => true).catch(() => false);
@@ -15951,32 +17133,32 @@ async function resolveByteRoverCli() {
15951
17133
  return null;
15952
17134
  }
15953
17135
  async function readHolographicProviderConfig(profileName) {
15954
- const raw = await readFile13(resolveHermesConfigPath(profileName), "utf8").catch(
17136
+ const raw = await readFile14(resolveHermesConfigPath(profileName), "utf8").catch(
15955
17137
  (error) => {
15956
- if (isNodeError14(error, "ENOENT")) {
17138
+ if (isNodeError15(error, "ENOENT")) {
15957
17139
  return "";
15958
17140
  }
15959
17141
  throw error;
15960
17142
  }
15961
17143
  );
15962
- const config = raw ? toRecord13(YAML4.parse(raw)) : {};
15963
- const plugins = toRecord13(config.plugins);
15964
- return toRecord13(plugins["hermes-memory-store"]);
17144
+ const config = raw ? toRecord14(YAML4.parse(raw)) : {};
17145
+ const plugins = toRecord14(config.plugins);
17146
+ return toRecord14(plugins["hermes-memory-store"]);
15965
17147
  }
15966
17148
  async function patchHolographicProviderConfig(profileName, patch) {
15967
17149
  const configPath = resolveHermesConfigPath(profileName);
15968
- const existingRaw = await readFile13(configPath, "utf8").catch(
17150
+ const existingRaw = await readFile14(configPath, "utf8").catch(
15969
17151
  (error) => {
15970
- if (isNodeError14(error, "ENOENT")) {
17152
+ if (isNodeError15(error, "ENOENT")) {
15971
17153
  return null;
15972
17154
  }
15973
17155
  throw error;
15974
17156
  }
15975
17157
  );
15976
17158
  const document = existingRaw ? YAML4.parseDocument(existingRaw) : new YAML4.Document({});
15977
- const config = toRecord13(document.toJSON());
15978
- const plugins = toRecord13(config.plugins);
15979
- const memoryStore = toRecord13(plugins["hermes-memory-store"]);
17159
+ const config = toRecord14(document.toJSON());
17160
+ const plugins = toRecord14(config.plugins);
17161
+ const memoryStore = toRecord14(plugins["hermes-memory-store"]);
15980
17162
  for (const [key, value] of Object.entries(patch)) {
15981
17163
  if (value !== void 0) {
15982
17164
  memoryStore[key] = value;
@@ -15984,7 +17166,7 @@ async function patchHolographicProviderConfig(profileName, patch) {
15984
17166
  }
15985
17167
  plugins["hermes-memory-store"] = memoryStore;
15986
17168
  config.plugins = plugins;
15987
- await mkdir12(path18.dirname(configPath), { recursive: true, mode: 448 });
17169
+ await mkdir12(path19.dirname(configPath), { recursive: true, mode: 448 });
15988
17170
  if (existingRaw) {
15989
17171
  await copyFile3(configPath, `${configPath}.bak.${Date.now()}`);
15990
17172
  }
@@ -16003,9 +17185,9 @@ async function patchHermesMemoryEnv(profileName, patch) {
16003
17185
  if (entries.length === 0) {
16004
17186
  return;
16005
17187
  }
16006
- const envPath = path18.join(resolveHermesProfileDir(profileName), ".env");
16007
- const existingRaw = await readFile13(envPath, "utf8").catch((error) => {
16008
- if (isNodeError14(error, "ENOENT")) {
17188
+ const envPath = path19.join(resolveHermesProfileDir(profileName), ".env");
17189
+ const existingRaw = await readFile14(envPath, "utf8").catch((error) => {
17190
+ if (isNodeError15(error, "ENOENT")) {
16009
17191
  return "";
16010
17192
  }
16011
17193
  throw error;
@@ -16035,7 +17217,7 @@ async function patchHermesMemoryEnv(profileName, patch) {
16035
17217
  }
16036
17218
  }
16037
17219
  const nextRaw = nextLines.join("\n").replace(/\n*$/u, "\n");
16038
- await mkdir12(path18.dirname(envPath), { recursive: true, mode: 448 });
17220
+ await mkdir12(path19.dirname(envPath), { recursive: true, mode: 448 });
16039
17221
  if (existingRaw) {
16040
17222
  await copyFile3(envPath, `${envPath}.bak.${Date.now()}`);
16041
17223
  }
@@ -16054,29 +17236,29 @@ function isMemoryEnvKeyWritable(key) {
16054
17236
  ].includes(key);
16055
17237
  }
16056
17238
  function normalizeHindsightMode(value) {
16057
- const mode = readString14(value) ?? "cloud";
17239
+ const mode = readString15(value) ?? "cloud";
16058
17240
  return mode === "local" ? "local_embedded" : mode;
16059
17241
  }
16060
17242
  async function readActiveMemoryProvider(profileName) {
16061
- const raw = await readFile13(
17243
+ const raw = await readFile14(
16062
17244
  resolveHermesConfigPath(profileName),
16063
17245
  "utf8"
16064
17246
  ).catch((error) => {
16065
- if (isNodeError14(error, "ENOENT")) {
17247
+ if (isNodeError15(error, "ENOENT")) {
16066
17248
  return "";
16067
17249
  }
16068
17250
  throw error;
16069
17251
  });
16070
- const config = raw ? toRecord13(YAML4.parse(raw)) : {};
16071
- const memory = toRecord13(config.memory);
16072
- const provider = readString14(memory.provider);
17252
+ const config = raw ? toRecord14(YAML4.parse(raw)) : {};
17253
+ const memory = toRecord14(config.memory);
17254
+ const provider = readString15(memory.provider);
16073
17255
  if (!provider || provider === "built-in" || provider === "builtin" || provider === "built_in") {
16074
17256
  return null;
16075
17257
  }
16076
17258
  return provider;
16077
17259
  }
16078
17260
  async function patchJsonProviderConfig(profileName, relativePath, patch) {
16079
- const configPath = path18.join(
17261
+ const configPath = path19.join(
16080
17262
  resolveHermesProfileDir(profileName),
16081
17263
  relativePath
16082
17264
  );
@@ -16087,7 +17269,7 @@ async function patchJsonProviderConfig(profileName, relativePath, patch) {
16087
17269
  next[key] = value;
16088
17270
  }
16089
17271
  }
16090
- await mkdir12(path18.dirname(configPath), { recursive: true, mode: 448 });
17272
+ await mkdir12(path19.dirname(configPath), { recursive: true, mode: 448 });
16091
17273
  await writeFile5(configPath, `${JSON.stringify(next, null, 2)}
16092
17274
  `, {
16093
17275
  encoding: "utf8",
@@ -16095,18 +17277,18 @@ async function patchJsonProviderConfig(profileName, relativePath, patch) {
16095
17277
  });
16096
17278
  }
16097
17279
  async function readJsonObject(filePath) {
16098
- const raw = await readFile13(filePath, "utf8").catch((error) => {
16099
- if (isNodeError14(error, "ENOENT")) {
17280
+ const raw = await readFile14(filePath, "utf8").catch((error) => {
17281
+ if (isNodeError15(error, "ENOENT")) {
16100
17282
  return "{}";
16101
17283
  }
16102
17284
  throw error;
16103
17285
  });
16104
17286
  try {
16105
- return toRecord13(JSON.parse(raw || "{}"));
17287
+ return toRecord14(JSON.parse(raw || "{}"));
16106
17288
  } catch {
16107
17289
  throw new HermesMemoryError(
16108
17290
  "memory_provider_config_invalid",
16109
- `${path18.basename(filePath)} \u4E0D\u662F\u6709\u6548\u7684 JSON \u914D\u7F6E\u6587\u4EF6\u3002`
17291
+ `${path19.basename(filePath)} \u4E0D\u662F\u6709\u6548\u7684 JSON \u914D\u7F6E\u6587\u4EF6\u3002`
16110
17292
  );
16111
17293
  }
16112
17294
  }
@@ -16114,7 +17296,7 @@ function booleanSetting(key, label, value) {
16114
17296
  return {
16115
17297
  key,
16116
17298
  label,
16117
- value: readBoolean2(value) ?? false,
17299
+ value: readBoolean3(value) ?? false,
16118
17300
  editable: true,
16119
17301
  kind: "boolean"
16120
17302
  };
@@ -16127,7 +17309,7 @@ function stringSetting(key, label, value, editable = true) {
16127
17309
  return {
16128
17310
  key,
16129
17311
  label,
16130
- value: readString14(value) ?? "",
17312
+ value: readString15(value) ?? "",
16131
17313
  editable,
16132
17314
  kind: "string"
16133
17315
  };
@@ -16142,21 +17324,21 @@ function textSetting(key, label, value, editable = true) {
16142
17324
  };
16143
17325
  }
16144
17326
  function selectSetting(key, label, value, options, editable = true) {
16145
- const stringValue = readString14(value) ?? options[0] ?? null;
17327
+ const stringValue = readString15(value) ?? options[0] ?? null;
16146
17328
  return { key, label, value: stringValue, editable, kind: "select", options };
16147
17329
  }
16148
17330
  async function readMemoryLimits(profileName) {
16149
- const raw = await readFile13(
17331
+ const raw = await readFile14(
16150
17332
  resolveHermesConfigPath(profileName),
16151
17333
  "utf8"
16152
17334
  ).catch((error) => {
16153
- if (isNodeError14(error, "ENOENT")) {
17335
+ if (isNodeError15(error, "ENOENT")) {
16154
17336
  return "";
16155
17337
  }
16156
17338
  throw error;
16157
17339
  });
16158
- const config = raw ? toRecord13(YAML4.parse(raw)) : {};
16159
- const memory = toRecord13(config.memory);
17340
+ const config = raw ? toRecord14(YAML4.parse(raw)) : {};
17341
+ const memory = toRecord14(config.memory);
16160
17342
  return {
16161
17343
  memory: readPositiveInteger3(memory.memory_char_limit) ?? DEFAULT_MEMORY_LIMIT,
16162
17344
  user: readPositiveInteger3(memory.user_char_limit) ?? DEFAULT_USER_LIMIT
@@ -16212,17 +17394,17 @@ function hashString(value) {
16212
17394
  }
16213
17395
  return hash.toString(16);
16214
17396
  }
16215
- function toRecord13(value) {
17397
+ function toRecord14(value) {
16216
17398
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
16217
17399
  }
16218
- function readString14(value) {
17400
+ function readString15(value) {
16219
17401
  return typeof value === "string" && value.trim() ? value.trim() : null;
16220
17402
  }
16221
17403
  function readPositiveInteger3(value) {
16222
17404
  const numberValue = typeof value === "number" ? value : typeof value === "string" ? Number(value.trim()) : NaN;
16223
17405
  return Number.isFinite(numberValue) && numberValue > 0 ? Math.floor(numberValue) : void 0;
16224
17406
  }
16225
- function readBoolean2(value) {
17407
+ function readBoolean3(value) {
16226
17408
  if (typeof value === "boolean") {
16227
17409
  return value;
16228
17410
  }
@@ -16243,7 +17425,7 @@ function formatEnvValue3(value) {
16243
17425
  function escapeRegExp3(value) {
16244
17426
  return value.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
16245
17427
  }
16246
- function isNodeError14(error, code) {
17428
+ function isNodeError15(error, code) {
16247
17429
  return error instanceof Error && "code" in error && error.code === code;
16248
17430
  }
16249
17431
 
@@ -16357,7 +17539,7 @@ function registerProfileMemoryRoutes(router, options) {
16357
17539
  );
16358
17540
  }
16359
17541
  function readMemoryTarget(body) {
16360
- const raw = readString13(body, "target");
17542
+ const raw = readString14(body, "target");
16361
17543
  if (raw === "memory" || raw === "user") {
16362
17544
  return raw;
16363
17545
  }
@@ -16368,7 +17550,7 @@ function readMemoryTarget(body) {
16368
17550
  );
16369
17551
  }
16370
17552
  function readMemoryResetTarget(body) {
16371
- const raw = readString13(body, "target") ?? "all";
17553
+ const raw = readString14(body, "target") ?? "all";
16372
17554
  if (raw === "all" || raw === "memory" || raw === "user") {
16373
17555
  return raw;
16374
17556
  }
@@ -16379,7 +17561,7 @@ function readMemoryResetTarget(body) {
16379
17561
  );
16380
17562
  }
16381
17563
  function readRequiredMemoryContent(body) {
16382
- const content = readString13(body, "content") ?? readString13(body, "text");
17564
+ const content = readString14(body, "content") ?? readString14(body, "text");
16383
17565
  if (!content) {
16384
17566
  throw new LinkHttpError(
16385
17567
  400,
@@ -16390,7 +17572,7 @@ function readRequiredMemoryContent(body) {
16390
17572
  return content;
16391
17573
  }
16392
17574
  function readRequiredMemoryMatch(body) {
16393
- const oldText = readString13(body, "old_text") ?? readString13(body, "oldText") ?? readString13(body, "match");
17575
+ const oldText = readString14(body, "old_text") ?? readString14(body, "oldText") ?? readString14(body, "match");
16394
17576
  if (!oldText) {
16395
17577
  throw new LinkHttpError(
16396
17578
  400,
@@ -16401,7 +17583,7 @@ function readRequiredMemoryMatch(body) {
16401
17583
  return oldText;
16402
17584
  }
16403
17585
  function readRequiredMemoryProvider(body) {
16404
- const provider = readString13(body, "provider") ?? readString13(body, "provider_id") ?? readString13(body, "providerId");
17586
+ const provider = readString14(body, "provider") ?? readString14(body, "provider_id") ?? readString14(body, "providerId");
16405
17587
  if (!provider) {
16406
17588
  throw new LinkHttpError(
16407
17589
  400,
@@ -16413,7 +17595,7 @@ function readRequiredMemoryProvider(body) {
16413
17595
  }
16414
17596
  function readMemorySettingsPatch(body) {
16415
17597
  const input = {};
16416
- const mode = readString13(body, "mode");
17598
+ const mode = readString14(body, "mode");
16417
17599
  if (mode) {
16418
17600
  input.mode = mode;
16419
17601
  }
@@ -16425,7 +17607,7 @@ function readMemorySettingsPatch(body) {
16425
17607
  if (bankId !== void 0) {
16426
17608
  input.bankId = bankId;
16427
17609
  }
16428
- const llmProvider = readString13(body, "llm_provider") ?? readString13(body, "llmProvider");
17610
+ const llmProvider = readString14(body, "llm_provider") ?? readString14(body, "llmProvider");
16429
17611
  if (llmProvider) {
16430
17612
  input.llmProvider = llmProvider;
16431
17613
  }
@@ -16441,23 +17623,23 @@ function readMemorySettingsPatch(body) {
16441
17623
  if (containerTag !== void 0) {
16442
17624
  input.containerTag = containerTag;
16443
17625
  }
16444
- const autoRecall = readBoolean(body.auto_recall ?? body.autoRecall);
17626
+ const autoRecall = readBoolean2(body.auto_recall ?? body.autoRecall);
16445
17627
  if (autoRecall !== void 0) {
16446
17628
  input.autoRecall = autoRecall;
16447
17629
  }
16448
- const autoCapture = readBoolean(body.auto_capture ?? body.autoCapture);
17630
+ const autoCapture = readBoolean2(body.auto_capture ?? body.autoCapture);
16449
17631
  if (autoCapture !== void 0) {
16450
17632
  input.autoCapture = autoCapture;
16451
17633
  }
16452
- const autoRetain = readBoolean(body.auto_retain ?? body.autoRetain);
17634
+ const autoRetain = readBoolean2(body.auto_retain ?? body.autoRetain);
16453
17635
  if (autoRetain !== void 0) {
16454
17636
  input.autoRetain = autoRetain;
16455
17637
  }
16456
- const memoryMode = readString13(body, "memory_mode") ?? readString13(body, "memoryMode");
17638
+ const memoryMode = readString14(body, "memory_mode") ?? readString14(body, "memoryMode");
16457
17639
  if (memoryMode) {
16458
17640
  input.memoryMode = memoryMode;
16459
17641
  }
16460
- const recallBudget = readString13(body, "recall_budget") ?? readString13(body, "recallBudget");
17642
+ const recallBudget = readString14(body, "recall_budget") ?? readString14(body, "recallBudget");
16461
17643
  if (recallBudget) {
16462
17644
  input.recallBudget = recallBudget;
16463
17645
  }
@@ -16473,11 +17655,11 @@ function readMemorySettingsPatch(body) {
16473
17655
  if (profileFrequency !== void 0) {
16474
17656
  input.profileFrequency = profileFrequency;
16475
17657
  }
16476
- const captureMode = readString13(body, "capture_mode") ?? readString13(body, "captureMode");
17658
+ const captureMode = readString14(body, "capture_mode") ?? readString14(body, "captureMode");
16477
17659
  if (captureMode) {
16478
17660
  input.captureMode = captureMode;
16479
17661
  }
16480
- const searchMode = readString13(body, "search_mode") ?? readString13(body, "searchMode");
17662
+ const searchMode = readString14(body, "search_mode") ?? readString14(body, "searchMode");
16481
17663
  if (searchMode) {
16482
17664
  input.searchMode = searchMode;
16483
17665
  }
@@ -16511,19 +17693,19 @@ function readMemorySettingsPatch(body) {
16511
17693
  if (aiPeer !== void 0) {
16512
17694
  input.aiPeer = aiPeer;
16513
17695
  }
16514
- const recallMode = readString13(body, "recall_mode") ?? readString13(body, "recallMode");
17696
+ const recallMode = readString14(body, "recall_mode") ?? readString14(body, "recallMode");
16515
17697
  if (recallMode) {
16516
17698
  input.recallMode = recallMode;
16517
17699
  }
16518
- const writeFrequency = readString13(body, "write_frequency") ?? readString13(body, "writeFrequency");
17700
+ const writeFrequency = readString14(body, "write_frequency") ?? readString14(body, "writeFrequency");
16519
17701
  if (writeFrequency) {
16520
17702
  input.writeFrequency = writeFrequency;
16521
17703
  }
16522
- const saveMessages = readBoolean(body.save_messages ?? body.saveMessages);
17704
+ const saveMessages = readBoolean2(body.save_messages ?? body.saveMessages);
16523
17705
  if (saveMessages !== void 0) {
16524
17706
  input.saveMessages = saveMessages;
16525
17707
  }
16526
- const sessionStrategy = readString13(body, "session_strategy") ?? readString13(body, "sessionStrategy");
17708
+ const sessionStrategy = readString14(body, "session_strategy") ?? readString14(body, "sessionStrategy");
16527
17709
  if (sessionStrategy) {
16528
17710
  input.sessionStrategy = sessionStrategy;
16529
17711
  }
@@ -16559,7 +17741,7 @@ function readMemorySettingsPatch(body) {
16559
17741
  if (agentId !== void 0) {
16560
17742
  input.agentId = agentId;
16561
17743
  }
16562
- const rerank = readBoolean(body.rerank);
17744
+ const rerank = readBoolean2(body.rerank);
16563
17745
  if (rerank !== void 0) {
16564
17746
  input.rerank = rerank;
16565
17747
  }
@@ -16583,7 +17765,7 @@ function readMemorySettingsPatch(body) {
16583
17765
  if (dbPath !== void 0) {
16584
17766
  input.dbPath = dbPath;
16585
17767
  }
16586
- const autoExtract = readBoolean(body.auto_extract ?? body.autoExtract);
17768
+ const autoExtract = readBoolean2(body.auto_extract ?? body.autoExtract);
16587
17769
  if (autoExtract !== void 0) {
16588
17770
  input.autoExtract = autoExtract;
16589
17771
  }
@@ -16654,12 +17836,12 @@ function toMemoryHttpError(error) {
16654
17836
  import {
16655
17837
  copyFile as copyFile4,
16656
17838
  mkdir as mkdir13,
16657
- readFile as readFile14,
16658
- readdir as readdir9,
17839
+ readFile as readFile15,
17840
+ readdir as readdir10,
16659
17841
  rename as rename7,
16660
17842
  writeFile as writeFile6
16661
17843
  } from "fs/promises";
16662
- import path19 from "path";
17844
+ import path20 from "path";
16663
17845
  import YAML5 from "yaml";
16664
17846
  var HermesSkillNotFoundError = class extends Error {
16665
17847
  constructor(skillName) {
@@ -16673,7 +17855,7 @@ var EXCLUDED_SKILL_DIRS = /* @__PURE__ */ new Set([".git", ".github", ".hub"]);
16673
17855
  async function listHermesProfileSkills(profileName, paths = resolveRuntimePaths()) {
16674
17856
  const profile = await readExistingProfile(profileName, paths);
16675
17857
  const profileDir = resolveHermesProfileDir(profile.name);
16676
- const skillsRoot = path19.join(profileDir, "skills");
17858
+ const skillsRoot = path20.join(profileDir, "skills");
16677
17859
  const [skillFiles, disabled, provenance] = await Promise.all([
16678
17860
  findSkillFiles(skillsRoot),
16679
17861
  readDisabledSkillNames(resolveHermesConfigPath(profile.name)),
@@ -16750,9 +17932,9 @@ async function findSkillFiles(root) {
16750
17932
  return results.sort((left, right) => left.localeCompare(right));
16751
17933
  }
16752
17934
  async function collectSkillFiles(directory, results) {
16753
- const entries = await readdir9(directory, { withFileTypes: true }).catch(
17935
+ const entries = await readdir10(directory, { withFileTypes: true }).catch(
16754
17936
  (error) => {
16755
- if (isNodeError15(error, "ENOENT")) {
17937
+ if (isNodeError16(error, "ENOENT")) {
16756
17938
  return [];
16757
17939
  }
16758
17940
  throw error;
@@ -16764,7 +17946,7 @@ async function collectSkillFiles(directory, results) {
16764
17946
  if (EXCLUDED_SKILL_DIRS.has(entry.name)) {
16765
17947
  continue;
16766
17948
  }
16767
- const entryPath = path19.join(directory, entry.name);
17949
+ const entryPath = path20.join(directory, entry.name);
16768
17950
  if (entry.isDirectory()) {
16769
17951
  await collectSkillFiles(entryPath, results);
16770
17952
  continue;
@@ -16775,9 +17957,9 @@ async function collectSkillFiles(directory, results) {
16775
17957
  }
16776
17958
  }
16777
17959
  async function readSkillMetadata(input) {
16778
- const raw = await readFile14(input.skillFile, "utf8").catch(
17960
+ const raw = await readFile15(input.skillFile, "utf8").catch(
16779
17961
  (error) => {
16780
- if (isNodeError15(error, "ENOENT") || isNodeError15(error, "EACCES")) {
17962
+ if (isNodeError16(error, "ENOENT") || isNodeError16(error, "EACCES")) {
16781
17963
  return null;
16782
17964
  }
16783
17965
  throw error;
@@ -16786,16 +17968,16 @@ async function readSkillMetadata(input) {
16786
17968
  if (raw === null) {
16787
17969
  return null;
16788
17970
  }
16789
- const skillDir = path19.dirname(input.skillFile);
17971
+ const skillDir = path20.dirname(input.skillFile);
16790
17972
  const { frontmatter, body } = parseSkillDocument(raw.slice(0, 4e3));
16791
17973
  const name = normalizeSkillName(
16792
- readString15(frontmatter.name) ?? path19.basename(skillDir)
17974
+ readString16(frontmatter.name) ?? path20.basename(skillDir)
16793
17975
  );
16794
17976
  if (!name) {
16795
17977
  return null;
16796
17978
  }
16797
17979
  const description = normalizeDescription(
16798
- readString15(frontmatter.description) ?? firstBodyDescription(body)
17980
+ readString16(frontmatter.description) ?? firstBodyDescription(body)
16799
17981
  );
16800
17982
  const provenance = input.provenance.get(name) ?? {
16801
17983
  source: "local",
@@ -16808,7 +17990,7 @@ async function readSkillMetadata(input) {
16808
17990
  enabled: !input.disabled.has(name),
16809
17991
  source: provenance.source,
16810
17992
  trust: provenance.trust,
16811
- relativePath: path19.relative(input.skillsRoot, skillDir)
17993
+ relativePath: path20.relative(input.skillsRoot, skillDir)
16812
17994
  };
16813
17995
  }
16814
17996
  function parseSkillDocument(raw) {
@@ -16821,7 +18003,7 @@ function parseSkillDocument(raw) {
16821
18003
  }
16822
18004
  try {
16823
18005
  return {
16824
- frontmatter: toRecord14(YAML5.parse(match[1] ?? "")),
18006
+ frontmatter: toRecord15(YAML5.parse(match[1] ?? "")),
16825
18007
  body: content.slice(match[0].length)
16826
18008
  };
16827
18009
  } catch {
@@ -16829,8 +18011,8 @@ function parseSkillDocument(raw) {
16829
18011
  }
16830
18012
  }
16831
18013
  function categoryFromPath(skillsRoot, skillFile) {
16832
- const relative = path19.relative(skillsRoot, skillFile);
16833
- const parts = relative.split(path19.sep).filter(Boolean);
18014
+ const relative = path20.relative(skillsRoot, skillFile);
18015
+ const parts = relative.split(path20.sep).filter(Boolean);
16834
18016
  return parts.length >= 3 ? parts[0] : null;
16835
18017
  }
16836
18018
  function firstBodyDescription(body) {
@@ -16853,8 +18035,8 @@ function normalizeDescription(value) {
16853
18035
  return `${description.slice(0, MAX_DESCRIPTION_LENGTH - 3)}...`;
16854
18036
  }
16855
18037
  async function readDisabledSkillNames(configPath) {
16856
- const raw = await readFile14(configPath, "utf8").catch((error) => {
16857
- if (isNodeError15(error, "ENOENT")) {
18038
+ const raw = await readFile15(configPath, "utf8").catch((error) => {
18039
+ if (isNodeError16(error, "ENOENT")) {
16858
18040
  return "";
16859
18041
  }
16860
18042
  throw error;
@@ -16862,8 +18044,8 @@ async function readDisabledSkillNames(configPath) {
16862
18044
  if (!raw.trim()) {
16863
18045
  return /* @__PURE__ */ new Set();
16864
18046
  }
16865
- const config = toRecord14(YAML5.parse(raw));
16866
- const skills = toRecord14(config.skills);
18047
+ const config = toRecord15(YAML5.parse(raw));
18048
+ const skills = toRecord15(config.skills);
16867
18049
  return new Set(readStringList3(skills.disabled));
16868
18050
  }
16869
18051
  async function readSkillProvenance(root) {
@@ -16877,9 +18059,9 @@ async function readSkillProvenance(root) {
16877
18059
  return provenance;
16878
18060
  }
16879
18061
  async function readBundledSkillNames(root) {
16880
- const raw = await readFile14(path19.join(root, ".bundled_manifest"), "utf8").catch(
18062
+ const raw = await readFile15(path20.join(root, ".bundled_manifest"), "utf8").catch(
16881
18063
  (error) => {
16882
- if (isNodeError15(error, "ENOENT")) {
18064
+ if (isNodeError16(error, "ENOENT")) {
16883
18065
  return "";
16884
18066
  }
16885
18067
  throw error;
@@ -16900,9 +18082,9 @@ async function readBundledSkillNames(root) {
16900
18082
  return names;
16901
18083
  }
16902
18084
  async function readHubInstalledSkills(root) {
16903
- const raw = await readFile14(path19.join(root, ".hub", "lock.json"), "utf8").catch(
18085
+ const raw = await readFile15(path20.join(root, ".hub", "lock.json"), "utf8").catch(
16904
18086
  (error) => {
16905
- if (isNodeError15(error, "ENOENT")) {
18087
+ if (isNodeError16(error, "ENOENT")) {
16906
18088
  return "";
16907
18089
  }
16908
18090
  throw error;
@@ -16913,17 +18095,17 @@ async function readHubInstalledSkills(root) {
16913
18095
  }
16914
18096
  let lock;
16915
18097
  try {
16916
- lock = toRecord14(JSON.parse(raw));
18098
+ lock = toRecord15(JSON.parse(raw));
16917
18099
  } catch {
16918
18100
  return /* @__PURE__ */ new Map();
16919
18101
  }
16920
- const installed = toRecord14(lock.installed);
18102
+ const installed = toRecord15(lock.installed);
16921
18103
  const result = /* @__PURE__ */ new Map();
16922
18104
  for (const [name, rawEntry] of Object.entries(installed)) {
16923
- const entry = toRecord14(rawEntry);
18105
+ const entry = toRecord15(rawEntry);
16924
18106
  result.set(normalizeSkillName(name), {
16925
- source: readString15(entry.source) ?? "hub",
16926
- trust: readString15(entry.trust_level) ?? null
18107
+ source: readString16(entry.source) ?? "hub",
18108
+ trust: readString16(entry.trust_level) ?? null
16927
18109
  });
16928
18110
  }
16929
18111
  return result;
@@ -16972,9 +18154,9 @@ function compareCategoryNames(left, right) {
16972
18154
  return left.localeCompare(right);
16973
18155
  }
16974
18156
  async function readHermesConfigDocument2(configPath) {
16975
- const existingRaw = await readFile14(configPath, "utf8").catch(
18157
+ const existingRaw = await readFile15(configPath, "utf8").catch(
16976
18158
  (error) => {
16977
- if (isNodeError15(error, "ENOENT")) {
18159
+ if (isNodeError16(error, "ENOENT")) {
16978
18160
  return null;
16979
18161
  }
16980
18162
  throw error;
@@ -16983,13 +18165,13 @@ async function readHermesConfigDocument2(configPath) {
16983
18165
  const document = existingRaw ? YAML5.parseDocument(existingRaw) : new YAML5.Document({});
16984
18166
  return {
16985
18167
  document,
16986
- config: toRecord14(document.toJSON()),
18168
+ config: toRecord15(document.toJSON()),
16987
18169
  existingRaw
16988
18170
  };
16989
18171
  }
16990
18172
  async function writeHermesConfigDocument2(input) {
16991
18173
  const backupPath = input.existingRaw ? `${input.configPath}.bak.${Date.now()}` : null;
16992
- await mkdir13(path19.dirname(input.configPath), { recursive: true, mode: 448 });
18174
+ await mkdir13(path20.dirname(input.configPath), { recursive: true, mode: 448 });
16993
18175
  if (backupPath) {
16994
18176
  await copyFile4(input.configPath, backupPath);
16995
18177
  }
@@ -17005,21 +18187,21 @@ function readStringList3(value) {
17005
18187
  }
17006
18188
  return value.filter((item) => typeof item === "string").map((item) => item.trim()).filter(Boolean);
17007
18189
  }
17008
- function readString15(value) {
18190
+ function readString16(value) {
17009
18191
  return typeof value === "string" && value.trim() ? value.trim() : null;
17010
18192
  }
17011
- function toRecord14(value) {
18193
+ function toRecord15(value) {
17012
18194
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
17013
18195
  }
17014
18196
  function ensureRecord3(target, key) {
17015
- const current = toRecord14(target[key]);
18197
+ const current = toRecord15(target[key]);
17016
18198
  if (current === target[key]) {
17017
18199
  return current;
17018
18200
  }
17019
18201
  target[key] = current;
17020
18202
  return current;
17021
18203
  }
17022
- function isNodeError15(error, code) {
18204
+ function isNodeError16(error, code) {
17023
18205
  return typeof error === "object" && error !== null && "code" in error && error.code === code;
17024
18206
  }
17025
18207
 
@@ -17034,7 +18216,7 @@ function registerProfileSkillRoutes(router, options) {
17034
18216
  router.patch("/api/v1/profiles/:name/skills/:skillName", async (ctx) => {
17035
18217
  await authenticateRequest(ctx, paths);
17036
18218
  const body = await readJsonBody(ctx.req);
17037
- const enabled = readBoolean(body.enabled);
18219
+ const enabled = readBoolean2(body.enabled);
17038
18220
  if (enabled === void 0) {
17039
18221
  throw new LinkHttpError(
17040
18222
  400,
@@ -17322,7 +18504,7 @@ function registerRunRoutes(router, options) {
17322
18504
  router.post("/api/v1/runs", async (ctx) => {
17323
18505
  await authenticateRequest(ctx, paths);
17324
18506
  const body = await readJsonBody(ctx.req);
17325
- const input = readString13(body, "input");
18507
+ const input = readString14(body, "input");
17326
18508
  if (!input) {
17327
18509
  throw new LinkHttpError(400, "run_input_required", "input is required");
17328
18510
  }
@@ -17330,11 +18512,11 @@ function registerRunRoutes(router, options) {
17330
18512
  ctx.body = await createHermesRun(
17331
18513
  {
17332
18514
  input,
17333
- instructions: readString13(body, "instructions") ?? void 0,
18515
+ instructions: readString14(body, "instructions") ?? void 0,
17334
18516
  conversation_history: readConversationHistory(
17335
18517
  body.conversation_history ?? body.conversationHistory
17336
18518
  ),
17337
- session_id: readString13(body, "session_id") ?? readString13(body, "sessionId") ?? void 0
18519
+ session_id: readString14(body, "session_id") ?? readString14(body, "sessionId") ?? void 0
17338
18520
  },
17339
18521
  { logger, profileName: readOptionalProfileName(body) }
17340
18522
  );
@@ -17505,8 +18687,8 @@ function readModelList(payload) {
17505
18687
  // src/hermes/updates.ts
17506
18688
  import { EventEmitter as EventEmitter3 } from "events";
17507
18689
  import { spawn as spawn3 } from "child_process";
17508
- import { mkdir as mkdir14, readFile as readFile15, rm as rm8 } from "fs/promises";
17509
- import path20 from "path";
18690
+ import { mkdir as mkdir14, readFile as readFile16, rm as rm8 } from "fs/promises";
18691
+ import path21 from "path";
17510
18692
  var SERVER_HERMES_RELEASES_LATEST_PATH = "/api/v1/hermes-agent/releases/latest";
17511
18693
  var RELEASE_CACHE_TTL_MS = 6 * 60 * 60 * 1e3;
17512
18694
  var RELEASE_FETCH_TIMEOUT_MS = 5e3;
@@ -17727,24 +18909,24 @@ async function readRemoteRelease(options, now) {
17727
18909
  }
17728
18910
  }
17729
18911
  function normalizeServerReleaseSnapshot(payload) {
17730
- const snapshot = toRecord15(payload);
18912
+ const snapshot = toRecord16(payload);
17731
18913
  const remote = toNullableRecord(snapshot.remote);
17732
18914
  return {
17733
18915
  remote: remote ? normalizeServerRelease(remote) : null,
17734
- cacheState: readString16(snapshot, "cache_state") ?? readString16(snapshot, "cacheState"),
17735
- issue: readString16(snapshot, "issue")
18916
+ cacheState: readString17(snapshot, "cache_state") ?? readString17(snapshot, "cacheState"),
18917
+ issue: readString17(snapshot, "issue")
17736
18918
  };
17737
18919
  }
17738
18920
  function normalizeServerRelease(payload) {
17739
- const tag = readString16(payload, "tag");
17740
- const name = readString16(payload, "name");
18921
+ const tag = readString17(payload, "tag");
18922
+ const name = readString17(payload, "name");
17741
18923
  return {
17742
- version: readString16(payload, "version") ?? extractSemver(name) ?? extractTagSemver(tag),
18924
+ version: readString17(payload, "version") ?? extractSemver(name) ?? extractTagSemver(tag),
17743
18925
  tag,
17744
18926
  name,
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()
18927
+ releaseUrl: readString17(payload, "releaseUrl") ?? readString17(payload, "release_url"),
18928
+ publishedAt: readString17(payload, "publishedAt") ?? readString17(payload, "published_at"),
18929
+ fetchedAt: readString17(payload, "fetchedAt") ?? readString17(payload, "fetched_at") ?? (/* @__PURE__ */ new Date()).toISOString()
17748
18930
  };
17749
18931
  }
17750
18932
  async function readReleaseCache(paths) {
@@ -17763,7 +18945,7 @@ async function writeUpdateState(paths, state) {
17763
18945
  await writeJsonFile(updateStatePath(paths), state);
17764
18946
  }
17765
18947
  async function readUpdateLogLines(paths) {
17766
- const raw = await readFile15(updateLogPath(paths), "utf8").catch(() => "");
18948
+ const raw = await readFile16(updateLogPath(paths), "utf8").catch(() => "");
17767
18949
  if (!raw.trim()) {
17768
18950
  return [];
17769
18951
  }
@@ -17772,13 +18954,13 @@ async function readUpdateLogLines(paths) {
17772
18954
  );
17773
18955
  }
17774
18956
  function releaseCachePath(paths) {
17775
- return path20.join(paths.indexesDir, "hermes-release-check.json");
18957
+ return path21.join(paths.indexesDir, "hermes-release-check.json");
17776
18958
  }
17777
18959
  function updateStatePath(paths) {
17778
- return path20.join(paths.runDir, "hermes-update-state.json");
18960
+ return path21.join(paths.runDir, "hermes-update-state.json");
17779
18961
  }
17780
18962
  function updateLogPath(paths) {
17781
- return path20.join(paths.logsDir, UPDATE_LOG_FILE);
18963
+ return path21.join(paths.logsDir, UPDATE_LOG_FILE);
17782
18964
  }
17783
18965
  async function clearUpdateLogFiles(paths) {
17784
18966
  const primary = updateLogPath(paths);
@@ -17816,7 +18998,7 @@ function compareSemver2(left, right) {
17816
18998
  }
17817
18999
  return 0;
17818
19000
  }
17819
- function toRecord15(value) {
19001
+ function toRecord16(value) {
17820
19002
  return typeof value === "object" && value !== null ? value : {};
17821
19003
  }
17822
19004
  function toNullableRecord(value) {
@@ -17862,7 +19044,7 @@ function isRecentRunningState2(state) {
17862
19044
  const startedAt = Date.parse(state.started_at);
17863
19045
  return Number.isFinite(startedAt) && Date.now() - startedAt < 3e4;
17864
19046
  }
17865
- function readString16(payload, key) {
19047
+ function readString17(payload, key) {
17866
19048
  const value = payload[key];
17867
19049
  return typeof value === "string" && value.trim() ? value.trim() : null;
17868
19050
  }
@@ -17870,13 +19052,13 @@ function readString16(payload, key) {
17870
19052
  // src/link/updates.ts
17871
19053
  import { spawn as spawn5 } from "child_process";
17872
19054
  import { EventEmitter as EventEmitter4 } from "events";
17873
- import { mkdir as mkdir17, readFile as readFile17, rm as rm11 } from "fs/promises";
17874
- import path22 from "path";
19055
+ import { mkdir as mkdir17, readFile as readFile18, rm as rm11 } from "fs/promises";
19056
+ import path23 from "path";
17875
19057
 
17876
19058
  // src/daemon/process.ts
17877
19059
  import { spawn as spawn4 } from "child_process";
17878
- import { mkdir as mkdir16, readFile as readFile16, rm as rm10 } from "fs/promises";
17879
- import path21 from "path";
19060
+ import { mkdir as mkdir16, readFile as readFile17, rm as rm10 } from "fs/promises";
19061
+ import path22 from "path";
17880
19062
 
17881
19063
  // src/daemon/service.ts
17882
19064
  import { createServer } from "http";
@@ -18054,7 +19236,7 @@ async function handleFrame(socket, raw, localPort, abortControllers) {
18054
19236
  // src/runtime/system-info.ts
18055
19237
  import { execFileSync } from "child_process";
18056
19238
  import { readFileSync } from "fs";
18057
- import os5 from "os";
19239
+ import os6 from "os";
18058
19240
  function readLinkSystemInfo() {
18059
19241
  const platform = process.platform;
18060
19242
  const hostname = readHostname(platform);
@@ -18093,7 +19275,7 @@ function readHostname(platform) {
18093
19275
  return computerName;
18094
19276
  }
18095
19277
  }
18096
- return normalizeText(os5.hostname());
19278
+ return normalizeText(os6.hostname());
18097
19279
  }
18098
19280
  function readOsLabel(platform) {
18099
19281
  if (platform === "darwin") {
@@ -18101,12 +19283,12 @@ function readOsLabel(platform) {
18101
19283
  return version ? `macOS ${version}` : "macOS";
18102
19284
  }
18103
19285
  if (platform === "linux") {
18104
- return readLinuxOsRelease() ?? `Linux ${os5.release()}`;
19286
+ return readLinuxOsRelease() ?? `Linux ${os6.release()}`;
18105
19287
  }
18106
19288
  if (platform === "win32") {
18107
- return `Windows ${os5.release()}`;
19289
+ return `Windows ${os6.release()}`;
18108
19290
  }
18109
- return `${os5.type()} ${os5.release()}`.trim();
19291
+ return `${os6.type()} ${os6.release()}`.trim();
18110
19292
  }
18111
19293
  function readLinuxOsRelease() {
18112
19294
  for (const file of ["/etc/os-release", "/usr/lib/os-release"]) {
@@ -18153,11 +19335,11 @@ function truncateText(value, maxLength) {
18153
19335
  }
18154
19336
 
18155
19337
  // src/topology/network.ts
18156
- import os7 from "os";
19338
+ import os8 from "os";
18157
19339
 
18158
19340
  // src/topology/environment.ts
18159
19341
  import { existsSync, readFileSync as readFileSync2 } from "fs";
18160
- import os6 from "os";
19342
+ import os7 from "os";
18161
19343
  function detectRuntimeEnvironment(env = process.env) {
18162
19344
  if (isWsl(env)) {
18163
19345
  return {
@@ -18186,7 +19368,7 @@ function isWsl(env) {
18186
19368
  if (env.WSL_DISTRO_NAME || env.WSL_INTEROP) {
18187
19369
  return true;
18188
19370
  }
18189
- const release = os6.release().toLowerCase();
19371
+ const release = os7.release().toLowerCase();
18190
19372
  return release.includes("microsoft") || release.includes("wsl");
18191
19373
  }
18192
19374
  function isContainer(env) {
@@ -18231,7 +19413,7 @@ async function discoverRouteCandidates(options) {
18231
19413
  };
18232
19414
  }
18233
19415
  function discoverLanIps() {
18234
- return discoverLanIpsFromInterfaces(os7.networkInterfaces());
19416
+ return discoverLanIpsFromInterfaces(os8.networkInterfaces());
18235
19417
  }
18236
19418
  function discoverLanIpsFromInterfaces(interfaces) {
18237
19419
  const result = /* @__PURE__ */ new Set();
@@ -18724,6 +19906,33 @@ function startCronDeliveryScheduler(options) {
18724
19906
  }
18725
19907
  };
18726
19908
  }
19909
+ function startHermesSessionSyncScheduler(options) {
19910
+ let running = false;
19911
+ const syncSessions = async () => {
19912
+ if (running) {
19913
+ return;
19914
+ }
19915
+ running = true;
19916
+ try {
19917
+ await options.conversations.syncHermesSessions();
19918
+ } catch (error) {
19919
+ void options.logger.warn("hermes_session_sync_failed", {
19920
+ error: error instanceof Error ? error.message : String(error)
19921
+ });
19922
+ } finally {
19923
+ running = false;
19924
+ }
19925
+ };
19926
+ const timer = setInterval(() => {
19927
+ void syncSessions();
19928
+ }, options.intervalMs ?? 10 * 60 * 1e3);
19929
+ timer.unref?.();
19930
+ return {
19931
+ close() {
19932
+ clearInterval(timer);
19933
+ }
19934
+ };
19935
+ }
18727
19936
 
18728
19937
  // src/daemon/service.ts
18729
19938
  async function startLinkService(options = {}) {
@@ -18744,11 +19953,21 @@ async function startLinkService(options = {}) {
18744
19953
  }
18745
19954
  const conversations = new ConversationService(paths, logger);
18746
19955
  await conversations.rebuildStatisticsIndex();
19956
+ const triggerHermesSessionSync = () => {
19957
+ void conversations.syncHermesSessions().catch((error) => {
19958
+ void logger.warn("hermes_session_sync_failed", {
19959
+ error: error instanceof Error ? error.message : String(error)
19960
+ });
19961
+ });
19962
+ };
18747
19963
  const app = await createApp({
18748
19964
  paths,
18749
19965
  logger,
18750
19966
  conversations,
18751
- onPairingClaimed: options.onPairingClaimed
19967
+ onPairingClaimed: async () => {
19968
+ triggerHermesSessionSync();
19969
+ await options.onPairingClaimed?.();
19970
+ }
18752
19971
  });
18753
19972
  const server = createServer(app.callback());
18754
19973
  try {
@@ -18768,11 +19987,16 @@ async function startLinkService(options = {}) {
18768
19987
  port: config.port,
18769
19988
  link_id: identity?.link_id ?? null
18770
19989
  });
19990
+ triggerHermesSessionSync();
18771
19991
  const scheduler = startCronDeliveryScheduler({
18772
19992
  paths,
18773
19993
  conversations,
18774
19994
  logger
18775
19995
  });
19996
+ const hermesSessionSyncScheduler = startHermesSessionSyncScheduler({
19997
+ conversations,
19998
+ logger
19999
+ });
18776
20000
  let relay = null;
18777
20001
  if (identity?.link_id) {
18778
20002
  relay = connectRelayControl({
@@ -18805,6 +20029,7 @@ async function startLinkService(options = {}) {
18805
20029
  return {
18806
20030
  async close() {
18807
20031
  scheduler.close();
20032
+ hermesSessionSyncScheduler.close();
18808
20033
  lanIpMonitor.close();
18809
20034
  relay?.close();
18810
20035
  await closeServer(server);
@@ -18917,7 +20142,7 @@ async function runDaemonSupervisor(paths = resolveRuntimePaths()) {
18917
20142
  await mkdir16(paths.logsDir, { recursive: true, mode: 448 });
18918
20143
  const log = createRotatingTextLogWriter({
18919
20144
  paths,
18920
- fileName: path21.basename(daemonLogFile(paths))
20145
+ fileName: path22.basename(daemonLogFile(paths))
18921
20146
  });
18922
20147
  const scriptPath = currentCliScriptPath();
18923
20148
  const child = spawn4(process.execPath, [scriptPath, "daemon", "--foreground"], {
@@ -19046,7 +20271,7 @@ function currentCliScriptPath() {
19046
20271
  return process.argv[1];
19047
20272
  }
19048
20273
  async function readPid(filePath) {
19049
- const raw = await readFile16(filePath, "utf8").catch(() => null);
20274
+ const raw = await readFile17(filePath, "utf8").catch(() => null);
19050
20275
  if (!raw) {
19051
20276
  return null;
19052
20277
  }
@@ -19372,21 +20597,21 @@ async function readRemoteLinkPolicy(options) {
19372
20597
  }
19373
20598
  }
19374
20599
  function normalizeServerSnapshot(payload) {
19375
- const snapshot = toRecord16(payload);
20600
+ const snapshot = toRecord17(payload);
19376
20601
  const policy = toNullableRecord2(snapshot.policy);
19377
20602
  if (!policy) {
19378
20603
  return {
19379
20604
  remote: null,
19380
- issue: readString17(snapshot, "issue")
20605
+ issue: readString18(snapshot, "issue")
19381
20606
  };
19382
20607
  }
19383
20608
  const release = toNullableRecord2(snapshot.release);
19384
- const currentVersion = readString17(policy, "current_version") ?? readString17(policy, "currentVersion");
19385
- const minSafeVersion = readString17(policy, "min_safe_version") ?? readString17(policy, "minSafeVersion");
20609
+ const currentVersion = readString18(policy, "current_version") ?? readString18(policy, "currentVersion");
20610
+ const minSafeVersion = readString18(policy, "min_safe_version") ?? readString18(policy, "minSafeVersion");
19386
20611
  if (!currentVersion) {
19387
20612
  return {
19388
20613
  remote: null,
19389
- issue: readString17(snapshot, "issue")
20614
+ issue: readString18(snapshot, "issue")
19390
20615
  };
19391
20616
  }
19392
20617
  return {
@@ -19394,10 +20619,10 @@ function normalizeServerSnapshot(payload) {
19394
20619
  current_version: currentVersion,
19395
20620
  min_safe_version: minSafeVersion,
19396
20621
  target_version: currentVersion,
19397
- release_url: release ? readString17(release, "release_url") ?? readString17(release, "releaseUrl") : null,
19398
- published_at: release ? readString17(release, "published_at") ?? readString17(release, "publishedAt") : null
20622
+ release_url: release ? readString18(release, "release_url") ?? readString18(release, "releaseUrl") : null,
20623
+ published_at: release ? readString18(release, "published_at") ?? readString18(release, "publishedAt") : null
19399
20624
  },
19400
- issue: readString17(snapshot, "issue")
20625
+ issue: readString18(snapshot, "issue")
19401
20626
  };
19402
20627
  }
19403
20628
  async function fetchCurrentLinkReleaseFromServer(options, fetcher) {
@@ -19447,7 +20672,7 @@ async function writeUpdateState2(paths, state) {
19447
20672
  await writeJsonFile(updateStatePath2(paths), state);
19448
20673
  }
19449
20674
  async function readUpdateLogLines2(paths) {
19450
- const raw = await readFile17(updateLogPath2(paths), "utf8").catch(() => "");
20675
+ const raw = await readFile18(updateLogPath2(paths), "utf8").catch(() => "");
19451
20676
  if (!raw.trim()) {
19452
20677
  return [];
19453
20678
  }
@@ -19456,10 +20681,10 @@ async function readUpdateLogLines2(paths) {
19456
20681
  );
19457
20682
  }
19458
20683
  function updateStatePath2(paths) {
19459
- return path22.join(paths.runDir, "link-update-state.json");
20684
+ return path23.join(paths.runDir, "link-update-state.json");
19460
20685
  }
19461
20686
  function updateLogPath2(paths) {
19462
- return path22.join(paths.logsDir, UPDATE_LOG_FILE2);
20687
+ return path23.join(paths.logsDir, UPDATE_LOG_FILE2);
19463
20688
  }
19464
20689
  async function clearUpdateLogFiles2(paths) {
19465
20690
  const primary = updateLogPath2(paths);
@@ -19511,19 +20736,19 @@ function isProcessAlive4(pid) {
19511
20736
  return false;
19512
20737
  }
19513
20738
  }
19514
- function toRecord16(value) {
20739
+ function toRecord17(value) {
19515
20740
  return typeof value === "object" && value !== null ? value : {};
19516
20741
  }
19517
20742
  function toNullableRecord2(value) {
19518
20743
  return typeof value === "object" && value !== null ? value : null;
19519
20744
  }
19520
- function readString17(payload, key) {
20745
+ function readString18(payload, key) {
19521
20746
  const value = payload[key];
19522
20747
  return typeof value === "string" && value.trim() ? value.trim() : null;
19523
20748
  }
19524
20749
 
19525
20750
  // src/pairing/pairing.ts
19526
- import path23 from "path";
20751
+ import path24 from "path";
19527
20752
  import { rm as rm12 } from "fs/promises";
19528
20753
 
19529
20754
  // src/relay/bootstrap.ts
@@ -19799,8 +21024,8 @@ async function loadRequiredIdentity2(paths) {
19799
21024
  }
19800
21025
  return identity;
19801
21026
  }
19802
- async function postServerJson(serverBaseUrl, path24, body) {
19803
- const response = await fetch(`${serverBaseUrl.replace(/\/+$/u, "")}${path24}`, {
21027
+ async function postServerJson(serverBaseUrl, path25, body) {
21028
+ const response = await fetch(`${serverBaseUrl.replace(/\/+$/u, "")}${path25}`, {
19804
21029
  method: "POST",
19805
21030
  headers: {
19806
21031
  accept: "application/json",
@@ -19840,8 +21065,8 @@ function pairingErrorSnapshot(stage, error) {
19840
21065
  occurred_at: (/* @__PURE__ */ new Date()).toISOString()
19841
21066
  };
19842
21067
  }
19843
- async function patchServerJson(serverBaseUrl, path24, token, body) {
19844
- const response = await fetch(`${serverBaseUrl.replace(/\/+$/u, "")}${path24}`, {
21068
+ async function patchServerJson(serverBaseUrl, path25, token, body) {
21069
+ const response = await fetch(`${serverBaseUrl.replace(/\/+$/u, "")}${path25}`, {
19845
21070
  method: "PATCH",
19846
21071
  headers: {
19847
21072
  accept: "application/json",
@@ -19872,10 +21097,10 @@ function readErrorMessage5(payload) {
19872
21097
  return typeof message === "string" ? message : null;
19873
21098
  }
19874
21099
  function pairingClaimPath(sessionId, paths) {
19875
- return path23.join(paths.pairingDir, `${Buffer.from(sessionId).toString("base64url")}.claimed.json`);
21100
+ return path24.join(paths.pairingDir, `${Buffer.from(sessionId).toString("base64url")}.claimed.json`);
19876
21101
  }
19877
21102
  function pairingSessionPath(sessionId, paths) {
19878
- return path23.join(paths.pairingDir, `${Buffer.from(sessionId).toString("base64url")}.json`);
21103
+ return path24.join(paths.pairingDir, `${Buffer.from(sessionId).toString("base64url")}.json`);
19879
21104
  }
19880
21105
  function qrPreferredUrls(routes) {
19881
21106
  return routes.preferredUrls.filter((url) => !url.includes("/api/v1/relay/links/")).slice(0, 1);
@@ -19946,8 +21171,8 @@ function registerSystemRoutes(router, options) {
19946
21171
  });
19947
21172
  router.post("/api/v1/pairing/claim", async (ctx) => {
19948
21173
  const body = await readJsonBody(ctx.req);
19949
- const sessionId = readString13(body, "session_id") ?? readString13(body, "sessionId");
19950
- const claimToken = readString13(body, "claim_token") ?? readString13(body, "claimToken");
21174
+ const sessionId = readString14(body, "session_id") ?? readString14(body, "sessionId");
21175
+ const claimToken = readString14(body, "claim_token") ?? readString14(body, "claimToken");
19951
21176
  if (!sessionId || !claimToken) {
19952
21177
  throw new LinkHttpError(
19953
21178
  400,
@@ -19958,10 +21183,10 @@ function registerSystemRoutes(router, options) {
19958
21183
  const claimed = await claimPairing({
19959
21184
  sessionId,
19960
21185
  claimToken,
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"),
21186
+ deviceLabel: readString14(body, "device_label") ?? readString14(body, "deviceLabel") ?? "HermesPilot App",
21187
+ devicePlatform: readString14(body, "device_platform") ?? readString14(body, "devicePlatform") ?? "unknown",
21188
+ deviceModel: readString14(body, "device_model") ?? readString14(body, "deviceModel"),
21189
+ appInstanceId: readString14(body, "app_instance_id") ?? readString14(body, "appInstanceId"),
19965
21190
  paths
19966
21191
  });
19967
21192
  ctx.body = claimed;
@@ -20036,9 +21261,9 @@ function registerSystemRoutes(router, options) {
20036
21261
  const body = await readJsonBody(ctx.req);
20037
21262
  const session = await createDeviceSession(
20038
21263
  {
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"),
21264
+ label: readString14(body, "device_label") ?? readString14(body, "deviceLabel") ?? "HermesPilot App",
21265
+ platform: readString14(body, "device_platform") ?? readString14(body, "devicePlatform") ?? "unknown",
21266
+ model: readString14(body, "device_model") ?? readString14(body, "deviceModel"),
20042
21267
  appInstanceId: auth.appInstanceId
20043
21268
  },
20044
21269
  paths
@@ -20067,7 +21292,7 @@ function registerSystemRoutes(router, options) {
20067
21292
  });
20068
21293
  router.post("/api/v1/auth/refresh", async (ctx) => {
20069
21294
  const body = await readJsonBody(ctx.req);
20070
- const refreshToken = readString13(body, "refresh_token") ?? readString13(body, "refreshToken");
21295
+ const refreshToken = readString14(body, "refresh_token") ?? readString14(body, "refreshToken");
20071
21296
  if (!refreshToken) {
20072
21297
  throw new LinkHttpError(
20073
21298
  400,
@@ -20078,10 +21303,10 @@ function registerSystemRoutes(router, options) {
20078
21303
  const session = await refreshDeviceSession(
20079
21304
  refreshToken,
20080
21305
  {
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")
21306
+ appInstanceId: readString14(body, "app_instance_id") ?? readString14(body, "appInstanceId"),
21307
+ label: readString14(body, "device_label") ?? readString14(body, "deviceLabel"),
21308
+ platform: readString14(body, "device_platform") ?? readString14(body, "devicePlatform"),
21309
+ model: readString14(body, "device_model") ?? readString14(body, "deviceModel")
20085
21310
  },
20086
21311
  paths
20087
21312
  );
@@ -20100,7 +21325,7 @@ function registerSystemRoutes(router, options) {
20100
21325
  });
20101
21326
  router.post("/api/v1/auth/logout", async (ctx) => {
20102
21327
  const body = await readJsonBody(ctx.req);
20103
- const refreshToken = readString13(body, "refresh_token") ?? readString13(body, "refreshToken");
21328
+ const refreshToken = readString14(body, "refresh_token") ?? readString14(body, "refreshToken");
20104
21329
  if (refreshToken) {
20105
21330
  await revokeDeviceRefreshToken(refreshToken, paths);
20106
21331
  }
@@ -20325,7 +21550,7 @@ function registerSystemRoutes(router, options) {
20325
21550
  router.patch("/api/v1/devices/:deviceId", async (ctx) => {
20326
21551
  const auth = await authenticateRequest(ctx, paths);
20327
21552
  const body = await readJsonBody(ctx.req);
20328
- const label = readString13(body, "label") ?? readString13(body, "device_label");
21553
+ const label = readString14(body, "label") ?? readString14(body, "device_label");
20329
21554
  if (!label) {
20330
21555
  throw new LinkHttpError(
20331
21556
  400,
@@ -20365,11 +21590,11 @@ async function readActiveCronJobCount(profiles, logger) {
20365
21590
  }, 0);
20366
21591
  }
20367
21592
  function isActiveCronJob(job) {
20368
- const enabled = readBoolean(job.enabled) ?? true;
21593
+ const enabled = readBoolean2(job.enabled) ?? true;
20369
21594
  if (!enabled) {
20370
21595
  return false;
20371
21596
  }
20372
- const state = readString13(job, "state")?.toLowerCase();
21597
+ const state = readString14(job, "state")?.toLowerCase();
20373
21598
  return !["paused", "disabled", "completed", "deleted"].includes(state ?? "");
20374
21599
  }
20375
21600
  function filterLogsWithinHours(logs, hours, now = Date.now()) {
@@ -20463,7 +21688,7 @@ function registerLinkUpdateRoutes(router, options) {
20463
21688
  ctx.body = await startLinkUpdate({
20464
21689
  paths,
20465
21690
  logger,
20466
- targetVersion: readString13(body, "target_version") ?? readString13(body, "targetVersion")
21691
+ targetVersion: readString14(body, "target_version") ?? readString14(body, "targetVersion")
20467
21692
  });
20468
21693
  });
20469
21694
  router.get("/api/v1/link/update/events", async (ctx) => {
@@ -20497,7 +21722,7 @@ import QRCode from "qrcode";
20497
21722
  function registerPairingRoutes(router, options) {
20498
21723
  const { paths } = options;
20499
21724
  router.get("/pair", async (ctx) => {
20500
- const sessionId = readString13(ctx.query, "session_id");
21725
+ const sessionId = readString14(ctx.query, "session_id");
20501
21726
  if (!sessionId) {
20502
21727
  throw new LinkHttpError(400, "pairing_session_required", "session_id is required");
20503
21728
  }
@@ -20522,7 +21747,7 @@ function registerPairingRoutes(router, options) {
20522
21747
  ctx.body = page;
20523
21748
  });
20524
21749
  router.get("/api/v1/pairing/session", async (ctx) => {
20525
- const sessionId = readString13(ctx.query, "session_id");
21750
+ const sessionId = readString14(ctx.query, "session_id");
20526
21751
  if (!sessionId) {
20527
21752
  throw new LinkHttpError(400, "pairing_session_required", "session_id is required");
20528
21753
  }
@@ -20926,7 +22151,7 @@ function registerInternalRoutes(router, options) {
20926
22151
  router.post("/internal/deliver", async (ctx) => {
20927
22152
  assertLoopbackRequest(ctx.req);
20928
22153
  const body = await readJsonBody(ctx.req);
20929
- const stagingDir = readString13(body, "staging_dir") ?? readString13(body, "stagingDir");
22154
+ const stagingDir = readString14(body, "staging_dir") ?? readString14(body, "stagingDir");
20930
22155
  if (!stagingDir) {
20931
22156
  throw new LinkHttpError(
20932
22157
  400,