robrain 2.3.3 → 2.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -202,7 +202,7 @@ export async function installCommand(opts) {
202
202
  planningKey: provisioned.planningKey,
203
203
  embeddingProvider: embeddingProvider ?? 'openai',
204
204
  installedAt: new Date().toISOString(),
205
- version: '2.3.3',
205
+ version: '2.3.4',
206
206
  });
207
207
  spinner.succeed('MCP servers configured');
208
208
  // ── Done ───────────────────────────────────────────────────
@@ -352,7 +352,7 @@ async function installSelfHosted(opts) {
352
352
  ...(perceptionKey ? { perceptionKey } : {}),
353
353
  embeddingProvider: provider,
354
354
  installedAt: new Date().toISOString(),
355
- version: '2.3.3',
355
+ version: '2.3.4',
356
356
  selfHosted: true,
357
357
  });
358
358
  spinner.succeed('MCP servers configured for self-hosted mode');
@@ -2,7 +2,6 @@ export declare function statusCommand(): Promise<void>;
2
2
  export declare function ruleCommand(opts: {
3
3
  add?: string;
4
4
  list?: boolean;
5
- remove?: string;
6
5
  type?: string;
7
6
  }): Promise<void>;
8
7
  export declare function logoutCommand(): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAQA,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAsEnD;AAOD,wBAAsB,WAAW,CAAC,IAAI,EAAE;IACtC,GAAG,CAAC,EAAK,MAAM,CAAA;IACf,IAAI,CAAC,EAAI,OAAO,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAI,MAAM,CAAA;CAChB,GAAG,OAAO,CAAC,IAAI,CAAC,CAwFhB;AAKD,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAMnD"}
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAQA,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAsEnD;AAMD,wBAAsB,WAAW,CAAC,IAAI,EAAE;IACtC,GAAG,CAAC,EAAK,MAAM,CAAA;IACf,IAAI,CAAC,EAAI,OAAO,CAAA;IAChB,IAAI,CAAC,EAAI,MAAM,CAAA;CAChB,GAAG,OAAO,CAAC,IAAI,CAAC,CAwFhB;AAKD,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAMnD"}
@@ -74,7 +74,6 @@ export async function statusCommand() {
74
74
  // ─────────────────────────────────────────────────────────────
75
75
  // robrain rule --add TEXT [--type always_include|always_exclude|preference]
76
76
  // --list
77
- // --remove ID
78
77
  export async function ruleCommand(opts) {
79
78
  console.log();
80
79
  if (!isAuthenticated()) {
@@ -1 +1 @@
1
- {"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"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"}
@@ -2,9 +2,9 @@ import { describe, it } from 'node:test';
2
2
  import assert from 'node:assert/strict';
3
3
  import { ensureStackEnvContent, readEnvValue, renderStackCompose, DEFAULT_IMAGE_REPO } from './up.js';
4
4
  describe('renderStackCompose', () => {
5
- const compose = renderStackCompose(`${DEFAULT_IMAGE_REPO}:2.3.3`);
5
+ const compose = renderStackCompose(`${DEFAULT_IMAGE_REPO}:2.3.4`);
6
6
  it('runs Perception from the published image with an env override hook', () => {
7
- assert.match(compose, /image: \$\{PERCEPTION_IMAGE:-ghcr\.io\/adelinamart\/robrain-perception:2\.3\.3\}/);
7
+ assert.match(compose, /image: \$\{PERCEPTION_IMAGE:-ghcr\.io\/adelinamart\/robrain-perception:2\.3\.4\}/);
8
8
  assert.doesNotMatch(compose, /build:/);
9
9
  });
10
10
  it('mounts the stack-local schema and env file', () => {
package/dist/index.js CHANGED
@@ -9,7 +9,7 @@
9
9
  // init-project Warm-start memory from existing codebase
10
10
  // status Show auth status + service health
11
11
  // doctor Diagnose install, editor wiring, keys, and service health
12
- // rule Add / list / remove explicit Planning rules
12
+ // rule Add / list explicit Planning rules
13
13
  // logout Clear local credentials
14
14
  // ─────────────────────────────────────────────────────────────
15
15
  import { program } from 'commander';
@@ -27,7 +27,8 @@ import { outcomesScanCommand, outcomesRecordCommand } from './commands/outcomes.
27
27
  import { explainCommand } from './commands/explain.js';
28
28
  import { projectsListCommand, projectsMergeCommand } from './commands/projects.js';
29
29
  import { upCommand, downCommand, DEFAULT_IMAGE_REPO } from './commands/up.js';
30
- const VERSION = '2.3.3';
30
+ import { installHermesPlugin, resolveHermesHome } from './lib/hermes-plugin.js';
31
+ const VERSION = '2.3.4';
31
32
  program
32
33
  .name('robrain')
33
34
  .description('Institutional memory for AI coding agents — by Rory Plans')
@@ -150,10 +151,26 @@ program
150
151
  .option('-t, --token <token>', 'Rory Plans API token (or set RORY_TOKEN env var)')
151
152
  .option('-e, --editor <editor>', 'Target editor: claude-code | cursor | copilot | codex')
152
153
  .option('--self-hosted', 'Self-hosted mode — skip Rory Plans auth')
154
+ .option('--hermes', 'Install the Hermes memory-provider plugin into $HERMES_HOME/plugins')
153
155
  .option('--perception-url <url>', 'Perception URL for self-hosted mode (default: http://localhost:3001)')
154
156
  .option('--repo-root <path>', 'Path to your robrain git clone (links built sensing-mcp into ~/.robrain/mcp). Or set ROBRAIN_REPO.')
155
157
  .option('--skip-init-project', 'Do not run init-project in the current directory after install')
156
158
  .action(async (opts) => {
159
+ if (opts.hermes) {
160
+ const { dest } = installHermesPlugin();
161
+ console.log(`✔ Hermes memory-provider plugin installed → ${dest}`);
162
+ console.log('\nNext steps:');
163
+ console.log(' 1. hermes memory setup # select "robrain"');
164
+ console.log(' 2. PERCEPTION_API_KEY lives in ~/.robrain/stack/.env (after `robrain up`)');
165
+ console.log(' or your repo .env (clone path)');
166
+ console.log(`\nHermes home: ${resolveHermesHome()} (override with HERMES_HOME)`);
167
+ // --hermes alone is a complete install; editor wiring only runs when
168
+ // another install intent is present.
169
+ if (!opts.token && !opts.selfHosted && !opts.editor && !opts.repoRoot && !process.env.RORY_TOKEN) {
170
+ return;
171
+ }
172
+ console.log('');
173
+ }
157
174
  await installCommand({
158
175
  token: opts.token ?? process.env.RORY_TOKEN,
159
176
  editor: opts.editor,
@@ -209,7 +226,6 @@ program
209
226
  .description('Manage explicit Planning rules (Rory Plans cloud Planning API — not OSS Perception)')
210
227
  .option('--add <text>', 'Add a new rule in plain language')
211
228
  .option('--list', 'List active rules for this project')
212
- .option('--remove <id>', 'Remove a rule by ID')
213
229
  .option('--type <type>', 'Rule type: always_include | always_exclude | preference (default: preference)')
214
230
  .action(async (opts) => {
215
231
  await ruleCommand(opts);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,eAAe;AACf,gEAAgE;AAChE,4BAA4B;AAC5B,kCAAkC;AAClC,EAAE;AACF,YAAY;AACZ,qEAAqE;AACrE,4DAA4D;AAC5D,qDAAqD;AACrD,6EAA6E;AAC7E,+DAA+D;AAC/D,2CAA2C;AAC3C,gEAAgE;AAEhE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,UAAU,EAAE,MAAkC,mBAAmB,CAAA;AAC1E,OAAO,EAAE,cAAc,EAAE,MAAU,uBAAuB,CAAA;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAO,4BAA4B,CAAA;AAChE,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAChF,OAAO,EAAE,aAAa,EAAE,MAAY,sBAAsB,CAAA;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAY,sBAAsB,CAAA;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAY,sBAAsB,CAAA;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAa,qBAAqB,CAAA;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAA;AACjE,OAAO,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAA;AAC3E,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAA;AACnF,OAAO,EAAE,cAAc,EAAE,MAAW,uBAAuB,CAAA;AAC3D,OAAO,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAA;AAClF,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAE7E,MAAM,OAAO,GAAG,OAAO,CAAA;AAEvB,OAAO;KACJ,IAAI,CAAC,SAAS,CAAC;KACf,WAAW,CAAC,2DAA2D,CAAC;KACxE,OAAO,CAAC,OAAO,CAAC,CAAA;AAEnB,iEAAiE;AAEjE,OAAO;KACJ,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,uDAAuD,CAAC;KACpE,MAAM,CAAC,oBAAoB,EAAE,sDAAsD,CAAC;KACpF,MAAM,CAAC,WAAW,EAAW,sDAAsD,CAAC;KACpF,MAAM,CAAC,WAAW,EAAW,oDAAoD,CAAC;KAClF,MAAM,CAAC,eAAe,EAAO,kEAAkE,CAAC;KAChG,MAAM,CAAC,iBAAiB,EAAK,qCAAqC,EAAE,QAAQ,CAAC;KAC7E,MAAM,CAAC,KAAK,EAAE,IAAkG,EAAE,EAAE;IACnH,MAAM,aAAa,CAAC;QAClB,OAAO,EAAK,IAAI,CAAC,OAAO,IAAI,MAAM;QAClC,GAAG,EAAS,IAAI,CAAC,GAAG;QACpB,OAAO,EAAK,IAAI,CAAC,OAAO;QACxB,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,KAAK,EAAO,IAAI,CAAC,KAAK;KACvB,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEJ,iEAAiE;AAEjE,OAAO;KACJ,OAAO,CAAC,gBAAgB,CAAC;KACzB,WAAW,CAAC,8DAA8D,CAAC;KAC3E,MAAM,CAAC,WAAW,EAAG,+CAA+C,CAAC;KACrE,MAAM,CAAC,YAAY,EAAE,0BAA0B,CAAC;KAChD,MAAM,CAAC,KAAK,EAAE,IAAY,EAAE,IAAuC,EAAE,EAAE;IACtE,MAAM,cAAc,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;AAClC,CAAC,CAAC,CAAA;AAEJ,iEAAiE;AAEjE,OAAO;KACJ,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,kFAAkF,CAAC;KAC/F,MAAM,CAAC,oBAAoB,EAAI,8CAA8C,CAAC;KAC9E,MAAM,CAAC,qBAAqB,EAAG,oEAAoE,CAAC;KACpG,MAAM,CAAC,YAAY,EAAY,mCAAmC,CAAC;KACnE,MAAM,CAAC,iBAAiB,EAAO,uCAAuC,EAAE,QAAQ,CAAC;KACjF,MAAM,CAAC,WAAW,EAAa,sHAAsH,CAAC;KACtJ,MAAM,CAAC,KAAK,EAAE,IAAuF,EAAE,EAAE;IACxG,MAAM,aAAa,CAAC,IAAI,CAAC,CAAA;AAC3B,CAAC,CAAC,CAAA;AAEJ,iEAAiE;AAEjE,OAAO;KACJ,OAAO,CAAC,OAAO,CAAC;KAChB,WAAW,CAAC,uFAAuF,CAAC;KACpG,MAAM,CAAC,WAAW,EAAE,kDAAkD,CAAC;KACvE,MAAM,CAAC,QAAQ,EAAE,uEAAuE,CAAC;KACzF,MAAM,CAAC,mBAAmB,EAAE,2CAA2C,EAAE,QAAQ,CAAC;KAClF,MAAM,CAAC,gBAAgB,EAAE,yBAAyB,CAAC;KACnD,MAAM,CAAC,KAAK,EAAE,IAA+E,EAAE,EAAE;IAChG,MAAM,YAAY,CAAC;QACjB,MAAM,EAAI,IAAI,CAAC,MAAM;QACrB,IAAI,EAAM,IAAI,CAAC,IAAI;QACnB,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,OAAO,EAAG,IAAI,CAAC,OAAO;KACvB,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEJ,iEAAiE;AAEjE,OAAO;KACJ,OAAO,CAAC,eAAe,CAAC;KACxB,WAAW,CAAC,wFAAwF,CAAC;KACrG,MAAM,CAAC,WAAW,EAAY,qDAAqD,CAAC;KACpF,MAAM,CAAC,sBAAsB,EAAE,qEAAqE,CAAC;KACrG,MAAM,CAAC,YAAY,EAAW,0EAA0E,CAAC;KACzG,MAAM,CAAC,iBAAiB,EAAM,sFAAsF,CAAC;KACrH,MAAM,CAAC,cAAc,EAAS,oFAAoF,CAAC;KACnH,MAAM,CAAC,mBAAmB,EAAI,gEAAgE,CAAC;KAC/F,MAAM,CAAC,KAAK,EAAE,IAAiI,EAAE,EAAE;IAClJ,MAAM,mBAAmB,CAAC,IAAI,CAAC,CAAA;AACjC,CAAC,CAAC,CAAA;AAEJ,iEAAiE;AAEjE,OAAO;KACJ,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,sFAAsF,CAAC;KACnG,MAAM,CAAC,mBAAmB,EAAG,sCAAsC,EAAE,aAAa,CAAC;KACnF,MAAM,CAAC,cAAc,EAAQ,mCAAmC,CAAC;KACjE,MAAM,CAAC,cAAc,EAAQ,qEAAqE,CAAC;KACnG,MAAM,CAAC,mBAAmB,EAAG,gEAAgE,CAAC;KAC9F,MAAM,CAAC,KAAK,EAAE,IAAyE,EAAE,EAAE;IAC1F,MAAM,wBAAwB,CAAC,IAAI,CAAC,CAAA;AACtC,CAAC,CAAC,CAAA;AAEJ,iEAAiE;AAEjE,MAAM,WAAW,GAAG,OAAO;KACxB,OAAO,CAAC,UAAU,CAAC;KACnB,WAAW,CAAC,qFAAqF,CAAC;KAClG,MAAM,CAAC,oBAAoB,EAAE,+DAA+D,CAAC;KAC7F,MAAM,CAAC,WAAW,EAAW,mDAAmD,CAAC;KACjF,MAAM,CAAC,KAAK,EAAE,IAA0C,EAAE,EAAE;IAC3D,MAAM,mBAAmB,CAAC,IAAI,CAAC,CAAA;AACjC,CAAC,CAAC,CAAA;AAEJ,WAAW;KACR,OAAO,CAAC,sBAAsB,CAAC;KAC/B,WAAW,CAAC,2CAA2C,CAAC;KACxD,cAAc,CAAC,kBAAkB,EAAE,+BAA+B,CAAC;KACnE,MAAM,CAAC,mBAAmB,EAAS,wDAAwD,CAAC;KAC5F,MAAM,CAAC,KAAK,EAAE,UAAkB,EAAE,IAA4C,EAAE,EAAE;IACjF,MAAM,qBAAqB,CAAC,UAAU,EAAE,IAAI,CAAC,CAAA;AAC/C,CAAC,CAAC,CAAA;AAEJ,iEAAiE;AAEjE,OAAO;KACJ,OAAO,CAAC,IAAI,CAAC;KACb,WAAW,CAAC,uHAAuH,CAAC;KACpI,MAAM,CAAC,aAAa,EAAM,8CAA8C,OAAO,GAAG,CAAC;KACnF,MAAM,CAAC,iBAAiB,EAAE,iCAAiC,kBAAkB,SAAS,CAAC;KACvF,MAAM,CAAC,KAAK,EAAE,IAAsC,EAAE,EAAE;IACvD,MAAM,SAAS,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC,CAAA;AAC5E,CAAC,CAAC,CAAA;AAEJ,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,wFAAwF,CAAC;KACrG,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,WAAW,EAAE,CAAA;AACrB,CAAC,CAAC,CAAA;AAEJ,iEAAiE;AAEjE,OAAO;KACJ,OAAO,CAAC,SAAS,CAAC;KAClB,WAAW,CAAC,qEAAqE,CAAC;KAClF,MAAM,CAAC,qBAAqB,EAAO,kDAAkD,CAAC;KACtF,MAAM,CAAC,uBAAuB,EAAK,uDAAuD,CAAC;KAC3F,MAAM,CAAC,eAAe,EAAa,yCAAyC,CAAC;KAC7E,MAAM,CAAC,wBAAwB,EAAI,sEAAsE,CAAC;KAC1G,MAAM,CACL,oBAAoB,EACpB,oGAAoG,CACrG;KACA,MAAM,CAAC,qBAAqB,EAAE,gEAAgE,CAAC;KAC/F,MAAM,CAAC,KAAK,EAAE,IAOd,EAAE,EAAE;IACH,MAAM,cAAc,CAAC;QACnB,KAAK,EAAa,IAAI,CAAC,KAAK,IAAI,OAAO,CAAC,GAAG,CAAC,UAAU;QACtD,MAAM,EAAY,IAAI,CAAC,MAAM;QAC7B,UAAU,EAAQ,IAAI,CAAC,UAAU;QACjC,aAAa,EAAK,IAAI,CAAC,aAAa;QACpC,QAAQ,EAAU,IAAI,CAAC,QAAQ;QAC/B,eAAe,EAAG,IAAI,CAAC,eAAe;KACvC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEJ,iEAAiE;AAEjE,OAAO;KACJ,OAAO,CAAC,cAAc,CAAC;KACvB,KAAK,CAAC,MAAM,CAAC;KACb,WAAW,CAAC,qEAAqE,CAAC;KAClF,MAAM,CAAC,mBAAmB,EAAE,sCAAsC,CAAC;KACnE,MAAM,CAAC,sBAAsB,EAAE,0EAA0E,CAAC;KAC1G,MAAM,CAAC,KAAK,EAAE,IAAwD,EAAE,EAAE;IACzE,MAAM,kBAAkB,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,gBAAgB,EAAE,IAAI,CAAC,gBAAgB,EAAE,CAAC,CAAA;AAClG,CAAC,CAAC,CAAA;AAEJ,iEAAiE;AAEjE,MAAM,WAAW,GAAG,OAAO;KACxB,OAAO,CAAC,UAAU,CAAC;KACnB,WAAW,CAAC,qFAAqF,CAAC,CAAA;AAErG,WAAW;KACR,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,oDAAoD,CAAC;KACjE,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,mBAAmB,EAAE,CAAA;AAC7B,CAAC,CAAC,CAAA;AAEJ,WAAW;KACR,OAAO,CAAC,yBAAyB,CAAC;KAClC,WAAW,CAAC,mGAAmG,CAAC;KAChH,MAAM,CAAC,KAAK,EAAE,MAAc,EAAE,IAAY,EAAE,EAAE;IAC7C,MAAM,oBAAoB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAA;AAC1C,CAAC,CAAC,CAAA;AAEJ,iEAAiE;AAEjE,OAAO;KACJ,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,4FAA4F,CAAC;KACzG,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,aAAa,EAAE,CAAA;AACvB,CAAC,CAAC,CAAA;AAEJ,iEAAiE;AAEjE,OAAO;KACJ,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,mHAAmH,CAAC;KAChI,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,aAAa,EAAE,CAAA;AACvB,CAAC,CAAC,CAAA;AAEJ,iEAAiE;AAEjE,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,qFAAqF,CAAC;KAClG,MAAM,CAAC,cAAc,EAAK,kCAAkC,CAAC;KAC7D,MAAM,CAAC,QAAQ,EAAW,oCAAoC,CAAC;KAC/D,MAAM,CAAC,eAAe,EAAI,qBAAqB,CAAC;KAChD,MAAM,CAAC,eAAe,EAAI,+EAA+E,CAAC;KAC1G,MAAM,CAAC,KAAK,EAAE,IAAsE,EAAE,EAAE;IACvF,MAAM,WAAW,CAAC,IAAI,CAAC,CAAA;AACzB,CAAC,CAAC,CAAA;AAEJ,iEAAiE;AAEjE,OAAO;KACJ,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,yBAAyB,CAAC;KACtC,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,aAAa,EAAE,CAAA;AACvB,CAAC,CAAC,CAAA;AAEJ,kEAAkE;AAElE,OAAO,CAAC,WAAW,CAAC,WAAW,EAAE;aACpB,OAAO;;CAEnB,CAAC,CAAA;AAEF,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,YAAY,EAAE,aAAa,EAAE,EAAE;IACxD,MAAM,IAAI,GAAG,aAAa,CAAC,IAAI,EAA2B,CAAA;IAC1D,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,YAAY,CAAA;IAC1D,UAAU,CAAC,QAAQ,CAAC,CAAA;AACtB,CAAC,CAAC,CAAA;AAEF,OAAO,CAAC,WAAW,CAAC,UAAU,EAAE;;;;;;;;;;;;;;;;;;;;;;CAsB/B,CAAC,CAAA;AAEF,OAAO,CAAC,KAAK,EAAE,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ export declare class HermesPluginError extends Error {
2
+ name: string;
3
+ }
4
+ /**
5
+ * Hermes home resolution — mirrors hermes_constants.get_hermes_home():
6
+ * HERMES_HOME env var, else the platform-native default (~/.hermes on
7
+ * macOS/Linux, %LOCALAPPDATA%\hermes on Windows).
8
+ */
9
+ export declare function resolveHermesHome(env?: NodeJS.ProcessEnv): string;
10
+ export declare function hermesPluginComplete(dir: string): boolean;
11
+ /**
12
+ * Locate the plugin source shipped with this CLI.
13
+ * Published tarballs carry it under vendor/hermes-plugin/robrain;
14
+ * monorepo dev resolves integrations/hermes/robrain from the repo root.
15
+ */
16
+ export declare function resolveHermesPluginSourceDir(): string | undefined;
17
+ export interface HermesInstallResult {
18
+ dest: string;
19
+ hermesHome: string;
20
+ }
21
+ /**
22
+ * Copy the plugin into `<hermesHome>/plugins/robrain`, replacing whatever is
23
+ * there (including dangling symlinks and half-finished copies). Throws
24
+ * HermesPluginError when no complete source ships with this CLI build.
25
+ * Exposed with an explicit `sourceDir` for tests.
26
+ */
27
+ export declare function installHermesPlugin(hermesHome?: string, sourceDir?: string | undefined): HermesInstallResult;
28
+ //# sourceMappingURL=hermes-plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hermes-plugin.d.ts","sourceRoot":"","sources":["../../src/lib/hermes-plugin.ts"],"names":[],"mappings":"AAgBA,qBAAa,iBAAkB,SAAQ,KAAK;IACjC,IAAI,SAAsB;CACpC;AAiBD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAQ9E;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED;;;;GAIG;AACH,wBAAgB,4BAA4B,IAAI,MAAM,GAAG,SAAS,CASjE;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,MAAM,CAAA;CACnB;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,UAAU,GAAE,MAA4B,EACxC,SAAS,GAAE,MAAM,GAAG,SAA0C,GAC7D,mBAAmB,CAoBrB"}
@@ -0,0 +1,90 @@
1
+ // packages/cli/src/lib/hermes-plugin.ts
2
+ // Materialize the Hermes memory-provider plugin into $HERMES_HOME/plugins.
3
+ //
4
+ // hermes-agent's contribution policy keeps memory providers out of their
5
+ // tree — providers install as standalone plugins under ~/.hermes/plugins/,
6
+ // where Hermes' discovery loads them with the same lifecycle hooks as
7
+ // bundled ones. `robrain install --hermes` performs that copy so no repo
8
+ // clone is needed: published tarballs carry the plugin under
9
+ // vendor/hermes-plugin (same self-containment pattern as the vendored
10
+ // sensing-mcp bundle); monorepo dev resolves integrations/hermes.
11
+ import { cpSync, existsSync, lstatSync, mkdirSync, rmSync, unlinkSync } from 'fs';
12
+ import { homedir, platform } from 'os';
13
+ import { basename, dirname, join } from 'path';
14
+ import { fileURLToPath } from 'url';
15
+ export class HermesPluginError extends Error {
16
+ name = 'HermesPluginError';
17
+ }
18
+ /** Files that must exist for a plugin source dir to be considered complete. */
19
+ const REQUIRED_FILES = ['__init__.py', 'client.py', 'plugin.yaml'];
20
+ /** Remove whatever sits at `dest`, including a dangling symlink (see mcp-bundle.ts). */
21
+ function removeDest(dest) {
22
+ let stats;
23
+ try {
24
+ stats = lstatSync(dest);
25
+ }
26
+ catch {
27
+ return;
28
+ }
29
+ if (stats.isSymbolicLink())
30
+ unlinkSync(dest);
31
+ else
32
+ rmSync(dest, { recursive: true, force: true });
33
+ }
34
+ /**
35
+ * Hermes home resolution — mirrors hermes_constants.get_hermes_home():
36
+ * HERMES_HOME env var, else the platform-native default (~/.hermes on
37
+ * macOS/Linux, %LOCALAPPDATA%\hermes on Windows).
38
+ */
39
+ export function resolveHermesHome(env = process.env) {
40
+ const fromEnv = env.HERMES_HOME?.trim();
41
+ if (fromEnv)
42
+ return fromEnv;
43
+ if (platform() === 'win32') {
44
+ const localAppData = env.LOCALAPPDATA?.trim();
45
+ return join(localAppData || join(homedir(), 'AppData', 'Local'), 'hermes');
46
+ }
47
+ return join(homedir(), '.hermes');
48
+ }
49
+ export function hermesPluginComplete(dir) {
50
+ return REQUIRED_FILES.every(f => existsSync(join(dir, f)));
51
+ }
52
+ /**
53
+ * Locate the plugin source shipped with this CLI.
54
+ * Published tarballs carry it under vendor/hermes-plugin/robrain;
55
+ * monorepo dev resolves integrations/hermes/robrain from the repo root.
56
+ */
57
+ export function resolveHermesPluginSourceDir() {
58
+ // Compiled location: <cli-root>/dist/lib/hermes-plugin.js — cli root is two up.
59
+ const here = dirname(fileURLToPath(import.meta.url));
60
+ const cliRoot = join(here, '..', '..');
61
+ const candidates = [
62
+ join(cliRoot, 'vendor', 'hermes-plugin', 'robrain'), // published tarball
63
+ join(cliRoot, '..', '..', 'integrations', 'hermes', 'robrain'), // monorepo dev
64
+ ];
65
+ return candidates.find(hermesPluginComplete);
66
+ }
67
+ /**
68
+ * Copy the plugin into `<hermesHome>/plugins/robrain`, replacing whatever is
69
+ * there (including dangling symlinks and half-finished copies). Throws
70
+ * HermesPluginError when no complete source ships with this CLI build.
71
+ * Exposed with an explicit `sourceDir` for tests.
72
+ */
73
+ export function installHermesPlugin(hermesHome = resolveHermesHome(), sourceDir = resolveHermesPluginSourceDir()) {
74
+ if (!sourceDir || !hermesPluginComplete(sourceDir)) {
75
+ throw new HermesPluginError('Hermes plugin source not found in this CLI build — expected vendor/hermes-plugin (published) or integrations/hermes (repo clone).');
76
+ }
77
+ const pluginsDir = join(hermesHome, 'plugins');
78
+ const dest = join(pluginsDir, 'robrain');
79
+ mkdirSync(pluginsDir, { recursive: true });
80
+ removeDest(dest);
81
+ cpSync(sourceDir, dest, {
82
+ recursive: true,
83
+ filter: src => basename(src) !== '__pycache__' && !src.endsWith('.pyc'),
84
+ });
85
+ if (!hermesPluginComplete(dest)) {
86
+ throw new HermesPluginError(`Hermes plugin copy to ${dest} is incomplete — re-run the install.`);
87
+ }
88
+ return { dest, hermesHome };
89
+ }
90
+ //# sourceMappingURL=hermes-plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hermes-plugin.js","sourceRoot":"","sources":["../../src/lib/hermes-plugin.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=hermes-plugin.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hermes-plugin.test.d.ts","sourceRoot":"","sources":["../../src/lib/hermes-plugin.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,54 @@
1
+ // packages/cli/src/lib/hermes-plugin.test.ts
2
+ import assert from 'node:assert/strict';
3
+ import { mkdirSync, mkdtempSync, readdirSync, symlinkSync, writeFileSync } from 'node:fs';
4
+ import { tmpdir } from 'node:os';
5
+ import { join } from 'node:path';
6
+ import { test } from 'node:test';
7
+ import { HermesPluginError, hermesPluginComplete, installHermesPlugin, resolveHermesHome, } from './hermes-plugin.js';
8
+ function makePluginSource(root) {
9
+ const src = join(root, 'src-plugin');
10
+ mkdirSync(src, { recursive: true });
11
+ writeFileSync(join(src, '__init__.py'), '# provider\n');
12
+ writeFileSync(join(src, 'client.py'), '# client\n');
13
+ writeFileSync(join(src, 'plugin.yaml'), 'name: robrain\n');
14
+ writeFileSync(join(src, 'README.md'), '# docs\n');
15
+ mkdirSync(join(src, '__pycache__'));
16
+ writeFileSync(join(src, '__pycache__', 'junk.pyc'), '');
17
+ return src;
18
+ }
19
+ test('resolveHermesHome prefers HERMES_HOME env', () => {
20
+ assert.equal(resolveHermesHome({ HERMES_HOME: '/custom/home' }), '/custom/home');
21
+ });
22
+ test('resolveHermesHome defaults under the user home when env unset', () => {
23
+ const resolved = resolveHermesHome({});
24
+ assert.ok(resolved.includes('hermes'));
25
+ });
26
+ test('installs plugin into <home>/plugins/robrain, excluding __pycache__', () => {
27
+ const root = mkdtempSync(join(tmpdir(), 'hermes-plugin-'));
28
+ const src = makePluginSource(root);
29
+ const home = join(root, 'hermes-home');
30
+ const { dest } = installHermesPlugin(home, src);
31
+ assert.equal(dest, join(home, 'plugins', 'robrain'));
32
+ assert.ok(hermesPluginComplete(dest));
33
+ assert.ok(!readdirSync(dest).includes('__pycache__'));
34
+ });
35
+ test('replaces an existing install, including a dangling symlink', () => {
36
+ const root = mkdtempSync(join(tmpdir(), 'hermes-plugin-'));
37
+ const src = makePluginSource(root);
38
+ const home = join(root, 'hermes-home');
39
+ mkdirSync(join(home, 'plugins'), { recursive: true });
40
+ symlinkSync(join(root, 'nowhere'), join(home, 'plugins', 'robrain'));
41
+ const { dest } = installHermesPlugin(home, src);
42
+ assert.ok(hermesPluginComplete(dest));
43
+ });
44
+ test('throws when the source is missing or incomplete', () => {
45
+ const root = mkdtempSync(join(tmpdir(), 'hermes-plugin-'));
46
+ const incomplete = join(root, 'incomplete');
47
+ mkdirSync(incomplete);
48
+ writeFileSync(join(incomplete, '__init__.py'), '');
49
+ assert.throws(() => installHermesPlugin(join(root, 'home'), incomplete), HermesPluginError);
50
+ // '' = "resolution found nothing" — passing undefined would re-trigger the
51
+ // default resolver, which legitimately finds the real plugin in a monorepo.
52
+ assert.throws(() => installHermesPlugin(join(root, 'home'), ''), HermesPluginError);
53
+ });
54
+ //# sourceMappingURL=hermes-plugin.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hermes-plugin.test.js","sourceRoot":"","sources":["../../src/lib/hermes-plugin.test.ts"],"names":[],"mappings":"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"}
@@ -53,11 +53,11 @@ describe('materializeSensingBundle', () => {
53
53
  it('re-copies when the package version changed', () => {
54
54
  writeFakePackage(pkgDir, '2.2.0', 'old');
55
55
  assert.equal(materializeSensingBundle(pkgDir, mcpDir), true);
56
- writeFakePackage(pkgDir, '2.3.3', 'new');
56
+ writeFakePackage(pkgDir, '2.3.4', 'new');
57
57
  assert.equal(materializeSensingBundle(pkgDir, mcpDir), true);
58
58
  assert.equal(readFileSync(join(mcpDir, 'sensing', 'dist', 'index.js'), 'utf8'), 'new');
59
59
  const marker = JSON.parse(readFileSync(join(mcpDir, 'sensing', 'package.json'), 'utf8'));
60
- assert.equal(marker.version, '2.3.3');
60
+ assert.equal(marker.version, '2.3.4');
61
61
  });
62
62
  it('replaces a symlinked destination from a previous --repo-root install', () => {
63
63
  // Old dev install: ~/.robrain/mcp/sensing -> clone/packages/sensing-mcp
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "robrain",
3
- "version": "2.3.3",
3
+ "version": "2.3.4",
4
4
  "type": "module",
5
5
  "description": "RoBrain CLI for installation, setup, and memory workflows",
6
6
  "author": "Rory Plans, Inc.",
@@ -40,6 +40,15 @@
40
40
  "publishConfig": {
41
41
  "access": "public"
42
42
  },
43
+ "scripts": {
44
+ "build": "tsc",
45
+ "prepublishOnly": "pnpm build && node scripts/vendor-sensing-mcp.mjs && node scripts/vendor-hermes-plugin.mjs",
46
+ "dev": "tsc --watch",
47
+ "typecheck": "tsc --noEmit",
48
+ "test": "pnpm build && node --test dist/lib/editor.codex.test.js dist/lib/mcp-bundle.test.js dist/lib/claude-plugin.test.js dist/lib/hermes-plugin.test.js dist/commands/outcomes.test.js dist/commands/export-interchange.test.js dist/commands/up.test.js",
49
+ "pack:verify": "node scripts/verify-publish-tarball.mjs",
50
+ "postinstall": "node scripts/chmod-bin.cjs"
51
+ },
43
52
  "dependencies": {
44
53
  "dotenv": "^16.4.5",
45
54
  "chalk": "^5.3.0",
@@ -51,13 +60,5 @@
51
60
  "typescript": "^5.4.0",
52
61
  "@types/node": "^20.0.0",
53
62
  "@types/prompts": "^2.4.9"
54
- },
55
- "scripts": {
56
- "build": "tsc",
57
- "dev": "tsc --watch",
58
- "typecheck": "tsc --noEmit",
59
- "test": "pnpm build && node --test dist/lib/editor.codex.test.js dist/lib/mcp-bundle.test.js dist/lib/claude-plugin.test.js dist/commands/outcomes.test.js dist/commands/export-interchange.test.js dist/commands/up.test.js",
60
- "pack:verify": "node scripts/verify-publish-tarball.mjs",
61
- "postinstall": "node scripts/chmod-bin.cjs"
62
63
  }
63
- }
64
+ }
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env node
2
+ // Copy the Hermes memory-provider plugin into vendor/ so the published
3
+ // robrain tarball can materialize it via `robrain install --hermes`
4
+ // without a repo clone — same self-containment pattern as vendor-sensing-mcp.
5
+ import { cpSync, existsSync, mkdirSync, rmSync } from 'fs'
6
+ import { basename, dirname, join } from 'path'
7
+ import { fileURLToPath } from 'url'
8
+
9
+ const cliRoot = join(dirname(fileURLToPath(import.meta.url)), '..')
10
+ const src = join(cliRoot, '..', '..', 'integrations', 'hermes', 'robrain')
11
+ const dest = join(cliRoot, 'vendor', 'hermes-plugin', 'robrain')
12
+
13
+ for (const required of ['__init__.py', 'client.py', 'plugin.yaml']) {
14
+ if (!existsSync(join(src, required))) {
15
+ console.error('vendor-hermes-plugin: missing', join(src, required))
16
+ process.exit(1)
17
+ }
18
+ }
19
+
20
+ rmSync(dest, { recursive: true, force: true })
21
+ mkdirSync(dirname(dest), { recursive: true })
22
+ cpSync(src, dest, {
23
+ recursive: true,
24
+ filter: p => basename(p) !== '__pycache__' && !p.endsWith('.pyc'),
25
+ })
26
+ console.log('Vendored Hermes plugin → packages/cli/vendor/hermes-plugin/robrain')
@@ -19,6 +19,7 @@ mkdirSync(work, { recursive: true })
19
19
 
20
20
  try {
21
21
  execFileSync('node', ['scripts/vendor-sensing-mcp.mjs'], { cwd: cliRoot, stdio: 'inherit' })
22
+ execFileSync('node', ['scripts/vendor-hermes-plugin.mjs'], { cwd: cliRoot, stdio: 'inherit' })
22
23
 
23
24
  execFileSync('pnpm', ['pack', '--pack-destination', work], { cwd: cliRoot, stdio: 'inherit' })
24
25
 
@@ -49,7 +50,27 @@ try {
49
50
  fail(`resolved dir has no dist/index.js: ${dir}`)
50
51
  }
51
52
 
52
- console.log(`pack:verify ok — vendor resolves from ${dir}`)
53
+ const hermesVendorEntry = join(extracted, 'vendor', 'hermes-plugin', 'robrain', '__init__.py')
54
+ if (!existsSync(hermesVendorEntry)) {
55
+ fail('vendor/hermes-plugin/robrain/__init__.py missing from tarball')
56
+ }
57
+
58
+ const hermesUrl = pathToFileURL(join(extracted, 'dist', 'lib', 'hermes-plugin.js')).href
59
+ const { installHermesPlugin, resolveHermesPluginSourceDir } = await import(hermesUrl)
60
+ const hermesSrc = resolveHermesPluginSourceDir()
61
+ // realpath both sides — on macOS the tmpdir is reached via the /var →
62
+ // /private/var symlink, so raw prefix comparison false-negatives.
63
+ const { realpathSync } = await import('fs')
64
+ if (!hermesSrc || !realpathSync(hermesSrc).startsWith(realpathSync(extracted))) {
65
+ fail(`resolveHermesPluginSourceDir() did not resolve inside the tarball: ${hermesSrc}`)
66
+ }
67
+ const hermesHome = join(work, 'hermes-home')
68
+ const { dest } = installHermesPlugin(hermesHome)
69
+ if (!existsSync(join(dest, 'plugin.yaml'))) {
70
+ fail(`installHermesPlugin() copy incomplete at ${dest}`)
71
+ }
72
+
73
+ console.log(`pack:verify ok — sensing vendor resolves from ${dir}; hermes plugin installs from ${hermesSrc}`)
53
74
  } finally {
54
75
  rmSync(work, { recursive: true, force: true })
55
76
  }
@@ -0,0 +1,103 @@
1
+ # RoBrain memory provider
2
+
3
+ [RoBrain](https://github.com/adelinamart/robrain) is self-hosted decision
4
+ memory: it passively captures what got decided in your sessions **and the
5
+ alternatives you explicitly ruled out**, storing each veto as a structured
6
+ `rejected[]` field (option + reason) in your own Postgres. Recall is ranked
7
+ by a 5-signal composite score (semantic similarity, file overlap, recency,
8
+ historical relevance, approval state). Nothing leaves your machine.
9
+
10
+ The differentiator over fact-style memory: a rejection survives as data, not
11
+ prose. When a task drifts toward something you already declined, the veto
12
+ arrives in context as an explicit warning with the original reason —
13
+ `REJECTED: Redis — second datastore to operate; ops budget is one datastore`.
14
+
15
+ ## What the provider does
16
+
17
+ | Hermes hook | RoBrain behavior |
18
+ |---|---|
19
+ | system prompt | Injects the project's always-on summary (top decisions + vetoes) at session start |
20
+ | prefetch | Background semantic retrieval per turn; rejected alternatives rendered as `REJECTED:` warnings |
21
+ | sync_turn | Ships each turn to Perception, which runs its own server-side decision extraction — no local LLM, no extra API key |
22
+ | `robrain_search` tool | On-demand decision + veto lookup before the agent commits to an approach |
23
+
24
+ Fail-open: if the Perception API is down, recall degrades to nothing and
25
+ writes are dropped with a log warning — the agent never blocks. Writes are
26
+ skipped in cron/subagent contexts so system prompts never pollute the
27
+ decision corpus. Previously injected memory context is stripped before
28
+ capture, so recall can't re-enter the corpus as a fresh "decision".
29
+
30
+ ## Setup
31
+
32
+ This is a **standalone Hermes plugin** — hermes-agent's contribution policy
33
+ asks memory providers to ship outside their tree, installed into
34
+ `$HERMES_HOME/plugins/` where Hermes' plugin discovery picks them up with
35
+ the same lifecycle hooks as bundled providers.
36
+
37
+ 1. Run RoBrain (~2 minutes — [install guide](https://github.com/adelinamart/robrain#install)):
38
+
39
+ ```bash
40
+ # No clone:
41
+ npx robrain@latest up
42
+ # Or from a clone:
43
+ git clone https://github.com/adelinamart/robrain && cd robrain
44
+ pnpm install && pnpm build && pnpm docker:up
45
+ ```
46
+
47
+ Add `ANTHROPIC_API_KEY` and your embedding key to `~/.robrain/stack/.env` (after `robrain up`) or the repo `.env` (clone path), then ensure Perception is healthy: `curl -sf http://localhost:3001/health`.
48
+
49
+ 2. Install the plugin — no clone needed; the published CLI carries it:
50
+
51
+ ```bash
52
+ npx robrain@latest install --hermes
53
+ ```
54
+
55
+ (`$HERMES_HOME` defaults to `~/.hermes` on macOS/Linux; the command
56
+ respects the env var. From a repo clone, `cp -r
57
+ integrations/hermes/robrain "${HERMES_HOME:-$HOME/.hermes}/plugins/robrain"`
58
+ does the same thing.)
59
+
60
+ 3. Point Hermes at it:
61
+
62
+ ```bash
63
+ hermes memory setup # select "robrain"
64
+ ```
65
+
66
+ You'll be asked for:
67
+ - **base_url** — Perception's URL (default `http://localhost:3001`)
68
+ - **project_id** — your RoBrain project (default `default`)
69
+ - **scope** — recorded on captured decisions (default `team`)
70
+ - **PERCEPTION_API_KEY** — from `~/.robrain/stack/.env` (after `robrain up`) or the repo `.env` (clone path)
71
+
72
+ Config lands in `$HERMES_HOME/robrain/config.json` (non-secrets) and the
73
+ profile env store (the key). Env fallbacks for headless setups:
74
+ `ROBRAIN_BASE_URL`, `ROBRAIN_PROJECT_ID`, `PERCEPTION_API_KEY`.
75
+
76
+ ## Notes
77
+
78
+ - Decisions captured from Hermes sessions land in the same Postgres store
79
+ RoBrain fills from Claude Code, Cursor, Copilot, and Codex CLI — one
80
+ shared decision memory across your tools. Review captures with
81
+ `npx robrain review`; batch judgment (contradictions, drift) with
82
+ `npx robrain synth`.
83
+ - Perception re-redacts secrets server-side before anything is embedded or
84
+ stored, and RoBrain supports a fully-local mode (OpenAI-compatible local
85
+ server for extraction + embeddings) if you want zero external LLM calls.
86
+ - Requires a reachable RoBrain deployment; there is no hosted default.
87
+
88
+ ## Running the tests
89
+
90
+ The test suite (`../test_robrain_provider.py`) runs against a hermes-agent
91
+ checkout, since it exercises the real `MemoryProvider` ABC:
92
+
93
+ ```bash
94
+ git clone https://github.com/NousResearch/hermes-agent
95
+ cp -r integrations/hermes/robrain hermes-agent/plugins/memory/robrain
96
+ cp integrations/hermes/test_robrain_provider.py hermes-agent/tests/plugins/memory/
97
+ cd hermes-agent && python -m pytest tests/plugins/memory/test_robrain_provider.py
98
+ ```
99
+
100
+ (21 tests, no network — the HTTP client is stubbed. Verified end-to-end
101
+ against a live RoBrain deployment on 2026-07-08: raw Hermes turn →
102
+ server-side extraction → decision with structured veto → recall through
103
+ both prefetch and the robrain_search tool.)
@@ -0,0 +1,428 @@
1
+ """RoBrain memory plugin — decision memory with structured rejected alternatives.
2
+
3
+ RoBrain (https://github.com/adelinamart/robrain) is self-hosted decision
4
+ memory for agents: it passively captures what got decided in a session AND
5
+ the alternatives that were explicitly ruled out, storing each veto as a
6
+ structured ``rejected[]`` field (option + reason) in the user's own
7
+ Postgres. The point is preventing an agent from re-proposing an approach
8
+ the user already rejected — the veto arrives in context as an explicit
9
+ warning, with the original reason.
10
+
11
+ Integration shape:
12
+
13
+ system prompt ← the project's always-on summary (session-start recall)
14
+ prefetch ← composite-scored semantic retrieval; rejected
15
+ alternatives rendered as REJECTED warnings
16
+ sync_turn ← raw turns shipped to Perception, which runs its own
17
+ server-side decision extraction (no local LLM needed)
18
+ robrain_search ← on-demand tool for decision + veto lookup
19
+
20
+ Config chain:
21
+ 1. $HERMES_HOME/robrain/config.json (base_url, project_id, scope)
22
+ 2. Environment: PERCEPTION_API_KEY (secret), ROBRAIN_BASE_URL,
23
+ ROBRAIN_PROJECT_ID
24
+
25
+ Fail-open by design: if the Perception API is down, recall degrades to
26
+ nothing and writes are dropped with a warning — the agent never blocks.
27
+ """
28
+
29
+ from __future__ import annotations
30
+
31
+ import json
32
+ import logging
33
+ import os
34
+ import queue
35
+ import threading
36
+ import time
37
+ from datetime import datetime, timezone
38
+ from pathlib import Path
39
+ from typing import Any, Dict, List, Optional
40
+
41
+ from agent.memory_manager import sanitize_context
42
+ from agent.memory_provider import MemoryProvider
43
+ from tools.registry import tool_error
44
+
45
+ from .client import RoBrainClient, RoBrainClientError
46
+
47
+ logger = logging.getLogger(__name__)
48
+
49
+ _CONFIG_DIRNAME = "robrain"
50
+ _CONFIG_FILENAME = "config.json"
51
+
52
+ # Turns shorter than this carry no decision signal — don't ship them.
53
+ _MIN_TURN_CHARS = 20
54
+ # Cap what we send per turn; Perception enforces its own MAX_TURN_TEXT too.
55
+ _MAX_TURN_CHARS = 20_000
56
+ # Shutdown flush window — one POST /signals rides a server-side LLM
57
+ # extraction, so the last turn of a short session needs real time to land.
58
+ _SHUTDOWN_DRAIN_S = 25.0
59
+
60
+ SEARCH_SCHEMA = {
61
+ "name": "robrain_search",
62
+ "description": (
63
+ "Search the team's RoBrain decision memory. Returns prior decisions "
64
+ "ranked by relevance, each with its rationale and — critically — the "
65
+ "alternatives that were explicitly REJECTED and why. Use before "
66
+ "proposing a tool, library, architecture, or approach, to avoid "
67
+ "re-suggesting something the user already ruled out."
68
+ ),
69
+ "parameters": {
70
+ "type": "object",
71
+ "properties": {
72
+ "query": {
73
+ "type": "string",
74
+ "description": "What you are about to decide or propose (natural language).",
75
+ },
76
+ "limit": {
77
+ "type": "integer",
78
+ "description": "Max decisions to return (default 5, max 20).",
79
+ },
80
+ },
81
+ "required": ["query"],
82
+ },
83
+ }
84
+
85
+
86
+ def _utc_now_iso() -> str:
87
+ return datetime.now(timezone.utc).isoformat()
88
+
89
+
90
+ def _format_decisions(rows: List[Dict[str, Any]]) -> str:
91
+ """Render decisions the way RoBrain's own inject does — vetoes as warnings."""
92
+ lines: List[str] = []
93
+ for row in rows:
94
+ decision = str(row.get("decision") or "").strip()
95
+ if not decision:
96
+ continue
97
+ rationale = str(row.get("rationale") or "").strip()
98
+ lines.append(f"- {decision}" + (f" — {rationale}" if rationale else ""))
99
+ for veto in row.get("rejected") or []:
100
+ option = str(veto.get("option") or "").strip()
101
+ reason = str(veto.get("reason") or "").strip()
102
+ if option:
103
+ lines.append(f" - REJECTED: {option}" + (f" — {reason}" if reason else ""))
104
+ return "\n".join(lines)
105
+
106
+
107
+ class RoBrainProvider(MemoryProvider):
108
+ """MemoryProvider backed by a self-hosted RoBrain Perception API."""
109
+
110
+ def __init__(self) -> None:
111
+ self._client: Any = None
112
+ self._config: Dict[str, Any] = {}
113
+ self._hermes_home: str = ""
114
+ self._session_id: str = ""
115
+ self._writes_enabled = True
116
+ self._degraded = False
117
+
118
+ self._summary: str = ""
119
+ self._summary_lock = threading.Lock()
120
+
121
+ self._prefetch_cache: Dict[str, str] = {}
122
+ self._prefetch_lock = threading.Lock()
123
+
124
+ self._sequence = 0
125
+ self._sequence_lock = threading.Lock()
126
+
127
+ self._write_queue: "queue.Queue[Optional[Dict[str, Any]]]" = queue.Queue(maxsize=200)
128
+ self._writer: Optional[threading.Thread] = None
129
+ self._writer_busy = False
130
+
131
+ # -- config ---------------------------------------------------------------
132
+
133
+ @property
134
+ def name(self) -> str:
135
+ return "robrain"
136
+
137
+ @staticmethod
138
+ def _config_path(hermes_home: str) -> Path:
139
+ return Path(hermes_home) / _CONFIG_DIRNAME / _CONFIG_FILENAME
140
+
141
+ def _load_config(self, hermes_home: str) -> Dict[str, Any]:
142
+ config: Dict[str, Any] = {}
143
+ path = self._config_path(hermes_home) if hermes_home else None
144
+ if path and path.is_file():
145
+ try:
146
+ config = json.loads(path.read_text(encoding="utf-8")) or {}
147
+ except Exception:
148
+ logger.warning("robrain: unreadable config at %s — using env/defaults", path)
149
+ config.setdefault("base_url", os.environ.get("ROBRAIN_BASE_URL", ""))
150
+ config.setdefault("project_id", os.environ.get("ROBRAIN_PROJECT_ID", ""))
151
+ config.setdefault("scope", "team")
152
+ config["api_key"] = os.environ.get("PERCEPTION_API_KEY", "")
153
+ return config
154
+
155
+ def is_available(self) -> bool:
156
+ """Configured = the config file exists or the API key env var is set.
157
+
158
+ No network calls here (contract) — reachability is probed in
159
+ initialize(), which fails open.
160
+ """
161
+ try:
162
+ from hermes_constants import get_hermes_home
163
+ if self._config_path(str(get_hermes_home())).is_file():
164
+ return True
165
+ except Exception:
166
+ pass
167
+ return bool(os.environ.get("PERCEPTION_API_KEY"))
168
+
169
+ # -- lifecycle -------------------------------------------------------------
170
+
171
+ def initialize(self, session_id: str, **kwargs) -> None:
172
+ self._session_id = session_id
173
+ self._hermes_home = str(kwargs.get("hermes_home") or "")
174
+ # Cron/subagent/flush contexts must not write into the decision corpus.
175
+ self._writes_enabled = kwargs.get("agent_context", "primary") == "primary"
176
+
177
+ self._config = self._load_config(self._hermes_home)
178
+ self._client = RoBrainClient(
179
+ base_url=self._config.get("base_url") or "",
180
+ api_key=self._config.get("api_key") or "",
181
+ project_id=self._config.get("project_id") or "",
182
+ )
183
+
184
+ self._writer = threading.Thread(
185
+ target=self._writer_loop, name="robrain-writer", daemon=True,
186
+ )
187
+ self._writer.start()
188
+
189
+ threading.Thread(
190
+ target=self._fetch_summary, name="robrain-summary", daemon=True,
191
+ ).start()
192
+
193
+ def _fetch_summary(self) -> None:
194
+ try:
195
+ payload = self._client.get_summary()
196
+ except RoBrainClientError as exc:
197
+ self._degraded = True
198
+ logger.warning("robrain: Perception unreachable at startup (fail-open): %s", exc)
199
+ return
200
+ summary = str(payload.get("always_on_summary") or "").strip()
201
+ with self._summary_lock:
202
+ self._summary = summary
203
+ self._degraded = False
204
+
205
+ def shutdown(self) -> None:
206
+ """Flush pending turn captures, then stop the writer.
207
+
208
+ A single POST /signals waits on Perception's server-side LLM
209
+ extraction (typically 5–20s), and short-lived sessions (``hermes
210
+ -z``) reach shutdown with the final turn still in flight — a
211
+ too-short drain here silently loses exactly the turn that made
212
+ the session worth remembering. Bounded by _SHUTDOWN_DRAIN_S so a
213
+ wedged server still can't block exit; the writer is a daemon
214
+ thread, so anything past the deadline dies with the interpreter.
215
+ """
216
+ deadline = time.monotonic() + _SHUTDOWN_DRAIN_S
217
+ while not self._write_queue.empty() or self._writer_busy:
218
+ if time.monotonic() >= deadline:
219
+ logger.warning(
220
+ "robrain: shutdown drain timed out with %d turn(s) unflushed",
221
+ self._write_queue.qsize(),
222
+ )
223
+ break
224
+ time.sleep(0.2)
225
+ try:
226
+ self._write_queue.put_nowait(None)
227
+ except queue.Full:
228
+ pass
229
+ if self._writer is not None:
230
+ self._writer.join(timeout=max(0.0, deadline - time.monotonic()) + 1.0)
231
+
232
+ # -- recall ----------------------------------------------------------------
233
+
234
+ def system_prompt_block(self) -> str:
235
+ with self._summary_lock:
236
+ summary = self._summary
237
+ lines = [
238
+ "RoBrain decision memory is active. Prior team decisions — including "
239
+ "explicitly REJECTED alternatives — are injected as context. Never "
240
+ "re-propose a REJECTED option without flagging the recorded reason "
241
+ "and asking the user to confirm the reversal. Use robrain_search "
242
+ "before committing to a tool, library, or architectural approach.",
243
+ ]
244
+ if summary:
245
+ lines.append("")
246
+ lines.append("Project decisions (always-on summary):")
247
+ lines.append(summary)
248
+ return "\n".join(lines)
249
+
250
+ def queue_prefetch(self, query: str, *, session_id: str = "") -> None:
251
+ query = (query or "").strip()
252
+ if len(query) < 12 or self._client is None:
253
+ return
254
+ threading.Thread(
255
+ target=self._background_search,
256
+ args=(query, session_id or self._session_id),
257
+ name="robrain-prefetch",
258
+ daemon=True,
259
+ ).start()
260
+
261
+ def _background_search(self, query: str, session_id: str) -> None:
262
+ try:
263
+ rows = self._client.search_decisions(query, limit=5)
264
+ except RoBrainClientError as exc:
265
+ logger.debug("robrain: prefetch search failed (fail-open): %s", exc)
266
+ return
267
+ formatted = _format_decisions(rows)
268
+ with self._prefetch_lock:
269
+ self._prefetch_cache[session_id] = (
270
+ f"Relevant prior decisions (RoBrain):\n{formatted}" if formatted else ""
271
+ )
272
+
273
+ def prefetch(self, query: str, *, session_id: str = "") -> str:
274
+ with self._prefetch_lock:
275
+ return self._prefetch_cache.get(session_id or self._session_id, "")
276
+
277
+ # -- capture -----------------------------------------------------------------
278
+
279
+ def sync_turn(
280
+ self,
281
+ user_content: str,
282
+ assistant_content: str,
283
+ *,
284
+ session_id: str = "",
285
+ messages: Optional[List[Dict[str, Any]]] = None,
286
+ ) -> None:
287
+ if not self._writes_enabled or self._client is None:
288
+ return
289
+
290
+ # Strip previously injected memory context so recall never re-enters
291
+ # the corpus as a fresh "decision" (feedback loop).
292
+ user_clean = sanitize_context(user_content or "").strip()[:_MAX_TURN_CHARS]
293
+ assistant_clean = sanitize_context(assistant_content or "").strip()[:_MAX_TURN_CHARS]
294
+ if len(user_clean) + len(assistant_clean) < _MIN_TURN_CHARS:
295
+ return
296
+
297
+ with self._sequence_lock:
298
+ self._sequence += 1
299
+ sequence = self._sequence
300
+
301
+ item = {
302
+ "session_id": session_id or self._session_id,
303
+ "sequence": sequence,
304
+ "user_message": user_clean,
305
+ "assistant_message": assistant_clean,
306
+ "timestamp": _utc_now_iso(),
307
+ "scope": str(self._config.get("scope") or "team"),
308
+ }
309
+ try:
310
+ self._write_queue.put_nowait(item)
311
+ except queue.Full:
312
+ logger.warning("robrain: write queue full — dropping turn %s", sequence)
313
+
314
+ def _writer_loop(self) -> None:
315
+ while True:
316
+ item = self._write_queue.get()
317
+ if item is None:
318
+ return
319
+ self._writer_busy = True
320
+ try:
321
+ self._client.post_turn_signal(**item)
322
+ except RoBrainClientError as exc:
323
+ logger.debug("robrain: turn capture failed (fail-open): %s", exc)
324
+ finally:
325
+ self._writer_busy = False
326
+
327
+ # -- session lifecycle -------------------------------------------------------
328
+
329
+ def on_session_switch(
330
+ self,
331
+ new_session_id: str,
332
+ *,
333
+ parent_session_id: str = "",
334
+ reset: bool = False,
335
+ rewound: bool = False,
336
+ **kwargs,
337
+ ) -> None:
338
+ self._session_id = new_session_id
339
+ if reset:
340
+ with self._sequence_lock:
341
+ self._sequence = 0
342
+ with self._prefetch_lock:
343
+ self._prefetch_cache.clear()
344
+
345
+ # -- tools ---------------------------------------------------------------------
346
+
347
+ def get_tool_schemas(self) -> List[Dict[str, Any]]:
348
+ return [SEARCH_SCHEMA]
349
+
350
+ def handle_tool_call(self, tool_name: str, args: Dict[str, Any], **kwargs) -> str:
351
+ if tool_name != "robrain_search":
352
+ return tool_error(f"Unknown tool: {tool_name}")
353
+ if self._client is None:
354
+ return tool_error("RoBrain provider is not initialized")
355
+
356
+ query = str(args.get("query") or "").strip()
357
+ if not query:
358
+ return tool_error("query is required")
359
+ limit = args.get("limit") or 5
360
+ try:
361
+ limit = max(1, min(int(limit), 20))
362
+ except (TypeError, ValueError):
363
+ limit = 5
364
+
365
+ try:
366
+ rows = self._client.search_decisions(query, limit=limit)
367
+ except RoBrainClientError as exc:
368
+ return tool_error(f"RoBrain search failed: {exc}")
369
+
370
+ decisions = [
371
+ {
372
+ "decision": row.get("decision"),
373
+ "rationale": row.get("rationale"),
374
+ "rejected": row.get("rejected") or [],
375
+ "score": row.get("planning_score"),
376
+ "created_at": row.get("created_at"),
377
+ "reviewed": bool(row.get("reviewed_at")),
378
+ }
379
+ for row in rows
380
+ ]
381
+ return json.dumps({"decisions": decisions, "count": len(decisions)})
382
+
383
+ # -- setup ------------------------------------------------------------------------
384
+
385
+ def get_config_schema(self) -> List[Dict[str, Any]]:
386
+ return [
387
+ {
388
+ "key": "base_url",
389
+ "description": "Perception API URL of your RoBrain deployment",
390
+ "default": "http://localhost:3001",
391
+ "required": True,
392
+ },
393
+ {
394
+ "key": "project_id",
395
+ "description": "RoBrain project id (see `npx robrain review` or the projects table)",
396
+ "default": "default",
397
+ "required": True,
398
+ },
399
+ {
400
+ "key": "scope",
401
+ "description": "Scope recorded on captured decisions",
402
+ "default": "team",
403
+ "choices": ["user", "local", "team", "global"],
404
+ },
405
+ {
406
+ "key": "api_key",
407
+ "description": "PERCEPTION_API_KEY from your RoBrain .env",
408
+ "secret": True,
409
+ "required": True,
410
+ "env_var": "PERCEPTION_API_KEY",
411
+ "url": "https://github.com/adelinamart/robrain#security",
412
+ },
413
+ ]
414
+
415
+ def save_config(self, values: Dict[str, Any], hermes_home: str) -> None:
416
+ path = self._config_path(hermes_home)
417
+ path.parent.mkdir(parents=True, exist_ok=True)
418
+ config = {
419
+ "base_url": values.get("base_url") or "http://localhost:3001",
420
+ "project_id": values.get("project_id") or "default",
421
+ "scope": values.get("scope") or "team",
422
+ }
423
+ path.write_text(json.dumps(config, indent=2) + "\n", encoding="utf-8")
424
+
425
+
426
+ def register_memory_provider() -> MemoryProvider:
427
+ """Entry point used by plugins/memory discovery."""
428
+ return RoBrainProvider()
@@ -0,0 +1,168 @@
1
+ """HTTP client for RoBrain's self-hosted Perception API.
2
+
3
+ RoBrain (https://github.com/adelinamart/robrain) is a self-hosted decision
4
+ memory: it records what a team decided AND the alternatives it explicitly
5
+ rejected (a structured ``rejected[]`` field per decision), stores both in
6
+ the user's own Postgres, and serves them back ranked by a 5-signal
7
+ composite score. Nothing leaves the user's machine.
8
+
9
+ This client covers the three Perception endpoints the Hermes provider
10
+ needs:
11
+
12
+ GET /projects/:id/summary — the always-on summary (session-start recall)
13
+ GET /decisions?query=... — composite-scored semantic retrieval
14
+ POST /signals — raw-turn capture; Perception extracts the
15
+ decision server-side (needs_classification)
16
+
17
+ Auth is a static bearer token (``PERCEPTION_API_KEY`` from the RoBrain
18
+ deployment's .env). All calls carry short timeouts and raise
19
+ ``RoBrainClientError`` — callers are expected to fail open: memory being
20
+ down should degrade recall, never block the agent.
21
+ """
22
+
23
+ from __future__ import annotations
24
+
25
+ import logging
26
+ from typing import Any, Dict, List, Optional
27
+
28
+ import requests
29
+
30
+ logger = logging.getLogger(__name__)
31
+
32
+ DEFAULT_BASE_URL = "http://localhost:3001"
33
+ DEFAULT_PROJECT_ID = "default"
34
+
35
+ _READ_TIMEOUT = 6 # summary / search — user-visible latency path
36
+ _WRITE_TIMEOUT = 45 # /signals runs LLM extraction + embedding server-side
37
+ # before responding; writes happen on a background
38
+ # thread, so a generous timeout costs no turn latency
39
+
40
+
41
+ class RoBrainClientError(Exception):
42
+ """Raised for any transport or non-2xx failure against Perception."""
43
+
44
+
45
+ class RoBrainClient:
46
+ """Thin, dependency-light wrapper over the Perception HTTP API."""
47
+
48
+ def __init__(
49
+ self,
50
+ base_url: str = DEFAULT_BASE_URL,
51
+ api_key: str = "",
52
+ project_id: str = DEFAULT_PROJECT_ID,
53
+ ) -> None:
54
+ self.base_url = (base_url or DEFAULT_BASE_URL).rstrip("/")
55
+ self.api_key = api_key
56
+ self.project_id = project_id or DEFAULT_PROJECT_ID
57
+ self._session = requests.Session()
58
+
59
+ # -- internals ----------------------------------------------------------
60
+
61
+ def _headers(self, extra: Optional[Dict[str, str]] = None) -> Dict[str, str]:
62
+ headers = {"Content-Type": "application/json"}
63
+ if self.api_key:
64
+ headers["Authorization"] = f"Bearer {self.api_key}"
65
+ if extra:
66
+ headers.update(extra)
67
+ return headers
68
+
69
+ def _request(self, method: str, path: str, *, timeout: float, **kwargs) -> Any:
70
+ url = f"{self.base_url}{path}"
71
+ try:
72
+ resp = self._session.request(
73
+ method, url, headers=self._headers(kwargs.pop("extra_headers", None)),
74
+ timeout=timeout, **kwargs,
75
+ )
76
+ except requests.RequestException as exc:
77
+ raise RoBrainClientError(f"{method} {path}: {exc}") from exc
78
+ if resp.status_code >= 400:
79
+ raise RoBrainClientError(
80
+ f"{method} {path}: HTTP {resp.status_code} — {resp.text[:200]}"
81
+ )
82
+ try:
83
+ return resp.json()
84
+ except ValueError as exc:
85
+ raise RoBrainClientError(f"{method} {path}: non-JSON response") from exc
86
+
87
+ # -- API surface ---------------------------------------------------------
88
+
89
+ def health(self) -> bool:
90
+ """True when Perception answers /health (unauthenticated by design)."""
91
+ try:
92
+ self._request("GET", "/health", timeout=3)
93
+ return True
94
+ except RoBrainClientError:
95
+ return False
96
+
97
+ def get_summary(self) -> Dict[str, Any]:
98
+ """Fetch the project's always-on summary.
99
+
100
+ Returns ``{"always_on_summary": str | None, "mission": str | None}``.
101
+ 404 (project not registered) raises like any other error — the
102
+ provider treats it as "no summary yet", not a hard failure.
103
+ """
104
+ return self._request(
105
+ "GET", f"/projects/{self.project_id}/summary", timeout=_READ_TIMEOUT,
106
+ )
107
+
108
+ def search_decisions(
109
+ self,
110
+ query: str,
111
+ *,
112
+ limit: int = 5,
113
+ boost_files: Optional[List[str]] = None,
114
+ ) -> List[Dict[str, Any]]:
115
+ """Composite-scored semantic retrieval over the decision corpus.
116
+
117
+ Each row carries ``decision``, ``rationale``, ``rejected`` (list of
118
+ ``{option, reason}``), ``planning_score``, lifecycle fields, etc.
119
+ """
120
+ params: Dict[str, str] = {
121
+ "project_id": self.project_id,
122
+ "query": query,
123
+ "limit": str(limit),
124
+ }
125
+ if boost_files:
126
+ params["boost_files"] = ",".join(boost_files)
127
+ payload = self._request("GET", "/decisions", timeout=_READ_TIMEOUT, params=params)
128
+ rows = payload.get("decisions") if isinstance(payload, dict) else payload
129
+ return rows if isinstance(rows, list) else []
130
+
131
+ def post_turn_signal(
132
+ self,
133
+ *,
134
+ session_id: str,
135
+ sequence: int,
136
+ user_message: str,
137
+ assistant_message: str,
138
+ timestamp: str,
139
+ scope: str = "team",
140
+ ) -> Dict[str, Any]:
141
+ """Ship a raw turn; Perception extracts the decision server-side.
142
+
143
+ ``needs_classification: true`` bypasses the confidence gate and makes
144
+ Perception run its own extraction (the flush-on-close path), so this
145
+ client needs no LLM of its own. Perception also re-redacts secrets
146
+ before anything is embedded or stored.
147
+ """
148
+ body = {
149
+ "signal": {
150
+ "turn": {
151
+ "session_id": session_id,
152
+ "sequence": sequence,
153
+ "user_message": user_message,
154
+ "claude_reply": assistant_message,
155
+ "files_touched": [],
156
+ "timestamp": timestamp,
157
+ },
158
+ "decision_type": "unclassified",
159
+ "confidence": 0,
160
+ "files_affected": [],
161
+ "scope": scope,
162
+ "needs_classification": True,
163
+ }
164
+ }
165
+ return self._request(
166
+ "POST", "/signals", timeout=_WRITE_TIMEOUT, json=body,
167
+ extra_headers={"X-Project-Id": self.project_id},
168
+ )
@@ -0,0 +1,3 @@
1
+ name: robrain
2
+ version: 1.0.0
3
+ description: "RoBrain decision memory — self-hosted capture of decisions AND rejected alternatives (structured vetoes), with composite-scored recall so the agent never re-proposes what you already ruled out."
@@ -23037,7 +23037,7 @@ function resolveSessionId(raw) {
23037
23037
  function buildServer() {
23038
23038
  const server = new McpServer({
23039
23039
  name: "sensing-mcp",
23040
- version: "2.3.2"
23040
+ version: "2.3.4"
23041
23041
  });
23042
23042
  server.tool(
23043
23043
  "sensing_start_session",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@robrain/sensing-mcp",
3
- "version": "2.3.3",
3
+ "version": "2.3.4",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "main": "./dist/index.js"