@webority/ensemble 0.5.9 → 0.5.11

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.
Files changed (2) hide show
  1. package/lib/core.js +38 -3
  2. package/package.json +9 -6
package/lib/core.js CHANGED
@@ -364,6 +364,36 @@ function writeRunnerConfig(api, machineToken) {
364
364
  } catch (e) { /* best-effort */ }
365
365
  }
366
366
 
367
+ function ensureWindowsRuntimePath() {
368
+ const pathKey = Object.keys(process.env).find((key) => key.toLowerCase() === 'path') || 'Path';
369
+ const currentProcessPath = process.env[pathKey] || '';
370
+ const normalize = (value) => value.replace(/[\\/]+$/, '').toLowerCase();
371
+ if (!currentProcessPath.split(';').some((entry) => normalize(entry) === normalize(BIN_DIR))) {
372
+ process.env[pathKey] = [currentProcessPath, BIN_DIR].filter(Boolean).join(';');
373
+ }
374
+
375
+ const script =
376
+ "$ErrorActionPreference = 'Stop'; " +
377
+ '$target = $env:ENSEMBLE_BIN_TO_ADD; ' +
378
+ "$current = [Environment]::GetEnvironmentVariable('Path', 'User'); " +
379
+ "$entries = @($current -split ';' | Where-Object { $_ }); " +
380
+ "if (-not ($entries | Where-Object { [string]::Equals($_.TrimEnd('\\'), $target.TrimEnd('\\'), " +
381
+ "[StringComparison]::OrdinalIgnoreCase) })) { " +
382
+ "[Environment]::SetEnvironmentVariable('Path', (($entries + $target) -join ';'), 'User') }";
383
+ const result = spawnSync(
384
+ 'powershell.exe',
385
+ ['-NoLogo', '-NoProfile', '-NonInteractive', '-Command', script],
386
+ {
387
+ encoding: 'utf8',
388
+ env: { ...process.env, ENSEMBLE_BIN_TO_ADD: BIN_DIR },
389
+ },
390
+ );
391
+ if (result.status !== 0) {
392
+ throw new Error('could not add ' + BIN_DIR + ' to the Windows user PATH: ' +
393
+ ((result.stderr || result.error || 'unknown error').toString().trim()));
394
+ }
395
+ }
396
+
367
397
  // --- wire ensemble-runtime into each installed harness (hooks + MCP) ---
368
398
  // Fleet engines: Claude, Codex, Grok, OpenCode, OMP (oh-my-pi), Gemini, Antigravity (when present).
369
399
  // Hooks = mail at turn boundaries. MCP = who/send/read/reply tools every turn.
@@ -399,7 +429,11 @@ function wireHooks() {
399
429
  if (mergeClaudeHooks(path.join(HOME, '.claude', 'settings.json'), runtimeInvoke)) report.push('claude:hooks');
400
430
  }
401
431
  if (enginePresent('codex')) {
402
- if (writeEngineHooks(path.join(HOME, '.codex', 'hooks.json'), runtimeInvoke, 'codex')) report.push('codex:hooks');
432
+ const windowsRuntime = pf.os === 'windows' ? path.basename(runtimeExe) : null;
433
+ if (windowsRuntime) ensureWindowsRuntimePath();
434
+ if (writeEngineHooks(path.join(HOME, '.codex', 'hooks.json'), runtimeInvoke, 'codex', windowsRuntime)) {
435
+ report.push('codex:hooks');
436
+ }
403
437
  }
404
438
  if (enginePresent('grok')) {
405
439
  if (writeEngineHooks(path.join(HOME, '.grok', 'hooks', 'agent-bus.json'), runtimeInvoke, 'grok')) report.push('grok:hooks');
@@ -704,7 +738,7 @@ function isEnsembleHook(h) {
704
738
  // only MCP worked). MERGE-preserving: keep other events + the user's own groups on our events, dedup
705
739
  // our entry so re-runs don't stack, and migrate away the legacy lowercase keys. [BUG-06673-hooks]
706
740
  // Returns true when written, false when skipped (malformed JSON left untouched).
707
- function writeEngineHooks(file, runtimeInvoke, engine) {
741
+ function writeEngineHooks(file, runtimeInvoke, engine, windowsRuntime) {
708
742
  fs.mkdirSync(path.dirname(file), { recursive: true });
709
743
  let existing = {};
710
744
  if (fs.existsSync(file)) {
@@ -729,7 +763,8 @@ function writeEngineHooks(file, runtimeInvoke, engine) {
729
763
  // command directly and the hook handler is already silent-safe on failure.
730
764
  const events = { SessionStart: 'session-start', UserPromptSubmit: 'user-prompt', Stop: 'stop', SessionEnd: 'session-end' };
731
765
  for (const [evt, ev] of Object.entries(events)) {
732
- const command = `"${runtimeInvoke}" hook ${ev} --engine ${engine}`;
766
+ const runtimeCommand = windowsRuntime || `"${runtimeInvoke}"`;
767
+ const command = `${runtimeCommand} hook ${ev} --engine ${engine}`;
733
768
  const groups = Array.isArray(hooks[evt]) ? hooks[evt] : (hooks[evt] == null ? [] : [hooks[evt]]);
734
769
  const kept = groups
735
770
  .filter((g) => g && typeof g === 'object' && !Array.isArray(g))
package/package.json CHANGED
@@ -1,19 +1,22 @@
1
1
  {
2
2
  "name": "@webority/ensemble",
3
- "version": "0.5.9",
3
+ "version": "0.5.11",
4
4
  "description": "Connect this machine to Ensemble — runs the local agent runner and wires the ensemble session bus so your coding sessions talk (per-org, isolated).",
5
5
  "bin": {
6
6
  "ensemble": "bin/ensemble.js"
7
7
  },
8
+ "scripts": {
9
+ "test": "node --test"
10
+ },
8
11
  "engines": {
9
12
  "node": ">=18"
10
13
  },
11
14
  "optionalDependencies": {
12
- "@webority/ensemble-darwin-arm64": "0.5.9",
13
- "@webority/ensemble-darwin-x64": "0.5.9",
14
- "@webority/ensemble-linux-arm64": "0.5.9",
15
- "@webority/ensemble-linux-x64": "0.5.9",
16
- "@webority/ensemble-win-x64": "0.5.9"
15
+ "@webority/ensemble-darwin-arm64": "0.5.11",
16
+ "@webority/ensemble-darwin-x64": "0.5.11",
17
+ "@webority/ensemble-linux-arm64": "0.5.11",
18
+ "@webority/ensemble-linux-x64": "0.5.11",
19
+ "@webority/ensemble-win-x64": "0.5.11"
17
20
  },
18
21
  "files": [
19
22
  "bin",