omnara 0.1.5 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -5,8 +5,8 @@ const __filename = fileURLToPath(import.meta.url);
5
5
  const __dirname = dirname(__filename);
6
6
 
7
7
  // src/cli.ts
8
- import path3 from "path";
9
- import { createRequire } from "node:module";
8
+ import path4 from "path";
9
+ import { createRequire as createRequire2 } from "node:module";
10
10
  import { Command as Command3 } from "commander";
11
11
 
12
12
  // src/commands/agent.ts
@@ -17,7 +17,9 @@ import { randomUUID as randomUUID3 } from "crypto";
17
17
 
18
18
  // src/orchestrator/ai-client.ts
19
19
  import fs from "fs";
20
- import { query } from "@anthropic-ai/claude-agent-sdk";
20
+ import {
21
+ query
22
+ } from "@anthropic-ai/claude-agent-sdk";
21
23
  var BASE_ALLOWED_ORCHESTRATOR_TOOLS = [
22
24
  "Glob",
23
25
  "Grep",
@@ -52,7 +54,7 @@ var AIClient = class {
52
54
  constructor(config) {
53
55
  const defaultOptions = {
54
56
  maxTurns: 100,
55
- model: "opus",
57
+ model: "sonnet",
56
58
  cwd: process.cwd(),
57
59
  includePartialMessages: false,
58
60
  allowedTools: [...BASE_ALLOWED_ORCHESTRATOR_TOOLS]
@@ -740,7 +742,47 @@ var WorkerManager = class extends EventEmitter {
740
742
  record.sessionId,
741
743
  record.messageQueue
742
744
  );
743
- const query2 = client.createQuery(messageStream);
745
+ const query2 = client.createQuery(messageStream, {
746
+ hooks: {
747
+ "PostToolUse": [
748
+ {
749
+ // No matcher means it applies to all tools (Bash, Read, Write, etc.)
750
+ // If we wanted to only capture Bash results, we could add: matcher: 'Bash'
751
+ hooks: [
752
+ async (input2, toolUseID, options) => {
753
+ if (input2.hook_event_name !== "PostToolUse") {
754
+ return {};
755
+ }
756
+ const postToolInput = input2;
757
+ console.log("[WorkerManager] PostToolUse hook triggered:", {
758
+ toolName: postToolInput.tool_name,
759
+ toolUseID,
760
+ hasResponse: !!postToolInput.tool_response,
761
+ workerId: record.id,
762
+ task: record.task
763
+ });
764
+ if (postToolInput.tool_name === "Bash") {
765
+ console.log("[WorkerManager] Bash tool response structure:", {
766
+ responseType: typeof postToolInput.tool_response,
767
+ responseKeys: postToolInput.tool_response ? Object.keys(postToolInput.tool_response) : [],
768
+ fullResponse: postToolInput.tool_response
769
+ });
770
+ }
771
+ this.emit("message", {
772
+ record,
773
+ messageType: "tool_result",
774
+ toolUseId: toolUseID || randomUUID2(),
775
+ toolContent: postToolInput.tool_response,
776
+ isError: false
777
+ // PostToolUse is for successful executions
778
+ });
779
+ return {};
780
+ }
781
+ ]
782
+ }
783
+ ]
784
+ }
785
+ });
744
786
  this.runningQueries.set(record.id, query2);
745
787
  const summarizedChunks = [];
746
788
  try {
@@ -1530,7 +1572,8 @@ var AgentOrchestrator = class {
1530
1572
  toolName: event.toolName,
1531
1573
  workerId: event.record.id,
1532
1574
  task: event.record.task,
1533
- targetSessionId
1575
+ targetSessionId,
1576
+ toolUseId: event.toolUseId
1534
1577
  });
1535
1578
  this.broadcastToAll({
1536
1579
  type: "tool_call",
@@ -1547,6 +1590,13 @@ var AgentOrchestrator = class {
1547
1590
  if (!event.toolUseId) {
1548
1591
  return;
1549
1592
  }
1593
+ console.log("[Orchestrator] Broadcasting worker tool_result:", {
1594
+ toolName: event.toolName,
1595
+ workerId: event.record.id,
1596
+ task: event.record.task,
1597
+ targetSessionId,
1598
+ toolUseId: event.toolUseId
1599
+ });
1550
1600
  this.broadcastToAll({
1551
1601
  type: "tool_result",
1552
1602
  sessionId: targetSessionId,
@@ -1784,8 +1834,8 @@ var ApiClient = class {
1784
1834
  constructor(options) {
1785
1835
  this.baseUrl = normalizeBaseUrl(options.baseUrl);
1786
1836
  }
1787
- async getJson(path4, options) {
1788
- const url = resolveUrl(this.baseUrl, path4);
1837
+ async getJson(path5, options) {
1838
+ const url = resolveUrl(this.baseUrl, path5);
1789
1839
  const headers = this.buildHeaders(options);
1790
1840
  const response = await fetch(url, {
1791
1841
  method: "GET",
@@ -1794,8 +1844,8 @@ var ApiClient = class {
1794
1844
  });
1795
1845
  return await this.handleResponse(response);
1796
1846
  }
1797
- async postJson(path4, body, options) {
1798
- const url = resolveUrl(this.baseUrl, path4);
1847
+ async postJson(path5, body, options) {
1848
+ const url = resolveUrl(this.baseUrl, path5);
1799
1849
  const headers = this.buildHeaders(options, { includeJson: true });
1800
1850
  const response = await fetch(url, {
1801
1851
  method: "POST",
@@ -1853,12 +1903,12 @@ function normalizeBaseUrl(raw) {
1853
1903
  }
1854
1904
  return raw.endsWith("/") ? raw : `${raw}/`;
1855
1905
  }
1856
- function resolveUrl(base, path4) {
1906
+ function resolveUrl(base, path5) {
1857
1907
  const baseUrl = new URL(base);
1858
- if (!path4.startsWith("/")) {
1859
- path4 = `/${path4}`;
1908
+ if (!path5.startsWith("/")) {
1909
+ path5 = `/${path5}`;
1860
1910
  }
1861
- const resolved = new URL(path4, baseUrl);
1911
+ const resolved = new URL(path5, baseUrl);
1862
1912
  return resolved.toString();
1863
1913
  }
1864
1914
  function extractDetail(payload) {
@@ -2011,9 +2061,6 @@ function deriveAccessExpiry(session) {
2011
2061
  return void 0;
2012
2062
  }
2013
2063
 
2014
- // src/auth/login-flow.ts
2015
- import { spawn } from "child_process";
2016
-
2017
2064
  // src/utils/prompt.ts
2018
2065
  import readline from "readline/promises";
2019
2066
  import { stdin as input, stdout as output } from "process";
@@ -2185,7 +2232,7 @@ var LoopbackListener = class _LoopbackListener {
2185
2232
  }
2186
2233
  };
2187
2234
  function buildSuccessHtml() {
2188
- const redirectTarget = "https://voice.omnara.com/dashboard";
2235
+ const redirectTarget = "https://www.omnara.com/dashboard";
2189
2236
  return `<!doctype html>
2190
2237
  <html lang="en">
2191
2238
  <head>
@@ -2240,6 +2287,18 @@ function buildMessageHtml(message) {
2240
2287
  </html>`;
2241
2288
  }
2242
2289
 
2290
+ // src/utils/browser.ts
2291
+ import { spawn } from "child_process";
2292
+ function tryOpenBrowser(url) {
2293
+ const command = process.platform === "darwin" ? "open" : process.platform === "win32" ? "cmd" : "xdg-open";
2294
+ const args = process.platform === "win32" ? ["/c", "start", "", url] : [url];
2295
+ try {
2296
+ const child = spawn(command, args, { stdio: "ignore", detached: true });
2297
+ child.unref();
2298
+ } catch {
2299
+ }
2300
+ }
2301
+
2243
2302
  // src/auth/login-flow.ts
2244
2303
  async function performVerificationLogin({
2245
2304
  backendUrlOption,
@@ -2339,8 +2398,8 @@ async function performVerificationLogin({
2339
2398
  }
2340
2399
  return latestCredentials;
2341
2400
  }
2342
- var DEFAULT_BACKEND_URL = "https://omnara-voice.onrender.com/";
2343
- var DEFAULT_FRONTEND_URL = "https://voice.omnara.com/";
2401
+ var DEFAULT_BACKEND_URL = "https://api.omnara.com/";
2402
+ var DEFAULT_FRONTEND_URL = "https://www.omnara.com/";
2344
2403
  function resolveBackendUrl(option) {
2345
2404
  const candidate = option ?? process.env.OMNARA_BACKEND_URL ?? DEFAULT_BACKEND_URL;
2346
2405
  return normalizeBaseUrl(candidate);
@@ -2393,15 +2452,6 @@ function printSessionInstructions(session) {
2393
2452
  console.log(` ${session.verificationUriComplete}`);
2394
2453
  console.log("Approve the request, then return to the CLI.");
2395
2454
  }
2396
- function tryOpenBrowser(url) {
2397
- const command = process.platform === "darwin" ? "open" : process.platform === "win32" ? "cmd" : "xdg-open";
2398
- const args = process.platform === "win32" ? ["/c", "start", "", url] : [url];
2399
- try {
2400
- const child = spawn(command, args, { stdio: "ignore", detached: true });
2401
- child.unref();
2402
- } catch {
2403
- }
2404
- }
2405
2455
  function extractErrorMessage4(error) {
2406
2456
  if (error instanceof Error && error.message) {
2407
2457
  return error.message;
@@ -4736,6 +4786,7 @@ var RelayBridge = class extends EventEmitter2 {
4736
4786
  authProviderPromise = null;
4737
4787
  userSessionId = null;
4738
4788
  currentAgentSessionId = null;
4789
+ browserOpened = false;
4739
4790
  constructor(orchestrator, options) {
4740
4791
  super();
4741
4792
  this.orchestrator = orchestrator;
@@ -4779,6 +4830,7 @@ var RelayBridge = class extends EventEmitter2 {
4779
4830
  async stop() {
4780
4831
  this.stopped = true;
4781
4832
  this.currentAgentSessionId = null;
4833
+ this.browserOpened = false;
4782
4834
  if (this.pingTimer) {
4783
4835
  clearInterval(this.pingTimer);
4784
4836
  this.pingTimer = null;
@@ -4818,6 +4870,13 @@ var RelayBridge = class extends EventEmitter2 {
4818
4870
  this.heartbeatIntervalMs = registration.relayHeartbeatIntervalSec * 1e3;
4819
4871
  this.startPingTimer();
4820
4872
  await this.sendPrimarySessionInit(ws);
4873
+ if (this.frontendUrl && !this.browserOpened) {
4874
+ const dashboardUrl = new URL("dashboard", this.frontendUrl);
4875
+ dashboardUrl.searchParams.set("session", agentSessionId);
4876
+ tryOpenBrowser(dashboardUrl.toString());
4877
+ this.logger.log(`Opened dashboard at ${dashboardUrl.toString()}`);
4878
+ this.browserOpened = true;
4879
+ }
4821
4880
  this.flushQueue();
4822
4881
  await this.handleWebsocketLifecycle(ws);
4823
4882
  }
@@ -4836,7 +4895,7 @@ var RelayBridge = class extends EventEmitter2 {
4836
4895
  if (!this.currentAgentSessionId) {
4837
4896
  this.currentAgentSessionId = randomUUID4();
4838
4897
  }
4839
- const session = this.orchestrator.ensureSessionExists(this.currentAgentSessionId);
4898
+ this.orchestrator.ensureSessionExists(this.currentAgentSessionId);
4840
4899
  this.orchestrator.setMainCodingSessionId(this.currentAgentSessionId);
4841
4900
  return this.currentAgentSessionId;
4842
4901
  }
@@ -5316,16 +5375,16 @@ var RelayBridge = class extends EventEmitter2 {
5316
5375
  }
5317
5376
  }
5318
5377
  };
5319
- function buildRelayWebsocketUrl(baseUrl, path4) {
5378
+ function buildRelayWebsocketUrl(baseUrl, path5) {
5320
5379
  const url = new URL(baseUrl);
5321
5380
  url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
5322
5381
  url.search = "";
5323
5382
  url.hash = "";
5324
- if (path4.startsWith("/")) {
5325
- url.pathname = path4;
5383
+ if (path5.startsWith("/")) {
5384
+ url.pathname = path5;
5326
5385
  } else {
5327
5386
  const basePath = url.pathname.endsWith("/") ? url.pathname : `${url.pathname}/`;
5328
- url.pathname = `${basePath}${path4}`;
5387
+ url.pathname = `${basePath}${path5}`;
5329
5388
  }
5330
5389
  return url.toString();
5331
5390
  }
@@ -5666,7 +5725,7 @@ Commands:
5666
5725
 
5667
5726
  // src/voice/voice-service.ts
5668
5727
  async function launchVoiceForSession(client, accessToken, options) {
5669
- const path4 = `/api/v1/voice/sessions/${options.sessionId}/launch`;
5728
+ const path5 = `/api/v1/voice/sessions/${options.sessionId}/launch`;
5670
5729
  const requestBody = {};
5671
5730
  if (options.force) {
5672
5731
  requestBody.force = true;
@@ -5675,7 +5734,7 @@ async function launchVoiceForSession(client, accessToken, options) {
5675
5734
  requestBody.room_name = options.roomName;
5676
5735
  }
5677
5736
  const response = await client.postJson(
5678
- path4,
5737
+ path5,
5679
5738
  requestBody,
5680
5739
  { accessToken }
5681
5740
  );
@@ -5693,6 +5752,287 @@ async function launchVoiceForSession(client, accessToken, options) {
5693
5752
  };
5694
5753
  }
5695
5754
 
5755
+ // src/utils/claude-code-check.ts
5756
+ import { execSync } from "child_process";
5757
+ import chalk from "chalk";
5758
+ function checkClaudeCodeInstallation() {
5759
+ try {
5760
+ execSync("claude --version", {
5761
+ stdio: "ignore",
5762
+ encoding: "utf-8"
5763
+ });
5764
+ return true;
5765
+ } catch (error) {
5766
+ return false;
5767
+ }
5768
+ }
5769
+ function displayClaudeCodeWarning() {
5770
+ console.log(chalk.yellow("\nWarning: Claude Code is not installed or not found in PATH"));
5771
+ console.log(chalk.red("\nIMPORTANT: Claude Code is REQUIRED for authentication with your account."));
5772
+ console.log(chalk.white("\nClaude Code provides:"));
5773
+ console.log(chalk.gray(" - AI-powered code assistance"));
5774
+ console.log(chalk.gray(" - Intelligent code completion"));
5775
+ console.log(chalk.gray(" - Natural language to code translation"));
5776
+ console.log(chalk.gray(" - User authentication for API access"));
5777
+ console.log(chalk.white("\nTo install Claude Code:"));
5778
+ console.log(chalk.cyan(" 1. Visit: https://claude.ai/download"));
5779
+ console.log(chalk.cyan(" 2. Download and install Claude Code for your platform"));
5780
+ console.log(chalk.cyan(' 3. Make sure the "claude" command is available in your PATH'));
5781
+ console.log(chalk.yellow("\nNote: Without Claude Code, you cannot authenticate and access"));
5782
+ console.log(chalk.yellow("personalized features that require your user credentials.\n"));
5783
+ }
5784
+ function performClaudeCodeCheck(options = {}) {
5785
+ const { silent = false, exitOnMissing = false } = options;
5786
+ if (process.env.OMNARA_SKIP_CLAUDE_CHECK === "true") {
5787
+ return true;
5788
+ }
5789
+ const isInstalled = checkClaudeCodeInstallation();
5790
+ if (!isInstalled && !silent) {
5791
+ displayClaudeCodeWarning();
5792
+ if (exitOnMissing) {
5793
+ console.error(chalk.red("Exiting: Claude Code is required for this operation."));
5794
+ process.exit(1);
5795
+ }
5796
+ }
5797
+ return isInstalled;
5798
+ }
5799
+ function getClaudeCodeVersion() {
5800
+ try {
5801
+ const version = execSync("claude --version", {
5802
+ encoding: "utf-8",
5803
+ stdio: ["ignore", "pipe", "ignore"]
5804
+ }).trim();
5805
+ return version;
5806
+ } catch (error) {
5807
+ return null;
5808
+ }
5809
+ }
5810
+
5811
+ // src/utils/logger.ts
5812
+ import path3 from "path";
5813
+ function isProduction() {
5814
+ if (process.env.NODE_ENV === "production") {
5815
+ return true;
5816
+ }
5817
+ try {
5818
+ const currentFile = typeof __filename !== "undefined" ? __filename : "";
5819
+ const isInDist = currentFile.includes(path3.sep + "dist" + path3.sep);
5820
+ if (isInDist && process.env.NODE_ENV !== "development") {
5821
+ return true;
5822
+ }
5823
+ } catch {
5824
+ }
5825
+ const logLevel = process.env.OMNARA_LOG_LEVEL?.toLowerCase();
5826
+ if (logLevel === "none" || logLevel === "silent") {
5827
+ return true;
5828
+ }
5829
+ return false;
5830
+ }
5831
+ function getLogLevel() {
5832
+ const envLevel = process.env.OMNARA_LOG_LEVEL?.toLowerCase();
5833
+ switch (envLevel) {
5834
+ case "none":
5835
+ case "silent":
5836
+ return 0 /* NONE */;
5837
+ case "error":
5838
+ return 1 /* ERROR */;
5839
+ case "warn":
5840
+ case "warning":
5841
+ return 2 /* WARN */;
5842
+ case "info":
5843
+ return 3 /* INFO */;
5844
+ case "debug":
5845
+ return 4 /* DEBUG */;
5846
+ case "verbose":
5847
+ case "trace":
5848
+ return 5 /* VERBOSE */;
5849
+ default:
5850
+ return isProduction() ? 1 /* ERROR */ : 3 /* INFO */;
5851
+ }
5852
+ }
5853
+ var ControlledLogger = class {
5854
+ logLevel;
5855
+ forceOutput;
5856
+ _console;
5857
+ // Console properties we need to implement
5858
+ Console;
5859
+ constructor(options) {
5860
+ this.logLevel = options?.logLevel ?? getLogLevel();
5861
+ this.forceOutput = options?.forceOutput ?? false;
5862
+ this._console = console;
5863
+ this.Console = console.Console;
5864
+ }
5865
+ /**
5866
+ * Standard log output (INFO level)
5867
+ */
5868
+ log(...args) {
5869
+ if (this.shouldLog(3 /* INFO */)) {
5870
+ console.log(...args);
5871
+ }
5872
+ }
5873
+ /**
5874
+ * Error output (always shown unless NONE)
5875
+ */
5876
+ error(...args) {
5877
+ if (this.shouldLog(1 /* ERROR */)) {
5878
+ console.error(...args);
5879
+ }
5880
+ }
5881
+ /**
5882
+ * Warning output
5883
+ */
5884
+ warn(...args) {
5885
+ if (this.shouldLog(2 /* WARN */)) {
5886
+ console.warn(...args);
5887
+ }
5888
+ }
5889
+ /**
5890
+ * Info level output
5891
+ */
5892
+ info(...args) {
5893
+ if (this.shouldLog(3 /* INFO */)) {
5894
+ console.info(...args);
5895
+ }
5896
+ }
5897
+ /**
5898
+ * Debug output (only in development)
5899
+ */
5900
+ debug(...args) {
5901
+ if (this.shouldLog(4 /* DEBUG */)) {
5902
+ console.debug(...args);
5903
+ }
5904
+ }
5905
+ /**
5906
+ * Verbose/trace output
5907
+ */
5908
+ trace(...args) {
5909
+ if (this.shouldLog(5 /* VERBOSE */)) {
5910
+ console.log("[TRACE]", ...args);
5911
+ }
5912
+ }
5913
+ /**
5914
+ * Important messages that should always be shown to user
5915
+ * (authentication status, connection info, etc.)
5916
+ */
5917
+ important(...args) {
5918
+ if (this.logLevel !== 0 /* NONE */ || this.forceOutput) {
5919
+ console.log(...args);
5920
+ }
5921
+ }
5922
+ /**
5923
+ * Success messages that should typically be shown
5924
+ */
5925
+ success(...args) {
5926
+ if (this.shouldLog(2 /* WARN */) || this.forceOutput) {
5927
+ console.log(...args);
5928
+ }
5929
+ }
5930
+ /**
5931
+ * Check if a message should be logged at the given level
5932
+ */
5933
+ shouldLog(level) {
5934
+ return this.forceOutput || this.logLevel >= level;
5935
+ }
5936
+ /**
5937
+ * Update the log level dynamically
5938
+ */
5939
+ setLogLevel(level) {
5940
+ this.logLevel = level;
5941
+ }
5942
+ /**
5943
+ * Get current log level
5944
+ */
5945
+ getLogLevel() {
5946
+ return this.logLevel;
5947
+ }
5948
+ // Console methods we delegate or control based on log level
5949
+ assert(condition, ...data) {
5950
+ if (this.shouldLog(1 /* ERROR */)) {
5951
+ this._console.assert(condition, ...data);
5952
+ }
5953
+ }
5954
+ clear() {
5955
+ this._console.clear();
5956
+ }
5957
+ count(label) {
5958
+ if (this.shouldLog(4 /* DEBUG */)) {
5959
+ this._console.count(label);
5960
+ }
5961
+ }
5962
+ countReset(label) {
5963
+ if (this.shouldLog(4 /* DEBUG */)) {
5964
+ this._console.countReset(label);
5965
+ }
5966
+ }
5967
+ dir(item, options) {
5968
+ if (this.shouldLog(4 /* DEBUG */)) {
5969
+ this._console.dir(item, options);
5970
+ }
5971
+ }
5972
+ dirxml(...data) {
5973
+ if (this.shouldLog(4 /* DEBUG */)) {
5974
+ this._console.dirxml(...data);
5975
+ }
5976
+ }
5977
+ group(...data) {
5978
+ if (this.shouldLog(4 /* DEBUG */)) {
5979
+ this._console.group(...data);
5980
+ }
5981
+ }
5982
+ groupCollapsed(...data) {
5983
+ if (this.shouldLog(4 /* DEBUG */)) {
5984
+ this._console.groupCollapsed(...data);
5985
+ }
5986
+ }
5987
+ groupEnd() {
5988
+ if (this.shouldLog(4 /* DEBUG */)) {
5989
+ this._console.groupEnd();
5990
+ }
5991
+ }
5992
+ table(tabularData, properties) {
5993
+ if (this.shouldLog(3 /* INFO */)) {
5994
+ this._console.table(tabularData, properties);
5995
+ }
5996
+ }
5997
+ time(label) {
5998
+ if (this.shouldLog(4 /* DEBUG */)) {
5999
+ this._console.time(label);
6000
+ }
6001
+ }
6002
+ timeEnd(label) {
6003
+ if (this.shouldLog(4 /* DEBUG */)) {
6004
+ this._console.timeEnd(label);
6005
+ }
6006
+ }
6007
+ timeLog(label, ...data) {
6008
+ if (this.shouldLog(4 /* DEBUG */)) {
6009
+ this._console.timeLog(label, ...data);
6010
+ }
6011
+ }
6012
+ timeStamp(label) {
6013
+ if (this.shouldLog(4 /* DEBUG */)) {
6014
+ this._console.timeStamp(label);
6015
+ }
6016
+ }
6017
+ profile(label) {
6018
+ if (this.shouldLog(4 /* DEBUG */)) {
6019
+ this._console.profile?.(label);
6020
+ }
6021
+ }
6022
+ profileEnd(label) {
6023
+ if (this.shouldLog(4 /* DEBUG */)) {
6024
+ this._console.profileEnd?.(label);
6025
+ }
6026
+ }
6027
+ };
6028
+ var logger = new ControlledLogger();
6029
+ function extractErrorMessage6(error) {
6030
+ if (error instanceof Error) {
6031
+ return error.message;
6032
+ }
6033
+ return String(error);
6034
+ }
6035
+
5696
6036
  // src/commands/agent.ts
5697
6037
  function buildAgentCommand() {
5698
6038
  const agent = new Command("agent").description(
@@ -5710,6 +6050,12 @@ function buildAgentCommand() {
5710
6050
  return agent;
5711
6051
  }
5712
6052
  async function runAgentOrchestrator(options = {}) {
6053
+ const claudeVersion = getClaudeCodeVersion();
6054
+ if (claudeVersion) {
6055
+ logger.info(`\u2713 Claude Code detected: ${claudeVersion}`);
6056
+ } else {
6057
+ logger.info("\u2139 Running without Claude Code integration");
6058
+ }
5713
6059
  const orchestrator = new AgentOrchestrator();
5714
6060
  await orchestrator.start();
5715
6061
  const backendUrl = resolveBackendUrl(options.backendUrl);
@@ -5731,7 +6077,7 @@ async function runAgentOrchestrator(options = {}) {
5731
6077
  try {
5732
6078
  await bridge.start();
5733
6079
  } catch (error) {
5734
- console.error(`Relay orchestrator terminated: ${extractErrorMessage6(error)}`);
6080
+ logger.error(`Relay orchestrator terminated: ${extractErrorMessage6(error)}`);
5735
6081
  process.exitCode = process.exitCode || 1;
5736
6082
  } finally {
5737
6083
  await stop();
@@ -5745,10 +6091,10 @@ function createSignalHandler(onStop) {
5745
6091
  return;
5746
6092
  }
5747
6093
  stopping = true;
5748
- console.log(`
6094
+ logger.important(`
5749
6095
  Received ${signal}. Shutting down agent orchestrator...`);
5750
6096
  void onStop().catch((error) => {
5751
- console.error("Error while shutting down agent orchestrator:", error);
6097
+ logger.error("Error while shutting down agent orchestrator:", error);
5752
6098
  });
5753
6099
  };
5754
6100
  const remove = () => {
@@ -5757,12 +6103,6 @@ Received ${signal}. Shutting down agent orchestrator...`);
5757
6103
  };
5758
6104
  return { handler, remove };
5759
6105
  }
5760
- function extractErrorMessage6(error) {
5761
- if (error instanceof Error) {
5762
- return error.message;
5763
- }
5764
- return String(error);
5765
- }
5766
6106
  async function runRepl(options) {
5767
6107
  const backendUrl = resolveBackendUrl(options.backendUrl);
5768
6108
  const frontendUrl = resolveFrontendUrl(options.frontendUrl);
@@ -5780,7 +6120,7 @@ async function runRepl(options) {
5780
6120
  clientKind: "cli"
5781
6121
  });
5782
6122
  const wsUrl = buildRelayWebsocketUrl2(backendUrl, registration.relayWsPath);
5783
- console.log(
6123
+ logger.important(
5784
6124
  `Using agent session ${options.sessionId} (user session ${registration.userSessionId})`
5785
6125
  );
5786
6126
  await runTerminalRepl({
@@ -5808,30 +6148,30 @@ async function runVoice(options) {
5808
6148
  force: options.force ?? false,
5809
6149
  roomName: options.roomName
5810
6150
  });
5811
- console.log("\nVoice agent dispatched successfully.");
5812
- console.log(`Session ID: ${launch.sessionId}`);
5813
- console.log(`LiveKit URL: ${launch.livekitUrl}`);
5814
- console.log(`Room name: ${launch.roomName}`);
5815
- console.log(`Participant identity: ${launch.accessTokenIdentity}`);
5816
- console.log("\nUse this token to join the room:");
5817
- console.log(launch.accessToken);
5818
- console.log("\nOnce connected (for example via the LiveKit Agents playground),");
5819
- console.log("the voice worker will coordinate with the CLI coding agent through the relay.");
5820
- console.log(`Relay websocket: ${launch.relayWsUrl}`);
5821
- console.log(`Relay token (expires in ${launch.relayTokenExpiresIn}s):`);
5822
- console.log(launch.relayToken);
5823
- console.log("\nKeep this information secure\u2014tokens grant access to your agent session.");
6151
+ logger.success("\nVoice agent dispatched successfully.");
6152
+ logger.important(`Session ID: ${launch.sessionId}`);
6153
+ logger.important(`LiveKit URL: ${launch.livekitUrl}`);
6154
+ logger.important(`Room name: ${launch.roomName}`);
6155
+ logger.important(`Participant identity: ${launch.accessTokenIdentity}`);
6156
+ logger.important("\nUse this token to join the room:");
6157
+ logger.important(launch.accessToken);
6158
+ logger.log("\nOnce connected (for example via the LiveKit Agents playground),");
6159
+ logger.log("the voice worker will coordinate with the CLI coding agent through the relay.");
6160
+ logger.debug(`Relay websocket: ${launch.relayWsUrl}`);
6161
+ logger.debug(`Relay token (expires in ${launch.relayTokenExpiresIn}s):`);
6162
+ logger.debug(launch.relayToken);
6163
+ logger.important("\nKeep this information secure\u2014tokens grant access to your agent session.");
5824
6164
  }
5825
- function buildRelayWebsocketUrl2(baseUrl, path4) {
6165
+ function buildRelayWebsocketUrl2(baseUrl, path5) {
5826
6166
  const url = new URL(baseUrl);
5827
6167
  url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
5828
6168
  url.search = "";
5829
6169
  url.hash = "";
5830
- if (path4.startsWith("/")) {
5831
- url.pathname = path4;
6170
+ if (path5.startsWith("/")) {
6171
+ url.pathname = path5;
5832
6172
  } else {
5833
6173
  const basePath = url.pathname.endsWith("/") ? url.pathname : `${url.pathname}/`;
5834
- url.pathname = `${basePath}${path4}`;
6174
+ url.pathname = `${basePath}${path5}`;
5835
6175
  }
5836
6176
  return url.toString();
5837
6177
  }
@@ -5907,9 +6247,79 @@ function extractErrorMessage7(error) {
5907
6247
  return String(error);
5908
6248
  }
5909
6249
 
5910
- // src/cli.ts
6250
+ // src/utils/version-check.ts
6251
+ import https from "https";
6252
+ import { createRequire } from "node:module";
5911
6253
  var require2 = createRequire(import.meta.url);
5912
- var packageJson = require2("../package.json");
6254
+ async function fetchLatestVersion(packageName) {
6255
+ return new Promise((resolve) => {
6256
+ const url = `https://registry.npmjs.org/${packageName}`;
6257
+ https.get(url, { timeout: 3e3 }, (res) => {
6258
+ let data = "";
6259
+ res.on("data", (chunk) => {
6260
+ data += chunk;
6261
+ });
6262
+ res.on("end", () => {
6263
+ try {
6264
+ if (res.statusCode !== 200) {
6265
+ resolve(null);
6266
+ return;
6267
+ }
6268
+ const packageInfo = JSON.parse(data);
6269
+ resolve(packageInfo["dist-tags"]?.latest || null);
6270
+ } catch {
6271
+ resolve(null);
6272
+ }
6273
+ });
6274
+ }).on("error", () => {
6275
+ resolve(null);
6276
+ }).on("timeout", () => {
6277
+ resolve(null);
6278
+ });
6279
+ });
6280
+ }
6281
+ function compareVersions(v1, v2) {
6282
+ const parts1 = v1.split(".").map(Number);
6283
+ const parts2 = v2.split(".").map(Number);
6284
+ for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {
6285
+ const part1 = parts1[i] || 0;
6286
+ const part2 = parts2[i] || 0;
6287
+ if (part1 > part2) return 1;
6288
+ if (part1 < part2) return -1;
6289
+ }
6290
+ return 0;
6291
+ }
6292
+ async function checkForUpdates() {
6293
+ try {
6294
+ const packageJson2 = require2("../../package.json");
6295
+ const currentVersion = packageJson2.version;
6296
+ const packageName = packageJson2.name;
6297
+ if (!currentVersion || !packageName) {
6298
+ return;
6299
+ }
6300
+ const latestVersion = await fetchLatestVersion(packageName);
6301
+ if (!latestVersion) {
6302
+ return;
6303
+ }
6304
+ if (compareVersions(latestVersion, currentVersion) > 0) {
6305
+ console.log("\n" + "\u2550".repeat(60));
6306
+ console.log("Update available!");
6307
+ console.log(`Current version: ${currentVersion}`);
6308
+ console.log(`Latest version: ${latestVersion}`);
6309
+ console.log(`Run \`npm install -g ${packageName}@latest\` to update`);
6310
+ console.log("\u2550".repeat(60) + "\n");
6311
+ }
6312
+ } catch {
6313
+ }
6314
+ }
6315
+ function checkForUpdatesInBackground() {
6316
+ checkForUpdates().catch(() => {
6317
+ });
6318
+ }
6319
+
6320
+ // src/cli.ts
6321
+ var require3 = createRequire2(import.meta.url);
6322
+ var packageJson = require3("../package.json");
5913
6323
  function createProgram() {
5914
6324
  const program = new Command3();
5915
6325
  program.name("omnara").description(packageJson.description ?? "Command-line interface for Omnara.").version(packageJson.version ?? "0.0.0").option("--backend-url <url>", "Override backend API base URL used for login").option("--frontend-url <url>", "Override frontend URL opened during login").action(async () => {
@@ -5922,6 +6332,8 @@ function createProgram() {
5922
6332
  }
5923
6333
  async function run(argv) {
5924
6334
  const program = createProgram();
6335
+ performClaudeCodeCheck({ silent: false, exitOnMissing: false });
6336
+ checkForUpdatesInBackground();
5925
6337
  try {
5926
6338
  await program.parseAsync(argv);
5927
6339
  } catch (error) {
@@ -5932,13 +6344,13 @@ function isMainModule() {
5932
6344
  if (!import.meta.url || !process.argv[1]) {
5933
6345
  return false;
5934
6346
  }
5935
- const executedPath = path3.resolve(process.argv[1]);
6347
+ const executedPath = path4.resolve(process.argv[1]);
5936
6348
  const currentPath = import.meta.url.startsWith("file://") ? decodeURIComponent(import.meta.url.slice(7)) : import.meta.url;
5937
- return path3.normalize(currentPath) === path3.normalize(executedPath);
6349
+ return path4.normalize(currentPath) === path4.normalize(executedPath);
5938
6350
  }
5939
6351
  if (isMainModule()) {
5940
6352
  run(process.argv).catch((error) => {
5941
- console.error(error);
6353
+ logger.error(error);
5942
6354
  process.exitCode = 1;
5943
6355
  });
5944
6356
  }