@episoda/cli 0.2.163 → 0.2.164

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.
@@ -343,6 +343,8 @@ var require_git_executor = __commonJS({
343
343
  case "delete_branch":
344
344
  return await this.executeDeleteBranch(command, cwd, options);
345
345
  // EP597: Read operations for production local dev mode
346
+ case "list_branches":
347
+ return await this.executeListBranches(cwd, options);
346
348
  case "branch_exists":
347
349
  return await this.executeBranchExists(command, cwd, options);
348
350
  case "branch_has_commits":
@@ -632,6 +634,65 @@ var require_git_executor = __commonJS({
632
634
  args.push(command.branch);
633
635
  return await this.runGitCommand(args, cwd, options);
634
636
  }
637
+ /**
638
+ * List local branches with remote-tracking signal and current branch marker.
639
+ */
640
+ async executeListBranches(cwd, options) {
641
+ try {
642
+ const timeout = options?.timeout || 1e4;
643
+ const branchMap = /* @__PURE__ */ new Map();
644
+ const addBranch = (name, attrs) => {
645
+ const normalized = name.trim();
646
+ if (!normalized)
647
+ return;
648
+ const existing = branchMap.get(normalized);
649
+ if (existing) {
650
+ existing.current = existing.current || !!attrs?.current;
651
+ existing.remote = existing.remote || !!attrs?.remote;
652
+ return;
653
+ }
654
+ branchMap.set(normalized, {
655
+ name: normalized,
656
+ current: !!attrs?.current,
657
+ remote: !!attrs?.remote
658
+ });
659
+ };
660
+ const statusResult = await this.executeStatus(cwd, options);
661
+ const currentBranch = statusResult.success ? statusResult.details?.branchName : void 0;
662
+ try {
663
+ const { stdout } = await execAsync3(`git for-each-ref --format='%(refname:short)' refs/heads`, { cwd, timeout });
664
+ stdout.split("\n").map((line) => line.trim()).filter(Boolean).forEach((name) => addBranch(name, { current: name === currentBranch }));
665
+ } catch {
666
+ }
667
+ try {
668
+ const { stdout } = await execAsync3(`git for-each-ref --format='%(refname:short)' refs/remotes/origin`, { cwd, timeout });
669
+ stdout.split("\n").map((line) => line.trim()).filter(Boolean).forEach((refName) => {
670
+ if (refName === "origin/HEAD")
671
+ return;
672
+ const normalized = refName.startsWith("origin/") ? refName.slice("origin/".length) : refName;
673
+ addBranch(normalized, { remote: true, current: normalized === currentBranch });
674
+ });
675
+ } catch {
676
+ }
677
+ if (currentBranch && currentBranch !== "HEAD") {
678
+ addBranch(currentBranch, { current: true });
679
+ }
680
+ const branches = Array.from(branchMap.values()).sort((a, b) => a.name.localeCompare(b.name));
681
+ return {
682
+ success: true,
683
+ details: {
684
+ branchName: currentBranch,
685
+ branches
686
+ }
687
+ };
688
+ } catch (error) {
689
+ return {
690
+ success: false,
691
+ error: "UNKNOWN_ERROR",
692
+ output: error.message || "Failed to list branches"
693
+ };
694
+ }
695
+ }
635
696
  /**
636
697
  * EP597: Execute branch_exists command
637
698
  * Checks if a branch exists locally and/or remotely
@@ -2153,6 +2214,8 @@ var require_websocket_client = __commonJS({
2153
2214
  this.osArch = deviceInfo?.osArch;
2154
2215
  this.daemonPid = deviceInfo?.daemonPid;
2155
2216
  this.cliVersion = deviceInfo?.cliVersion;
2217
+ this.cliPackageName = deviceInfo?.cliPackageName;
2218
+ this.capabilities = deviceInfo?.capabilities;
2156
2219
  this.environment = deviceInfo?.environment;
2157
2220
  this.containerId = deviceInfo?.containerId;
2158
2221
  this.isDisconnecting = false;
@@ -2192,6 +2255,8 @@ var require_websocket_client = __commonJS({
2192
2255
  type: "auth",
2193
2256
  token,
2194
2257
  version: this.cliVersion || version_1.VERSION,
2258
+ cliPackageName: this.cliPackageName,
2259
+ capabilities: this.capabilities,
2195
2260
  environment: this.environment,
2196
2261
  machineId,
2197
2262
  containerId: this.containerId,
@@ -2511,6 +2576,8 @@ var require_websocket_client = __commonJS({
2511
2576
  osArch: this.osArch,
2512
2577
  daemonPid: this.daemonPid,
2513
2578
  cliVersion: this.cliVersion,
2579
+ cliPackageName: this.cliPackageName,
2580
+ capabilities: this.capabilities,
2514
2581
  environment: this.environment,
2515
2582
  containerId: this.containerId
2516
2583
  }).then(() => {
@@ -2911,7 +2978,7 @@ var require_package = __commonJS({
2911
2978
  "package.json"(exports2, module2) {
2912
2979
  module2.exports = {
2913
2980
  name: "@episoda/cli",
2914
- version: "0.2.163",
2981
+ version: "0.2.164",
2915
2982
  description: "CLI tool for Episoda local development workflow orchestration",
2916
2983
  main: "dist/index.js",
2917
2984
  types: "dist/index.d.ts",
@@ -7527,7 +7594,7 @@ ${message}`;
7527
7594
  const args2 = parts.slice(1);
7528
7595
  let env;
7529
7596
  if (server.name === "github") {
7530
- env = { ...baseEnv };
7597
+ env = void 0;
7531
7598
  } else {
7532
7599
  env = {
7533
7600
  ...baseEnv,
@@ -8620,8 +8687,8 @@ var WorktreeManager = class _WorktreeManager {
8620
8687
  const allWorktrees = this.listWorktrees();
8621
8688
  const activeSet = new Set(activeModuleUids);
8622
8689
  const orphaned = allWorktrees.filter((w) => !activeSet.has(w.moduleUid));
8623
- const valid = allWorktrees.filter((w) => activeSet.has(w.moduleUid));
8624
- return { orphaned, valid };
8690
+ const valid3 = allWorktrees.filter((w) => activeSet.has(w.moduleUid));
8691
+ return { orphaned, valid: valid3 };
8625
8692
  }
8626
8693
  /**
8627
8694
  * Update last accessed timestamp for a worktree
@@ -8656,7 +8723,7 @@ var WorktreeManager = class _WorktreeManager {
8656
8723
  */
8657
8724
  async validateWorktrees() {
8658
8725
  const config = this.readConfig();
8659
- const valid = [];
8726
+ const valid3 = [];
8660
8727
  const stale = [];
8661
8728
  const orphaned = [];
8662
8729
  const listResult = await this.gitExecutor.execute({
@@ -8667,7 +8734,7 @@ var WorktreeManager = class _WorktreeManager {
8667
8734
  );
8668
8735
  for (const worktree of config?.worktrees || []) {
8669
8736
  if (actualWorktrees.has(worktree.worktreePath)) {
8670
- valid.push(worktree);
8737
+ valid3.push(worktree);
8671
8738
  actualWorktrees.delete(worktree.worktreePath);
8672
8739
  } else {
8673
8740
  stale.push(worktree);
@@ -8678,7 +8745,7 @@ var WorktreeManager = class _WorktreeManager {
8678
8745
  orphaned.push(wpath);
8679
8746
  }
8680
8747
  }
8681
- return { valid, stale, orphaned };
8748
+ return { valid: valid3, stale, orphaned };
8682
8749
  }
8683
8750
  /**
8684
8751
  * EP1190: Clean up non-module worktrees (like 'main')
@@ -11551,6 +11618,18 @@ async function deleteWorktree(config, moduleUid) {
11551
11618
  // src/daemon/package-manager.ts
11552
11619
  var fs21 = __toESM(require("fs"));
11553
11620
  var path22 = __toESM(require("path"));
11621
+ function pnpmCommand(args) {
11622
+ return [
11623
+ "if command -v pnpm >/dev/null 2>&1; then",
11624
+ ` pnpm ${args}`,
11625
+ "elif command -v corepack >/dev/null 2>&1; then",
11626
+ ` corepack pnpm ${args}`,
11627
+ "else",
11628
+ ' echo "[setup] ERROR: pnpm is not installed and corepack is unavailable" >&2',
11629
+ " exit 127",
11630
+ "fi"
11631
+ ].join(" ");
11632
+ }
11554
11633
  var PACKAGE_MANAGERS = {
11555
11634
  javascript: [
11556
11635
  {
@@ -11572,7 +11651,7 @@ var PACKAGE_MANAGERS = {
11572
11651
  return null;
11573
11652
  },
11574
11653
  config: {
11575
- installCmd: "pnpm install --frozen-lockfile",
11654
+ installCmd: pnpmCommand("install --frozen-lockfile"),
11576
11655
  cacheEnvVar: "PNPM_HOME"
11577
11656
  }
11578
11657
  },
@@ -11604,7 +11683,7 @@ var PACKAGE_MANAGERS = {
11604
11683
  name: "pnpm",
11605
11684
  detector: (p) => fs21.existsSync(path22.join(p, "package.json")) ? "package.json (no lockfile - defaulting to pnpm)" : null,
11606
11685
  config: {
11607
- installCmd: "pnpm install",
11686
+ installCmd: pnpmCommand("install"),
11608
11687
  cacheEnvVar: "PNPM_HOME"
11609
11688
  }
11610
11689
  }
@@ -11752,7 +11831,7 @@ async function autoDetectSetupScript(worktreePath) {
11752
11831
  function getBuildPackagesCommand(packageManagerName) {
11753
11832
  switch (packageManagerName) {
11754
11833
  case "pnpm":
11755
- return "pnpm run build:packages";
11834
+ return 'if command -v pnpm >/dev/null 2>&1; then pnpm run build:packages; elif command -v corepack >/dev/null 2>&1; then corepack pnpm run build:packages; else echo "[setup] ERROR: pnpm is not installed and corepack is unavailable" >&2; exit 127; fi';
11756
11835
  case "yarn":
11757
11836
  return "yarn build:packages";
11758
11837
  case "npm":
@@ -12771,6 +12850,7 @@ var fs25 = __toESM(require("fs"));
12771
12850
  var path26 = __toESM(require("path"));
12772
12851
  var import_child_process18 = require("child_process");
12773
12852
  var import_core17 = __toESM(require_dist());
12853
+ var semver2 = __toESM(require("semver"));
12774
12854
 
12775
12855
  // src/utils/update-checker.ts
12776
12856
  var import_child_process17 = require("child_process");
@@ -12781,6 +12861,7 @@ var import_core16 = __toESM(require_dist());
12781
12861
 
12782
12862
  // src/utils/update-checker.ts
12783
12863
  var PACKAGE_NAME = "@episoda/cli";
12864
+ var LEGACY_PACKAGE_NAME = "episoda";
12784
12865
  var NPM_REGISTRY = "https://registry.npmjs.org";
12785
12866
  function isFileLinkedInstall() {
12786
12867
  try {
@@ -12853,6 +12934,39 @@ function getInstalledVersion() {
12853
12934
  return null;
12854
12935
  }
12855
12936
  }
12937
+ function getLegacyInstalledVersion() {
12938
+ try {
12939
+ const output = (0, import_child_process17.execSync)(`npm list -g ${LEGACY_PACKAGE_NAME} --json`, {
12940
+ stdio: ["pipe", "pipe", "pipe"],
12941
+ timeout: 1e4
12942
+ }).toString();
12943
+ const data = JSON.parse(output);
12944
+ return data?.dependencies?.[LEGACY_PACKAGE_NAME]?.version || null;
12945
+ } catch {
12946
+ return null;
12947
+ }
12948
+ }
12949
+ function detectCliInstallChannel(embeddedVersion) {
12950
+ const scopedVersion = getInstalledVersion();
12951
+ const legacyVersion = getLegacyInstalledVersion();
12952
+ const effectiveVersion = scopedVersion || legacyVersion || embeddedVersion || null;
12953
+ return {
12954
+ scopedVersion,
12955
+ legacyVersion,
12956
+ legacyOnly: !scopedVersion && !!legacyVersion,
12957
+ effectiveVersion
12958
+ };
12959
+ }
12960
+ function resolveEffectiveCliVersion(embeddedVersion) {
12961
+ const installedVersion = detectCliInstallChannel(embeddedVersion).effectiveVersion;
12962
+ if (!installedVersion) {
12963
+ return embeddedVersion;
12964
+ }
12965
+ if (semver.valid(installedVersion) && semver.valid(embeddedVersion)) {
12966
+ return semver.gt(installedVersion, embeddedVersion) ? installedVersion : embeddedVersion;
12967
+ }
12968
+ return installedVersion === embeddedVersion ? embeddedVersion : installedVersion;
12969
+ }
12856
12970
 
12857
12971
  // src/daemon/update-manager.ts
12858
12972
  var UpdateManager = class _UpdateManager {
@@ -12875,6 +12989,19 @@ var UpdateManager = class _UpdateManager {
12875
12989
  // 4 hours
12876
12990
  this.MAX_UPDATE_ATTEMPTS = 3;
12877
12991
  }
12992
+ /**
12993
+ * Prefer installed CLI version when it's newer than embedded bundle metadata.
12994
+ * This avoids update churn when daemon bundle version lags package install version.
12995
+ */
12996
+ getEffectiveCurrentVersion() {
12997
+ return resolveEffectiveCliVersion(this.currentVersion);
12998
+ }
12999
+ isTargetVersionNewer(targetVersion, currentVersion) {
13000
+ if (semver2.valid(targetVersion) && semver2.valid(currentVersion)) {
13001
+ return semver2.gt(targetVersion, currentVersion);
13002
+ }
13003
+ return targetVersion !== currentVersion;
13004
+ }
12878
13005
  /**
12879
13006
  * Start periodic update checks (every 4 hours).
12880
13007
  * Does nothing if EPISODA_CLI_PIN_VERSION is set.
@@ -12919,7 +13046,8 @@ var UpdateManager = class _UpdateManager {
12919
13046
  return;
12920
13047
  }
12921
13048
  try {
12922
- const result = await checkForUpdates(this.currentVersion);
13049
+ const effectiveCurrentVersion = this.getEffectiveCurrentVersion();
13050
+ const result = await checkForUpdates(effectiveCurrentVersion);
12923
13051
  if (result.updateAvailable) {
12924
13052
  await this.applyUpdateIfIdle(result.latestVersion, "startup");
12925
13053
  }
@@ -12941,8 +13069,9 @@ var UpdateManager = class _UpdateManager {
12941
13069
  }
12942
13070
  async applyUpdateIfIdle(targetVersion, source) {
12943
13071
  if (this.updateInProgress) return;
12944
- if (targetVersion === this.currentVersion) {
12945
- console.log(`[Daemon] EP1324: Already running version ${targetVersion}, skipping update`);
13072
+ const effectiveCurrentVersion = this.getEffectiveCurrentVersion();
13073
+ if (!this.isTargetVersionNewer(targetVersion, effectiveCurrentVersion)) {
13074
+ console.log(`[Daemon] EP1390: Skipping update target=${targetVersion}, current=${effectiveCurrentVersion} (source=${source})`);
12946
13075
  return;
12947
13076
  }
12948
13077
  if (this.lastFailedUpdateVersion === targetVersion && this.updateFailedAttempts >= _UpdateManager.MAX_UPDATE_ATTEMPTS) {
@@ -12952,12 +13081,12 @@ var UpdateManager = class _UpdateManager {
12952
13081
  const activeAgentSessions = this.getActiveAgentSessionCount();
12953
13082
  if (activeAgentSessions > 0) {
12954
13083
  this.pendingUpdateVersion = targetVersion;
12955
- console.log(`[Daemon] EP1319: Update available (${this.currentVersion} \u2192 ${targetVersion}) but ${activeAgentSessions} active agent session(s) \u2014 deferring`);
13084
+ console.log(`[Daemon] EP1319: Update available (${effectiveCurrentVersion} \u2192 ${targetVersion}) but ${activeAgentSessions} active agent session(s) \u2014 deferring`);
12956
13085
  return;
12957
13086
  }
12958
- const currentInstalled = getInstalledVersion();
12959
- if (currentInstalled && currentInstalled === targetVersion) {
12960
- console.log(`[Daemon] EP1343: Already installed version ${targetVersion} (embedded: ${this.currentVersion}), skipping update`);
13087
+ const latestEffectiveCurrent = this.getEffectiveCurrentVersion();
13088
+ if (!this.isTargetVersionNewer(targetVersion, latestEffectiveCurrent)) {
13089
+ console.log(`[Daemon] EP1390: Update no longer needed target=${targetVersion}, current=${latestEffectiveCurrent}`);
12961
13090
  return;
12962
13091
  }
12963
13092
  this.updateInProgress = true;
@@ -12983,6 +13112,14 @@ var UpdateManager = class _UpdateManager {
12983
13112
  stdio: ["ignore", logFd, logFd],
12984
13113
  env: { ...process.env, EPISODA_DAEMON_MODE: "1" }
12985
13114
  });
13115
+ if (!child.pid) {
13116
+ try {
13117
+ fs25.closeSync(logFd);
13118
+ } catch {
13119
+ }
13120
+ this.recordUpdateFailure(targetVersion, "Failed to spawn replacement daemon (missing pid)");
13121
+ return;
13122
+ }
12986
13123
  child.unref();
12987
13124
  const pidPath = getPidFilePath();
12988
13125
  fs25.writeFileSync(pidPath, child.pid.toString(), "utf-8");
@@ -13019,7 +13156,8 @@ var UpdateManager = class _UpdateManager {
13019
13156
  return;
13020
13157
  }
13021
13158
  try {
13022
- const result = await checkForUpdates(this.currentVersion);
13159
+ const effectiveCurrentVersion = this.getEffectiveCurrentVersion();
13160
+ const result = await checkForUpdates(effectiveCurrentVersion);
13023
13161
  if (!result.updateAvailable) {
13024
13162
  if (this.pendingUpdateVersion) {
13025
13163
  console.log(`[Daemon] EP1319: Pending update to ${this.pendingUpdateVersion} is no longer needed (already current)`);
@@ -13679,6 +13817,52 @@ var ConnectionManager = class {
13679
13817
  }
13680
13818
  };
13681
13819
 
13820
+ // src/daemon/ws-endpoint.ts
13821
+ var DEFAULT_API_URL = "https://episoda.dev";
13822
+ var CANONICAL_PROD_WS_HOST = "ws.episoda.dev";
13823
+ var PRODUCTION_API_HOSTS = /* @__PURE__ */ new Set([
13824
+ "episoda.dev",
13825
+ "www.episoda.dev",
13826
+ "api.episoda.dev"
13827
+ ]);
13828
+ function parseApiUrl(rawUrl) {
13829
+ try {
13830
+ return new URL(rawUrl);
13831
+ } catch {
13832
+ return new URL(DEFAULT_API_URL);
13833
+ }
13834
+ }
13835
+ function resolveDaemonWsEndpoint(config, env = process.env) {
13836
+ if (config.ws_url) {
13837
+ return {
13838
+ wsUrl: config.ws_url,
13839
+ source: "config.ws_url",
13840
+ serverUrl: config.project_settings?.local_server_url || config.api_url || env.EPISODA_API_URL || DEFAULT_API_URL
13841
+ };
13842
+ }
13843
+ if (env.EPISODA_WS_URL) {
13844
+ return {
13845
+ wsUrl: env.EPISODA_WS_URL,
13846
+ source: "env.EPISODA_WS_URL",
13847
+ serverUrl: config.project_settings?.local_server_url || config.api_url || env.EPISODA_API_URL || DEFAULT_API_URL
13848
+ };
13849
+ }
13850
+ const rawServerUrl = config.project_settings?.local_server_url || config.api_url || env.EPISODA_API_URL || DEFAULT_API_URL;
13851
+ const serverUrl = parseApiUrl(rawServerUrl);
13852
+ const wsProtocol = serverUrl.protocol === "https:" ? "wss:" : "ws:";
13853
+ const useCanonicalProdHost = PRODUCTION_API_HOSTS.has(serverUrl.hostname);
13854
+ const wsHostname = useCanonicalProdHost ? CANONICAL_PROD_WS_HOST : serverUrl.hostname;
13855
+ const explicitPort = env.EPISODA_WS_PORT?.trim();
13856
+ const inheritedServerPort = !useCanonicalProdHost ? serverUrl.port : "";
13857
+ const wsPort = explicitPort || inheritedServerPort;
13858
+ const wsUrl = wsPort ? `${wsProtocol}//${wsHostname}:${wsPort}` : `${wsProtocol}//${wsHostname}`;
13859
+ return {
13860
+ wsUrl,
13861
+ source: "derived",
13862
+ serverUrl: serverUrl.toString()
13863
+ };
13864
+ }
13865
+
13682
13866
  // src/daemon/project-message-router.ts
13683
13867
  var import_core19 = __toESM(require_dist());
13684
13868
  var path28 = __toESM(require("path"));
@@ -14182,7 +14366,7 @@ function getBuildPackagesCommand2(installCmd) {
14182
14366
  const runner = installCmd?.command?.[0];
14183
14367
  switch (runner) {
14184
14368
  case "pnpm":
14185
- return "pnpm run build:packages";
14369
+ return 'if command -v pnpm >/dev/null 2>&1; then pnpm run build:packages; elif command -v corepack >/dev/null 2>&1; then corepack pnpm run build:packages; else echo "[setup] ERROR: pnpm is not installed and corepack is unavailable" >&2; exit 127; fi';
14186
14370
  case "yarn":
14187
14371
  return "yarn build:packages";
14188
14372
  case "npm":
@@ -14217,10 +14401,11 @@ var Daemon = class _Daemon {
14217
14401
  // 2 minutes
14218
14402
  // EP1360: Per-session monotonic event seq for daemon→platform stream gap detection.
14219
14403
  this.agentEventSeq = /* @__PURE__ */ new Map();
14404
+ this.cliRuntimeVersion = resolveEffectiveCliVersion(packageJson.version);
14220
14405
  this.ipcServer = new IPCServer();
14221
14406
  this.connectionManager = new ConnectionManager();
14222
14407
  this.ipcRouter = new IPCRouter(this, this.ipcServer);
14223
- this.updateManager = new UpdateManager(this, packageJson.version, __filename);
14408
+ this.updateManager = new UpdateManager(this, this.cliRuntimeVersion, __filename);
14224
14409
  this.healthOrchestrator = new HealthOrchestrator(this);
14225
14410
  this.daemonCore = new DaemonCore(this);
14226
14411
  this.projectMessageRouter = new ProjectMessageRouter({
@@ -14485,23 +14670,15 @@ var Daemon = class _Daemon {
14485
14670
  if (!config || !config.access_token) {
14486
14671
  throw new Error("No access token found. Please run: episoda auth");
14487
14672
  }
14488
- let serverUrl = config.api_url || process.env.EPISODA_API_URL || "https://episoda.dev";
14489
- if (config.project_settings?.local_server_url) {
14490
- serverUrl = config.project_settings.local_server_url;
14491
- console.log(`[Daemon] Using cached server URL: ${serverUrl}`);
14492
- }
14493
- let wsUrl;
14494
- if (config.ws_url) {
14495
- wsUrl = config.ws_url;
14496
- console.log(`[Daemon] Using configured ws_url: ${wsUrl}`);
14497
- } else {
14498
- const serverUrlObj = new URL(serverUrl);
14499
- const wsProtocol = serverUrlObj.protocol === "https:" ? "wss:" : "ws:";
14500
- const wsHostname = serverUrlObj.hostname === "episoda.dev" ? "ws.episoda.dev" : serverUrlObj.hostname;
14501
- const wsPort = process.env.EPISODA_WS_PORT;
14502
- wsUrl = wsPort ? `${wsProtocol}//${wsHostname}:${wsPort}` : `${wsProtocol}//${wsHostname}`;
14673
+ const wsEndpoint = resolveDaemonWsEndpoint(config);
14674
+ if (wsEndpoint.source === "config.ws_url") {
14675
+ console.log(`[Daemon] Using configured ws_url: ${wsEndpoint.wsUrl}`);
14676
+ } else if (wsEndpoint.source === "env.EPISODA_WS_URL") {
14677
+ console.log(`[Daemon] Using EPISODA_WS_URL override: ${wsEndpoint.wsUrl}`);
14678
+ } else if (config.project_settings?.local_server_url) {
14679
+ console.log(`[Daemon] Using cached server URL: ${wsEndpoint.serverUrl}`);
14503
14680
  }
14504
- console.log(`[Daemon] Connecting to ${wsUrl} for project ${projectId}...`);
14681
+ console.log(`[Daemon] Connecting to ${wsEndpoint.wsUrl} for project ${projectId} (source: ${wsEndpoint.source})...`);
14505
14682
  const client = new import_core22.EpisodaClient();
14506
14683
  const gitExecutor = new import_core22.GitExecutor();
14507
14684
  const connection = {
@@ -14995,12 +15172,15 @@ var Daemon = class _Daemon {
14995
15172
  const modeConfig = getDaemonModeConfig();
14996
15173
  const environment = modeConfig.mode;
14997
15174
  const containerId = process.env.EPISODA_CONTAINER_ID;
14998
- await client.connect(wsUrl, config.access_token, this.machineId, {
15175
+ const capabilities = ["worktree_create_v1"];
15176
+ await client.connect(wsEndpoint.wsUrl, config.access_token, this.machineId, {
14999
15177
  hostname: os12.hostname(),
15000
15178
  osPlatform: os12.platform(),
15001
15179
  osArch: os12.arch(),
15002
15180
  daemonPid,
15003
- cliVersion: packageJson.version,
15181
+ cliVersion: this.cliRuntimeVersion,
15182
+ cliPackageName: packageJson.name,
15183
+ capabilities,
15004
15184
  environment,
15005
15185
  containerId
15006
15186
  });