@hermespilot/link 0.3.9 → 0.4.1

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.
@@ -1 +1,6 @@
1
1
  #!/usr/bin/env node
2
+ import { R as RuntimePaths } from '../paths-CmAiZsna.js';
3
+
4
+ declare function waitForPairingOrShutdown(sessionId: string, expiresAt: string, paths: RuntimePaths): Promise<'claimed' | 'expired' | 'shutdown'>;
5
+
6
+ export { waitForPairingOrShutdown };
package/dist/cli/index.js CHANGED
@@ -5,6 +5,7 @@ import {
5
5
  LINK_VERSION,
6
6
  LinkHttpError,
7
7
  clearPairingClaim,
8
+ connectRelayControl,
8
9
  createFileLogger,
9
10
  currentCliScriptPath,
10
11
  daemonLogFile,
@@ -33,10 +34,11 @@ import {
33
34
  startDaemonProcess,
34
35
  startLinkService,
35
36
  stopDaemonProcess
36
- } from "../chunk-7OVDWXR7.js";
37
+ } from "../chunk-476X63MC.js";
37
38
 
38
39
  // src/cli/index.ts
39
40
  import { Command } from "commander";
41
+ import path3 from "path";
40
42
  import { createInterface } from "readline/promises";
41
43
  import qrcode from "qrcode-terminal";
42
44
 
@@ -285,6 +287,7 @@ var messages = {
285
287
  "pair.openPairingPage": "If the QR code is hard to scan, you can open this page locally: {url}",
286
288
  "pair.manualCode": "You can also use the HermesPilot App manual connection mode and enter this pairing code:",
287
289
  "pair.expires": "Pairing expires in 10 minutes. Press Ctrl+C to cancel waiting.",
290
+ "pair.expired": "Pairing expired. Please run `hermeslink pair` again.",
288
291
  "pair.claimed": "Pairing succeeded. Starting Hermes Link in the background...",
289
292
  "pair.claimedRunning": "Pairing succeeded. Hermes Link is already running in the background.",
290
293
  "pair.relayOnlyNotice": "Network note: this {kind} environment does not expose a phone-reachable LAN/public direct address by default. The App will connect through Relay.",
@@ -379,6 +382,7 @@ var messages = {
379
382
  "pair.openPairingPage": "\u5982\u679C\u4E8C\u7EF4\u7801\u4E0D\u5BB9\u6613\u626B\u63CF\uFF0C\u4F60\u53EF\u4EE5\u5728\u672C\u673A\u6253\u5F00\u8FD9\u4E2A\u9875\u9762\uFF1A{url}",
380
383
  "pair.manualCode": "\u4F60\u4E5F\u53EF\u4EE5\u5728 HermesPilot App \u4E2D\u4F7F\u7528\u624B\u52A8\u8FDE\u63A5\u6A21\u5F0F\uFF0C\u8F93\u5165\u4EE5\u4E0B\u914D\u5BF9\u7801\u8FDB\u884C\u8FDE\u63A5\uFF1A",
381
384
  "pair.expires": "\u914D\u5BF9\u4F1A\u8BDD 10 \u5206\u949F\u540E\u8FC7\u671F\u3002\u6309 Ctrl+C \u9000\u51FA\u7B49\u5F85\u3002",
385
+ "pair.expired": "\u914D\u5BF9\u4F1A\u8BDD\u5DF2\u8FC7\u671F\uFF0C\u8BF7\u91CD\u65B0\u8FD0\u884C `hermeslink pair`\u3002",
382
386
  "pair.claimed": "\u914D\u5BF9\u5DF2\u6210\u529F\u3002\u6B63\u5728\u628A Hermes Link \u5207\u6362\u5230\u540E\u53F0\u8FD0\u884C...",
383
387
  "pair.claimedRunning": "\u914D\u5BF9\u5DF2\u6210\u529F\u3002Hermes Link \u5DF2\u5728\u540E\u53F0\u6301\u7EED\u8FD0\u884C\u3002",
384
388
  "pair.relayOnlyNotice": "\u7F51\u7EDC\u63D0\u793A\uFF1A\u5F53\u524D\u662F {kind} \u73AF\u5883\uFF0C\u9ED8\u8BA4\u4E0D\u4F1A\u66B4\u9732\u624B\u673A\u53EF\u8BBF\u95EE\u7684\u5C40\u57DF\u7F51\u6216\u516C\u7F51\u76F4\u8FDE\u5730\u5740\u3002App \u4F1A\u901A\u8FC7 Relay \u8FDE\u63A5\u3002",
@@ -847,55 +851,77 @@ program.command("pair").description(helpText("pair.description")).action(async (
847
851
  }
848
852
  const reusedRunningService = probe.reusable;
849
853
  const restartReusedServiceAfterClaim = reusedRunningService && !probeBeforePair.linkId;
850
- const service = reusedRunningService ? null : await startLinkService({ paths });
854
+ const service = reusedRunningService ? null : await startLinkService({
855
+ paths,
856
+ waitForRelayReady: true
857
+ });
858
+ let pairingRelayBridge = null;
859
+ if (restartReusedServiceAfterClaim) {
860
+ pairingRelayBridge = connectRelayControl({
861
+ relayBaseUrl: prepared.relayBaseUrl,
862
+ linkId: prepared.linkId,
863
+ localPort: config.port
864
+ });
865
+ pairingRelayBridge.publishNetworkRoutes(prepared.routes);
866
+ }
851
867
  const qrValue = JSON.stringify(prepared.qrPayload);
852
868
  const pairingPageUrl = `http://127.0.0.1:${config.port}/pair?session_id=${encodeURIComponent(prepared.sessionId)}`;
853
- console.log(t("pair.scan"));
854
- qrcode.generate(qrValue, { small: true });
855
- await openSystemBrowser(pairingPageUrl);
856
- console.log(t("pair.openPairingPage", { url: pairingPageUrl }));
857
- console.log(t("pair.manualCode"));
858
- console.log(prepared.code);
859
- console.log(t("pair.expires"));
860
- const result = await waitForPairingOrShutdown(prepared.sessionId, paths);
861
- if (service) {
862
- await service.close();
863
- }
864
- if (result === "claimed") {
865
- await clearPairingClaim(prepared.sessionId, paths);
866
- console.log(t(reusedRunningService ? "pair.claimedRunning" : "pair.claimed"));
867
- printPostPairingNetworkNotice(prepared.routes.environment, config, t);
868
- try {
869
- if (hadActiveDevices) {
870
- console.log(t("pair.autostartUnchanged"));
871
- } else {
872
- const currentAutostart = await getAutostartStatus();
873
- if (currentAutostart.supported && currentAutostart.enabled) {
874
- console.log(
875
- t("autostart.alreadyEnabled", {
876
- method: currentAutostart.method,
877
- path: currentAutostart.filePath ?? ""
878
- })
879
- );
869
+ try {
870
+ console.log(t("pair.scan"));
871
+ qrcode.generate(qrValue, { small: true });
872
+ await openSystemBrowser(pairingPageUrl);
873
+ console.log(t("pair.openPairingPage", { url: pairingPageUrl }));
874
+ console.log(t("pair.manualCode"));
875
+ console.log(prepared.code);
876
+ console.log(t("pair.expires"));
877
+ const result = await waitForPairingOrShutdown(
878
+ prepared.sessionId,
879
+ prepared.expiresAt,
880
+ paths
881
+ );
882
+ if (service) {
883
+ await service.close();
884
+ }
885
+ if (result === "claimed") {
886
+ await clearPairingClaim(prepared.sessionId, paths);
887
+ console.log(t(reusedRunningService ? "pair.claimedRunning" : "pair.claimed"));
888
+ printPostPairingNetworkNotice(prepared.routes.environment, config, t);
889
+ try {
890
+ if (hadActiveDevices) {
891
+ console.log(t("pair.autostartUnchanged"));
880
892
  } else {
881
- const autostart2 = await enableAutostart();
882
- if (autostart2.supported && autostart2.enabled) {
883
- console.log(t("autostart.enabled", { method: autostart2.method, path: autostart2.filePath ?? "" }));
893
+ const currentAutostart = await getAutostartStatus();
894
+ if (currentAutostart.supported && currentAutostart.enabled) {
895
+ console.log(
896
+ t("autostart.alreadyEnabled", {
897
+ method: currentAutostart.method,
898
+ path: currentAutostart.filePath ?? ""
899
+ })
900
+ );
901
+ } else {
902
+ const autostart2 = await enableAutostart();
903
+ if (autostart2.supported && autostart2.enabled) {
904
+ console.log(t("autostart.enabled", { method: autostart2.method, path: autostart2.filePath ?? "" }));
905
+ }
884
906
  }
885
907
  }
908
+ } catch (error) {
909
+ const message = error instanceof Error ? error.message : String(error);
910
+ console.log(t("pair.autostartFailed", { message }));
886
911
  }
887
- } catch (error) {
888
- const message = error instanceof Error ? error.message : String(error);
889
- console.log(t("pair.autostartFailed", { message }));
890
- }
891
- if (restartReusedServiceAfterClaim) {
892
- await stopDaemonProcess(paths);
893
- const status = await startDaemonProcess(paths);
894
- console.log(t("start.backgroundStarted", { pid: status.pid ?? "unknown" }));
895
- } else if (!reusedRunningService) {
896
- const status = await startDaemonProcess(paths);
897
- console.log(t("start.backgroundStarted", { pid: status.pid ?? "unknown" }));
912
+ if (restartReusedServiceAfterClaim) {
913
+ await stopDaemonProcess(paths);
914
+ const status = await startDaemonProcess(paths);
915
+ console.log(t("start.backgroundStarted", { pid: status.pid ?? "unknown" }));
916
+ } else if (!reusedRunningService) {
917
+ const status = await startDaemonProcess(paths);
918
+ console.log(t("start.backgroundStarted", { pid: status.pid ?? "unknown" }));
919
+ }
920
+ } else if (result === "expired") {
921
+ console.log(t("pair.expired"));
898
922
  }
923
+ } finally {
924
+ pairingRelayBridge?.close();
899
925
  }
900
926
  });
901
927
  var autostart = program.command("autostart").description(helpText("autostart.description"));
@@ -973,11 +999,13 @@ program.command("doctor").description(helpText("doctor.description")).action(asy
973
999
  console.log(t("doctor.apiUnavailable", { message: error instanceof Error ? error.message : String(error) }));
974
1000
  }
975
1001
  });
976
- program.parseAsync(process.argv).catch(async (error) => {
977
- const language = await loadCliLanguage().catch(() => detectSystemLanguage());
978
- console.error(localizeErrorMessage(error, language));
979
- process.exitCode = 1;
980
- });
1002
+ if (isCliEntrypoint()) {
1003
+ program.parseAsync(process.argv).catch(async (error) => {
1004
+ const language = await loadCliLanguage().catch(() => detectSystemLanguage());
1005
+ console.error(localizeErrorMessage(error, language));
1006
+ process.exitCode = 1;
1007
+ });
1008
+ }
981
1009
  async function loadCliLanguage() {
982
1010
  const config = await loadConfig();
983
1011
  return resolveLanguage(config.language);
@@ -1083,8 +1111,9 @@ async function waitForShutdown(cleanup) {
1083
1111
  });
1084
1112
  await cleanup();
1085
1113
  }
1086
- async function waitForPairingOrShutdown(sessionId, paths) {
1114
+ async function waitForPairingOrShutdown(sessionId, expiresAt, paths) {
1087
1115
  let shutdownRequested = false;
1116
+ const expiresAtMs = Date.parse(expiresAt);
1088
1117
  const stop = () => {
1089
1118
  shutdownRequested = true;
1090
1119
  };
@@ -1092,6 +1121,9 @@ async function waitForPairingOrShutdown(sessionId, paths) {
1092
1121
  process.once("SIGTERM", stop);
1093
1122
  try {
1094
1123
  while (!shutdownRequested) {
1124
+ if (Number.isFinite(expiresAtMs) && Date.now() >= expiresAtMs) {
1125
+ return "expired";
1126
+ }
1095
1127
  const record = await readPairingClaim(sessionId, paths);
1096
1128
  if (record) {
1097
1129
  return "claimed";
@@ -1124,3 +1156,10 @@ function printPostPairingNetworkNotice(environment, config, t) {
1124
1156
  console.log(t("pair.relayOnlyLanHostHint"));
1125
1157
  console.log(t("pair.relayOnlySafetyHint"));
1126
1158
  }
1159
+ function isCliEntrypoint() {
1160
+ const entry = process.argv[1];
1161
+ return Boolean(entry && import.meta.url === new URL(`file://${path3.resolve(entry)}`).href);
1162
+ }
1163
+ export {
1164
+ waitForPairingOrShutdown
1165
+ };
@@ -1,4 +1,5 @@
1
1
  import Koa from 'koa';
2
+ import { R as RuntimePaths } from '../paths-CmAiZsna.js';
2
3
 
3
4
  interface ConversationProfileSummary {
4
5
  uid?: string;
@@ -183,6 +184,19 @@ interface BulkDeleteConversationResult {
183
184
  message: string;
184
185
  };
185
186
  }
187
+ type ConversationClearPlanStatus = 'prepared' | 'executing' | 'completed' | 'failed';
188
+ interface ConversationClearPlan {
189
+ id: string;
190
+ status: ConversationClearPlanStatus;
191
+ created_at: string;
192
+ updated_at: string;
193
+ total_count: number;
194
+ deleted_count: number;
195
+ failed_count: number;
196
+ conversation_ids: string[];
197
+ conversations: BulkDeleteConversationResult[];
198
+ completed_at?: string;
199
+ }
186
200
  interface LinkRun {
187
201
  id: string;
188
202
  kind?: 'agent' | 'command';
@@ -254,21 +268,6 @@ interface CancelRunResult {
254
268
  }
255
269
  type ConversationEventListener = (event: ConversationEvent) => void;
256
270
 
257
- interface RuntimePaths {
258
- homeDir: string;
259
- identityFile: string;
260
- configFile: string;
261
- stateFile: string;
262
- credentialsFile: string;
263
- databaseFile: string;
264
- conversationsDir: string;
265
- blobsDir: string;
266
- indexesDir: string;
267
- logsDir: string;
268
- runDir: string;
269
- pairingDir: string;
270
- }
271
-
272
271
  interface LinkStatistics {
273
272
  conversations: {
274
273
  total: number;
@@ -462,6 +461,10 @@ declare class ConversationService {
462
461
  last_event_seq: number;
463
462
  }>;
464
463
  deleteConversation(conversationId: string): Promise<DeleteConversationResult>;
464
+ prepareClearAllConversationPlan(): Promise<ConversationClearPlan>;
465
+ readClearAllConversationPlan(planId: string): Promise<ConversationClearPlan>;
466
+ executeClearAllConversationPlan(planId: string): Promise<ConversationClearPlan>;
467
+ startClearAllConversationPlan(planId: string): Promise<ConversationClearPlan>;
465
468
  deleteConversations(conversationIds: string[]): Promise<{
466
469
  deleted_count: number;
467
470
  failed_count: number;
package/dist/http/app.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  createApp
3
- } from "../chunk-7OVDWXR7.js";
3
+ } from "../chunk-476X63MC.js";
4
4
  export {
5
5
  createApp
6
6
  };
@@ -0,0 +1,16 @@
1
+ interface RuntimePaths {
2
+ homeDir: string;
3
+ identityFile: string;
4
+ configFile: string;
5
+ stateFile: string;
6
+ credentialsFile: string;
7
+ databaseFile: string;
8
+ conversationsDir: string;
9
+ blobsDir: string;
10
+ indexesDir: string;
11
+ logsDir: string;
12
+ runDir: string;
13
+ pairingDir: string;
14
+ }
15
+
16
+ export type { RuntimePaths as R };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hermespilot/link",
3
- "version": "0.3.9",
3
+ "version": "0.4.1",
4
4
  "private": false,
5
5
  "description": "Hermes Link companion service and CLI for connecting hermes-agent through HermesPilot",
6
6
  "license": "MIT",