omnara 0.1.4 → 0.1.5

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 (80) hide show
  1. package/dist/cli.js +5945 -50
  2. package/dist/cli.js.map +7 -1
  3. package/dist/orchestrator/agent-orchestrator.d.ts +4 -1
  4. package/dist/orchestrator/orchestrator-prompt.d.ts +8 -2
  5. package/dist/orchestrator/{types.d.ts → orchestrator-types.d.ts} +14 -0
  6. package/dist/orchestrator/session.d.ts +1 -1
  7. package/dist/orchestrator/tools/worker-tools.d.ts +1 -0
  8. package/dist/orchestrator/utils/session-logger.d.ts +1 -1
  9. package/package.json +11 -5
  10. package/scripts/preinstall.js +141 -0
  11. package/scripts/test-preinstall.js +125 -0
  12. package/dist/auth/auth-provider.js +0 -56
  13. package/dist/auth/auth-provider.js.map +0 -1
  14. package/dist/auth/cli-auth-service.js +0 -44
  15. package/dist/auth/cli-auth-service.js.map +0 -1
  16. package/dist/auth/credential-manager.js +0 -71
  17. package/dist/auth/credential-manager.js.map +0 -1
  18. package/dist/auth/credentials-store.js +0 -69
  19. package/dist/auth/credentials-store.js.map +0 -1
  20. package/dist/auth/login-flow.js +0 -196
  21. package/dist/auth/login-flow.js.map +0 -1
  22. package/dist/auth/loopback-listener.js +0 -155
  23. package/dist/auth/loopback-listener.js.map +0 -1
  24. package/dist/auth/pkce.js +0 -15
  25. package/dist/auth/pkce.js.map +0 -1
  26. package/dist/auth/supabase-client.js +0 -10
  27. package/dist/auth/supabase-client.js.map +0 -1
  28. package/dist/auth/supabase-config.js +0 -21
  29. package/dist/auth/supabase-config.js.map +0 -1
  30. package/dist/commands/agent.js +0 -172
  31. package/dist/commands/agent.js.map +0 -1
  32. package/dist/commands/auth.js +0 -84
  33. package/dist/commands/auth.js.map +0 -1
  34. package/dist/commands/index.js +0 -3
  35. package/dist/commands/index.js.map +0 -1
  36. package/dist/http/api-client.js +0 -118
  37. package/dist/http/api-client.js.map +0 -1
  38. package/dist/http/user-sessions.js +0 -9
  39. package/dist/http/user-sessions.js.map +0 -1
  40. package/dist/orchestrator/agent-orchestrator.js +0 -592
  41. package/dist/orchestrator/agent-orchestrator.js.map +0 -1
  42. package/dist/orchestrator/ai-client.js +0 -77
  43. package/dist/orchestrator/ai-client.js.map +0 -1
  44. package/dist/orchestrator/orchestrator-prompt.js +0 -13
  45. package/dist/orchestrator/orchestrator-prompt.js.map +0 -1
  46. package/dist/orchestrator/session.js +0 -295
  47. package/dist/orchestrator/session.js.map +0 -1
  48. package/dist/orchestrator/tools/worker-status-tool.js +0 -41
  49. package/dist/orchestrator/tools/worker-status-tool.js.map +0 -1
  50. package/dist/orchestrator/tools/worker-tools.js +0 -149
  51. package/dist/orchestrator/tools/worker-tools.js.map +0 -1
  52. package/dist/orchestrator/types.js +0 -30
  53. package/dist/orchestrator/types.js.map +0 -1
  54. package/dist/orchestrator/utils/async-queue.js +0 -70
  55. package/dist/orchestrator/utils/async-queue.js.map +0 -1
  56. package/dist/orchestrator/utils/session-logger.js +0 -47
  57. package/dist/orchestrator/utils/session-logger.js.map +0 -1
  58. package/dist/orchestrator/worker-manager.js +0 -418
  59. package/dist/orchestrator/worker-manager.js.map +0 -1
  60. package/dist/relay/relay-bridge.js +0 -601
  61. package/dist/relay/relay-bridge.js.map +0 -1
  62. package/dist/relay/relay-service.js +0 -23
  63. package/dist/relay/relay-service.js.map +0 -1
  64. package/dist/repl/terminal-repl.js +0 -262
  65. package/dist/repl/terminal-repl.js.map +0 -1
  66. package/dist/schemas/generated.d.ts +0 -244
  67. package/dist/schemas/generated.js +0 -5
  68. package/dist/schemas/generated.js.map +0 -1
  69. package/dist/schemas/index.js +0 -2
  70. package/dist/schemas/index.js.map +0 -1
  71. package/dist/scripts/generate-schema-types.d.ts +0 -1
  72. package/dist/scripts/generate-schema-types.js +0 -53
  73. package/dist/scripts/generate-schema-types.js.map +0 -1
  74. package/dist/scripts/sync-schemas.d.ts +0 -1
  75. package/dist/scripts/sync-schemas.js +0 -28
  76. package/dist/scripts/sync-schemas.js.map +0 -1
  77. package/dist/utils/prompt.js +0 -13
  78. package/dist/utils/prompt.js.map +0 -1
  79. package/dist/voice/voice-service.js +0 -25
  80. package/dist/voice/voice-service.js.map +0 -1
@@ -1,7 +1,7 @@
1
1
  import { type AgentClient } from './ai-client.js';
2
2
  import { Session } from './session.js';
3
3
  import { WorkerManager } from './worker-manager.js';
4
- import type { InboundMessage, OutboundMessage } from './types.js';
4
+ import type { InboundMessage, OutboundMessage } from './orchestrator-types.js';
5
5
  interface AgentOrchestratorDependencies {
6
6
  createMainClient?: () => AgentClient;
7
7
  createWorkerClient?: () => AgentClient;
@@ -23,11 +23,14 @@ export declare class AgentOrchestrator {
23
23
  private readonly sessions;
24
24
  private readonly clients;
25
25
  private readonly toolUseMap;
26
+ private mainCodingSessionId;
27
+ readonly voiceSessionIds: Set<string>;
26
28
  private started;
27
29
  constructor(dependencies?: AgentOrchestratorDependencies);
28
30
  ensureSessionExists(sessionId: string): Session;
29
31
  getSession(sessionId: string): Session | undefined;
30
32
  getWorkerManager(): WorkerManager;
33
+ setMainCodingSessionId(sessionId: string): void;
31
34
  addClient(adapter: AgentOrchestratorClientAdapter): AgentOrchestratorConnection;
32
35
  start(): Promise<void>;
33
36
  stop(): Promise<void>;
@@ -1,2 +1,8 @@
1
- export declare const ORCHESTRATOR_SYSTEM_PROMPT: string;
2
- export default ORCHESTRATOR_SYSTEM_PROMPT;
1
+ /**
2
+ * System prompt for the main orchestrator agent.
3
+ *
4
+ * The orchestrator's role is to coordinate and delegate work, not to execute tasks directly.
5
+ * It should ALWAYS use workers to handle all implementation work.
6
+ */
7
+ import ORCHESTRATOR_SYSTEM_PROMPT from './orchestrator-prompt.md';
8
+ export { ORCHESTRATOR_SYSTEM_PROMPT };
@@ -1,16 +1,30 @@
1
+ /**
2
+ * Internal orchestrator message types for communication between components
3
+ * These are NOT wire protocol types - they're internal to the orchestrator
4
+ *
5
+ * For wire protocol types (sent over WebSocket), use:
6
+ * - ControlMessage from @omnara/shared-js/schemas
7
+ * - MessageEnvelope from @omnara/shared-js/schemas
8
+ */
1
9
  import { z } from 'zod';
2
10
  export declare const inboundMessageSchema: z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
3
11
  type: z.ZodLiteral<"chat">;
4
12
  sessionId: z.ZodOptional<z.ZodString>;
5
13
  text: z.ZodString;
14
+ senderId: z.ZodOptional<z.ZodString>;
15
+ senderKind: z.ZodOptional<z.ZodEnum<["user", "agent_session"]>>;
6
16
  }, "strip", z.ZodTypeAny, {
7
17
  type: "chat";
8
18
  text: string;
9
19
  sessionId?: string | undefined;
20
+ senderId?: string | undefined;
21
+ senderKind?: "user" | "agent_session" | undefined;
10
22
  }, {
11
23
  type: "chat";
12
24
  text: string;
13
25
  sessionId?: string | undefined;
26
+ senderId?: string | undefined;
27
+ senderKind?: "user" | "agent_session" | undefined;
14
28
  }>, z.ZodObject<{
15
29
  type: z.ZodLiteral<"session_init">;
16
30
  sessionId: z.ZodString;
@@ -1,5 +1,5 @@
1
1
  import type { AgentClient } from './ai-client.js';
2
- import type { SessionSubscriber } from './types.js';
2
+ import type { SessionSubscriber } from './orchestrator-types.js';
3
3
  type StreamEvent = {
4
4
  type: string;
5
5
  [key: string]: unknown;
@@ -2,6 +2,7 @@ import type { WorkerManager } from '../worker-manager.js';
2
2
  interface WorkerMcpContext {
3
3
  resolveSessionIdBySdk: (sdkSessionId?: string) => string | undefined;
4
4
  resolveSessionIdByToolUse: (toolUseId: string) => string | undefined;
5
+ getMainCodingSessionId: () => string | null;
5
6
  }
6
7
  export declare function createWorkerMcpServer(workerManager: WorkerManager, context: WorkerMcpContext): import("@anthropic-ai/claude-agent-sdk").McpSdkServerConfigWithInstance;
7
8
  export {};
@@ -1,4 +1,4 @@
1
- import type { OutboundMessage } from '../types.js';
1
+ import type { OutboundMessage } from '../orchestrator-types.js';
2
2
  export type SessionLogger = {
3
3
  logInbound: (payload: unknown) => void;
4
4
  logOutbound: (message: OutboundMessage) => void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "omnara",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "type": "module",
5
5
  "description": "Command-line interface for Omnara.",
6
6
  "main": "dist/cli.js",
@@ -9,11 +9,13 @@
9
9
  "omnara": "./bin/omnara.js"
10
10
  },
11
11
  "scripts": {
12
- "build": "tsc --project tsconfig.json && npm run copy-assets",
13
- "copy-assets": "cp -r src/orchestrator/*.md dist/orchestrator/",
12
+ "build": "npm run build:types && node build.mjs && npm run copy-assets",
13
+ "build:types": "tsc --emitDeclarationOnly --project tsconfig.json",
14
+ "copy-assets": "mkdir -p dist/orchestrator && cp -r src/orchestrator/*.md dist/orchestrator/",
15
+ "preinstall": "node scripts/preinstall.js",
14
16
  "dev": "tsx watch src/cli.ts",
15
17
  "test": "tsx --test \"tests/**/*.ts\" \"tests/*.ts\"",
16
- "typecheck": "tsc -p tsconfig.test.json",
18
+ "typecheck": "tsc --noEmit",
17
19
  "lint": "eslint --format unix \"src/**/*.ts\" \"tests/**/*.ts\"",
18
20
  "lint:fix": "eslint --format unix --fix \"src/**/*.ts\" \"tests/**/*.ts\"",
19
21
  "format": "prettier --check \"src/**/*.ts\" \"tests/**/*.ts\"",
@@ -31,23 +33,27 @@
31
33
  "files": [
32
34
  "dist",
33
35
  "bin",
36
+ "scripts",
34
37
  "README.md"
35
38
  ],
36
39
  "dependencies": {
37
40
  "@anthropic-ai/claude-agent-sdk": "^0.1.23",
38
41
  "@anthropic-ai/sdk": "^0.67.0",
39
42
  "@modelcontextprotocol/sdk": "^1.20.1",
40
- "@omnara/shared-js": "file:../shared-js",
41
43
  "@supabase/supabase-js": "^2.76.1",
44
+ "ajv": "^8.17.1",
45
+ "ajv-formats": "^2.1.1",
42
46
  "commander": "^11.1.0",
43
47
  "ws": "^8.18.3",
44
48
  "zod": "^3.25.76"
45
49
  },
46
50
  "devDependencies": {
51
+ "@omnara/shared-js": "file:../shared-js",
47
52
  "@types/node": "^20.11.30",
48
53
  "@types/ws": "^8.18.1",
49
54
  "@typescript-eslint/eslint-plugin": "^8.46.2",
50
55
  "@typescript-eslint/parser": "^8.46.2",
56
+ "esbuild": "^0.25.12",
51
57
  "eslint": "^9.38.0",
52
58
  "eslint-formatter-unix": "^8.40.0",
53
59
  "json-schema-to-typescript": "^14.0.1",
@@ -0,0 +1,141 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { execSync } from 'child_process';
4
+
5
+ /**
6
+ * Preinstall script to uninstall old omnara packages (pip and brew).
7
+ * This ensures a clean migration to the npm package.
8
+ */
9
+
10
+ function log(message) {
11
+ console.log(`[omnara preinstall] ${message}`);
12
+ }
13
+
14
+ function checkPipCommand() {
15
+ const pipCommands = ['pip3', 'pip'];
16
+
17
+ for (const cmd of pipCommands) {
18
+ try {
19
+ execSync(`${cmd} --version`, { stdio: 'ignore' });
20
+ return cmd;
21
+ } catch {
22
+ // Command not found, try next
23
+ }
24
+ }
25
+
26
+ return null;
27
+ }
28
+
29
+ function isPipPackageInstalled(pipCommand) {
30
+ try {
31
+ execSync(`${pipCommand} show omnara`, { stdio: 'ignore' });
32
+ return true;
33
+ } catch {
34
+ return false;
35
+ }
36
+ }
37
+
38
+ function uninstallPipPackage(pipCommand) {
39
+ try {
40
+ log(`Detected old omnara pip package in ${pipCommand}. Uninstalling...`);
41
+
42
+ // Try without sudo first
43
+ try {
44
+ execSync(`${pipCommand} uninstall -y omnara`, { stdio: 'inherit' });
45
+ log(`Successfully uninstalled old omnara pip package from ${pipCommand}.`);
46
+ return true;
47
+ } catch (firstError) {
48
+ // If that fails, try with sudo
49
+ log('Permission denied. Attempting with sudo...');
50
+ try {
51
+ execSync(`sudo ${pipCommand} uninstall -y omnara`, { stdio: 'inherit' });
52
+ log(`Successfully uninstalled old omnara pip package from ${pipCommand} (with sudo).`);
53
+ return true;
54
+ } catch (sudoError) {
55
+ throw sudoError;
56
+ }
57
+ }
58
+ } catch (error) {
59
+ log(`Warning: Failed to uninstall pip package from ${pipCommand}: ${error.message}`);
60
+ log('You may need to manually run: sudo ' + pipCommand + ' uninstall omnara');
61
+ return false;
62
+ }
63
+ }
64
+
65
+ function checkBrewCommand() {
66
+ try {
67
+ execSync('brew --version', { stdio: 'ignore' });
68
+ return true;
69
+ } catch {
70
+ return false;
71
+ }
72
+ }
73
+
74
+ function isBrewPackageInstalled() {
75
+ try {
76
+ execSync('brew list omnara', { stdio: 'ignore' });
77
+ return true;
78
+ } catch {
79
+ return false;
80
+ }
81
+ }
82
+
83
+ function uninstallBrewPackage() {
84
+ try {
85
+ log('Detected old omnara brew package. Uninstalling...');
86
+ execSync('brew uninstall omnara', { stdio: 'inherit' });
87
+ log('Successfully uninstalled old omnara brew package.');
88
+ return true;
89
+ } catch (error) {
90
+ log(`Warning: Failed to uninstall brew package: ${error.message}`);
91
+ return false;
92
+ }
93
+ }
94
+
95
+ function main() {
96
+ log('Checking for old omnara installations...');
97
+
98
+ // Check for pip packages - check BOTH pip and pip3
99
+ log('Checking for pip packages...');
100
+ const pipCommands = ['pip3', 'pip'];
101
+ let foundAnyPip = false;
102
+
103
+ for (const pipCmd of pipCommands) {
104
+ try {
105
+ execSync(`${pipCmd} --version`, { stdio: 'ignore' });
106
+ foundAnyPip = true;
107
+ log(`Found ${pipCmd} command`);
108
+
109
+ if (isPipPackageInstalled(pipCmd)) {
110
+ uninstallPipPackage(pipCmd);
111
+ } else {
112
+ log(`No old omnara package found in ${pipCmd}.`);
113
+ }
114
+ } catch {
115
+ // Command not found, skip
116
+ }
117
+ }
118
+
119
+ if (!foundAnyPip) {
120
+ log('pip/pip3 not found. Skipping pip package check.');
121
+ }
122
+
123
+ // Check for brew package
124
+ log('Checking for brew package...');
125
+ if (!checkBrewCommand()) {
126
+ log('brew not found. Skipping brew package check.');
127
+ } else {
128
+ log('Found brew command');
129
+
130
+ if (isBrewPackageInstalled()) {
131
+ uninstallBrewPackage();
132
+ } else {
133
+ log('No old brew package found.');
134
+ }
135
+ }
136
+
137
+ log('Package check complete. Continuing with installation.');
138
+ }
139
+
140
+ main();
141
+
@@ -0,0 +1,125 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Test script for preinstall.js
5
+ * This simulates various scenarios to ensure the preinstall script works correctly.
6
+ */
7
+
8
+ import { execSync } from 'child_process';
9
+ import { readFileSync } from 'fs';
10
+
11
+ console.log('='.repeat(60));
12
+ console.log('Testing preinstall.js');
13
+ console.log('='.repeat(60));
14
+
15
+ // Test 0: Verify package.json configuration
16
+ console.log('\n[TEST 0] Verifying package.json configuration...');
17
+ try {
18
+ const packageJson = JSON.parse(readFileSync('package.json', 'utf8'));
19
+
20
+ // Check if preinstall script exists
21
+ if (packageJson.scripts?.preinstall) {
22
+ console.log('✅ preinstall script found in package.json');
23
+ console.log(` Command: ${packageJson.scripts.preinstall}`);
24
+ } else {
25
+ console.error('❌ preinstall script NOT found in package.json');
26
+ process.exit(1);
27
+ }
28
+
29
+ // Check if scripts directory is included in files
30
+ if (packageJson.files?.includes('scripts')) {
31
+ console.log('✅ scripts directory included in package files');
32
+ } else {
33
+ console.error('❌ scripts directory NOT included in package files');
34
+ process.exit(1);
35
+ }
36
+ } catch (error) {
37
+ console.error('❌ Failed to read package.json:', error.message);
38
+ process.exit(1);
39
+ }
40
+
41
+ // Test 1: Check if the script runs without errors
42
+ console.log('\n[TEST 1] Running preinstall.js...');
43
+ try {
44
+ execSync('node scripts/preinstall.js', {
45
+ stdio: 'inherit',
46
+ cwd: process.cwd()
47
+ });
48
+ console.log('✅ Script executed successfully');
49
+ } catch (error) {
50
+ console.error('❌ Script failed:', error.message);
51
+ process.exit(1);
52
+ }
53
+
54
+ // Test 2: Check if pip/pip3 is available and check BOTH
55
+ console.log('\n[TEST 2] Checking pip availability...');
56
+ const pipCommands = ['pip3', 'pip'];
57
+ let pipFound = false;
58
+ for (const cmd of pipCommands) {
59
+ try {
60
+ execSync(`${cmd} --version`, { stdio: 'ignore' });
61
+ console.log(`✅ Found ${cmd}`);
62
+ pipFound = true;
63
+
64
+ // Check if omnara pip package is installed
65
+ try {
66
+ const result = execSync(`${cmd} show omnara`, { encoding: 'utf8', stdio: 'pipe' });
67
+ console.log(`⚠️ Warning: omnara pip package IS installed in ${cmd}`);
68
+ console.log(' Package info:', result.split('\n')[0]);
69
+ } catch {
70
+ console.log(`✅ No omnara pip package found in ${cmd} (good)`);
71
+ }
72
+ } catch {
73
+ // Command not found
74
+ }
75
+ }
76
+ if (!pipFound) {
77
+ console.log('ℹ️ No pip/pip3 found on system');
78
+ }
79
+
80
+ // Test 3: Check if brew is available
81
+ console.log('\n[TEST 3] Checking brew availability...');
82
+ try {
83
+ execSync('brew --version', { stdio: 'ignore' });
84
+ console.log('✅ Found brew');
85
+
86
+ // Check if omnara brew package is installed
87
+ try {
88
+ execSync('brew list omnara', { stdio: 'ignore' });
89
+ console.log('⚠️ Warning: omnara brew package IS installed');
90
+ } catch {
91
+ console.log('✅ No omnara brew package found (good)');
92
+ }
93
+ } catch {
94
+ console.log('ℹ️ No brew found on system');
95
+ }
96
+
97
+ // Test 4: Verify script file permissions
98
+ console.log('\n[TEST 4] Checking script permissions...');
99
+ try {
100
+ const fs = await import('fs');
101
+ const stats = fs.statSync('scripts/preinstall.js');
102
+ const mode = (stats.mode & parseInt('777', 8)).toString(8);
103
+ console.log(`✅ Script permissions: ${mode}`);
104
+ } catch (error) {
105
+ console.error('❌ Could not check permissions:', error.message);
106
+ }
107
+
108
+ console.log('\n' + '='.repeat(60));
109
+ console.log('Test Summary:');
110
+ console.log('='.repeat(60));
111
+ console.log('✅ All tests passed! The preinstall script is ready to use.');
112
+ console.log('\nThe script will automatically run when users install with:');
113
+ console.log(' npm install -g omnara');
114
+ console.log('\nWhat the preinstall script does:');
115
+ console.log(' 1. Checks both pip3 AND pip for old omnara packages');
116
+ console.log(' 2. Checks brew for old omnara packages');
117
+ console.log(' 3. Uninstalls any found packages (using sudo if needed)');
118
+ console.log(' 4. Continues with npm installation');
119
+ console.log('\nTo test the full installation flow:');
120
+ console.log(' 1. Build: npm run build');
121
+ console.log(' 2. Pack: npm pack');
122
+ console.log(' 3. Install: npm install -g omnara-0.1.4.tgz');
123
+ console.log(' 4. Verify: omnara --version');
124
+ console.log('='.repeat(60));
125
+
@@ -1,56 +0,0 @@
1
- import { CredentialsStore } from './credentials-store.js';
2
- import { ensureAuthContext } from './credential-manager.js';
3
- import { performVerificationLogin } from './login-flow.js';
4
- import { normalizeBaseUrl } from '../http/api-client.js';
5
- export class AuthProvider {
6
- options;
7
- cached = null;
8
- backendUrl;
9
- constructor(options) {
10
- this.options = options;
11
- this.backendUrl = normalizeBaseUrl(options.backendUrl);
12
- }
13
- async getAuthContext() {
14
- const auth = await this.loadAuthContext();
15
- this.cached = auth;
16
- return auth;
17
- }
18
- async getAccessToken() {
19
- const auth = await this.getAuthContext();
20
- return auth.accessToken;
21
- }
22
- async loadAuthContext() {
23
- try {
24
- return await ensureAuthContext(this.options.store, this.backendUrl);
25
- }
26
- catch (error) {
27
- if (!shouldAttemptLogin(error)) {
28
- throw error;
29
- }
30
- this.options.logger?.log('Opening browser to authenticate…');
31
- await performVerificationLogin({
32
- backendUrlOption: this.backendUrl,
33
- frontendUrlOption: this.options.frontendUrl,
34
- store: this.options.store,
35
- });
36
- return await ensureAuthContext(this.options.store, this.backendUrl);
37
- }
38
- }
39
- }
40
- function shouldAttemptLogin(error) {
41
- if (!(error instanceof Error)) {
42
- return false;
43
- }
44
- const message = error.message.toLowerCase();
45
- return (message.includes('no credentials found') ||
46
- message.includes('run `omnara auth login` first') ||
47
- message.includes('refresh token expired') ||
48
- message.includes('refresh token unavailable') ||
49
- message.includes('access token expired'));
50
- }
51
- export async function createAuthProvider(options) {
52
- const provider = new AuthProvider(options);
53
- await provider.getAuthContext();
54
- return provider;
55
- }
56
- //# sourceMappingURL=auth-provider.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"auth-provider.js","sourceRoot":"","sources":["../../src/auth/auth-provider.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAoB,MAAM,yBAAyB,CAAC;AAC9E,OAAO,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AASzD,MAAM,OAAO,YAAY;IAIM;IAHrB,MAAM,GAAuB,IAAI,CAAC;IACzB,UAAU,CAAS;IAEpC,YAA6B,OAA4B;QAA5B,YAAO,GAAP,OAAO,CAAqB;QACvD,IAAI,CAAC,UAAU,GAAG,gBAAgB,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IACzD,CAAC;IAED,KAAK,CAAC,cAAc;QAClB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,eAAe,EAAE,CAAC;QAC1C,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACnB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,CAAC,cAAc;QAClB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,cAAc,EAAE,CAAC;QACzC,OAAO,IAAI,CAAC,WAAW,CAAC;IAC1B,CAAC;IAEO,KAAK,CAAC,eAAe;QAC3B,IAAI,CAAC;YACH,OAAO,MAAM,iBAAiB,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;QACtE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC/B,MAAM,KAAK,CAAC;YACd,CAAC;YACD,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,kCAAkC,CAAC,CAAC;YAC7D,MAAM,wBAAwB,CAAC;gBAC7B,gBAAgB,EAAE,IAAI,CAAC,UAAU;gBACjC,iBAAiB,EAAE,IAAI,CAAC,OAAO,CAAC,WAAW;gBAC3C,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,KAAK;aAC1B,CAAC,CAAC;YACH,OAAO,MAAM,iBAAiB,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;QACtE,CAAC;IACH,CAAC;CACF;AAED,SAAS,kBAAkB,CAAC,KAAc;IACxC,IAAI,CAAC,CAAC,KAAK,YAAY,KAAK,CAAC,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;IAC5C,OAAO,CACL,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAC;QACxC,OAAO,CAAC,QAAQ,CAAC,+BAA+B,CAAC;QACjD,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAAC;QACzC,OAAO,CAAC,QAAQ,CAAC,2BAA2B,CAAC;QAC7C,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAC,CACzC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,OAA4B;IACnE,MAAM,QAAQ,GAAG,IAAI,YAAY,CAAC,OAAO,CAAC,CAAC;IAC3C,MAAM,QAAQ,CAAC,cAAc,EAAE,CAAC;IAChC,OAAO,QAAQ,CAAC;AAClB,CAAC"}
@@ -1,44 +0,0 @@
1
- import { ApiClient } from '../http/api-client.js';
2
- export async function createCliAuthSession(client, options = {}) {
3
- const body = {};
4
- if (options.frontendUrl) {
5
- body.frontend_url = options.frontendUrl;
6
- }
7
- if (options.loopbackRedirectUri) {
8
- body.loopback_redirect_uri = options.loopbackRedirectUri;
9
- }
10
- if (options.loopbackState) {
11
- body.loopback_state = options.loopbackState;
12
- }
13
- if (options.pkceChallenge) {
14
- body.pkce_challenge = options.pkceChallenge;
15
- body.pkce_challenge_method = options.pkceChallengeMethod ?? 'S256';
16
- }
17
- const wire = await client.postJson('/api/v1/cli-auth/session', body);
18
- return {
19
- sessionId: wire.session_id,
20
- verificationUri: wire.verification_uri,
21
- verificationUriComplete: wire.verification_uri_complete,
22
- expiresIn: wire.expires_in,
23
- pollInterval: wire.poll_interval,
24
- };
25
- }
26
- export async function exchangeCliCode(client, sessionId, code, options = {}) {
27
- const requestBody = {
28
- session_id: sessionId,
29
- code,
30
- };
31
- if (options.codeVerifier) {
32
- requestBody.code_verifier = options.codeVerifier;
33
- }
34
- const wire = await client.postJson('/api/v1/cli-auth/exchange', requestBody);
35
- return {
36
- accessToken: wire.access_token,
37
- accessTokenExpiresIn: wire.access_token_expires_in,
38
- refreshToken: wire.refresh_token,
39
- refreshTokenExpiresIn: wire.refresh_token_expires_in,
40
- relayWsPath: wire.relay_ws_path,
41
- relayHeartbeatIntervalSec: wire.relay_heartbeat_interval_sec,
42
- };
43
- }
44
- //# sourceMappingURL=cli-auth-service.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cli-auth-service.js","sourceRoot":"","sources":["../../src/auth/cli-auth-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AA0DlD,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,MAAiB,EACjB,UAAuC,EAAE;IAEzC,MAAM,IAAI,GAA6B,EAAE,CAAC;IAC1C,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;QACxB,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC;IAC1C,CAAC;IACD,IAAI,OAAO,CAAC,mBAAmB,EAAE,CAAC;QAChC,IAAI,CAAC,qBAAqB,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAC3D,CAAC;IACD,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;QAC1B,IAAI,CAAC,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IAC9C,CAAC;IACD,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;QAC1B,IAAI,CAAC,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;QAC5C,IAAI,CAAC,qBAAqB,GAAG,OAAO,CAAC,mBAAmB,IAAI,MAAM,CAAC;IACrE,CAAC;IACD,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,QAAQ,CAChC,0BAA0B,EAC1B,IAAI,CACL,CAAC;IACF,OAAO;QACL,SAAS,EAAE,IAAI,CAAC,UAAU;QAC1B,eAAe,EAAE,IAAI,CAAC,gBAAgB;QACtC,uBAAuB,EAAE,IAAI,CAAC,yBAAyB;QACvD,SAAS,EAAE,IAAI,CAAC,UAAU;QAC1B,YAAY,EAAE,IAAI,CAAC,aAAa;KACjC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,MAAiB,EACjB,SAAiB,EACjB,IAAY,EACZ,UAAqC,EAAE;IAEvC,MAAM,WAAW,GAAwB;QACvC,UAAU,EAAE,SAAS;QACrB,IAAI;KACL,CAAC;IACF,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;QACzB,WAAW,CAAC,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;IACnD,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,QAAQ,CAChC,2BAA2B,EAC3B,WAAW,CACZ,CAAC;IACF,OAAO;QACL,WAAW,EAAE,IAAI,CAAC,YAAY;QAC9B,oBAAoB,EAAE,IAAI,CAAC,uBAAuB;QAClD,YAAY,EAAE,IAAI,CAAC,aAAa;QAChC,qBAAqB,EAAE,IAAI,CAAC,wBAAwB;QACpD,WAAW,EAAE,IAAI,CAAC,aAAa;QAC/B,yBAAyB,EAAE,IAAI,CAAC,4BAA4B;KAC7D,CAAC;AACJ,CAAC"}
@@ -1,71 +0,0 @@
1
- import { CredentialsStore } from './credentials-store.js';
2
- import { buildSupabaseClient } from './supabase-client.js';
3
- import { getSupabaseAuthConfig } from './supabase-config.js';
4
- const EXPIRY_BUFFER_MS = 60_000; // refresh tokens one minute before expiry
5
- export async function ensureAuthContext(store, backendUrl) {
6
- const credentials = await store.load();
7
- if (!credentials) {
8
- throw new Error('No credentials found. Run `omnara auth login` first.');
9
- }
10
- if (!credentials.refreshToken) {
11
- throw new Error('Refresh token unavailable. Please run `omnara auth login`.');
12
- }
13
- if (!credentials.accessToken) {
14
- return await refreshWithStoredToken(store, credentials, backendUrl, 'No access token stored.');
15
- }
16
- if (!isExpiring(credentials.accessTokenExpiresAt, EXPIRY_BUFFER_MS)) {
17
- return { credentials, accessToken: credentials.accessToken };
18
- }
19
- return await refreshWithStoredToken(store, credentials, backendUrl, 'Access token expired.');
20
- }
21
- async function refreshWithStoredToken(store, credentials, backendUrl, reason) {
22
- const refreshToken = credentials.refreshToken;
23
- if (!refreshToken) {
24
- throw new Error(`${reason} Refresh token unavailable. Please run \`omnara auth login\`.`);
25
- }
26
- if (credentials.refreshTokenExpiresAt && isExpiring(credentials.refreshTokenExpiresAt, 0)) {
27
- throw new Error('Refresh token expired. Please run `omnara auth login`.');
28
- }
29
- const supabaseConfig = await getSupabaseAuthConfig(backendUrl);
30
- const supabase = buildSupabaseClient(supabaseConfig);
31
- const { data, error } = await supabase.auth.refreshSession({ refresh_token: refreshToken });
32
- if (error || !data?.session) {
33
- throw new Error(`${reason} Failed to refresh Supabase session: ${error?.message ?? 'unknown error'}.`);
34
- }
35
- const updated = applySession(credentials, data.session);
36
- await store.save(updated);
37
- if (!updated.accessToken) {
38
- throw new Error('Supabase refresh completed without an access token.');
39
- }
40
- return { credentials: updated, accessToken: updated.accessToken };
41
- }
42
- function isExpiring(expiresAtIso, bufferMs) {
43
- if (!expiresAtIso) {
44
- return true;
45
- }
46
- const timestamp = Date.parse(expiresAtIso);
47
- if (Number.isNaN(timestamp)) {
48
- return true;
49
- }
50
- return timestamp - bufferMs <= Date.now();
51
- }
52
- function applySession(credentials, session) {
53
- const expiresAt = deriveAccessExpiry(session);
54
- return {
55
- ...credentials,
56
- accessToken: session.access_token,
57
- accessTokenExpiresAt: expiresAt,
58
- refreshToken: session.refresh_token ?? credentials.refreshToken,
59
- refreshTokenExpiresAt: credentials.refreshTokenExpiresAt,
60
- };
61
- }
62
- function deriveAccessExpiry(session) {
63
- if (session.expires_at) {
64
- return new Date(session.expires_at * 1000).toISOString();
65
- }
66
- if (session.expires_in) {
67
- return new Date(Date.now() + session.expires_in * 1000).toISOString();
68
- }
69
- return undefined;
70
- }
71
- //# sourceMappingURL=credential-manager.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"credential-manager.js","sourceRoot":"","sources":["../../src/auth/credential-manager.ts"],"names":[],"mappings":"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"}
@@ -1,69 +0,0 @@
1
- import fs from 'fs/promises';
2
- import os from 'os';
3
- import path from 'path';
4
- const DEFAULT_DIR = path.join(os.homedir(), '.omnara');
5
- export const DEFAULT_CREDENTIALS_PATH = path.join(DEFAULT_DIR, 'credentials.json');
6
- const DEFAULT_FILE_MODE = 0o600;
7
- const DEFAULT_DIR_MODE = 0o700;
8
- function isStoredCredentials(value) {
9
- return Boolean(value) && typeof value === 'object';
10
- }
11
- export class CredentialsStore {
12
- filePath;
13
- constructor(filePath = DEFAULT_CREDENTIALS_PATH) {
14
- this.filePath = filePath;
15
- }
16
- async load() {
17
- try {
18
- const raw = await fs.readFile(this.filePath, 'utf8');
19
- const parsed = JSON.parse(raw);
20
- if (!isStoredCredentials(parsed)) {
21
- throw new Error('File does not contain valid credentials data');
22
- }
23
- return parsed;
24
- }
25
- catch (error) {
26
- if (isFileNotFound(error)) {
27
- return null;
28
- }
29
- throw new Error(`Failed to read credentials from ${this.filePath}: ${extractErrorMessage(error)}`);
30
- }
31
- }
32
- async save(credentials) {
33
- const payload = {
34
- accessToken: credentials.accessToken,
35
- accessTokenExpiresAt: credentials.accessTokenExpiresAt,
36
- refreshToken: credentials.refreshToken,
37
- refreshTokenExpiresAt: credentials.refreshTokenExpiresAt,
38
- };
39
- await fs.mkdir(path.dirname(this.filePath), { recursive: true, mode: DEFAULT_DIR_MODE });
40
- const tempPath = `${this.filePath}.tmp`;
41
- const serialized = JSON.stringify(payload, null, 2);
42
- await fs.writeFile(tempPath, serialized, { mode: DEFAULT_FILE_MODE });
43
- await fs.chmod(tempPath, DEFAULT_FILE_MODE);
44
- await fs.rename(tempPath, this.filePath);
45
- }
46
- async clear() {
47
- try {
48
- await fs.unlink(this.filePath);
49
- }
50
- catch (error) {
51
- if (!isFileNotFound(error)) {
52
- throw new Error(`Failed to remove credentials file ${this.filePath}: ${extractErrorMessage(error)}`);
53
- }
54
- }
55
- }
56
- }
57
- function isFileNotFound(error) {
58
- return Boolean(error &&
59
- typeof error === 'object' &&
60
- 'code' in error &&
61
- error.code === 'ENOENT');
62
- }
63
- function extractErrorMessage(error) {
64
- if (error instanceof Error && error.message) {
65
- return error.message;
66
- }
67
- return String(error);
68
- }
69
- //# sourceMappingURL=credentials-store.js.map