omnara 0.2.3 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/bin/omnara.js +5 -0
  2. package/dist/auth/auth-provider.d.ts +2 -0
  3. package/dist/auth/credential-manager.d.ts +5 -1
  4. package/dist/auth/credentials-store.d.ts +2 -1
  5. package/dist/auth/supabase-client.d.ts +1 -1
  6. package/dist/cli.js +5886 -6382
  7. package/dist/cli.js.map +4 -4
  8. package/dist/commands/index.d.ts +1 -0
  9. package/dist/commands/kill.d.ts +2 -0
  10. package/dist/daemon/daemon-launcher.d.ts +7 -0
  11. package/dist/daemon/paths.d.ts +7 -0
  12. package/dist/daemon/session-runner.d.ts +1 -1
  13. package/dist/env/env-mode.d.ts +2 -0
  14. package/dist/http/api-client.d.ts +0 -5
  15. package/dist/orchestrator/agent-orchestrator.d.ts +39 -44
  16. package/dist/orchestrator/ai-client.d.ts +7 -6
  17. package/dist/orchestrator/orchestrator-types.d.ts +3 -2
  18. package/dist/orchestrator/session.d.ts +59 -38
  19. package/dist/orchestrator/tools/worker-tools.d.ts +2 -0
  20. package/dist/orchestrator/utils/envelope-utils.d.ts +13 -0
  21. package/dist/orchestrator/utils/index.d.ts +1 -2
  22. package/dist/orchestrator/utils/worker-events.d.ts +7 -0
  23. package/dist/orchestrator/utils/worktree-manager.d.ts +21 -146
  24. package/dist/orchestrator/worker-manager.d.ts +44 -99
  25. package/dist/orchestrator/worker-types.d.ts +23 -0
  26. package/dist/relay/relay-bridge.d.ts +2 -10
  27. package/dist/utils/logger.d.ts +15 -0
  28. package/instrument.mjs +14 -0
  29. package/package.json +6 -2
  30. package/scripts/test-preinstall.js +0 -1
  31. package/dist/daemon/file-logger.d.ts +0 -24
  32. package/dist/daemon/session-log-manager.d.ts +0 -10
  33. package/dist/orchestrator/tools/worker-status-tool.d.ts +0 -7
  34. package/dist/orchestrator/utils/async-queue.d.ts +0 -26
@@ -1,121 +1,66 @@
1
- import { EventEmitter } from 'events';
2
- import type { SDKUserMessage, McpServerConfig } from '@anthropic-ai/claude-agent-sdk';
3
- import type { AgentClient } from './ai-client.js';
4
- import { AsyncQueue } from './utils/async-queue.js';
1
+ import type { McpServerConfig } from '@anthropic-ai/claude-agent-sdk';
2
+ import { type AgentClient } from './ai-client.js';
5
3
  import { WorktreeManager } from './utils/worktree-manager.js';
6
- export type WorkerStatus = 'running' | 'completed' | 'error' | 'canceled';
7
- export interface WorkerProgressEntry {
8
- timestamp: number;
9
- message: string;
10
- }
11
- export interface WorkerRecord {
12
- id: string;
13
- task: string;
14
- prompt: string;
15
- sessionId: string;
16
- sdkSessionId?: string | null;
17
- status: WorkerStatus;
18
- startedAt: number;
19
- lastUpdateAt: number;
20
- originSessionId?: string;
21
- progress: WorkerProgressEntry[];
22
- result?: string;
23
- error?: string;
24
- metadata?: Record<string, unknown>;
25
- messageQueue: AsyncQueue<SDKUserMessage>;
26
- worktreePath?: string;
27
- branchName?: string;
28
- work_context?: string;
29
- worktree_name?: string;
30
- }
31
- export interface WorkerMessageEvent {
32
- record: WorkerRecord;
33
- messageType: 'assistant_text' | 'assistant_complete' | 'tool_call' | 'tool_result';
34
- text?: string;
35
- success?: boolean;
36
- toolName?: string;
37
- toolUseId?: string;
38
- toolInput?: unknown;
39
- toolContent?: unknown;
40
- isError?: boolean;
41
- }
4
+ import { Session, type CompleteMessageEnvelope } from './session.js';
5
+ import type { WorkerStatus } from './worker-types.js';
6
+ import type { MessageEnvelope } from '@omnara/shared-js/schemas';
7
+ export type { WorkerStatus, WorkerRecord, WorkerSessionMessageEvent } from './worker-types.js';
42
8
  interface LaunchWorkerOptions {
43
9
  task: string;
44
10
  prompt: string;
45
11
  work_context: string;
46
12
  worktree_name: string;
47
- originSessionId?: string;
13
+ originSessionId: string;
48
14
  metadata?: Record<string, unknown>;
49
15
  }
50
16
  interface WorkerManagerOptions {
51
17
  createClient: (mcpServers?: Record<string, McpServerConfig>, cwd?: string) => AgentClient;
52
- resolveSessionIdBySdk?: (sdkSessionId?: string) => string | undefined;
18
+ broadcastMessage: (msg: MessageEnvelope) => Promise<void> | void;
19
+ broadcastComplete: (complete: CompleteMessageEnvelope) => Promise<void> | void;
20
+ announceWorkerSession?: (info: {
21
+ sessionId: string;
22
+ parentSessionId?: string;
23
+ metadata?: Record<string, unknown>;
24
+ }) => Promise<void> | void;
53
25
  repoPath: string;
54
- worktreesEnabled: boolean;
55
- worktreesBaseRef?: string;
56
26
  }
57
- export declare class WorkerManager extends EventEmitter {
27
+ type Worker = {
28
+ status: WorkerStatus;
29
+ session: Session;
30
+ ai: AgentClient;
31
+ task: string;
32
+ parentSessionId: string;
33
+ worktreeName?: string;
34
+ directory: string;
35
+ startedAt: number;
36
+ lastUpdateAt: number;
37
+ };
38
+ export declare class WorkerManager {
58
39
  private readonly options;
59
- private readonly workers;
60
- private readonly runningQueries;
61
- private worktreeManager;
62
- repoPath: string;
40
+ private workers;
41
+ worktreeManager: WorktreeManager;
42
+ broadcastMessage: (msg: MessageEnvelope) => Promise<void> | void;
43
+ broadcastComplete: (complete: CompleteMessageEnvelope) => Promise<void> | void;
44
+ readonly repoPath: string;
45
+ private readonly announceWorkerSession?;
63
46
  constructor(options: WorkerManagerOptions);
64
- private initializeConfig;
65
- listWorkers(): WorkerRecord[];
66
- getWorker(id: string): WorkerRecord | undefined;
67
- getWorkerByTask(task: string): WorkerRecord | undefined;
68
- /**
69
- * Get a formatted summary of all current worker statuses for inclusion in system prompts.
70
- * Returns a string describing all active workers and their current state.
71
- */
72
- getWorkerStatusSummary(): string;
73
- launchWorker({ task, prompt, work_context, worktree_name, originSessionId, metadata }: LaunchWorkerOptions, toolUseId?: string): WorkerRecord;
74
- private createWorktreeAndRun;
75
- cancelWorker(id: string): boolean;
47
+ listWorkers(): Worker[];
48
+ getWorker(id: string): Worker | undefined;
49
+ getWorkerByTask(task: string): Worker | undefined;
50
+ cancelWorker(id: string): Promise<boolean>;
51
+ launchWorker({ task, prompt, worktree_name, originSessionId, }: LaunchWorkerOptions): Promise<Worker>;
76
52
  /**
77
53
  * Route a user message to a worker by session ID.
78
- * This is used when users send messages directly to subagent sessions from the frontend.
79
- *
80
- * @param sessionId - The session ID of the worker
81
- * @param message - The message content to send
82
- * @returns true if message was sent, false if worker not found
54
+ * Thin wrapper around enqueueMessage.
83
55
  */
84
- routeUserMessageToWorker(sessionId: string, message: string): Promise<boolean>;
56
+ userMessageWorker(sessionId: string, userId: string, message: string): Promise<boolean>;
85
57
  /**
86
58
  * Send a message to a worker (running or completed).
87
- *
88
- * @param task - The task name of the worker to message
89
- * @param message - The message content to send
90
- * @param interrupt - If true, interrupt current generation; if false, queue for next turn
91
- * @param toolUseId - Optional tool use ID to track this operation for relay forwarding
92
- * @returns true if message was sent, false if worker not found or message queue is closed
93
- */
94
- messageWorker(task: string, message: string, interrupt: boolean, toolUseId?: string): Promise<boolean>;
95
- private emitUpdate;
96
- private emitCompleted;
97
- private handleStatusUpdate;
98
- /**
99
- * Create an async iterable stream of user messages for the worker.
100
- * Yields the initial prompt, then streams any additional messages from the queue.
101
- * If initialPrompt is empty, skips the initial yield and only consumes from the queue.
102
- */
103
- private createMessageStream;
104
- private runWorker;
105
- private handleMessage;
106
- private extractAssistantText;
107
- private extractDeltaText;
108
- private extractError;
109
- private wrapPrompt;
110
- /**
111
- * Shutdown the worker manager and cleanup all resources
112
- * This should be called during application shutdown to ensure all worktrees are cleaned up
59
+ * Thin wrapper around enqueueMessage.
113
60
  */
61
+ toolMessageWorker(task: string, message: string): Promise<boolean>;
114
62
  shutdown(): Promise<void>;
115
- /**
116
- * Get the WorktreeManager instance
117
- * @returns The WorktreeManager instance
118
- */
119
- getWorktreeManager(): WorktreeManager;
63
+ private onComplete;
64
+ onMessage(id: string, msg: MessageEnvelope): Promise<void>;
65
+ private commitWorkerChanges;
120
66
  }
121
- export {};
@@ -0,0 +1,23 @@
1
+ import type { MessageEnvelope } from '@omnara/shared-js/schemas';
2
+ import type { Session } from './session.js';
3
+ export type WorkerStatus = 'running' | 'completed' | 'error' | 'canceled';
4
+ export interface WorkerRecord {
5
+ id: string;
6
+ task: string;
7
+ prompt: string;
8
+ sdkSessionId?: string | null;
9
+ status: WorkerStatus;
10
+ startedAt: number;
11
+ lastUpdateAt: number;
12
+ originSessionId?: string;
13
+ result?: string;
14
+ error?: string;
15
+ metadata?: Record<string, unknown>;
16
+ session?: Session;
17
+ worktreePath?: string;
18
+ worktreeName?: string;
19
+ }
20
+ export interface WorkerSessionMessageEvent {
21
+ record: WorkerRecord;
22
+ message: MessageEnvelope;
23
+ }
@@ -39,10 +39,9 @@ export declare class RelayBridge extends EventEmitter {
39
39
  private ensureUserSession;
40
40
  private sendPrimarySessionInit;
41
41
  private sendFrame;
42
+ private handleOutboundControl;
42
43
  private handleWebsocketLifecycle;
43
- private handleOutbound;
44
44
  private handleInbound;
45
- private toRelayFrame;
46
45
  private tryHandleControlMessage;
47
46
  private tryHandleMessageEnvelope;
48
47
  private handleSessionBootstrap;
@@ -54,16 +53,9 @@ export declare class RelayBridge extends EventEmitter {
54
53
  private handleRelayRequest;
55
54
  private handleMessageEnvelope;
56
55
  private isTextContent;
57
- private buildUserTextEnvelope;
58
- private buildTextEnvelope;
59
- private buildToolCallEnvelope;
60
- private normalizeToolArguments;
61
- private buildToolResultEnvelope;
62
- private buildAgentCompleteEnvelope;
63
- private buildProgressEnvelope;
64
- private buildEnvelope;
65
56
  private isMessageEnvelope;
66
57
  private enqueue;
58
+ private sendSessionInitControl;
67
59
  private flushQueue;
68
60
  private startPingTimer;
69
61
  private clearLoginWait;
@@ -32,18 +32,28 @@ export declare function getLogLevel(): LogLevel;
32
32
  export interface Logger extends Console {
33
33
  important(...args: unknown[]): void;
34
34
  success(...args: unknown[]): void;
35
+ close?(): Promise<void>;
35
36
  }
36
37
  /**
37
38
  * Creates a controlled logger instance
38
39
  */
40
+ type LogSink = (entry: {
41
+ line: string;
42
+ raw: unknown[];
43
+ }) => void;
39
44
  export declare class ControlledLogger implements Logger {
40
45
  private logLevel;
41
46
  private forceOutput;
42
47
  private _console;
48
+ private sinks;
49
+ private closers;
50
+ private formatLine;
43
51
  Console: typeof console.Console;
44
52
  constructor(options?: {
45
53
  logLevel?: LogLevel;
46
54
  forceOutput?: boolean;
55
+ sinks?: LogSink[];
56
+ closers?: Array<() => Promise<void> | void>;
47
57
  });
48
58
  /**
49
59
  * Standard log output (INFO level)
@@ -78,10 +88,12 @@ export declare class ControlledLogger implements Logger {
78
88
  * Success messages that should typically be shown
79
89
  */
80
90
  success(...args: unknown[]): void;
91
+ close(): Promise<void>;
81
92
  /**
82
93
  * Check if a message should be logged at the given level
83
94
  */
84
95
  private shouldLog;
96
+ private write;
85
97
  /**
86
98
  * Update the log level dynamically
87
99
  */
@@ -117,6 +129,8 @@ export declare const logger: ControlledLogger;
117
129
  export declare function createLogger(componentName?: string, options?: {
118
130
  logLevel?: LogLevel;
119
131
  forceOutput?: boolean;
132
+ sinks?: LogSink[];
133
+ closers?: Array<() => Promise<void> | void>;
120
134
  }): Logger;
121
135
  /**
122
136
  * Helper to extract error messages consistently
@@ -126,3 +140,4 @@ export declare function extractErrorMessage(error: unknown): string;
126
140
  * Print current logger configuration (useful for debugging)
127
141
  */
128
142
  export declare function printLoggerConfig(): void;
143
+ export {};
package/instrument.mjs ADDED
@@ -0,0 +1,14 @@
1
+ import * as Sentry from '@sentry/node';
2
+
3
+ const DEFAULT_DSN =
4
+ 'https://ad24dca67a2ab987c433aba53f738743@o4509630021828608.ingest.us.sentry.io/4510413097467904';
5
+
6
+ const dsn = process.env.OMNARA_SENTRY_DSN ?? process.env.SENTRY_DSN ?? DEFAULT_DSN;
7
+
8
+ if (dsn) {
9
+ Sentry.init({
10
+ dsn,
11
+ environment: process.env.OMNARA_ENV ?? process.env.NODE_ENV ?? 'production',
12
+ sendDefaultPii: false,
13
+ });
14
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "omnara",
3
- "version": "0.2.3",
3
+ "version": "0.3.0",
4
4
  "type": "module",
5
5
  "description": "Command-line interface for Omnara.",
6
6
  "main": "dist/cli.js",
@@ -23,6 +23,7 @@
23
23
  "files": [
24
24
  "dist",
25
25
  "bin",
26
+ "instrument.mjs",
26
27
  "scripts",
27
28
  "README.md"
28
29
  ],
@@ -30,6 +31,7 @@
30
31
  "@anthropic-ai/claude-agent-sdk": "^0.1.42",
31
32
  "@anthropic-ai/sdk": "^0.67.0",
32
33
  "@modelcontextprotocol/sdk": "^1.20.1",
34
+ "@sentry/node": "^10.26.0",
33
35
  "@supabase/supabase-js": "^2.76.1",
34
36
  "@types/glob": "^8.1.0",
35
37
  "ajv": "^8.17.1",
@@ -48,6 +50,7 @@
48
50
  "@types/ws": "^8.18.1",
49
51
  "@typescript-eslint/eslint-plugin": "^8.46.2",
50
52
  "@typescript-eslint/parser": "^8.46.2",
53
+ "@vitest/ui": "^2.1.8",
51
54
  "esbuild": "^0.25.12",
52
55
  "eslint": "^9.38.0",
53
56
  "eslint-formatter-unix": "^8.40.0",
@@ -55,7 +58,8 @@
55
58
  "prettier": "^3.6.2",
56
59
  "tsx": "^4.7.0",
57
60
  "typescript": "^5.4.0",
58
- "typescript-eslint": "^8.46.2"
61
+ "typescript-eslint": "^8.46.2",
62
+ "vitest": "^2.1.8"
59
63
  },
60
64
  "engines": {
61
65
  "node": ">=20"
@@ -122,4 +122,3 @@ console.log(' 2. Pack: npm pack');
122
122
  console.log(' 3. Install: npm install -g omnara-0.1.4.tgz');
123
123
  console.log(' 4. Verify: omnara --version');
124
124
  console.log('='.repeat(60));
125
-
@@ -1,24 +0,0 @@
1
- import fs from 'node:fs';
2
- import { ControlledLogger, LogLevel } from '../utils/logger.js';
3
- export declare class FileBackedLogger extends ControlledLogger {
4
- private readonly stream;
5
- private closed;
6
- constructor(stream: fs.WriteStream, options?: {
7
- logLevel?: LogLevel;
8
- forceOutput?: boolean;
9
- });
10
- log(...args: unknown[]): void;
11
- info(...args: unknown[]): void;
12
- debug(...args: unknown[]): void;
13
- warn(...args: unknown[]): void;
14
- error(...args: unknown[]): void;
15
- trace(...args: unknown[]): void;
16
- important(...args: unknown[]): void;
17
- success(...args: unknown[]): void;
18
- close(): Promise<void>;
19
- private writeLine;
20
- }
21
- export declare function createDaemonFileLogger(): Promise<{
22
- logger: FileBackedLogger;
23
- logPath: string;
24
- }>;
@@ -1,10 +0,0 @@
1
- import fs from 'node:fs';
2
- export interface SessionLogHandle {
3
- stream: fs.WriteStream;
4
- logPath: string;
5
- }
6
- export declare function createSessionLog(handle: {
7
- workspaceId: string;
8
- launchId: string;
9
- }): Promise<SessionLogHandle>;
10
- export declare function writeSessionLog(stream: fs.WriteStream, level: string, args: unknown[]): void;
@@ -1,7 +0,0 @@
1
- export interface StatusUpdateEvent {
2
- message: string;
3
- metadata?: Record<string, unknown>;
4
- timestamp: number;
5
- }
6
- export type StatusUpdateCallback = (event: StatusUpdateEvent) => void;
7
- export declare function createWorkerStatusMcpServer(onStatusUpdate: StatusUpdateCallback): import("@anthropic-ai/claude-agent-sdk").McpSdkServerConfigWithInstance;
@@ -1,26 +0,0 @@
1
- /**
2
- * A simple async queue for streaming messages to workers.
3
- * Allows pushing messages and consuming them via async iteration.
4
- */
5
- export declare class AsyncQueue<T> {
6
- private queue;
7
- private resolvers;
8
- private closed;
9
- /**
10
- * Push a new item to the queue.
11
- * If there are waiting consumers, resolve them immediately.
12
- */
13
- push(item: T): void;
14
- /**
15
- * Close the queue, signaling that no more items will be added.
16
- */
17
- close(): void;
18
- /**
19
- * Check if the queue is closed.
20
- */
21
- isClosed(): boolean;
22
- /**
23
- * Async iterator implementation for consuming items from the queue.
24
- */
25
- [Symbol.asyncIterator](): AsyncIterator<T>;
26
- }