@hermespilot/link 0.6.8 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/index.js CHANGED
@@ -17,6 +17,7 @@ import {
17
17
  ensureHermesApiServerAvailable,
18
18
  ensureHermesApiServerConfig,
19
19
  ensureHermesLinkSkillInstalledBestEffort,
20
+ ensureHermesUsageProbeForProfiles,
20
21
  ensureIdentity,
21
22
  fetchRelayStreamBatchPolicy,
22
23
  flushLogFiles,
@@ -50,8 +51,9 @@ import {
50
51
  startDaemonProcess,
51
52
  startLinkService,
52
53
  stopDaemonProcess,
54
+ summarizeUsageProbeEnsure,
53
55
  translate
54
- } from "../chunk-57ZJLOQA.js";
56
+ } from "../chunk-XWQRIQVR.js";
55
57
 
56
58
  // src/cli/index.ts
57
59
  import { Command } from "commander";
@@ -905,6 +907,7 @@ program.command("start").description(helpText("start.description")).action(async
905
907
  paths,
906
908
  source: "cli_start_already_running"
907
909
  });
910
+ await ensureUsageProbeFromCli(paths, t, language, false, "cli_start_already_running");
908
911
  return;
909
912
  }
910
913
  const nextStatus = await startDaemonProcess(paths);
@@ -913,6 +916,7 @@ program.command("start").description(helpText("start.description")).action(async
913
916
  paths,
914
917
  source: "cli_start"
915
918
  });
919
+ await ensureUsageProbeFromCli(paths, t, language, true, "cli_start");
916
920
  });
917
921
  program.command("stop").description(helpText("stop.description")).action(async () => {
918
922
  const config = await loadConfig();
@@ -938,6 +942,7 @@ program.command("restart").description(helpText("restart.description")).action(a
938
942
  paths,
939
943
  source: "cli_restart"
940
944
  });
945
+ await ensureUsageProbeFromCli(paths, t, language, true, "cli_restart");
941
946
  });
942
947
  program.command("deliver").argument("<staging-dir>").description(helpText("deliver.description")).action(async (stagingDir) => {
943
948
  const paths = resolveRuntimePaths();
@@ -1162,6 +1167,7 @@ logsCommand.command("flush").description(helpText("logs.flush.description")).opt
1162
1167
  );
1163
1168
  });
1164
1169
  program.command("doctor").option("--install", helpText("doctor.installOnly")).option("--no-profiles", helpText("doctor.noProfiles")).description(helpText("doctor.description")).action(async (options) => {
1170
+ const paths = resolveRuntimePaths();
1165
1171
  const installInfo = readInstallPathInfo();
1166
1172
  const installLanguage = await loadCliLanguage().catch(() => detectSystemLanguage());
1167
1173
  const installT = translate.bind(null, installLanguage);
@@ -1172,7 +1178,7 @@ program.command("doctor").option("--install", helpText("doctor.installOnly")).op
1172
1178
  if (hasInstallPathIssue(installInfo)) {
1173
1179
  printInstallDiagnostics(installInfo, installT, false);
1174
1180
  }
1175
- const [identity, config] = await Promise.all([ensureIdentity(), loadConfig()]);
1181
+ const [identity, config] = await Promise.all([ensureIdentity(paths), loadConfig(paths)]);
1176
1182
  const language = resolveLanguage(config.language);
1177
1183
  const t = translate.bind(null, language);
1178
1184
  const hermesConfig = await ensureHermesApiServerConfig("default", void 0, language);
@@ -1203,8 +1209,9 @@ program.command("doctor").option("--install", helpText("doctor.installOnly")).op
1203
1209
  } catch (error) {
1204
1210
  console.log(formatHermesApiServerUnavailable(error, language));
1205
1211
  }
1212
+ const usageProbe = await ensureUsageProbeFromCli(paths, t, language, true, "cli_doctor");
1206
1213
  if (options.profiles !== false) {
1207
- await printProfileDiagnostics(t);
1214
+ await printProfileDiagnostics(t, usageProbe.profiles);
1208
1215
  }
1209
1216
  });
1210
1217
  if (isCliEntrypoint()) {
@@ -1218,18 +1225,74 @@ async function loadCliLanguage() {
1218
1225
  const config = await loadConfig();
1219
1226
  return resolveLanguage(config.language);
1220
1227
  }
1221
- async function printProfileDiagnostics(t) {
1228
+ async function ensureUsageProbeFromCli(paths, t, language, activateGateways, source) {
1229
+ console.log(t("usageProbe.ensure.started"));
1230
+ let failedBeforeProfileScan = false;
1231
+ const result = await ensureHermesUsageProbeForProfiles({
1232
+ paths,
1233
+ language,
1234
+ activateGateways,
1235
+ retryLinkDisabled: source === "cli_start" || source === "cli_restart" || source === "cli_doctor",
1236
+ source
1237
+ }).catch((error) => {
1238
+ failedBeforeProfileScan = true;
1239
+ console.log(
1240
+ t("usageProbe.ensure.failedNonBlocking", {
1241
+ failed: 1,
1242
+ ready: 0,
1243
+ total: 1
1244
+ })
1245
+ );
1246
+ console.log(error instanceof Error ? error.message : String(error));
1247
+ return { profiles: [] };
1248
+ });
1249
+ if (failedBeforeProfileScan) {
1250
+ return result;
1251
+ }
1252
+ const summary = summarizeUsageProbeEnsure(result);
1253
+ const attentionCount = summary.failed + summary.needsRestart + summary.disabled;
1254
+ if (attentionCount > 0) {
1255
+ console.log(
1256
+ t(
1257
+ summary.ready > 0 || summary.needsRestart > 0 || summary.disabled > 0 ? "usageProbe.ensure.partial" : "usageProbe.ensure.failedNonBlocking",
1258
+ {
1259
+ ready: summary.ready,
1260
+ total: summary.total,
1261
+ failed: attentionCount
1262
+ }
1263
+ )
1264
+ );
1265
+ } else {
1266
+ console.log(
1267
+ t("usageProbe.ensure.done", {
1268
+ ready: summary.ready,
1269
+ total: summary.total
1270
+ })
1271
+ );
1272
+ }
1273
+ return result;
1274
+ }
1275
+ async function printProfileDiagnostics(t, usageProbeProfiles = []) {
1222
1276
  console.log(t("doctor.profilesHeader"));
1223
1277
  const profiles = await prepareHermesProfilesForUse();
1224
1278
  if (profiles.length === 0) {
1225
1279
  console.log(t("doctor.profilesNone"));
1226
1280
  return;
1227
1281
  }
1282
+ const usageProbeByProfile = new Map(
1283
+ usageProbeProfiles.map((profile) => [profile.profile, profile])
1284
+ );
1228
1285
  for (const profile of profiles) {
1229
- console.log(await formatProfileDiagnosticLine(profile, t));
1286
+ console.log(
1287
+ await formatProfileDiagnosticLine(
1288
+ profile,
1289
+ t,
1290
+ usageProbeByProfile.get(profile.profile.name)
1291
+ )
1292
+ );
1230
1293
  }
1231
1294
  }
1232
- async function formatProfileDiagnosticLine(profile, t) {
1295
+ async function formatProfileDiagnosticLine(profile, t, usageProbe) {
1233
1296
  if (profile.error || !profile.apiServer) {
1234
1297
  return t("doctor.profileLine", {
1235
1298
  profile: profile.profile.name,
@@ -1251,12 +1314,48 @@ async function formatProfileDiagnosticLine(profile, t) {
1251
1314
  message: health.issue ?? t("status.unknown")
1252
1315
  });
1253
1316
  const state = profile.changed ? t("doctor.profilePreparedState", { state: baseState }) : baseState;
1317
+ const usageProbeState = usageProbe ? formatUsageProbeState(usageProbe, t) : null;
1254
1318
  return t("doctor.profileLine", {
1255
1319
  profile: profile.profile.name,
1256
1320
  endpoint: `${host}:${port}`,
1257
- state
1321
+ state: usageProbeState ? `${state}; ${usageProbeState}` : state
1258
1322
  });
1259
1323
  }
1324
+ function formatUsageProbeState(profile, t) {
1325
+ if (profile.disabledByUser) {
1326
+ return t("usageProbe.disabledByUser");
1327
+ }
1328
+ if (profile.error) {
1329
+ if (profile.error.includes("unmanaged Hermes plugin file")) {
1330
+ return t("usageProbe.installConflict", { message: profile.error });
1331
+ }
1332
+ if (profile.error.includes("plugins.enabled")) {
1333
+ return t("usageProbe.configInvalid", { message: profile.error });
1334
+ }
1335
+ if (profile.restart.attempted && profile.restart.error) {
1336
+ return t("usageProbe.gateway.restartFailed", {
1337
+ message: profile.restart.error
1338
+ });
1339
+ }
1340
+ return t("usageProbe.configInvalid", { message: profile.error });
1341
+ }
1342
+ if (profile.restart.succeeded) {
1343
+ return t("usageProbe.gateway.restartDone");
1344
+ }
1345
+ if (profile.needsRestart) {
1346
+ return t("usageProbe.profile.needsRestart");
1347
+ }
1348
+ if (profile.pluginChanged && profile.configChanged) {
1349
+ return t("usageProbe.profile.installed");
1350
+ }
1351
+ if (profile.pluginChanged) {
1352
+ return t("usageProbe.profile.updated");
1353
+ }
1354
+ if (profile.configChanged) {
1355
+ return t("usageProbe.profile.enabled");
1356
+ }
1357
+ return t("usageProbe.profile.ready");
1358
+ }
1260
1359
  function buildRelayStatusPayload(input) {
1261
1360
  if (!input.paired) {
1262
1361
  return emptyRelayStatus(input.relayConfigured, "not_paired");
@@ -10,6 +10,8 @@ interface ConversationProfileSummary {
10
10
  interface ConversationSummary {
11
11
  id: string;
12
12
  title: string;
13
+ display_title?: string;
14
+ title_source?: ConversationTitleSource;
13
15
  created_at: string;
14
16
  updated_at: string;
15
17
  last_event_seq: number;
@@ -51,10 +53,11 @@ interface ConversationRuntimeMetadata {
51
53
  used_tokens?: number;
52
54
  window_tokens?: number;
53
55
  usage_percent?: number;
54
- source: 'explicit' | 'estimated' | 'unknown';
56
+ source: 'explicit' | 'probe' | 'estimated' | 'unknown';
55
57
  updated_at?: string;
56
58
  };
57
59
  }
60
+ type ConversationTitleSource = 'default' | 'temporary_user_message' | 'temporary_fallback' | 'manual' | 'generated' | 'hermes';
58
61
  interface ConversationMessagesPageInfo {
59
62
  limit: number;
60
63
  has_more_before: boolean;
@@ -248,6 +251,9 @@ interface ConversationArchivePlan {
248
251
  interface LinkRun {
249
252
  id: string;
250
253
  kind?: 'agent' | 'command';
254
+ queue_mode?: 'guided_interrupt';
255
+ queue_promoted_at?: string;
256
+ guided_after_run_id?: string;
251
257
  hermes_run_id?: string;
252
258
  hermes_response_id?: string;
253
259
  previous_response_id?: string;
@@ -263,6 +269,9 @@ interface LinkRun {
263
269
  profile_uid?: string;
264
270
  profile_name_snapshot?: string;
265
271
  profile?: string;
272
+ owner_account_id?: string;
273
+ owner_app_instance_id?: string;
274
+ language?: string;
266
275
  model?: string;
267
276
  provider?: string;
268
277
  context_window?: number;
@@ -273,7 +282,7 @@ interface LinkRun {
273
282
  context_tokens?: number;
274
283
  context_window?: number;
275
284
  usage_percent?: number;
276
- context_source?: 'explicit' | 'estimated';
285
+ context_source?: 'explicit' | 'probe' | 'estimated';
277
286
  };
278
287
  }
279
288
  interface SendMessageInput {
@@ -283,6 +292,9 @@ interface SendMessageInput {
283
292
  clientMessageId?: string;
284
293
  idempotencyKey?: string;
285
294
  profileName?: string;
295
+ accountId?: string;
296
+ appInstanceId?: string;
297
+ language?: string;
286
298
  }
287
299
  interface MessageAttachmentInput {
288
300
  blob_id?: string;
@@ -308,12 +320,18 @@ interface SendMessageResult {
308
320
  run: Pick<LinkRun, 'id' | 'status'>;
309
321
  last_event_seq: number;
310
322
  conversation?: ConversationSummary;
323
+ runtime?: ConversationRuntimeMetadata;
311
324
  }
312
325
  interface CancelRunResult {
313
326
  conversation_id: string;
314
327
  run: Pick<LinkRun, 'id' | 'status'>;
315
328
  last_event_seq: number;
316
329
  }
330
+ interface QueuedRunActionResult {
331
+ conversation_id: string;
332
+ queued_run: Pick<LinkRun, 'id' | 'status'>;
333
+ last_event_seq: number;
334
+ }
317
335
  type ConversationEventListener = (event: ConversationEvent) => void;
318
336
 
319
337
  interface LinkStatistics {
@@ -425,6 +443,7 @@ declare class ConversationService {
425
443
  private readonly queries;
426
444
  private readonly runLifecycle;
427
445
  private hermesSessionSyncPromise;
446
+ private cronDeliverySyncPromise;
428
447
  constructor(paths: RuntimePaths, logger: FileLogger);
429
448
  private withConversationLock;
430
449
  private restoreArchivedConversationForUserContinuationLocked;
@@ -452,20 +471,33 @@ declare class ConversationService {
452
471
  createConversation(input?: {
453
472
  title?: string;
454
473
  profileName?: string;
474
+ accountId?: string;
475
+ appInstanceId?: string;
455
476
  }): Promise<ConversationSummary>;
456
477
  ensureCronInboxConversation(input?: {
457
478
  profileName?: string;
458
479
  }): Promise<string>;
459
480
  appendCronDelivery(input: {
460
- conversationId: string;
481
+ conversationId?: string;
461
482
  profileName: string;
462
483
  jobId: string;
484
+ source: 'app' | 'natural_language';
463
485
  jobName?: string;
464
486
  outputPath: string;
465
487
  content: string;
488
+ failed?: boolean;
466
489
  runAt?: string;
467
- }): Promise<void>;
490
+ accountId?: string;
491
+ appInstanceId?: string;
492
+ }): Promise<boolean>;
493
+ private appendCronDeliveryToBoundConversation;
494
+ private findImportedCronConversation;
495
+ private reportCronNotification;
468
496
  syncCronDeliveries(): Promise<void>;
497
+ backfillCronOwnership(input: {
498
+ accountId?: string;
499
+ appInstanceId?: string;
500
+ }): Promise<void>;
469
501
  syncHermesSessions(): Promise<HermesSessionSyncResult>;
470
502
  deliverStagedFiles(stagingDir: string): Promise<ImportMediaReferencesResult>;
471
503
  getMessages(conversationId: string, options?: ConversationMessagesPageOptions): Promise<{
@@ -477,7 +509,7 @@ declare class ConversationService {
477
509
  }>;
478
510
  setConversationModel(conversationId: string, modelId: string): Promise<{
479
511
  conversation_id: string;
480
- model_override: string;
512
+ default_model: string;
481
513
  runtime: ConversationRuntimeMetadata;
482
514
  last_event_seq: number;
483
515
  }>;
@@ -508,6 +540,8 @@ declare class ConversationService {
508
540
  sendMessage(input: SendMessageInput): Promise<SendMessageResult>;
509
541
  cancelRun(conversationId: string, runId: string): Promise<CancelRunResult>;
510
542
  cancelRunById(runId: string): Promise<CancelRunResult>;
543
+ guideQueuedRun(conversationId: string, runId: string): Promise<QueuedRunActionResult>;
544
+ cancelQueuedRun(conversationId: string, runId: string): Promise<QueuedRunActionResult>;
511
545
  resolveApproval(input: {
512
546
  conversationId: string;
513
547
  approvalId: string;
package/dist/http/app.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  createApp
3
- } from "../chunk-57ZJLOQA.js";
3
+ } from "../chunk-XWQRIQVR.js";
4
4
  export {
5
5
  createApp
6
6
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hermespilot/link",
3
- "version": "0.6.8",
3
+ "version": "0.7.0",
4
4
  "private": false,
5
5
  "description": "Hermes Link companion service and CLI for connecting hermes-agent through HermesPilot",
6
6
  "license": "MIT",