@webority/ensemble 0.5.7 → 0.5.8

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/README.md CHANGED
@@ -53,7 +53,7 @@ Fleet playbook: `docs/FLEET.md`.
53
53
  ### Grok / Codex MCP (existing config)
54
54
  When `~/.grok/config.toml` (or Codex) already exists, install **upserts** only
55
55
  `[mcp_servers.ensemble]` — other servers (e.g. weborityos) and UI/cli sections are kept.
56
- Command points at `~/.ensemble/bin/ensemble-runtime` (plus an `ensemble-bus` compat copy of the same binary for older configs).
56
+ Command points at `~/.ensemble/bin/ensemble-runtime` only (no `ensemble-bus` binary or alias).
57
57
 
58
58
  ## Security model
59
59
  Machine ⇄ server auth is a **per-machine token**, resolved server-side to your organization; every
package/bin/ensemble.js CHANGED
@@ -123,9 +123,7 @@ async function status(args) {
123
123
  const t = fs.readFileSync(tokenFile, 'utf8').trim();
124
124
  core.log('Ensemble status @ ' + api);
125
125
  const runtimeExe = core.runtimeBin();
126
- const busCompat = path.join(core.BIN_DIR, 'ensemble-bus' + core.platform().exe);
127
126
  core.log('• runtime binary: ' + (core.isUsableBinary(runtimeExe) ? 'ok (' + runtimeExe + ')' : 'MISSING/STUB — ensemble install'));
128
- core.log('• bus compat alias: ' + (core.isUsableBinary(busCompat) ? 'ok' : 'missing — ensemble install'));
129
127
  const engines = ['claude', 'codex', 'grok', 'opencode', 'omp', 'gemini', 'antigravity'];
130
128
  const present = engines.filter((e) => core.enginePresent(e));
131
129
  core.log('• engines detected: ' + (present.join(', ') || 'none'));
@@ -135,10 +133,13 @@ async function status(args) {
135
133
  if (fs.existsSync(grokToml)) {
136
134
  const txt = fs.readFileSync(grokToml, 'utf8');
137
135
  const hasEnsemble = /\[mcp_servers\.ensemble\]/.test(txt);
138
- const pointsRuntime = /ensemble-runtime/.test(txt) || /ensemble-bus/.test(txt);
139
- core.log('• grok MCP: ' + (hasEnsemble && pointsRuntime
140
- ? 'configured in ~/.grok/config.toml'
141
- : 'NOT wired run: ensemble hooks'));
136
+ const pointsRuntime = /ensemble-runtime/.test(txt);
137
+ const hasLegacyBus = /ensemble-bus/.test(txt);
138
+ core.log('• grok MCP: ' + (hasEnsemble && pointsRuntime && !hasLegacyBus
139
+ ? 'configured (ensemble-runtime) in ~/.grok/config.toml'
140
+ : hasLegacyBus
141
+ ? 'LEGACY ensemble-bus path — run: ensemble hooks'
142
+ : 'NOT wired — run: ensemble hooks'));
142
143
  } else {
143
144
  core.log('• grok MCP: no ~/.grok/config.toml — run: ensemble hooks');
144
145
  }
@@ -195,8 +196,9 @@ Run \`ensemble login\` and approve the machine in your browser.`);
195
196
  else if (cmd === 'status') await status(args);
196
197
  else if (cmd === 'hooks') {
197
198
  // Ensure a usable (non-stub) runtime BEFORE wiring — otherwise every engine gets pointed at a
198
- // dead path. Replaces tiny leftover ensemble-bus stubs; fails closed on unsupported platforms.
199
+ // dead path. Fails closed on unsupported platforms. No ensemble-bus compat alias.
199
200
  await core.ensureRuntime();
201
+ core.removeLegacyBusArtifacts();
200
202
  const wired = core.wireHooks();
201
203
  core.log('wired hooks+MCP: ' + (wired.join(', ') || 'none'));
202
204
  if (!wired.some((w) => w.endsWith(':mcp'))) {
package/lib/core.js CHANGED
@@ -92,8 +92,7 @@ function runtimeBin() {
92
92
  return runtimePaths().runtimePath;
93
93
  }
94
94
 
95
- // Real runtime/runner single-file binaries are tens of MB. A ~100–200 KB "ensemble-bus" stub left
96
- // from earlier renames must never count as installed — wiring would point engines at a dead path.
95
+ // Real runtime/runner single-file binaries are tens of MB. Anything smaller is corrupt/stub.
97
96
  const MIN_BINARY_BYTES = 1_000_000;
98
97
 
99
98
  function isUsableBinary(filePath) {
@@ -202,7 +201,7 @@ async function ensureRuntime() {
202
201
  // an explicit `ensemble install`, which was the only upgrade path before and left the fleet stale. [BUG-06673]
203
202
  if (runtimeInstalled() && installedVersionCurrent()) {
204
203
  const p = runtimePaths();
205
- installRuntimeCompatAliases(p.runtimePath, p.pf);
204
+ removeLegacyBusArtifacts();
206
205
  return p;
207
206
  }
208
207
  return ensureBinaries({ force: true });
@@ -228,50 +227,44 @@ function platformPackageDir() {
228
227
  }
229
228
  }
230
229
 
231
- // Older hooks / MCP configs / docs invoked `ensemble-bus`. Keep a full copy of the runtime under
232
- // that name so those paths keep working after the rename to ensemble-runtime.
233
- // Windows often locks ensemble-bus.exe while an MCP client holds it open — rename-aside + temp
234
- // write so we can replace a tiny stub even when the old handle is sticky.
235
- function installRuntimeCompatAliases(runtimePath, pf) {
236
- if (!isUsableBinary(runtimePath)) return;
237
- const busPath = path.join(BIN_DIR, 'ensemble-bus' + pf.exe);
238
- if (isUsableBinary(busPath) && fs.statSync(busPath).size === fs.statSync(runtimePath).size) {
239
- return; // already a full runtime copy
240
- }
230
+ // No backward-compat binary. Delete leftover ensemble-bus* (and framework-dependent debris that
231
+ // sometimes landed next to a bad publish) so only ensemble-runtime remains the bus CLI.
232
+ function removeLegacyBusArtifacts() {
233
+ ensureDirs();
234
+ let names;
241
235
  try {
242
- if (fs.existsSync(busPath) && !isUsableBinary(busPath)) {
243
- const aside = busPath + '.old-stub';
244
- try {
245
- if (fs.existsSync(aside)) fs.unlinkSync(aside);
246
- fs.renameSync(busPath, aside);
247
- } catch (e) { /* locked — try overwrite paths below */ }
248
- }
249
- const tmp = busPath + '.new';
250
- fs.copyFileSync(runtimePath, tmp);
236
+ names = fs.readdirSync(BIN_DIR);
237
+ } catch (e) {
238
+ return;
239
+ }
240
+ for (const name of names) {
241
+ const lower = name.toLowerCase();
242
+ const drop =
243
+ lower.startsWith('ensemble-bus')
244
+ || lower.startsWith('microsoft.')
245
+ || lower.startsWith('modelcontextprotocol')
246
+ || lower === 'system.diagnostics.eventlog.dll'
247
+ || lower === 'runtimes';
248
+ if (!drop) continue;
249
+ const full = path.join(BIN_DIR, name);
251
250
  try {
252
- if (fs.existsSync(busPath)) {
253
- try { fs.unlinkSync(busPath); } catch (e) { /* locked */ }
251
+ if (fs.statSync(full).isDirectory()) {
252
+ fs.rmSync(full, { recursive: true, force: true });
253
+ } else {
254
+ fs.unlinkSync(full);
254
255
  }
255
- fs.renameSync(tmp, busPath);
256
256
  } catch (e) {
257
+ // Locked (running MCP still holds a handle): rename aside so nothing can launch it by name.
257
258
  try {
258
- fs.copyFileSync(tmp, busPath);
259
- try { fs.unlinkSync(tmp); } catch (_) { /* ignore */ }
259
+ const trash = full + '.trash-' + Date.now();
260
+ fs.renameSync(full, trash);
261
+ warn('moved locked legacy ' + name + ' aside → ' + path.basename(trash) +
262
+ ' (delete after restarting agents)');
260
263
  } catch (e2) {
261
- try { fs.unlinkSync(tmp); } catch (_) { /* ignore */ }
262
- // Still wired to ensemble-runtime in configs; compat is best-effort while MCP holds the file.
263
- warn('could not replace ensemble-bus compat alias (file locked by a running agent MCP?) — ' +
264
- 'new wiring uses ensemble-runtime; restart agents and re-run `ensemble hooks` to refresh the alias. ' +
265
- '(' + (e2 && e2.message ? e2.message : e2) + ')');
266
- return;
264
+ warn('could not remove legacy ' + name + ' (locked) restart agents and re-run `ensemble install`. (' +
265
+ (e2 && e2.message ? e2.message : e2) + ')');
267
266
  }
268
267
  }
269
- if (pf.os !== 'windows') {
270
- fs.chmodSync(busPath, 0o755);
271
- if (pf.os === 'mac') spawnSync('codesign', ['-s', '-', '-f', busPath], { stdio: 'ignore' });
272
- }
273
- } catch (e) {
274
- warn('could not write ensemble-bus compat alias: ' + (e && e.message ? e.message : e));
275
268
  }
276
269
  }
277
270
 
@@ -327,7 +320,7 @@ async function ensureBinaries(opts) {
327
320
  if (pf.os === 'mac') spawnSync('codesign', ['-s', '-', '-f', t.dest], { stdio: 'ignore' });
328
321
  }
329
322
  }
330
- installRuntimeCompatAliases(runtimePath, pf);
323
+ removeLegacyBusArtifacts();
331
324
  writeInstalledVersion();
332
325
  // A replaced runner binary only takes effect once the daemon restarts onto it.
333
326
  if (runnerRefreshed) restartRunner(pf, runnerPath);
@@ -699,6 +692,7 @@ function has(cmd) {
699
692
  // Ensemble owns — used to dedup on re-run so our entry never stacks.
700
693
  function isEnsembleHook(h) {
701
694
  const cmd = typeof h === 'string' ? h : (h && (h.command || h.cmd || h.run)) || '';
695
+ // Match ensemble-runtime and any leftover ensemble-bus paths so re-wire strips outdated entries.
702
696
  return /ensemble-(bus|runtime)/i.test(String(cmd));
703
697
  }
704
698
 
@@ -869,6 +863,6 @@ module.exports = {
869
863
  ensureBinaries, enrollMachine, writeRunnerConfig, wireHooks, wireMcpServers, enginePresent, installAutostart, startRunner, request,
870
864
  sleep, openBrowser, startDevice, pollDevice, finishSetup, assertSupported,
871
865
  runtimePaths, runtimeBin, runtimeInstalled, requireRuntime, ensureRuntime,
872
- isUsableBinary, installRuntimeCompatAliases, MIN_BINARY_BYTES,
866
+ isUsableBinary, removeLegacyBusArtifacts, MIN_BINARY_BYTES,
873
867
  writeEngineHooks, upsertTomlMcp, installedVersionCurrent, readInstalledVersion, PKG_VERSION,
874
868
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webority/ensemble",
3
- "version": "0.5.7",
3
+ "version": "0.5.8",
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"
@@ -9,11 +9,11 @@
9
9
  "node": ">=18"
10
10
  },
11
11
  "optionalDependencies": {
12
- "@webority/ensemble-darwin-arm64": "0.5.7",
13
- "@webority/ensemble-darwin-x64": "0.5.7",
14
- "@webority/ensemble-linux-arm64": "0.5.7",
15
- "@webority/ensemble-linux-x64": "0.5.7",
16
- "@webority/ensemble-win-x64": "0.5.7"
12
+ "@webority/ensemble-darwin-arm64": "0.5.8",
13
+ "@webority/ensemble-darwin-x64": "0.5.8",
14
+ "@webority/ensemble-linux-arm64": "0.5.8",
15
+ "@webority/ensemble-linux-x64": "0.5.8",
16
+ "@webority/ensemble-win-x64": "0.5.8"
17
17
  },
18
18
  "files": [
19
19
  "bin",