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/README.md +1 -1
- package/dist/cli.js +480 -68
- package/dist/cli.js.map +4 -4
- package/dist/relay/relay-bridge.d.ts +1 -0
- package/dist/utils/browser.d.ts +1 -0
- package/dist/utils/claude-code-check.d.ts +21 -0
- package/dist/utils/logger.d.ts +127 -0
- package/dist/utils/version-check.d.ts +9 -0
- package/package.json +2 -1
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
|
|
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 {
|
|
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: "
|
|
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(
|
|
1788
|
-
const url = resolveUrl(this.baseUrl,
|
|
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(
|
|
1798
|
-
const url = resolveUrl(this.baseUrl,
|
|
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,
|
|
1906
|
+
function resolveUrl(base, path5) {
|
|
1857
1907
|
const baseUrl = new URL(base);
|
|
1858
|
-
if (!
|
|
1859
|
-
|
|
1908
|
+
if (!path5.startsWith("/")) {
|
|
1909
|
+
path5 = `/${path5}`;
|
|
1860
1910
|
}
|
|
1861
|
-
const resolved = new URL(
|
|
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://
|
|
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
|
|
2343
|
-
var DEFAULT_FRONTEND_URL = "https://
|
|
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
|
-
|
|
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,
|
|
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 (
|
|
5325
|
-
url.pathname =
|
|
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}${
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
6094
|
+
logger.important(`
|
|
5749
6095
|
Received ${signal}. Shutting down agent orchestrator...`);
|
|
5750
6096
|
void onStop().catch((error) => {
|
|
5751
|
-
|
|
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
|
-
|
|
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
|
-
|
|
5812
|
-
|
|
5813
|
-
|
|
5814
|
-
|
|
5815
|
-
|
|
5816
|
-
|
|
5817
|
-
|
|
5818
|
-
|
|
5819
|
-
|
|
5820
|
-
|
|
5821
|
-
|
|
5822
|
-
|
|
5823
|
-
|
|
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,
|
|
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 (
|
|
5831
|
-
url.pathname =
|
|
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}${
|
|
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/
|
|
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
|
-
|
|
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 =
|
|
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
|
|
6349
|
+
return path4.normalize(currentPath) === path4.normalize(executedPath);
|
|
5938
6350
|
}
|
|
5939
6351
|
if (isMainModule()) {
|
|
5940
6352
|
run(process.argv).catch((error) => {
|
|
5941
|
-
|
|
6353
|
+
logger.error(error);
|
|
5942
6354
|
process.exitCode = 1;
|
|
5943
6355
|
});
|
|
5944
6356
|
}
|