@signetai/connector-hermes-agent 0.207.2 → 0.208.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.
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { BaseConnector, type InstallResult, type UninstallResult } from "@signetai/connector-base";
2
+ import { type HermesTarget } from "@signetai/core";
2
3
  export interface HermesDiagnosticCheck {
3
4
  readonly id: string;
4
5
  readonly label: string;
@@ -17,9 +18,36 @@ export interface HermesDoctorReport {
17
18
  readonly checks: readonly HermesDiagnosticCheck[];
18
19
  readonly warnings: readonly string[];
19
20
  }
21
+ type AgentReadPolicy = "isolated" | "shared" | "group";
22
+ export interface AgentRegistrationOptions {
23
+ readonly agentId: string;
24
+ readonly readPolicy?: AgentReadPolicy;
25
+ readonly policyGroup?: string | null;
26
+ /** Requested profile provisioning must fail closed instead of warning. */
27
+ readonly strict?: boolean;
28
+ }
29
+ export type AgentRegistrationResult = {
30
+ readonly ok: true;
31
+ readonly created: boolean;
32
+ readonly agentId: string;
33
+ } | {
34
+ readonly ok: false;
35
+ readonly agentId: string;
36
+ readonly error: string;
37
+ };
38
+ export declare function ensureNamedAgentRegistered(daemonUrl: string, agentIdOrOptions: string | AgentRegistrationOptions, warnings: string[]): Promise<AgentRegistrationResult>;
39
+ export interface HermesConnectorOptions {
40
+ readonly target?: HermesTarget;
41
+ readonly agentId?: string;
42
+ readonly readPolicy?: AgentReadPolicy;
43
+ readonly policyGroup?: string | null;
44
+ }
20
45
  export declare class HermesAgentConnector extends BaseConnector {
21
46
  readonly name = "Hermes Agent";
22
47
  readonly harnessId = "hermes-agent";
48
+ private readonly target?;
49
+ private readonly registration?;
50
+ constructor(options?: HermesTarget | HermesConnectorOptions);
23
51
  private getHermesHome;
24
52
  private getHermesRepo;
25
53
  getConfigPath(): string;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,aAAa,EAAE,KAAK,aAAa,EAAE,KAAK,eAAe,EAAuB,MAAM,wBAAwB,CAAC;AAoDtH,MAAM,WAAW,qBAAqB;IACrC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,kBAAkB;IAClC,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,QAAQ,CAAC,MAAM,EAAE,SAAS,qBAAqB,EAAE,CAAC;IAClD,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC;AAsrBD,qBAAa,oBAAqB,SAAQ,aAAa;IACtD,QAAQ,CAAC,IAAI,kBAAkB;IAC/B,QAAQ,CAAC,SAAS,kBAAkB;IAEpC,OAAO,CAAC,aAAa;IAIrB,OAAO,CAAC,aAAa;IAIrB,aAAa,IAAI,MAAM;IAIjB,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAgMjD,SAAS,IAAI,OAAO,CAAC,eAAe,CAAC;IAuD3C,WAAW,IAAI,OAAO;IAQhB,QAAQ,IAAI,OAAO,CAAC,kBAAkB,CAAC;CAS7C;AAED,wBAAsB,yBAAyB,CAAC,IAAI,CAAC,EAAE;IACtD,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC5B,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAuG9B;AAED,wBAAgB,eAAe,IAAI,oBAAoB,CAEtD;AAED,eAAe,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,14 +1,14 @@
1
1
  // src/index.ts
2
2
  import { spawnSync } from "node:child_process";
3
3
  import { createHash as createHash5 } from "node:crypto";
4
- import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, rmSync, writeFileSync as writeFileSync2 } from "node:fs";
4
+ import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, realpathSync as realpathSync3, rmSync, writeFileSync as writeFileSync2 } from "node:fs";
5
5
  import { homedir } from "node:os";
6
- import { dirname as dirname6, join as join4 } from "node:path";
6
+ import { dirname as dirname6, isAbsolute as isAbsolute2, join as join4, relative as relative2 } from "node:path";
7
7
  import { fileURLToPath as fileURLToPath3 } from "node:url";
8
8
 
9
9
  // ../../../libs/connector-base/dist/index.js
10
10
  import { randomBytes } from "node:crypto";
11
- import { existsSync, readFileSync, renameSync, statSync, unlinkSync, writeFileSync } from "node:fs";
11
+ import { existsSync, readFileSync, realpathSync, renameSync, statSync, unlinkSync, writeFileSync } from "node:fs";
12
12
  import { dirname as dirname2, isAbsolute, join as join3, relative, sep } from "node:path";
13
13
  import { createRequire } from "node:module";
14
14
  import { dirname, join } from "node:path";
@@ -15707,6 +15707,34 @@ function up135(db) {
15707
15707
  ON memory_head_publications(agent_id, status, revision DESC);
15708
15708
  `);
15709
15709
  }
15710
+ function up136(db) {
15711
+ const cols = new Set(db.prepare("PRAGMA table_info(memory_head_revisions)").all().map((r2) => r2.name));
15712
+ for (const [name, type] of [
15713
+ ["entry_id", "TEXT"],
15714
+ ["entry_text", "TEXT"],
15715
+ ["operation", "TEXT"],
15716
+ ["source_refs_json", "TEXT"],
15717
+ ["supporting_quotes_json", "TEXT"]
15718
+ ]) {
15719
+ if (!cols.has(name))
15720
+ db.exec(`ALTER TABLE memory_head_revisions ADD COLUMN ${name} ${type}`);
15721
+ }
15722
+ db.exec("CREATE UNIQUE INDEX IF NOT EXISTS idx_memory_head_revisions_entry ON memory_head_revisions(agent_id, revision, entry_id)");
15723
+ }
15724
+ function up137(db) {
15725
+ const cols = new Set(db.prepare("PRAGMA table_info(dreaming_passes)").all().map((r2) => r2.name));
15726
+ for (const [name, type] of [
15727
+ ["head_revision", "INTEGER"],
15728
+ ["head_hash", "TEXT"],
15729
+ ["head_added", "INTEGER NOT NULL DEFAULT 0"],
15730
+ ["head_updated", "INTEGER NOT NULL DEFAULT 0"],
15731
+ ["head_removed", "INTEGER NOT NULL DEFAULT 0"],
15732
+ ["head_deferred", "INTEGER NOT NULL DEFAULT 0"],
15733
+ ["head_no_op", "INTEGER NOT NULL DEFAULT 0"]
15734
+ ])
15735
+ if (!cols.has(name))
15736
+ db.exec(`ALTER TABLE dreaming_passes ADD COLUMN ${name} ${type}`);
15737
+ }
15710
15738
  var MIGRATIONS = [
15711
15739
  {
15712
15740
  version: 1,
@@ -16779,6 +16807,23 @@ var MIGRATIONS = [
16779
16807
  name: "memory-head-publication",
16780
16808
  up: up135,
16781
16809
  artifacts: { tables: ["memory_head_publications"] }
16810
+ },
16811
+ {
16812
+ version: 136,
16813
+ name: "memory-head-revisions",
16814
+ up: up136,
16815
+ artifacts: { tables: ["memory_head_revisions"] }
16816
+ },
16817
+ {
16818
+ version: 137,
16819
+ name: "dreaming-head-manifest",
16820
+ up: up137,
16821
+ artifacts: {
16822
+ columns: [
16823
+ { table: "dreaming_passes", column: "head_revision" },
16824
+ { table: "dreaming_passes", column: "head_hash" }
16825
+ ]
16826
+ }
16782
16827
  }
16783
16828
  ];
16784
16829
  var LATEST_SCHEMA_VERSION = MIGRATIONS[MIGRATIONS.length - 1]?.version ?? 0;
@@ -17174,6 +17219,12 @@ class BaseConnector {
17174
17219
  const cleaned = stripSignetBlock(raw);
17175
17220
  if (cleaned === raw)
17176
17221
  return null;
17222
+ const root = realpathSync(basePath);
17223
+ const parent = realpathSync(dirname2(agentsPath));
17224
+ const rel = relative(root, join3(parent, "AGENTS.md"));
17225
+ if (rel.startsWith("..") || isAbsolute(rel)) {
17226
+ throw new Error(`Target path escapes validated root: ${agentsPath}`);
17227
+ }
17177
17228
  const tmp = join3(basePath, `.${randomBytes(6).toString("hex")}.tmp`);
17178
17229
  try {
17179
17230
  writeFileSync(tmp, cleaned, "utf-8");
@@ -17253,7 +17304,7 @@ import { dirname as dirname42, join as join82, resolve as resolve22 } from "node
17253
17304
  import { homedir as homedir62, platform as platform22 } from "node:os";
17254
17305
  import { basename as basename2, dirname as dirname52, resolve as resolve42 } from "node:path";
17255
17306
  import { execFileSync as execFileSync3 } from "node:child_process";
17256
- import { existsSync as existsSync12, readFileSync as readFileSync10, readdirSync as readdirSync5, realpathSync, statSync as statSync7 } from "node:fs";
17307
+ import { existsSync as existsSync12, readFileSync as readFileSync10, readdirSync as readdirSync5, realpathSync as realpathSync2, statSync as statSync7 } from "node:fs";
17257
17308
  import { homedir as homedir9 } from "node:os";
17258
17309
  import { dirname as dirname8, join as join13 } from "node:path";
17259
17310
  import { homedir as homedir102 } from "node:os";
@@ -28614,7 +28665,7 @@ function memoriesFtsNeedsTokenizerRepair2(sql) {
28614
28665
  return true;
28615
28666
  return !normalized.includes(`tokenize='${MEMORIES_FTS_TOKENIZER2}'`);
28616
28667
  }
28617
- function up136(db) {
28668
+ function up138(db) {
28618
28669
  db.exec(`
28619
28670
  CREATE TABLE IF NOT EXISTS schema_migrations (
28620
28671
  version INTEGER PRIMARY KEY,
@@ -29098,7 +29149,7 @@ function addColumnIfMissing52(db, table, column, definition) {
29098
29149
  db.exec(`ALTER TABLE ${table} ADD COLUMN ${column} ${definition}`);
29099
29150
  }
29100
29151
  }
29101
- function up137(db) {
29152
+ function up139(db) {
29102
29153
  db.exec(`
29103
29154
  CREATE TABLE IF NOT EXISTS ingestion_jobs (
29104
29155
  id TEXT PRIMARY KEY,
@@ -32939,11 +32990,39 @@ function up1352(db) {
32939
32990
  ON memory_head_publications(agent_id, status, revision DESC);
32940
32991
  `);
32941
32992
  }
32993
+ function up1362(db) {
32994
+ const cols = new Set(db.prepare("PRAGMA table_info(memory_head_revisions)").all().map((r3) => r3.name));
32995
+ for (const [name, type] of [
32996
+ ["entry_id", "TEXT"],
32997
+ ["entry_text", "TEXT"],
32998
+ ["operation", "TEXT"],
32999
+ ["source_refs_json", "TEXT"],
33000
+ ["supporting_quotes_json", "TEXT"]
33001
+ ]) {
33002
+ if (!cols.has(name))
33003
+ db.exec(`ALTER TABLE memory_head_revisions ADD COLUMN ${name} ${type}`);
33004
+ }
33005
+ db.exec("CREATE UNIQUE INDEX IF NOT EXISTS idx_memory_head_revisions_entry ON memory_head_revisions(agent_id, revision, entry_id)");
33006
+ }
33007
+ function up1372(db) {
33008
+ const cols = new Set(db.prepare("PRAGMA table_info(dreaming_passes)").all().map((r3) => r3.name));
33009
+ for (const [name, type] of [
33010
+ ["head_revision", "INTEGER"],
33011
+ ["head_hash", "TEXT"],
33012
+ ["head_added", "INTEGER NOT NULL DEFAULT 0"],
33013
+ ["head_updated", "INTEGER NOT NULL DEFAULT 0"],
33014
+ ["head_removed", "INTEGER NOT NULL DEFAULT 0"],
33015
+ ["head_deferred", "INTEGER NOT NULL DEFAULT 0"],
33016
+ ["head_no_op", "INTEGER NOT NULL DEFAULT 0"]
33017
+ ])
33018
+ if (!cols.has(name))
33019
+ db.exec(`ALTER TABLE dreaming_passes ADD COLUMN ${name} ${type}`);
33020
+ }
32942
33021
  var MIGRATIONS2 = [
32943
33022
  {
32944
33023
  version: 1,
32945
33024
  name: "baseline",
32946
- up: up136,
33025
+ up: up138,
32947
33026
  artifacts: { tables: ["memories", "conversations", "embeddings"] }
32948
33027
  },
32949
33028
  {
@@ -33021,7 +33100,7 @@ var MIGRATIONS2 = [
33021
33100
  {
33022
33101
  version: 13,
33023
33102
  name: "ingestion-tracking",
33024
- up: up137,
33103
+ up: up139,
33025
33104
  artifacts: {
33026
33105
  columns: [
33027
33106
  { table: "memories", column: "source_path" },
@@ -34011,6 +34090,23 @@ var MIGRATIONS2 = [
34011
34090
  name: "memory-head-publication",
34012
34091
  up: up1352,
34013
34092
  artifacts: { tables: ["memory_head_publications"] }
34093
+ },
34094
+ {
34095
+ version: 136,
34096
+ name: "memory-head-revisions",
34097
+ up: up1362,
34098
+ artifacts: { tables: ["memory_head_revisions"] }
34099
+ },
34100
+ {
34101
+ version: 137,
34102
+ name: "dreaming-head-manifest",
34103
+ up: up1372,
34104
+ artifacts: {
34105
+ columns: [
34106
+ { table: "dreaming_passes", column: "head_revision" },
34107
+ { table: "dreaming_passes", column: "head_hash" }
34108
+ ]
34109
+ }
34014
34110
  }
34015
34111
  ];
34016
34112
  var LATEST_SCHEMA_VERSION2 = MIGRATIONS2[MIGRATIONS2.length - 1]?.version ?? 0;
@@ -34352,7 +34448,7 @@ function resolveHermesRepoPath() {
34352
34448
  timeout: 3000
34353
34449
  }).trim();
34354
34450
  if (hermesPath) {
34355
- const repoDir = dirname8(realpathSync(hermesPath));
34451
+ const repoDir = dirname8(realpathSync2(hermesPath));
34356
34452
  if (existsSync12(join13(repoDir, "plugins", "memory")))
34357
34453
  return repoDir;
34358
34454
  }
@@ -34398,6 +34494,44 @@ var REQUIRED_TOOL_NAMES = [
34398
34494
  "recall",
34399
34495
  "remember"
34400
34496
  ];
34497
+ function resolveContainedWritePath(targetPath, targetRoot) {
34498
+ let rootPath = targetRoot;
34499
+ while (!existsSync2(rootPath)) {
34500
+ const parent = dirname6(rootPath);
34501
+ if (parent === rootPath)
34502
+ throw new Error(`Hermes target root does not exist: ${targetRoot}`);
34503
+ rootPath = parent;
34504
+ }
34505
+ if (realpathSync3(rootPath) !== rootPath) {
34506
+ throw new Error(`Hermes target root is symlinked and cannot be used for writes: ${targetRoot}`);
34507
+ }
34508
+ rootPath = targetRoot;
34509
+ while (!existsSync2(rootPath)) {
34510
+ const parent = dirname6(rootPath);
34511
+ if (parent === rootPath)
34512
+ throw new Error(`Hermes target root does not exist: ${targetRoot}`);
34513
+ rootPath = parent;
34514
+ }
34515
+ const root = realpathSync3(rootPath);
34516
+ let existing = targetPath;
34517
+ const missing = [];
34518
+ while (!existsSync2(existing)) {
34519
+ const parent = dirname6(existing);
34520
+ if (parent === existing)
34521
+ throw new Error(`Hermes target path does not have an existing ancestor: ${targetPath}`);
34522
+ missing.unshift(existing.slice(parent.length + 1));
34523
+ existing = parent;
34524
+ }
34525
+ const candidate = join4(realpathSync3(existing), ...missing);
34526
+ const rel = relative2(root, candidate);
34527
+ if (rel.startsWith("..") || isAbsolute2(rel)) {
34528
+ throw new Error(`Hermes target path escapes validated root: ${targetPath}`);
34529
+ }
34530
+ return candidate;
34531
+ }
34532
+ function assertContainedTargetPath(targetPath, targetRoot) {
34533
+ resolveContainedWritePath(targetPath, targetRoot);
34534
+ }
34401
34535
  function getRepoPluginTargetDir(hermesRepo) {
34402
34536
  return join4(hermesRepo, "plugins", "memory", "signet");
34403
34537
  }
@@ -34407,28 +34541,31 @@ function getUserPluginTargetDir(hermesHome) {
34407
34541
  function getProviderBackupPath(hermesHome) {
34408
34542
  return join4(hermesHome, PROVIDER_BACKUP_FILE);
34409
34543
  }
34410
- function installPlugin(targetDir, targetKind) {
34544
+ function installPlugin(targetDir, targetKind, targetRoot) {
34545
+ const writeDir = targetRoot ? resolveContainedWritePath(targetDir, targetRoot) : targetDir;
34411
34546
  const sourceDir = getPluginSourceDir();
34412
- mkdirSync(targetDir, { recursive: true });
34547
+ mkdirSync(writeDir, { recursive: true });
34413
34548
  const written = [];
34414
34549
  for (const file of PLUGIN_FILES) {
34415
34550
  const src = join4(sourceDir, file);
34416
- const dst = join4(targetDir, file);
34551
+ const dst = join4(writeDir, file);
34417
34552
  if (existsSync2(src)) {
34418
34553
  writeFileSync2(dst, readFileSync2(src));
34419
34554
  written.push(dst);
34420
34555
  }
34421
34556
  }
34422
- written.push(writeInstallMarker(targetDir, targetKind));
34557
+ written.push(writeInstallMarker(writeDir, targetKind));
34423
34558
  return written;
34424
34559
  }
34425
- function uninstallPlugin(targetDir) {
34426
- const removed = [];
34427
- if (existsSync2(targetDir)) {
34428
- rmSync(targetDir, { recursive: true, force: true });
34429
- removed.push(targetDir);
34560
+ function uninstallPlugin(targetDir, targetRoot) {
34561
+ if (!existsSync2(targetDir))
34562
+ return [];
34563
+ const safeTargetDir = targetRoot ? resolveContainedWritePath(targetDir, targetRoot) : targetDir;
34564
+ if (!readInstallMarker(safeTargetDir)) {
34565
+ throw new Error(`Refusing to uninstall unowned Hermes plugin path: ${targetDir} (missing or invalid ${INSTALL_MARKER_FILE})`);
34430
34566
  }
34431
- return removed;
34567
+ rmSync(safeTargetDir, { recursive: true, force: true });
34568
+ return [targetDir];
34432
34569
  }
34433
34570
  function getConfigCandidates(hermesHome) {
34434
34571
  return [join4(hermesHome, "config.yaml"), join4(hermesHome, "cli-config.yaml")];
@@ -34547,10 +34684,10 @@ function parseDottedProviderLine(line) {
34547
34684
  function setDottedProviderLine(lines, line, value) {
34548
34685
  lines[line] = `memory.provider: ${value}`;
34549
34686
  }
34550
- function writeProviderBackup(hermesHome, configPath, providerKind, previousProvider) {
34687
+ function writeProviderBackup(hermesHome, targetRoot, configPath, providerKind, previousProvider) {
34551
34688
  if (previousProvider === "signet")
34552
34689
  return null;
34553
- const backupPath = getProviderBackupPath(hermesHome);
34690
+ const backupPath = resolveContainedWritePath(getProviderBackupPath(hermesHome), targetRoot);
34554
34691
  if (existsSync2(backupPath))
34555
34692
  return null;
34556
34693
  const backup = {
@@ -34579,8 +34716,8 @@ function readProviderBackup(hermesHome) {
34579
34716
  return null;
34580
34717
  }
34581
34718
  }
34582
- function removeProviderBackup(hermesHome) {
34583
- const backupPath = getProviderBackupPath(hermesHome);
34719
+ function removeProviderBackup(hermesHome, targetRoot) {
34720
+ const backupPath = targetRoot ? resolveContainedWritePath(getProviderBackupPath(hermesHome), targetRoot) : getProviderBackupPath(hermesHome);
34584
34721
  if (!existsSync2(backupPath))
34585
34722
  return null;
34586
34723
  rmSync(backupPath, { force: true });
@@ -34607,8 +34744,8 @@ function isProviderConfigured(hermesHome) {
34607
34744
  }
34608
34745
  return false;
34609
34746
  }
34610
- function configureProvider(hermesHome, warnings) {
34611
- const configPath = resolveConfigPath(hermesHome);
34747
+ function configureProvider(hermesHome, warnings, targetRoot = hermesHome) {
34748
+ const configPath = resolveContainedWritePath(resolveConfigPath(hermesHome), targetRoot);
34612
34749
  let content = "";
34613
34750
  if (existsSync2(configPath)) {
34614
34751
  try {
@@ -34629,13 +34766,13 @@ function configureProvider(hermesHome, warnings) {
34629
34766
  let changed = false;
34630
34767
  const dottedWasSignet = dottedProviderLineIsSignet(lines[dottedProvider] ?? "");
34631
34768
  if (!dottedWasSignet) {
34632
- backupPath = writeProviderBackup(hermesHome, configPath, "dotted", parseDottedProviderLine(lines[dottedProvider] ?? "") ?? "");
34769
+ backupPath = writeProviderBackup(hermesHome, targetRoot, configPath, "dotted", parseDottedProviderLine(lines[dottedProvider] ?? "") ?? "");
34633
34770
  setDottedProviderLine(lines, dottedProvider, "signet");
34634
34771
  changed = true;
34635
34772
  }
34636
34773
  if (block !== null && typeof block === "object" && block.provider !== null && block.provider !== undefined) {
34637
34774
  if (dottedWasSignet) {
34638
- const nestedBackupPath = writeProviderBackup(hermesHome, configPath, "nested", parseProviderLine(lines[block.provider] ?? "") ?? "");
34775
+ const nestedBackupPath = writeProviderBackup(hermesHome, targetRoot, configPath, "nested", parseProviderLine(lines[block.provider] ?? "") ?? "");
34639
34776
  backupPath = nestedBackupPath ?? backupPath;
34640
34777
  }
34641
34778
  lines.splice(block.provider, 1);
@@ -34656,7 +34793,7 @@ function configureProvider(hermesHome, warnings) {
34656
34793
  if (block !== null && typeof block === "object" && block.provider !== null && block.provider !== undefined) {
34657
34794
  if (providerLineIsSignet(lines[block.provider] ?? ""))
34658
34795
  return { configPath: null, backupPath: null };
34659
- backupPath = writeProviderBackup(hermesHome, configPath, "nested", parseProviderLine(lines[block.provider] ?? "") ?? "");
34796
+ backupPath = writeProviderBackup(hermesHome, targetRoot, configPath, "nested", parseProviderLine(lines[block.provider] ?? "") ?? "");
34660
34797
  lines[block.provider] = `${(lines[block.provider] ?? "").match(/^\s*/)?.[0] ?? " "}provider: signet`;
34661
34798
  } else if (block !== null && typeof block === "object") {
34662
34799
  lines.splice(block.start + 1, 0, `${" ".repeat(block.indent)}provider: signet`);
@@ -34671,10 +34808,12 @@ function configureProvider(hermesHome, warnings) {
34671
34808
  `);
34672
34809
  return { configPath, backupPath };
34673
34810
  }
34674
- function restoreOrClearProvider(hermesHome) {
34811
+ function restoreOrClearProvider(hermesHome, targetRoot) {
34812
+ const safeConfigPath = targetRoot ? resolveContainedWritePath(resolveConfigPath(hermesHome), targetRoot) : resolveConfigPath(hermesHome);
34675
34813
  const config = readConfigYaml(hermesHome);
34676
34814
  if (!config)
34677
- return { configPath: null, backupPath: removeProviderBackup(hermesHome) };
34815
+ return { configPath: null, backupPath: removeProviderBackup(hermesHome, targetRoot) };
34816
+ resolveContainedWritePath(config.path, targetRoot ?? hermesHome);
34678
34817
  const lines = config.content.replace(/\r\n/g, `
34679
34818
  `).split(`
34680
34819
  `);
@@ -34699,13 +34838,13 @@ function restoreOrClearProvider(hermesHome) {
34699
34838
  configChanged = true;
34700
34839
  }
34701
34840
  if (configChanged) {
34702
- writeFileSync2(config.path, `${lines.join(`
34841
+ writeFileSync2(safeConfigPath, `${lines.join(`
34703
34842
  `).replace(/\n+$/g, "")}
34704
34843
  `);
34705
34844
  }
34706
34845
  return {
34707
- configPath: configChanged ? config.path : null,
34708
- backupPath: removeProviderBackup(hermesHome)
34846
+ configPath: configChanged ? safeConfigPath : null,
34847
+ backupPath: removeProviderBackup(hermesHome, targetRoot)
34709
34848
  };
34710
34849
  }
34711
34850
  function pluginHasStaticToolSchemas(pluginFile) {
@@ -34868,13 +35007,16 @@ function trustedOriginForDaemonUrl(daemonUrl) {
34868
35007
  return null;
34869
35008
  }
34870
35009
  }
34871
- function configuredAgentReadPolicy(warnings) {
35010
+ function configuredAgentReadPolicy(warnings, strict = false) {
34872
35011
  const raw = sanitizedEnv("SIGNET_AGENT_READ_POLICY") || sanitizedEnv("SIGNET_AGENT_MEMORY_POLICY");
34873
35012
  if (!raw)
34874
35013
  return "shared";
34875
35014
  if (raw === "isolated" || raw === "shared" || raw === "group")
34876
35015
  return raw;
34877
- warnings.push(`Ignoring unsupported SIGNET_AGENT_READ_POLICY '${raw}'. Expected one of: isolated, shared, group.`);
35016
+ const error = `Unsupported SIGNET_AGENT_READ_POLICY '${raw}'. Expected one of: isolated, shared, group.`;
35017
+ if (strict)
35018
+ return null;
35019
+ warnings.push(`Ignoring ${error}`);
34878
35020
  return "shared";
34879
35021
  }
34880
35022
  async function resolveDaemonAgentId(daemonUrl) {
@@ -34898,11 +35040,20 @@ async function resolveDaemonAgentId(daemonUrl) {
34898
35040
  return null;
34899
35041
  }
34900
35042
  }
34901
- async function ensureNamedAgentRegistered(daemonUrl, agentId, warnings) {
34902
- if (!agentId || agentId === "default" || agentId === "hermes-agent")
34903
- return;
35043
+ async function ensureNamedAgentRegistered(daemonUrl, agentIdOrOptions, warnings) {
35044
+ const options = typeof agentIdOrOptions === "string" ? { agentId: agentIdOrOptions } : agentIdOrOptions;
35045
+ const { agentId } = options;
35046
+ const strict = options.strict === true;
35047
+ const fail = (error) => {
35048
+ if (!strict)
35049
+ warnings.push(error);
35050
+ return { ok: false, agentId, error };
35051
+ };
35052
+ if (!agentId || agentId === "default" || agentId === "hermes-agent") {
35053
+ return { ok: true, created: false, agentId };
35054
+ }
34904
35055
  if (process.env.SIGNET_SKIP_AGENT_REGISTER === "1")
34905
- return;
35056
+ return { ok: true, created: false, agentId };
34906
35057
  const baseUrl = trimTrailingSlashes(daemonUrl);
34907
35058
  const token = sanitizedAuthTokenEnv();
34908
35059
  const headers = {};
@@ -34915,16 +35066,24 @@ async function ensureNamedAgentRegistered(daemonUrl, agentId, warnings) {
34915
35066
  signal: AbortSignal.timeout(1000)
34916
35067
  });
34917
35068
  if (getResp.ok)
34918
- return;
35069
+ return { ok: true, created: false, agentId };
34919
35070
  if (getResp.status !== 404) {
34920
35071
  const body = await getResp.text();
34921
- warnings.push(`Could not check Signet agent '${agentId}' before registration: HTTP ${getResp.status} ${body.slice(0, 200)}`);
34922
- return;
35072
+ return fail(`Could not check Signet agent '${agentId}' before registration: HTTP ${getResp.status} ${body.slice(0, 200)}`);
34923
35073
  }
34924
- } catch {}
34925
- const readPolicy = configuredAgentReadPolicy(warnings);
34926
- const policyGroup = readPolicy === "group" ? sanitizedEnv("SIGNET_AGENT_POLICY_GROUP") || null : null;
35074
+ } catch (e) {
35075
+ if (strict) {
35076
+ const msg = e instanceof Error ? e.message : String(e);
35077
+ return fail(`Could not check Signet agent '${agentId}' because the daemon was unreachable. (${msg})`);
35078
+ }
35079
+ }
35080
+ const readPolicy = options.readPolicy ?? configuredAgentReadPolicy(warnings, strict);
35081
+ if (readPolicy === null)
35082
+ return fail(`Could not register Signet agent '${agentId}' because its read policy is invalid.`);
35083
+ const policyGroup = options.policyGroup !== undefined ? options.policyGroup : readPolicy === "group" ? sanitizedEnv("SIGNET_AGENT_POLICY_GROUP") || null : null;
34927
35084
  if (readPolicy === "group" && !policyGroup) {
35085
+ if (strict)
35086
+ return fail(`Agent '${agentId}' requested group policy but no policy group was provided.`);
34928
35087
  warnings.push(`SIGNET_AGENT_READ_POLICY=group requires SIGNET_AGENT_POLICY_GROUP. Registering '${agentId}' with isolated memory instead.`);
34929
35088
  }
34930
35089
  const effectiveReadPolicy = readPolicy === "group" && !policyGroup ? "isolated" : readPolicy;
@@ -34942,21 +35101,41 @@ async function ensureNamedAgentRegistered(daemonUrl, agentId, warnings) {
34942
35101
  });
34943
35102
  if (!resp.ok) {
34944
35103
  const body = await resp.text();
34945
- warnings.push(`Could not register Signet agent '${agentId}' with ${effectiveReadPolicy} memory policy: ${body.slice(0, 200)}. ${policyHint}`);
35104
+ return fail(`Could not register Signet agent '${agentId}' with ${effectiveReadPolicy} memory policy: ${body.slice(0, 200)}. ${policyHint}`);
34946
35105
  }
35106
+ return { ok: true, created: true, agentId };
34947
35107
  } catch (e) {
34948
35108
  const msg = e instanceof Error ? e.message : String(e);
34949
- warnings.push(`Could not register Signet agent '${agentId}' because the daemon was unreachable. ` + `${policyHint} (${msg})`);
35109
+ return fail(`Could not register Signet agent '${agentId}' because the daemon was unreachable. ${policyHint} (${msg})`);
34950
35110
  }
34951
35111
  }
34952
35112
 
34953
35113
  class HermesAgentConnector extends BaseConnector {
34954
35114
  name = "Hermes Agent";
34955
35115
  harnessId = "hermes-agent";
35116
+ target;
35117
+ registration;
35118
+ constructor(options) {
35119
+ super();
35120
+ if (options && "home" in options) {
35121
+ this.target = options;
35122
+ this.registration = { agentId: "", strict: options.kind === "profile" };
35123
+ } else {
35124
+ this.target = options?.target;
35125
+ this.registration = options ? {
35126
+ agentId: options.agentId ?? "",
35127
+ readPolicy: options.readPolicy,
35128
+ policyGroup: options.policyGroup,
35129
+ strict: options.target?.kind === "profile"
35130
+ } : undefined;
35131
+ }
35132
+ }
34956
35133
  getHermesHome() {
34957
- return resolveHermesHomePath();
35134
+ return this.target?.home ?? resolveHermesHomePath();
34958
35135
  }
34959
35136
  getHermesRepo() {
35137
+ if (this.target?.kind === "profile")
35138
+ return null;
34960
35139
  return resolveHermesRepoPath();
34961
35140
  }
34962
35141
  getConfigPath() {
@@ -34967,16 +35146,19 @@ class HermesAgentConnector extends BaseConnector {
34967
35146
  const configsPatched = [];
34968
35147
  const warnings = [];
34969
35148
  const expandedBasePath = expandHome(basePath || join4(homedir(), ".agents"));
34970
- const strippedAgentsPath = this.stripLegacySignetBlock(expandedBasePath);
35149
+ const hermesHome = this.getHermesHome();
35150
+ const legacyAgentsBasePath = this.target?.kind === "profile" ? hermesHome : expandedBasePath;
35151
+ const strippedAgentsPath = this.stripLegacySignetBlock(legacyAgentsBasePath);
34971
35152
  if (strippedAgentsPath !== null) {
34972
35153
  filesWritten.push(strippedAgentsPath);
34973
35154
  }
34974
- const hermesHome = this.getHermesHome();
35155
+ if (this.target?.kind === "profile")
35156
+ assertContainedTargetPath(hermesHome, this.target.home);
34975
35157
  const hermesRepo = this.getHermesRepo();
34976
35158
  let userPluginInstalled = false;
34977
35159
  let repoPluginInstalled = false;
34978
35160
  try {
34979
- const pluginFiles = installPlugin(getUserPluginTargetDir(hermesHome), "user");
35161
+ const pluginFiles = installPlugin(getUserPluginTargetDir(hermesHome), "user", hermesHome);
34980
35162
  filesWritten.push(...pluginFiles);
34981
35163
  userPluginInstalled = true;
34982
35164
  } catch (e) {
@@ -34985,7 +35167,7 @@ class HermesAgentConnector extends BaseConnector {
34985
35167
  }
34986
35168
  if (hermesRepo) {
34987
35169
  try {
34988
- const pluginFiles = installPlugin(getRepoPluginTargetDir(hermesRepo), "repo");
35170
+ const pluginFiles = installPlugin(getRepoPluginTargetDir(hermesRepo), "repo", hermesRepo);
34989
35171
  filesWritten.push(...pluginFiles);
34990
35172
  repoPluginInstalled = true;
34991
35173
  } catch (e) {
@@ -35003,7 +35185,7 @@ class HermesAgentConnector extends BaseConnector {
35003
35185
  warnings
35004
35186
  };
35005
35187
  }
35006
- const envPath = join4(hermesHome, ".env");
35188
+ const envPath = this.target?.kind === "profile" ? resolveContainedWritePath(join4(hermesHome, ".env"), this.target.home) : join4(hermesHome, ".env");
35007
35189
  let configuredSignetAgentId = "default";
35008
35190
  const configuredDaemonUrl = (process.env.SIGNET_DAEMON_URL?.trim() || "http://127.0.0.1:3850").replace(/[\r\n]+/g, "");
35009
35191
  try {
@@ -35018,7 +35200,7 @@ class HermesAgentConnector extends BaseConnector {
35018
35200
  if (process.env.SIGNET_TRUSTED_DAEMON_ORIGINS) {
35019
35201
  signetVars.SIGNET_TRUSTED_DAEMON_ORIGINS = sanitizedEnv("SIGNET_TRUSTED_DAEMON_ORIGINS");
35020
35202
  }
35021
- let signetAgentId = sanitizedEnv("SIGNET_AGENT_ID");
35203
+ let signetAgentId = this.registration?.agentId || sanitizedEnv("SIGNET_AGENT_ID");
35022
35204
  if (signetAgentId === "hermes-agent") {
35023
35205
  warnings.push("SIGNET_AGENT_ID='hermes-agent' is the harness name, not an agent scope. Re-resolving from the daemon.");
35024
35206
  signetAgentId = "";
@@ -35073,8 +35255,18 @@ ${key}=${value}
35073
35255
  const msg = e instanceof Error ? e.message : String(e);
35074
35256
  warnings.push(`Failed to update .env: ${msg}`);
35075
35257
  }
35076
- await ensureNamedAgentRegistered(configuredDaemonUrl, configuredSignetAgentId, warnings);
35077
- const providerConfig = configureProvider(hermesHome, warnings);
35258
+ const registration = this.registration ? { ...this.registration, agentId: this.registration.agentId || configuredSignetAgentId } : configuredSignetAgentId;
35259
+ const registrationResult = await ensureNamedAgentRegistered(configuredDaemonUrl, registration, warnings);
35260
+ if (!registrationResult.ok && this.target?.kind === "profile") {
35261
+ return {
35262
+ success: false,
35263
+ message: registrationResult.error,
35264
+ filesWritten,
35265
+ configsPatched,
35266
+ warnings
35267
+ };
35268
+ }
35269
+ const providerConfig = configureProvider(hermesHome, warnings, this.target?.kind === "profile" ? this.target.home : hermesHome);
35078
35270
  if (providerConfig.configPath) {
35079
35271
  configsPatched.push(providerConfig.configPath);
35080
35272
  }
@@ -35112,20 +35304,23 @@ ${key}=${value}
35112
35304
  const configsPatched = [];
35113
35305
  const hermesRepo = this.getHermesRepo();
35114
35306
  if (hermesRepo) {
35115
- const removed = uninstallPlugin(getRepoPluginTargetDir(hermesRepo));
35307
+ const removed = uninstallPlugin(getRepoPluginTargetDir(hermesRepo), hermesRepo);
35116
35308
  filesRemoved.push(...removed);
35117
35309
  }
35118
35310
  const hermesHome = this.getHermesHome();
35119
- const userPluginRemoved = uninstallPlugin(getUserPluginTargetDir(hermesHome));
35311
+ const targetRoot = this.target?.kind === "profile" ? this.target.home : undefined;
35312
+ if (targetRoot)
35313
+ assertContainedTargetPath(hermesHome, targetRoot);
35314
+ const userPluginRemoved = uninstallPlugin(getUserPluginTargetDir(hermesHome), targetRoot);
35120
35315
  filesRemoved.push(...userPluginRemoved);
35121
- const providerConfig = restoreOrClearProvider(hermesHome);
35316
+ const providerConfig = restoreOrClearProvider(hermesHome, targetRoot);
35122
35317
  if (providerConfig.configPath) {
35123
35318
  configsPatched.push(providerConfig.configPath);
35124
35319
  }
35125
35320
  if (providerConfig.backupPath) {
35126
35321
  filesRemoved.push(providerConfig.backupPath);
35127
35322
  }
35128
- const envPath = join4(hermesHome, ".env");
35323
+ const envPath = targetRoot ? resolveContainedWritePath(join4(hermesHome, ".env"), targetRoot) : join4(hermesHome, ".env");
35129
35324
  if (existsSync2(envPath)) {
35130
35325
  try {
35131
35326
  let envContent = readFileSync2(envPath, "utf-8");
@@ -35259,6 +35454,7 @@ function createConnector() {
35259
35454
  }
35260
35455
  var src_default = HermesAgentConnector;
35261
35456
  export {
35457
+ ensureNamedAgentRegistered,
35262
35458
  diagnoseHermesIntegration,
35263
35459
  src_default as default,
35264
35460
  createConnector,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@signetai/connector-hermes-agent",
3
- "version": "0.207.2",
3
+ "version": "0.208.1",
4
4
  "description": "Signet connector for Hermes Agent — installs Signet as a pluggable memory provider",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -25,8 +25,8 @@
25
25
  "typecheck": "tsc --noEmit"
26
26
  },
27
27
  "dependencies": {
28
- "@signetai/connector-base": "0.207.2",
29
- "@signetai/core": "0.207.2"
28
+ "@signetai/connector-base": "0.208.1",
29
+ "@signetai/core": "0.208.1"
30
30
  },
31
31
  "devDependencies": {
32
32
  "@types/node": "^22.0.0",